wip: template binding optimization
This commit is contained in:
@@ -64,7 +64,8 @@ export interface CodegenResult {
|
||||
map?: RawSourceMap
|
||||
}
|
||||
|
||||
export interface CodegenContext extends Required<CodegenOptions> {
|
||||
export interface CodegenContext
|
||||
extends Omit<Required<CodegenOptions>, 'bindingMetadata'> {
|
||||
source: string
|
||||
code: string
|
||||
line: number
|
||||
@@ -204,16 +205,19 @@ export function generate(
|
||||
}
|
||||
|
||||
// enter render function
|
||||
const optimizeSources = options.bindingMetadata
|
||||
? `, $props, $setup, $data, $options`
|
||||
: ``
|
||||
if (!ssr) {
|
||||
if (genScopeId) {
|
||||
push(`const render = ${PURE_ANNOTATION}_withId(`)
|
||||
}
|
||||
push(`function render(_ctx, _cache) {`)
|
||||
push(`function render(_ctx, _cache${optimizeSources}) {`)
|
||||
} else {
|
||||
if (genScopeId) {
|
||||
push(`const ssrRender = ${PURE_ANNOTATION}_withId(`)
|
||||
}
|
||||
push(`function ssrRender(_ctx, _push, _parent, _attrs) {`)
|
||||
push(`function ssrRender(_ctx, _push, _parent, _attrs${optimizeSources}) {`)
|
||||
}
|
||||
indent()
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ export {
|
||||
ParserOptions,
|
||||
TransformOptions,
|
||||
CodegenOptions,
|
||||
HoistTransform
|
||||
HoistTransform,
|
||||
BindingMetadata
|
||||
} from './options'
|
||||
export { baseParse, TextModes } from './parse'
|
||||
export {
|
||||
|
||||
@@ -57,6 +57,10 @@ export type HoistTransform = (
|
||||
parent: ParentNode
|
||||
) => void
|
||||
|
||||
export interface BindingMetadata {
|
||||
[key: string]: 'data' | 'props' | 'setup' | 'options'
|
||||
}
|
||||
|
||||
export interface TransformOptions {
|
||||
/**
|
||||
* An array of node transforms to be applied to every AST node.
|
||||
@@ -122,6 +126,11 @@ export interface TransformOptions {
|
||||
* `ssrRender` option instead of `render`.
|
||||
*/
|
||||
ssr?: boolean
|
||||
/**
|
||||
* Optional binding metadata analyzed from script - used to optimize
|
||||
* binding access when `prefixIdentifiers` is enabled.
|
||||
*/
|
||||
bindingMetadata?: BindingMetadata
|
||||
onError?: (error: CompilerError) => void
|
||||
}
|
||||
|
||||
@@ -169,6 +178,7 @@ export interface CodegenOptions {
|
||||
runtimeGlobalName?: string
|
||||
// we need to know this during codegen to generate proper preambles
|
||||
prefixIdentifiers?: boolean
|
||||
bindingMetadata?: BindingMetadata
|
||||
// generate ssr-specific code?
|
||||
ssr?: boolean
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ export function createTransformContext(
|
||||
expressionPlugins = [],
|
||||
scopeId = null,
|
||||
ssr = false,
|
||||
bindingMetadata = {},
|
||||
onError = defaultOnError
|
||||
}: TransformOptions
|
||||
): TransformContext {
|
||||
@@ -135,6 +136,7 @@ export function createTransformContext(
|
||||
expressionPlugins,
|
||||
scopeId,
|
||||
ssr,
|
||||
bindingMetadata,
|
||||
onError,
|
||||
|
||||
// state
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// - Parse expressions in templates into compound expressions so that each
|
||||
// identifier gets more accurate source-map locations.
|
||||
//
|
||||
// - Prefix identifiers with `_ctx.` so that they are accessed from the render
|
||||
// context
|
||||
// - Prefix identifiers with `_ctx.` or `$xxx` (for known binding types) so that
|
||||
// they are accessed from the right source
|
||||
//
|
||||
// - This transform is only applied in non-browser builds because it relies on
|
||||
// an additional JavaScript parser. In the browser, there is no source-map
|
||||
@@ -25,7 +25,8 @@ import {
|
||||
import {
|
||||
isGloballyWhitelisted,
|
||||
makeMap,
|
||||
babelParserDefautPlugins
|
||||
babelParserDefautPlugins,
|
||||
hasOwn
|
||||
} from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { Node, Function, Identifier, ObjectProperty } from '@babel/types'
|
||||
@@ -99,6 +100,14 @@ export function processExpression(
|
||||
return node
|
||||
}
|
||||
|
||||
const { bindingMetadata } = context
|
||||
const prefix = (raw: string) => {
|
||||
const source = hasOwn(bindingMetadata, raw)
|
||||
? `$` + bindingMetadata[raw]
|
||||
: `_ctx`
|
||||
return `${source}.${raw}`
|
||||
}
|
||||
|
||||
// fast path if expression is a simple identifier.
|
||||
const rawExp = node.content
|
||||
// bail on parens to prevent any possible function invocations.
|
||||
@@ -110,7 +119,7 @@ export function processExpression(
|
||||
!isGloballyWhitelisted(rawExp) &&
|
||||
!isLiteralWhitelisted(rawExp)
|
||||
) {
|
||||
node.content = `_ctx.${rawExp}`
|
||||
node.content = prefix(rawExp)
|
||||
} else if (!context.identifiers[rawExp] && !bailConstant) {
|
||||
// mark node constant for hoisting unless it's referring a scope variable
|
||||
node.isConstant = true
|
||||
@@ -148,7 +157,7 @@ export function processExpression(
|
||||
const isDuplicate = (node: Node & PrefixMeta): boolean =>
|
||||
ids.some(id => id.start === node.start)
|
||||
|
||||
// walk the AST and look for identifiers that need to be prefixed with `_ctx.`.
|
||||
// walk the AST and look for identifiers that need to be prefixed.
|
||||
walkJS(ast, {
|
||||
enter(node: Node & PrefixMeta, parent) {
|
||||
if (node.type === 'Identifier') {
|
||||
@@ -160,7 +169,7 @@ export function processExpression(
|
||||
// rewrite the value
|
||||
node.prefix = `${node.name}: `
|
||||
}
|
||||
node.name = `_ctx.${node.name}`
|
||||
node.name = prefix(node.name)
|
||||
ids.push(node)
|
||||
} else if (!isStaticPropertyKey(node, parent)) {
|
||||
// The identifier is considered constant unless it's pointing to a
|
||||
|
||||
Reference in New Issue
Block a user