@@ -14,6 +14,7 @@ import { createRollupError } from './utils/error'
14
14
import { resolveScript } from './script'
15
15
import { transformTemplateInMain } from './template'
16
16
import { isOnlyTemplateChanged } from './handleHotUpdate'
17
+ import { RawSourceMap , SourceMapConsumer , SourceMapGenerator } from 'source-map'
17
18
18
19
export async function genSfcFacade (
19
20
code : string ,
@@ -30,7 +31,6 @@ export async function genSfcFacade(
30
31
const { descriptor, errors } = parse ( code , {
31
32
sourceMap : true ,
32
33
filename,
33
- sourceRoot,
34
34
} )
35
35
setDescriptor ( filename , descriptor )
36
36
@@ -68,9 +68,17 @@ export async function genSfcFacade(
68
68
! ( descriptor . template && descriptor . template . src )
69
69
const hasTemplateImport = descriptor . template && ! useInlineTemplate
70
70
71
- const templateCode = hasTemplateImport
72
- ? genTemplateCode ( descriptor , scopeId , options , isServer , pluginContext )
73
- : ''
71
+ let templateCode = ''
72
+ let templateMap
73
+ if ( hasTemplateImport ) {
74
+ ; ( { code : templateCode , map : templateMap } = genTemplateCode (
75
+ descriptor ,
76
+ scopeId ,
77
+ options ,
78
+ isServer ,
79
+ pluginContext
80
+ ) )
81
+ }
74
82
75
83
const renderReplace = hasTemplateImport
76
84
? isServer
@@ -128,9 +136,34 @@ export async function genSfcFacade(
128
136
)
129
137
}
130
138
139
+ // if the template is inlined into the main module (indicated by the presence
140
+ // of templateMap, we need to concatenate the two source maps.
141
+ let resolvedMap = map
142
+ if ( map && templateMap ) {
143
+ const generator = SourceMapGenerator . fromSourceMap (
144
+ new SourceMapConsumer ( map )
145
+ )
146
+ const offset = scriptCode . match ( / \r ? \n / g) ?. length || 1
147
+ const templateMapConsumer = new SourceMapConsumer ( templateMap )
148
+ templateMapConsumer . eachMapping ( ( m ) => {
149
+ generator . addMapping ( {
150
+ source : m . source ,
151
+ original : { line : m . originalLine , column : m . originalColumn } ,
152
+ generated : {
153
+ line : m . generatedLine + offset ,
154
+ column : m . generatedColumn ,
155
+ } ,
156
+ } )
157
+ } )
158
+ resolvedMap = ( generator as any ) . toJSON ( )
159
+ // if this is a template only update, we will be reusing a cached version
160
+ // of the main module compile result, which has outdated sourcesContent.
161
+ resolvedMap . sourcesContent = templateMap . sourcesContent
162
+ }
163
+
131
164
return {
132
165
code : output . join ( '\n' ) ,
133
- map : map || {
166
+ map : resolvedMap || {
134
167
mappings : '' ,
135
168
} ,
136
169
}
@@ -146,6 +179,9 @@ function genTemplateCode(
146
179
const renderFnName = isServer ? 'ssrRender' : 'render'
147
180
const template = descriptor . template !
148
181
182
+ // If the template is not using pre-processor AND is not using external src,
183
+ // compile and inline it directly in the main module. When served in vite this
184
+ // saves an extra request per SFC which can improve load performance.
149
185
if ( ! template . lang && ! template . src ) {
150
186
return transformTemplateInMain (
151
187
template . content ,
@@ -160,9 +196,12 @@ function genTemplateCode(
160
196
const srcQuery = template . src ? `&src` : ``
161
197
const attrsQuery = attrsToQuery ( template . attrs , 'js' , true )
162
198
const query = `?vue&type=template${ idQuery } ${ srcQuery } ${ attrsQuery } `
163
- return `import { ${ renderFnName } as _sfc_${ renderFnName } } from ${ JSON . stringify (
164
- src + query
165
- ) } `
199
+ return {
200
+ code : `import { ${ renderFnName } as _sfc_${ renderFnName } } from ${ JSON . stringify (
201
+ src + query
202
+ ) } `,
203
+ map : undefined ,
204
+ }
166
205
}
167
206
}
168
207
@@ -173,7 +212,10 @@ async function genScriptCode(
173
212
isServer : boolean ,
174
213
options : Options ,
175
214
pluginContext : TransformPluginContext
176
- ) {
215
+ ) : Promise < {
216
+ code : string
217
+ map : RawSourceMap
218
+ } > {
177
219
let scriptCode = `const _sfc_main = {}`
178
220
let map
179
221
const script = resolveScript (
@@ -185,7 +227,8 @@ async function genScriptCode(
185
227
pluginContext
186
228
)
187
229
if ( script ) {
188
- // js or ts can be directly placed in the main module
230
+ // If the script is js/ts and has no external src, it can be directly placed
231
+ // in the main module.
189
232
if (
190
233
( ! script . lang ||
191
234
( script . lang === 'ts' && ( pluginContext as any ) . server ) ) &&
0 commit comments