11import hash from 'hash-sum'
22import path from 'path'
33import 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'
510import { 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'
813import { createRollupError } from './utils/error'
914import { resolveScript } from './script'
15+ import { transformTemplateInMain } from './template'
16+ import { isOnlyTemplateChanged } from './handleHotUpdate'
1017
11- export function transformSFCEntry (
18+ export function genSfcFacade (
1219 code : string ,
1320 filename : string ,
1421 options : Options ,
@@ -18,6 +25,8 @@ export function transformSFCEntry(
1825 filterCustomBlock : ( type : string ) => boolean ,
1926 pluginContext : TransformPluginContext
2027) {
28+ // prev descriptor is only set and used for hmr
29+ const prevDescriptor = getPrevDescriptor ( filename )
2130 const { descriptor, errors } = parse ( code , {
2231 sourceMap : true ,
2332 filename,
@@ -42,69 +51,86 @@ export function transformSFCEntry(
4251 // feature information
4352 const hasScoped = descriptor . styles . some ( ( s ) => s . scoped )
4453
54+ // script
55+ const { code : scriptCode , map } = genScriptCode (
56+ descriptor ,
57+ scopeId ,
58+ isProduction ,
59+ isServer ,
60+ options ,
61+ pluginContext
62+ )
63+
64+ // template
4565 const useInlineTemplate =
4666 ! options . hmr &&
4767 descriptor . scriptSetup &&
4868 ! ( descriptor . template && descriptor . template . src )
4969 const hasTemplateImport = descriptor . template && ! useInlineTemplate
5070
51- const templateImport = hasTemplateImport
52- ? genTemplateCode ( descriptor , scopeId , isServer )
71+ const templateCode = hasTemplateImport
72+ ? genTemplateCode ( descriptor , scopeId , options , isServer , pluginContext )
5373 : ''
5474
5575 const renderReplace = hasTemplateImport
5676 ? isServer
57- ? `script .ssrRender = ssrRender `
58- : `script .render = render `
77+ ? `_sfc_main .ssrRender = _sfc_ssrRender `
78+ : `_sfc_main .render = _sfc_render `
5979 : ''
6080
61- const scriptImport = genScriptCode (
62- descriptor ,
63- scopeId ,
64- isProduction ,
65- isServer ,
66- options ,
67- pluginContext
68- )
81+ // styles
6982 const stylesCode = genStyleCode (
7083 descriptor ,
7184 scopeId ,
7285 options . preprocessStyles ,
7386 options . vite
7487 )
88+
89+ // custom blocks
7590 const customBlocksCode = getCustomBlock ( descriptor , filterCustomBlock )
76- const output = [
77- scriptImport ,
78- templateImport ,
91+
92+ const output : string [ ] = [
93+ scriptCode ,
94+ templateCode ,
7995 stylesCode ,
8096 customBlocksCode ,
8197 renderReplace ,
8298 ]
8399 if ( hasScoped ) {
84- output . push ( `script .__scopeId = ${ JSON . stringify ( `data-v-${ scopeId } ` ) } ` )
100+ output . push ( `_sfc_main .__scopeId = ${ JSON . stringify ( `data-v-${ scopeId } ` ) } ` )
85101 }
86102 if ( ! isProduction ) {
87- output . push ( `script .__file = ${ JSON . stringify ( shortFilePath ) } ` )
103+ output . push ( `_sfc_main .__file = ${ JSON . stringify ( shortFilePath ) } ` )
88104 } else if ( options . exposeFilename ) {
89105 output . push (
90- `script .__file = ${ JSON . stringify ( path . basename ( shortFilePath ) ) } `
106+ `_sfc_main .__file = ${ JSON . stringify ( path . basename ( shortFilePath ) ) } `
91107 )
92108 }
93- output . push ( 'export default script ' )
109+ output . push ( 'export default _sfc_main ' )
94110
95111 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 ) } ` )
98117 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+ `})`
102128 )
103129 }
104130
105131 return {
106132 code : output . join ( '\n' ) ,
107- map : {
133+ map : map || {
108134 mappings : '' ,
109135 } ,
110136 }
@@ -113,22 +139,31 @@ export function transformSFCEntry(
113139function genTemplateCode (
114140 descriptor : SFCDescriptor ,
115141 id : string ,
116- isServer : boolean
142+ options : Options ,
143+ isServer : boolean ,
144+ pluginContext : PluginContext
117145) {
118146 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
123159 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 )
126162 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+ ) } `
129166 }
130-
131- return templateImport
132167}
133168
134169function genScriptCode (
@@ -139,7 +174,8 @@ function genScriptCode(
139174 options : Options ,
140175 pluginContext : TransformPluginContext
141176) {
142- let scriptImport = `const script = {}`
177+ let scriptCode = `const _sfc_main = {}`
178+ let map
143179 const script = resolveScript (
144180 descriptor ,
145181 scopeId ,
@@ -149,15 +185,25 @@ function genScriptCode(
149185 pluginContext
150186 )
151187 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,
159206 }
160- return scriptImport
161207}
162208
163209function genStyleCode (
@@ -187,7 +233,7 @@ function genStyleCode(
187233 const styleRequestWithoutModule = src + query + attrsQueryWithoutModule
188234 if ( style . module ) {
189235 if ( ! hasCSSModules ) {
190- stylesCode += `\nconst cssModules = script .__cssModules = {}`
236+ stylesCode += `\nconst cssModules = _sfc_main .__cssModules = {}`
191237 hasCSSModules = true
192238 }
193239 stylesCode += genCSSModulesCode (
@@ -220,7 +266,7 @@ function getCustomBlock(
220266 const query = `?vue&type=${ block . type } &index=${ index } ${ srcQuery } ${ attrsQuery } `
221267 const request = JSON . stringify ( src + query )
222268 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`
224270 }
225271 } )
226272
0 commit comments