mirror of https://github.com/vuejs/core.git
refactor(compiler-sfc): split normal script logic
This commit is contained in:
parent
3da1bb36b1
commit
ae5a9323b7
|
@ -1,4 +1,3 @@
|
||||||
import MagicString from 'magic-string'
|
|
||||||
import {
|
import {
|
||||||
BindingTypes,
|
BindingTypes,
|
||||||
UNREF,
|
UNREF,
|
||||||
|
@ -23,13 +22,12 @@ import {
|
||||||
import { walk } from 'estree-walker'
|
import { walk } from 'estree-walker'
|
||||||
import { RawSourceMap } from 'source-map-js'
|
import { RawSourceMap } from 'source-map-js'
|
||||||
import {
|
import {
|
||||||
CSS_VARS_HELPER,
|
processNormalScript,
|
||||||
genCssVarsCode,
|
normalScriptDefaultVar
|
||||||
genNormalScriptCssVarsCode
|
} from './script/normalScript'
|
||||||
} from './style/cssVars'
|
import { CSS_VARS_HELPER, genCssVarsCode } from './style/cssVars'
|
||||||
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
|
||||||
import { warnOnce } from './warn'
|
import { warnOnce } from './warn'
|
||||||
import { rewriteDefaultAST } from './rewriteDefault'
|
|
||||||
import { shouldTransform, transformAST } from '@vue/reactivity-transform'
|
import { shouldTransform, transformAST } from '@vue/reactivity-transform'
|
||||||
import { transformDestructuredProps } from './script/definePropsDestructure'
|
import { transformDestructuredProps } from './script/definePropsDestructure'
|
||||||
import { ScriptCompileContext } from './script/context'
|
import { ScriptCompileContext } from './script/context'
|
||||||
|
@ -130,15 +128,6 @@ export function compileScript(
|
||||||
sfc: SFCDescriptor,
|
sfc: SFCDescriptor,
|
||||||
options: SFCScriptCompileOptions
|
options: SFCScriptCompileOptions
|
||||||
): SFCScriptBlock {
|
): SFCScriptBlock {
|
||||||
let { script, scriptSetup, source, filename } = sfc
|
|
||||||
// feature flags
|
|
||||||
// TODO remove in 3.4
|
|
||||||
const enableReactivityTransform = !!options.reactivityTransform
|
|
||||||
const isProd = !!options.isProd
|
|
||||||
const genSourceMap = options.sourceMap !== false
|
|
||||||
const hoistStatic = options.hoistStatic !== false && !script
|
|
||||||
let refBindings: string[] | undefined
|
|
||||||
|
|
||||||
if (!options.id) {
|
if (!options.id) {
|
||||||
warnOnce(
|
warnOnce(
|
||||||
`compileScript now requires passing the \`id\` option.\n` +
|
`compileScript now requires passing the \`id\` option.\n` +
|
||||||
|
@ -147,85 +136,23 @@ export function compileScript(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ctx = new ScriptCompileContext(sfc, options)
|
||||||
|
const { script, scriptSetup, source, filename } = sfc
|
||||||
|
const hoistStatic = options.hoistStatic !== false && !script
|
||||||
const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
|
const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
|
||||||
const cssVars = sfc.cssVars
|
|
||||||
const scriptLang = script && script.lang
|
const scriptLang = script && script.lang
|
||||||
const scriptSetupLang = scriptSetup && scriptSetup.lang
|
const scriptSetupLang = scriptSetup && scriptSetup.lang
|
||||||
const genDefaultAs = options.genDefaultAs
|
|
||||||
? `const ${options.genDefaultAs} =`
|
|
||||||
: `export default`
|
|
||||||
const normalScriptDefaultVar = `__default__`
|
|
||||||
|
|
||||||
const ctx = new ScriptCompileContext(sfc, options)
|
// TODO remove in 3.4
|
||||||
const { isTS } = ctx
|
const enableReactivityTransform = !!options.reactivityTransform
|
||||||
|
let refBindings: string[] | undefined
|
||||||
|
|
||||||
if (!scriptSetup) {
|
if (!scriptSetup) {
|
||||||
if (!script) {
|
if (!script) {
|
||||||
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
|
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
|
||||||
}
|
}
|
||||||
if (scriptLang && !ctx.isJS && !ctx.isTS) {
|
|
||||||
// do not process non js/ts script blocks
|
|
||||||
return script
|
|
||||||
}
|
|
||||||
// normal <script> only
|
// normal <script> only
|
||||||
try {
|
return processNormalScript(ctx, scopeId)
|
||||||
let content = script.content
|
|
||||||
let map = script.map
|
|
||||||
const scriptAst = ctx.scriptAst!
|
|
||||||
const bindings = analyzeScriptBindings(scriptAst.body)
|
|
||||||
if (enableReactivityTransform && shouldTransform(content)) {
|
|
||||||
const s = new MagicString(source)
|
|
||||||
const startOffset = script.loc.start.offset
|
|
||||||
const endOffset = script.loc.end.offset
|
|
||||||
const { importedHelpers } = transformAST(scriptAst, s, startOffset)
|
|
||||||
if (importedHelpers.length) {
|
|
||||||
s.prepend(
|
|
||||||
`import { ${importedHelpers
|
|
||||||
.map(h => `${h} as _${h}`)
|
|
||||||
.join(', ')} } from 'vue'\n`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
s.remove(0, startOffset)
|
|
||||||
s.remove(endOffset, source.length)
|
|
||||||
content = s.toString()
|
|
||||||
if (genSourceMap) {
|
|
||||||
map = s.generateMap({
|
|
||||||
source: filename,
|
|
||||||
hires: true,
|
|
||||||
includeContent: true
|
|
||||||
}) as unknown as RawSourceMap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cssVars.length || options.genDefaultAs) {
|
|
||||||
const defaultVar = options.genDefaultAs || normalScriptDefaultVar
|
|
||||||
const s = new MagicString(content)
|
|
||||||
rewriteDefaultAST(ctx.scriptAst!.body, s, defaultVar)
|
|
||||||
content = s.toString()
|
|
||||||
if (cssVars.length) {
|
|
||||||
content += genNormalScriptCssVarsCode(
|
|
||||||
cssVars,
|
|
||||||
bindings,
|
|
||||||
scopeId,
|
|
||||||
isProd,
|
|
||||||
defaultVar
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (!options.genDefaultAs) {
|
|
||||||
content += `\nexport default ${defaultVar}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...script,
|
|
||||||
content,
|
|
||||||
map,
|
|
||||||
bindings,
|
|
||||||
scriptAst: scriptAst.body
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
// silently fallback if parse fails since user may be using custom
|
|
||||||
// babel syntax
|
|
||||||
return script
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (script && scriptLang !== scriptSetupLang) {
|
if (script && scriptLang !== scriptSetupLang) {
|
||||||
|
@ -288,7 +215,7 @@ export function compileScript(
|
||||||
let isUsedInTemplate = needTemplateUsageCheck
|
let isUsedInTemplate = needTemplateUsageCheck
|
||||||
if (
|
if (
|
||||||
needTemplateUsageCheck &&
|
needTemplateUsageCheck &&
|
||||||
isTS &&
|
ctx.isTS &&
|
||||||
sfc.template &&
|
sfc.template &&
|
||||||
!sfc.template.src &&
|
!sfc.template.src &&
|
||||||
!sfc.template.lang
|
!sfc.template.lang
|
||||||
|
@ -723,7 +650,7 @@ export function compileScript(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTS) {
|
if (ctx.isTS) {
|
||||||
// move all Type declarations to outer scope
|
// move all Type declarations to outer scope
|
||||||
if (
|
if (
|
||||||
node.type.startsWith('TS') ||
|
node.type.startsWith('TS') ||
|
||||||
|
@ -821,7 +748,7 @@ export function compileScript(
|
||||||
|
|
||||||
// 8. inject `useCssVars` calls
|
// 8. inject `useCssVars` calls
|
||||||
if (
|
if (
|
||||||
cssVars.length &&
|
sfc.cssVars.length &&
|
||||||
// no need to do this when targeting SSR
|
// no need to do this when targeting SSR
|
||||||
!(options.inlineTemplate && options.templateOptions?.ssr)
|
!(options.inlineTemplate && options.templateOptions?.ssr)
|
||||||
) {
|
) {
|
||||||
|
@ -829,7 +756,12 @@ export function compileScript(
|
||||||
ctx.helperImports.add('unref')
|
ctx.helperImports.add('unref')
|
||||||
ctx.s.prependLeft(
|
ctx.s.prependLeft(
|
||||||
startOffset,
|
startOffset,
|
||||||
`\n${genCssVarsCode(cssVars, ctx.bindingMetadata, scopeId, isProd)}\n`
|
`\n${genCssVarsCode(
|
||||||
|
sfc.cssVars,
|
||||||
|
ctx.bindingMetadata,
|
||||||
|
scopeId,
|
||||||
|
!!options.isProd
|
||||||
|
)}\n`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,7 +794,7 @@ export function compileScript(
|
||||||
}
|
}
|
||||||
// inject temp variables for async context preservation
|
// inject temp variables for async context preservation
|
||||||
if (hasAwait) {
|
if (hasAwait) {
|
||||||
const any = isTS ? `: any` : ``
|
const any = ctx.isTS ? `: any` : ``
|
||||||
ctx.s.prependLeft(startOffset, `\nlet __temp${any}, __restore${any}\n`)
|
ctx.s.prependLeft(startOffset, `\nlet __temp${any}, __restore${any}\n`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -938,7 +870,7 @@ export function compileScript(
|
||||||
...(options.templateOptions &&
|
...(options.templateOptions &&
|
||||||
options.templateOptions.compilerOptions),
|
options.templateOptions.compilerOptions),
|
||||||
inline: true,
|
inline: true,
|
||||||
isTS,
|
isTS: ctx.isTS,
|
||||||
bindingMetadata: ctx.bindingMetadata
|
bindingMetadata: ctx.bindingMetadata
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -993,6 +925,10 @@ export function compileScript(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11. finalize default export
|
// 11. finalize default export
|
||||||
|
const genDefaultAs = options.genDefaultAs
|
||||||
|
? `const ${options.genDefaultAs} =`
|
||||||
|
: `export default`
|
||||||
|
|
||||||
let runtimeOptions = ``
|
let runtimeOptions = ``
|
||||||
if (!ctx.hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) {
|
if (!ctx.hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) {
|
||||||
const match = filename.match(/([^/\\]+)\.\w+$/)
|
const match = filename.match(/([^/\\]+)\.\w+$/)
|
||||||
|
@ -1022,7 +958,7 @@ export function compileScript(
|
||||||
const exposeCall =
|
const exposeCall =
|
||||||
ctx.hasDefineExposeCall || options.inlineTemplate ? `` : ` __expose();\n`
|
ctx.hasDefineExposeCall || options.inlineTemplate ? `` : ` __expose();\n`
|
||||||
// wrap setup code with function.
|
// wrap setup code with function.
|
||||||
if (isTS) {
|
if (ctx.isTS) {
|
||||||
// for TS, make sure the exported type is still valid type with
|
// for TS, make sure the exported type is still valid type with
|
||||||
// correct props information
|
// correct props information
|
||||||
// we have to use object spread for types to be merged properly
|
// we have to use object spread for types to be merged properly
|
||||||
|
@ -1078,7 +1014,8 @@ export function compileScript(
|
||||||
bindings: ctx.bindingMetadata,
|
bindings: ctx.bindingMetadata,
|
||||||
imports: userImports,
|
imports: userImports,
|
||||||
content: ctx.s.toString(),
|
content: ctx.s.toString(),
|
||||||
map: genSourceMap
|
map:
|
||||||
|
options.sourceMap !== false
|
||||||
? (ctx.s.generateMap({
|
? (ctx.s.generateMap({
|
||||||
source: filename,
|
source: filename,
|
||||||
hires: true,
|
hires: true,
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { shouldTransform, transformAST } from '@vue/reactivity-transform'
|
||||||
|
import { analyzeScriptBindings } from './analyzeScriptBindings'
|
||||||
|
import { ScriptCompileContext } from './context'
|
||||||
|
import MagicString from 'magic-string'
|
||||||
|
import { RawSourceMap } from 'source-map-js'
|
||||||
|
import { rewriteDefaultAST } from '../rewriteDefault'
|
||||||
|
import { genNormalScriptCssVarsCode } from '../style/cssVars'
|
||||||
|
|
||||||
|
export const normalScriptDefaultVar = `__default__`
|
||||||
|
|
||||||
|
export function processNormalScript(
|
||||||
|
ctx: ScriptCompileContext,
|
||||||
|
scopeId: string
|
||||||
|
) {
|
||||||
|
const script = ctx.descriptor.script!
|
||||||
|
if (script.lang && !ctx.isJS && !ctx.isTS) {
|
||||||
|
// do not process non js/ts script blocks
|
||||||
|
return script
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let content = script.content
|
||||||
|
let map = script.map
|
||||||
|
const scriptAst = ctx.scriptAst!
|
||||||
|
const bindings = analyzeScriptBindings(scriptAst.body)
|
||||||
|
const { source, filename, cssVars } = ctx.descriptor
|
||||||
|
const { sourceMap, genDefaultAs, isProd } = ctx.options
|
||||||
|
|
||||||
|
// TODO remove in 3.4
|
||||||
|
if (ctx.options.reactivityTransform && shouldTransform(content)) {
|
||||||
|
const s = new MagicString(source)
|
||||||
|
const startOffset = script.loc.start.offset
|
||||||
|
const endOffset = script.loc.end.offset
|
||||||
|
const { importedHelpers } = transformAST(scriptAst, s, startOffset)
|
||||||
|
if (importedHelpers.length) {
|
||||||
|
s.prepend(
|
||||||
|
`import { ${importedHelpers
|
||||||
|
.map(h => `${h} as _${h}`)
|
||||||
|
.join(', ')} } from 'vue'\n`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
s.remove(0, startOffset)
|
||||||
|
s.remove(endOffset, source.length)
|
||||||
|
content = s.toString()
|
||||||
|
if (sourceMap !== false) {
|
||||||
|
map = s.generateMap({
|
||||||
|
source: filename,
|
||||||
|
hires: true,
|
||||||
|
includeContent: true
|
||||||
|
}) as unknown as RawSourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssVars.length || genDefaultAs) {
|
||||||
|
const defaultVar = genDefaultAs || normalScriptDefaultVar
|
||||||
|
const s = new MagicString(content)
|
||||||
|
rewriteDefaultAST(scriptAst.body, s, defaultVar)
|
||||||
|
content = s.toString()
|
||||||
|
if (cssVars.length) {
|
||||||
|
content += genNormalScriptCssVarsCode(
|
||||||
|
cssVars,
|
||||||
|
bindings,
|
||||||
|
scopeId,
|
||||||
|
!!isProd,
|
||||||
|
defaultVar
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!genDefaultAs) {
|
||||||
|
content += `\nexport default ${defaultVar}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...script,
|
||||||
|
content,
|
||||||
|
map,
|
||||||
|
bindings,
|
||||||
|
scriptAst: scriptAst.body
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
// silently fallback if parse fails since user may be using custom
|
||||||
|
// babel syntax
|
||||||
|
return script
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue