|
@@ -80,6 +80,7 @@ function createCodegenContext(
|
|
|
sourceMap = false,
|
|
sourceMap = false,
|
|
|
filename = `template.vue.html`,
|
|
filename = `template.vue.html`,
|
|
|
scopeId = null,
|
|
scopeId = null,
|
|
|
|
|
+ optimizeBindings = false,
|
|
|
runtimeGlobalName = `Vue`,
|
|
runtimeGlobalName = `Vue`,
|
|
|
runtimeModuleName = `vue`,
|
|
runtimeModuleName = `vue`,
|
|
|
ssr = false
|
|
ssr = false
|
|
@@ -91,6 +92,7 @@ function createCodegenContext(
|
|
|
sourceMap,
|
|
sourceMap,
|
|
|
filename,
|
|
filename,
|
|
|
scopeId,
|
|
scopeId,
|
|
|
|
|
+ optimizeBindings,
|
|
|
runtimeGlobalName,
|
|
runtimeGlobalName,
|
|
|
runtimeModuleName,
|
|
runtimeModuleName,
|
|
|
ssr,
|
|
ssr,
|
|
@@ -102,8 +104,7 @@ function createCodegenContext(
|
|
|
indentLevel: 0,
|
|
indentLevel: 0,
|
|
|
map: undefined,
|
|
map: undefined,
|
|
|
helper(key) {
|
|
helper(key) {
|
|
|
- const name = helperNameMap[key]
|
|
|
|
|
- return prefixIdentifiers ? name : `_${name}`
|
|
|
|
|
|
|
+ return `_${helperNameMap[key]}`
|
|
|
},
|
|
},
|
|
|
push(code, node) {
|
|
push(code, node) {
|
|
|
context.code += code
|
|
context.code += code
|
|
@@ -282,7 +283,6 @@ export function generate(
|
|
|
function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|
function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|
|
const {
|
|
const {
|
|
|
ssr,
|
|
ssr,
|
|
|
- helper,
|
|
|
|
|
prefixIdentifiers,
|
|
prefixIdentifiers,
|
|
|
push,
|
|
push,
|
|
|
newline,
|
|
newline,
|
|
@@ -293,13 +293,16 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|
|
!__BROWSER__ && ssr
|
|
!__BROWSER__ && ssr
|
|
|
? `require(${JSON.stringify(runtimeModuleName)})`
|
|
? `require(${JSON.stringify(runtimeModuleName)})`
|
|
|
: runtimeGlobalName
|
|
: runtimeGlobalName
|
|
|
|
|
+ const aliasHelper = (s: symbol) => `${helperNameMap[s]}: _${helperNameMap[s]}`
|
|
|
// Generate const declaration for helpers
|
|
// Generate const declaration for helpers
|
|
|
// In prefix mode, we place the const declaration at top so it's done
|
|
// In prefix mode, we place the const declaration at top so it's done
|
|
|
// only once; But if we not prefixing, we place the declaration inside the
|
|
// only once; But if we not prefixing, we place the declaration inside the
|
|
|
// with block so it doesn't incur the `in` check cost for every helper access.
|
|
// with block so it doesn't incur the `in` check cost for every helper access.
|
|
|
if (ast.helpers.length > 0) {
|
|
if (ast.helpers.length > 0) {
|
|
|
if (!__BROWSER__ && prefixIdentifiers) {
|
|
if (!__BROWSER__ && prefixIdentifiers) {
|
|
|
- push(`const { ${ast.helpers.map(helper).join(', ')} } = ${VueBinding}\n`)
|
|
|
|
|
|
|
+ push(
|
|
|
|
|
+ `const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`
|
|
|
|
|
+ )
|
|
|
} else {
|
|
} else {
|
|
|
// "with" mode.
|
|
// "with" mode.
|
|
|
// save Vue in a separate variable to avoid collision
|
|
// save Vue in a separate variable to avoid collision
|
|
@@ -310,7 +313,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|
|
if (ast.hoists.length) {
|
|
if (ast.hoists.length) {
|
|
|
const staticHelpers = [CREATE_VNODE, CREATE_COMMENT, CREATE_TEXT]
|
|
const staticHelpers = [CREATE_VNODE, CREATE_COMMENT, CREATE_TEXT]
|
|
|
.filter(helper => ast.helpers.includes(helper))
|
|
.filter(helper => ast.helpers.includes(helper))
|
|
|
- .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)
|
|
|
|
|
|
|
+ .map(aliasHelper)
|
|
|
.join(', ')
|
|
.join(', ')
|
|
|
push(`const { ${staticHelpers} } = _Vue\n`)
|
|
push(`const { ${staticHelpers} } = _Vue\n`)
|
|
|
}
|
|
}
|
|
@@ -321,7 +324,7 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
|
|
|
// ssr guaruntees prefixIdentifier: true
|
|
// ssr guaruntees prefixIdentifier: true
|
|
|
push(
|
|
push(
|
|
|
`const { ${ast.ssrHelpers
|
|
`const { ${ast.ssrHelpers
|
|
|
- .map(helper)
|
|
|
|
|
|
|
+ .map(aliasHelper)
|
|
|
.join(', ')} } = require("@vue/server-renderer")\n`
|
|
.join(', ')} } = require("@vue/server-renderer")\n`
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -335,7 +338,14 @@ function genModulePreamble(
|
|
|
context: CodegenContext,
|
|
context: CodegenContext,
|
|
|
genScopeId: boolean
|
|
genScopeId: boolean
|
|
|
) {
|
|
) {
|
|
|
- const { push, helper, newline, scopeId, runtimeModuleName } = context
|
|
|
|
|
|
|
+ const {
|
|
|
|
|
+ push,
|
|
|
|
|
+ helper,
|
|
|
|
|
+ newline,
|
|
|
|
|
+ scopeId,
|
|
|
|
|
+ optimizeBindings,
|
|
|
|
|
+ runtimeModuleName
|
|
|
|
|
+ } = context
|
|
|
|
|
|
|
|
if (genScopeId) {
|
|
if (genScopeId) {
|
|
|
ast.helpers.push(WITH_SCOPE_ID)
|
|
ast.helpers.push(WITH_SCOPE_ID)
|
|
@@ -346,17 +356,35 @@ function genModulePreamble(
|
|
|
|
|
|
|
|
// generate import statements for helpers
|
|
// generate import statements for helpers
|
|
|
if (ast.helpers.length) {
|
|
if (ast.helpers.length) {
|
|
|
- push(
|
|
|
|
|
- `import { ${ast.helpers.map(helper).join(', ')} } from ${JSON.stringify(
|
|
|
|
|
- runtimeModuleName
|
|
|
|
|
- )}\n`
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ if (optimizeBindings) {
|
|
|
|
|
+ // when bundled with webpack with code-split, calling an import binding
|
|
|
|
|
+ // as a function leads to it being wrapped with `Object(a.b)` or `(0,a.b)`,
|
|
|
|
|
+ // incurring both payload size increase and potential perf overhead.
|
|
|
|
|
+ // therefore we assign the imports to vairables (which is a constant ~50b
|
|
|
|
|
+ // cost per-component instead of scaling with template size)
|
|
|
|
|
+ push(
|
|
|
|
|
+ `import { ${ast.helpers
|
|
|
|
|
+ .map(s => helperNameMap[s])
|
|
|
|
|
+ .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`
|
|
|
|
|
+ )
|
|
|
|
|
+ push(
|
|
|
|
|
+ `\n// Binding optimization for webpack code-split\nconst ${ast.helpers
|
|
|
|
|
+ .map(s => `_${helperNameMap[s]} = ${helperNameMap[s]}`)
|
|
|
|
|
+ .join(', ')}\n`
|
|
|
|
|
+ )
|
|
|
|
|
+ } else {
|
|
|
|
|
+ push(
|
|
|
|
|
+ `import { ${ast.helpers
|
|
|
|
|
+ .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)
|
|
|
|
|
+ .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`
|
|
|
|
|
+ )
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (ast.ssrHelpers && ast.ssrHelpers.length) {
|
|
if (ast.ssrHelpers && ast.ssrHelpers.length) {
|
|
|
push(
|
|
push(
|
|
|
`import { ${ast.ssrHelpers
|
|
`import { ${ast.ssrHelpers
|
|
|
- .map(helper)
|
|
|
|
|
|
|
+ .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)
|
|
|
.join(', ')} } from "@vue/server-renderer"\n`
|
|
.join(', ')} } from "@vue/server-renderer"\n`
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|