1
1
import hash from 'hash-sum'
2
2
import path from 'path'
3
3
import qs from 'querystring'
4
- import { parse , SFCBlock , SFCDescriptor } from '@vue/compiler-sfc'
4
+ import {
5
+ parse ,
6
+ rewriteDefault ,
7
+ SFCBlock ,
8
+ SFCDescriptor ,
9
+ } from '@vue/compiler-sfc'
5
10
import { Options } from '.'
6
- import { setDescriptor } from './utils/descriptorCache'
7
- import { TransformPluginContext } from 'rollup'
11
+ import { getPrevDescriptor , setDescriptor } from './utils/descriptorCache'
12
+ import { PluginContext , TransformPluginContext } from 'rollup'
8
13
import { createRollupError } from './utils/error'
9
14
import { resolveScript } from './script'
15
+ import { transformTemplateInMain } from './template'
16
+ import { isOnlyTemplateChanged } from './handleHotUpdate'
10
17
11
- export function transformSFCEntry (
18
+ export function genSfcFacade (
12
19
code : string ,
13
20
filename : string ,
14
21
options : Options ,
@@ -18,6 +25,8 @@ export function transformSFCEntry(
18
25
filterCustomBlock : ( type : string ) => boolean ,
19
26
pluginContext : TransformPluginContext
20
27
) {
28
+ // prev descriptor is only set and used for hmr
29
+ const prevDescriptor = getPrevDescriptor ( filename )
21
30
const { descriptor, errors } = parse ( code , {
22
31
sourceMap : true ,
23
32
filename,
@@ -42,69 +51,86 @@ export function transformSFCEntry(
42
51
// feature information
43
52
const hasScoped = descriptor . styles . some ( ( s ) => s . scoped )
44
53
54
+ // script
55
+ const { code : scriptCode , map } = genScriptCode (
56
+ descriptor ,
57
+ scopeId ,
58
+ isProduction ,
59
+ isServer ,
60
+ options ,
61
+ pluginContext
62
+ )
63
+
64
+ // template
45
65
const useInlineTemplate =
46
66
! options . hmr &&
47
67
descriptor . scriptSetup &&
48
68
! ( descriptor . template && descriptor . template . src )
49
69
const hasTemplateImport = descriptor . template && ! useInlineTemplate
50
70
51
- const templateImport = hasTemplateImport
52
- ? genTemplateCode ( descriptor , scopeId , isServer )
71
+ const templateCode = hasTemplateImport
72
+ ? genTemplateCode ( descriptor , scopeId , options , isServer , pluginContext )
53
73
: ''
54
74
55
75
const renderReplace = hasTemplateImport
56
76
? isServer
57
- ? `script .ssrRender = ssrRender `
58
- : `script .render = render `
77
+ ? `_sfc_main .ssrRender = _sfc_ssrRender `
78
+ : `_sfc_main .render = _sfc_render `
59
79
: ''
60
80
61
- const scriptImport = genScriptCode (
62
- descriptor ,
63
- scopeId ,
64
- isProduction ,
65
- isServer ,
66
- options ,
67
- pluginContext
68
- )
81
+ // styles
69
82
const stylesCode = genStyleCode (
70
83
descriptor ,
71
84
scopeId ,
72
85
options . preprocessStyles ,
73
86
options . vite
74
87
)
88
+
89
+ // custom blocks
75
90
const customBlocksCode = getCustomBlock ( descriptor , filterCustomBlock )
76
- const output = [
77
- scriptImport ,
78
- templateImport ,
91
+
92
+ const output : string [ ] = [
93
+ scriptCode ,
94
+ templateCode ,
79
95
stylesCode ,
80
96
customBlocksCode ,
81
97
renderReplace ,
82
98
]
83
99
if ( hasScoped ) {
84
- output . push ( `script .__scopeId = ${ JSON . stringify ( `data-v-${ scopeId } ` ) } ` )
100
+ output . push ( `_sfc_main .__scopeId = ${ JSON . stringify ( `data-v-${ scopeId } ` ) } ` )
85
101
}
86
102
if ( ! isProduction ) {
87
- output . push ( `script .__file = ${ JSON . stringify ( shortFilePath ) } ` )
103
+ output . push ( `_sfc_main .__file = ${ JSON . stringify ( shortFilePath ) } ` )
88
104
} else if ( options . exposeFilename ) {
89
105
output . push (
90
- `script .__file = ${ JSON . stringify ( path . basename ( shortFilePath ) ) } `
106
+ `_sfc_main .__file = ${ JSON . stringify ( path . basename ( shortFilePath ) ) } `
91
107
)
92
108
}
93
- output . push ( 'export default script ' )
109
+ output . push ( 'export default _sfc_main ' )
94
110
95
111
if ( options . hmr ) {
96
- output . push ( `script.__hmrId = ${ JSON . stringify ( scopeId ) } ` )
97
- output . push ( `__VUE_HMR_RUNTIME__.createRecord(script.__hmrId, script)` )
112
+ // check if the template is the only thing that changed
113
+ if ( prevDescriptor && isOnlyTemplateChanged ( prevDescriptor , descriptor ) ) {
114
+ output . push ( `export const _rerender_only = true` )
115
+ }
116
+ output . push ( `_sfc_main.__hmrId = ${ JSON . stringify ( scopeId ) } ` )
98
117
output . push (
99
- `import.meta.hot.accept(({ default: script }) => {
100
- __VUE_HMR_RUNTIME__.reload(script.__hmrId, script)
101
- })`
118
+ `__VUE_HMR_RUNTIME__.createRecord(_sfc_main.__hmrId, _sfc_main)`
119
+ )
120
+ output . push (
121
+ `import.meta.hot.accept(({ default: updated, _rerender_only }) => {` ,
122
+ ` if (_rerender_only) {` ,
123
+ ` __VUE_HMR_RUNTIME__.rerender(updated.__hmrId, updated.render)` ,
124
+ ` } else {` ,
125
+ ` __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated)` ,
126
+ ` }` ,
127
+ `})`
102
128
)
103
129
}
104
130
105
131
return {
106
132
code : output . join ( '\n' ) ,
107
- map : {
133
+ map : map || {
108
134
mappings : '' ,
109
135
} ,
110
136
}
@@ -113,22 +139,31 @@ export function transformSFCEntry(
113
139
function genTemplateCode (
114
140
descriptor : SFCDescriptor ,
115
141
id : string ,
116
- isServer : boolean
142
+ options : Options ,
143
+ isServer : boolean ,
144
+ pluginContext : PluginContext
117
145
) {
118
146
const renderFnName = isServer ? 'ssrRender' : 'render'
119
- let templateImport = `const ${ renderFnName } = () => {}`
120
- let templateRequest
121
- if ( descriptor . template ) {
122
- const src = descriptor . template . src || descriptor . filename
147
+ const template = descriptor . template !
148
+
149
+ if ( ! template . lang && ! template . src ) {
150
+ return transformTemplateInMain (
151
+ template . content ,
152
+ descriptor ,
153
+ id ,
154
+ options ,
155
+ pluginContext
156
+ )
157
+ } else {
158
+ const src = template . src || descriptor . filename
123
159
const idQuery = `&id=${ id } `
124
- const srcQuery = descriptor . template . src ? `&src` : ``
125
- const attrsQuery = attrsToQuery ( descriptor . template . attrs , 'js' , true )
160
+ const srcQuery = template . src ? `&src` : ``
161
+ const attrsQuery = attrsToQuery ( template . attrs , 'js' , true )
126
162
const query = `?vue&type=template${ idQuery } ${ srcQuery } ${ attrsQuery } `
127
- templateRequest = JSON . stringify ( src + query )
128
- templateImport = `import { ${ renderFnName } } from ${ templateRequest } `
163
+ return `import { ${ renderFnName } as _sfc_${ renderFnName } } from ${ JSON . stringify (
164
+ src + query
165
+ ) } `
129
166
}
130
-
131
- return templateImport
132
167
}
133
168
134
169
function genScriptCode (
@@ -139,7 +174,8 @@ function genScriptCode(
139
174
options : Options ,
140
175
pluginContext : TransformPluginContext
141
176
) {
142
- let scriptImport = `const script = {}`
177
+ let scriptCode = `const _sfc_main = {}`
178
+ let map
143
179
const script = resolveScript (
144
180
descriptor ,
145
181
scopeId ,
@@ -149,15 +185,25 @@ function genScriptCode(
149
185
pluginContext
150
186
)
151
187
if ( script ) {
152
- const src = script . src || descriptor . filename
153
- const attrsQuery = attrsToQuery ( script . attrs , 'js' )
154
- const srcQuery = script . src ? `&src` : ``
155
- const query = `?vue&type=script${ srcQuery } ${ attrsQuery } `
156
- const scriptRequest = JSON . stringify ( src + query )
157
- scriptImport =
158
- `import script from ${ scriptRequest } \n` + `export * from ${ scriptRequest } ` // support named exports
188
+ // js or ts can be directly placed in the main module
189
+ if ( ( ! script . lang || script . lang === 'ts' ) && ! script . src ) {
190
+ scriptCode = rewriteDefault ( script . content , `_sfc_main` )
191
+ map = script . map
192
+ } else {
193
+ const src = script . src || descriptor . filename
194
+ const attrsQuery = attrsToQuery ( script . attrs , 'js' )
195
+ const srcQuery = script . src ? `&src` : ``
196
+ const query = `?vue&type=script${ srcQuery } ${ attrsQuery } `
197
+ const scriptRequest = JSON . stringify ( src + query )
198
+ scriptCode =
199
+ `import _sfc_main from ${ scriptRequest } \n` +
200
+ `export * from ${ scriptRequest } ` // support named exports
201
+ }
202
+ }
203
+ return {
204
+ code : scriptCode ,
205
+ map,
159
206
}
160
- return scriptImport
161
207
}
162
208
163
209
function genStyleCode (
@@ -187,7 +233,7 @@ function genStyleCode(
187
233
const styleRequestWithoutModule = src + query + attrsQueryWithoutModule
188
234
if ( style . module ) {
189
235
if ( ! hasCSSModules ) {
190
- stylesCode += `\nconst cssModules = script .__cssModules = {}`
236
+ stylesCode += `\nconst cssModules = _sfc_main .__cssModules = {}`
191
237
hasCSSModules = true
192
238
}
193
239
stylesCode += genCSSModulesCode (
@@ -220,7 +266,7 @@ function getCustomBlock(
220
266
const query = `?vue&type=${ block . type } &index=${ index } ${ srcQuery } ${ attrsQuery } `
221
267
const request = JSON . stringify ( src + query )
222
268
code += `import block${ index } from ${ request } \n`
223
- code += `if (typeof block${ index } === 'function') block${ index } (script )\n`
269
+ code += `if (typeof block${ index } === 'function') block${ index } (_sfc_main )\n`
224
270
}
225
271
} )
226
272
0 commit comments