Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(plugin-vue): fix sourcemap when no script block in sfc (close #8601) #8604

Merged
merged 5 commits into from Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
82 changes: 44 additions & 38 deletions packages/plugin-vue/src/main.ts
@@ -1,6 +1,6 @@
import path from 'path'
import type { SFCBlock, SFCDescriptor } from 'vue/compiler-sfc'
import type { PluginContext, SourceMap, TransformPluginContext } from 'rollup'
import type { PluginContext, TransformPluginContext } from 'rollup'
import type { RawSourceMap } from 'source-map'
import type { EncodedSourceMap as TraceEncodedSourceMap } from '@jridgewell/trace-mapping'
import { TraceMap, eachMapping } from '@jridgewell/trace-mapping'
Expand Down Expand Up @@ -46,7 +46,7 @@ export async function transformMain(
const hasScoped = descriptor.styles.some((s) => s.scoped)

// script
const { code: scriptCode, map } = await genScriptCode(
const { code: scriptCode, map: scriptMap } = await genScriptCode(
descriptor,
options,
pluginContext,
Expand All @@ -58,7 +58,7 @@ export async function transformMain(
descriptor.template && !isUseInlineTemplate(descriptor, !devServer)

let templateCode = ''
let templateMap: RawSourceMap | undefined
let templateMap: RawSourceMap | undefined = undefined
if (hasTemplateImport) {
;({ code: templateCode, map: templateMap } = await genTemplateCode(
descriptor,
Expand Down Expand Up @@ -156,40 +156,46 @@ export async function transformMain(
)
}

// if the template is inlined into the main module (indicated by the presence
// of templateMap, we need to concatenate the two source maps.
let resolvedMap = options.sourceMap ? map : undefined
if (resolvedMap && templateMap) {
const gen = fromMap(
// version property of result.map is declared as string
// but actually it is `3`
map as Omit<RawSourceMap, 'version'> as TraceEncodedSourceMap
)
const tracer = new TraceMap(
// same above
templateMap as Omit<RawSourceMap, 'version'> as TraceEncodedSourceMap
)
const offset = (scriptCode.match(/\r?\n/g)?.length ?? 0) + 1
eachMapping(tracer, (m) => {
if (m.source == null) return
addMapping(gen, {
source: m.source,
original: { line: m.originalLine, column: m.originalColumn },
generated: {
line: m.generatedLine + offset,
column: m.generatedColumn
}
let resolvedMap: RawSourceMap | undefined = undefined
if (options.sourceMap) {
if (scriptMap && templateMap) {
// if the template is inlined into the main module (indicated by the presence
// of templateMap, we need to concatenate the two source maps.

const gen = fromMap(
// version property of result.map is declared as string
// but actually it is `3`
scriptMap as Omit<RawSourceMap, 'version'> as TraceEncodedSourceMap
)
const tracer = new TraceMap(
// same above
templateMap as Omit<RawSourceMap, 'version'> as TraceEncodedSourceMap
)
const offset = (scriptCode.match(/\r?\n/g)?.length ?? 0) + 1
eachMapping(tracer, (m) => {
if (m.source == null) return
addMapping(gen, {
source: m.source,
original: { line: m.originalLine, column: m.originalColumn },
generated: {
line: m.generatedLine + offset,
column: m.generatedColumn
}
})
})
})

// same above
resolvedMap = toEncodedMap(gen) as Omit<
GenEncodedSourceMap,
'version'
> as RawSourceMap
// if this is a template only update, we will be reusing a cached version
// of the main module compile result, which has outdated sourcesContent.
resolvedMap.sourcesContent = templateMap.sourcesContent
// same above
resolvedMap = toEncodedMap(gen) as Omit<
GenEncodedSourceMap,
'version'
> as RawSourceMap
// if this is a template only update, we will be reusing a cached version
// of the main module compile result, which has outdated sourcesContent.
resolvedMap.sourcesContent = templateMap.sourcesContent
} else {
// if one of `scriptMap` and `templateMap` is empty, use the other one
resolvedMap = scriptMap ?? templateMap
}
}

if (!attachedProps.length) {
Expand Down Expand Up @@ -287,10 +293,10 @@ async function genScriptCode(
ssr: boolean
): Promise<{
code: string
map: RawSourceMap
map: RawSourceMap | undefined
}> {
let scriptCode = `const _sfc_main = {}`
let map: RawSourceMap | SourceMap | undefined
let map: RawSourceMap | undefined

const script = resolveScript(descriptor, options, ssr)
if (script) {
Expand Down Expand Up @@ -322,7 +328,7 @@ async function genScriptCode(
}
return {
code: scriptCode,
map: map as any
map
}
}

Expand Down
4 changes: 4 additions & 0 deletions playground/vue-sourcemap/Main.vue
Expand Up @@ -7,6 +7,8 @@
<SassWithImport />
<Less />
<SrcImport />
<NoScript />
<NoTemplate />
</template>

<script setup lang="ts">
Expand All @@ -17,4 +19,6 @@ import Sass from './Sass.vue'
import SassWithImport from './SassWithImport.vue'
import Less from './Less.vue'
import SrcImport from './src-import/SrcImport.vue'
import NoScript from './NoScript.vue'
import NoTemplate from './NoTemplate.vue'
</script>
3 changes: 3 additions & 0 deletions playground/vue-sourcemap/NoScript.vue
@@ -0,0 +1,3 @@
<template>
<p>&lt;no-script&gt;</p>
</template>
7 changes: 7 additions & 0 deletions playground/vue-sourcemap/NoTemplate.vue
@@ -0,0 +1,7 @@
<script>
console.log('script')
</script>

<script setup>
console.log('setup')
</script>
50 changes: 50 additions & 0 deletions playground/vue-sourcemap/__tests__/serve.spec.ts
Expand Up @@ -334,4 +334,54 @@ describe.runIf(isServe)('serve:vue-sourcemap', () => {
}
`)
})

test('no script', async () => {
const res = await page.request.get(
new URL('./NoScript.vue', page.url()).href
)
const js = await res.text()
const map = extractSourcemap(js)
expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
{
"mappings": ";;;wBACE",
"sources": [
"/root/NoScript.vue",
],
"sourcesContent": [
"<template>
<p>&lt;no-script&gt;</p>
</template>
",
],
"version": 3,
}
`)
})

test('no template', async () => {
const res = await page.request.get(
new URL('./NoTemplate.vue', page.url()).href
)
const js = await res.text()
const map = extractSourcemap(js)
expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
{
"mappings": "2IACA,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;;;;;;AAGP;AACd,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC",
"sources": [
"/root/NoTemplate.vue",
],
"sourcesContent": [
"<script>
console.log('script')
</script>

<script setup>
console.log('setup')
</script>
",
],
"version": 3,
}
`)
})
})