// 1.1 walk import delcarations of <script>
if(scriptAst){for(constnodeofscriptAst.body){if(node.type==='ImportDeclaration'){// record imports for dedupe
for(constspecifierofnode.specifiers){constimported=getImportedName(specifier)registerUserImport(node.source.value,specifier.local.name,imported,node.importKind==='type'||(specifier.type==='ImportSpecifier'&&specifier.importKind==='type'),false,!options.inlineTemplate)}}}}
// apply reactivity transform
// TODO remove in 3.4
if(enableReactivityTransform&&shouldTransform(script.content)){const{rootRefs,importedHelpers}=transformAST(scriptAst,ctx.s,scriptStartOffset!)refBindings=rootRefsfor(consthofimportedHelpers){ctx.helperImports.add(h)}}
// <script> after <script setup>
// we need to move the block up so that `const __default__` is
// declared before being used in the actual component definition
if(scriptStartOffset!>startOffset){// if content doesn't end with newline, add one
if(!/\n$/.test(script.content.trim())){ctx.s.appendLeft(scriptEndOffset!,`\n`)}ctx.s.move(scriptStartOffset!,scriptEndOffset!,0)}
if(enableReactivityTransform&&// normal <script> had ref bindings that maybe used in <script setup>
(refBindings||shouldTransform(scriptSetup.content))){const{rootRefs,importedHelpers}=transformAST(scriptSetupAst,ctx.s,startOffset,refBindings)refBindings=refBindings?[...refBindings,...rootRefs]:rootRefsfor(consthofimportedHelpers){ctx.helperImports.add(h)}}
5.检查参数 🔗
check macro args to make sure it doesn’t reference setup scope
if(script){if(startOffset<scriptStartOffset!){// <script setup> before <script>
ctx.s.remove(0,startOffset)ctx.s.remove(endOffset,scriptStartOffset!)ctx.s.remove(scriptEndOffset!,source.length)}else{// <script> before <script setup>
ctx.s.remove(0,scriptStartOffset!)ctx.s.remove(scriptEndOffset!,startOffset)ctx.s.remove(endOffset,source.length)}}else{// only <script setup>
ctx.s.remove(0,startOffset)ctx.s.remove(endOffset,source.length)}
if(scriptAst){Object.assign(ctx.bindingMetadata,analyzeScriptBindings(scriptAst.body))}for(const[key,{isType,imported,source}]ofObject.entries(ctx.userImports)){if(isType)continuectx.bindingMetadata[key]=imported==='*'||(imported==='default'&&source.endsWith('.vue'))||source==='vue'?BindingTypes.SETUP_CONST : BindingTypes.SETUP_MAYBE_REF}for(constkeyinscriptBindings){ctx.bindingMetadata[key]=scriptBindings[key]}for(constkeyinsetupBindings){ctx.bindingMetadata[key]=setupBindings[key]}// known ref bindings
if(refBindings){for(constkeyofrefBindings){ctx.bindingMetadata[key]=BindingTypes.SETUP_REF}}
8.处理css中绑定变量 🔗
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(sfc.cssVars.length&&// no need to do this when targeting SSR
!(options.inlineTemplate&&options.templateOptions?.ssr)){ctx.helperImports.add(CSS_VARS_HELPER)ctx.helperImports.add('unref')ctx.s.prependLeft(startOffset,`\n${genCssVarsCode(sfc.cssVars,ctx.bindingMetadata,scopeId,!!options.isProd)}\n`)}
9.处理script中的setup函数 🔗
9.1处理props定义声明 🔗
标记为任何且仅在分配时使用
因为用户定义的复杂类型可能与从生成的运行时声明中推断的类型不兼容
这个args在后面组装最终返回的时候使用
1
2
3
4
5
6
7
letargs=`__props`if(ctx.propsTypeDecl){// mark as any and only cast on assignment
// since the user defined complex types may be incompatible with the
// inferred type from generated runtime declarations
args+=`: any`}
returned=`{ `for(constkeyinallBindings){if(allBindings[key]===true&&ctx.userImports[key].source!=='vue'&&!ctx.userImports[key].source.endsWith('.vue')){// generate getter for import bindings
// skip vue imports since we know they will never change
returned+=`get ${key}() { return ${key} }, `}elseif(ctx.bindingMetadata[key]===BindingTypes.SETUP_LET){// local let binding, also add setter
constsetArg=key==='v'?`_v`:`v`returned+=`get ${key}() { return ${key} }, `+`set ${key}(${setArg}) { ${key} = ${setArg} }, `}else{returned+=`${key}, `}}returned=returned.replace(/, $/,'')+` }`
最终return 的返回应该就是类型下面这样的
1
2
3
4
5
6
7
8
9
10
11
`{
get aa() { return aa },
set aa(v) { aa = v },
bb, cc, dd,
get a() { return a },
set a(v) { a = v },
b, c, d,
get xx() { return xx },
get x() { return x }
}
`
有模版的情况 🔗
有模板需要进行模板变量绑定
需要把这里的绑定参数带入到编译模板那块
这就是另一个故事了
10.3. 插入生成返回的绑定变量 🔗
1
2
3
4
5
6
7
8
9
10
11
12
13
if(!options.inlineTemplate&&!__TEST__){// in non-inline mode, the `__isScriptSetup: true` flag is used by
// componentPublicInstance proxy to allow properties that start with $ or _
ctx.s.appendRight(endOffset,`\nconst __returned__ = ${returned}\n`+`Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })\n`+`return __returned__`+`\n}\n\n`)}else{ctx.s.appendRight(endOffset,`\nreturn ${returned}\n}\n\n`)}