perf(compiler): should only perform assertions during tests

Compiler assertions are made to ensure implementation correctness,
but they have performance costs that should not affect users
during development.
This commit is contained in:
Evan You 2019-11-15 17:29:08 -05:00
parent 51d57b4566
commit 353b06df77
4 changed files with 32 additions and 25 deletions

View File

@ -141,7 +141,7 @@ function parseChildren(
const nodes: TemplateChildNode[] = [] const nodes: TemplateChildNode[] = []
while (!isEnd(context, mode, ancestors)) { while (!isEnd(context, mode, ancestors)) {
__DEV__ && assert(context.source.length > 0) __TEST__ && assert(context.source.length > 0)
const s = context.source const s = context.source
let node: TemplateChildNode | TemplateChildNode[] | undefined = undefined let node: TemplateChildNode | TemplateChildNode[] | undefined = undefined
@ -286,16 +286,16 @@ function parseCDATA(
context: ParserContext, context: ParserContext,
ancestors: ElementNode[] ancestors: ElementNode[]
): TemplateChildNode[] { ): TemplateChildNode[] {
__DEV__ && __TEST__ &&
assert(last(ancestors) == null || last(ancestors)!.ns !== Namespaces.HTML) assert(last(ancestors) == null || last(ancestors)!.ns !== Namespaces.HTML)
__DEV__ && assert(startsWith(context.source, '<![CDATA[')) __TEST__ && assert(startsWith(context.source, '<![CDATA['))
advanceBy(context, 9) advanceBy(context, 9)
const nodes = parseChildren(context, TextModes.CDATA, ancestors) const nodes = parseChildren(context, TextModes.CDATA, ancestors)
if (context.source.length === 0) { if (context.source.length === 0) {
emitError(context, ErrorCodes.EOF_IN_CDATA) emitError(context, ErrorCodes.EOF_IN_CDATA)
} else { } else {
__DEV__ && assert(startsWith(context.source, ']]>')) __TEST__ && assert(startsWith(context.source, ']]>'))
advanceBy(context, 3) advanceBy(context, 3)
} }
@ -303,7 +303,7 @@ function parseCDATA(
} }
function parseComment(context: ParserContext): CommentNode { function parseComment(context: ParserContext): CommentNode {
__DEV__ && assert(startsWith(context.source, '<!--')) __TEST__ && assert(startsWith(context.source, '<!--'))
const start = getCursor(context) const start = getCursor(context)
let content: string let content: string
@ -345,7 +345,7 @@ function parseComment(context: ParserContext): CommentNode {
} }
function parseBogusComment(context: ParserContext): CommentNode | undefined { function parseBogusComment(context: ParserContext): CommentNode | undefined {
__DEV__ && assert(/^<(?:[\!\?]|\/[^a-z>])/i.test(context.source)) __TEST__ && assert(/^<(?:[\!\?]|\/[^a-z>])/i.test(context.source))
const start = getCursor(context) const start = getCursor(context)
const contentStart = context.source[1] === '?' ? 1 : 2 const contentStart = context.source[1] === '?' ? 1 : 2
@ -371,7 +371,7 @@ function parseElement(
context: ParserContext, context: ParserContext,
ancestors: ElementNode[] ancestors: ElementNode[]
): ElementNode | undefined { ): ElementNode | undefined {
__DEV__ && assert(/^<[a-z]/i.test(context.source)) __TEST__ && assert(/^<[a-z]/i.test(context.source))
// Start tag. // Start tag.
const wasInPre = context.inPre const wasInPre = context.inPre
@ -425,8 +425,8 @@ function parseTag(
type: TagType, type: TagType,
parent: ElementNode | undefined parent: ElementNode | undefined
): ElementNode { ): ElementNode {
__DEV__ && assert(/^<\/?[a-z]/i.test(context.source)) __TEST__ && assert(/^<\/?[a-z]/i.test(context.source))
__DEV__ && __TEST__ &&
assert( assert(
type === (startsWith(context.source, '</') ? TagType.End : TagType.Start) type === (startsWith(context.source, '</') ? TagType.End : TagType.Start)
) )
@ -538,7 +538,7 @@ function parseAttribute(
context: ParserContext, context: ParserContext,
nameSet: Set<string> nameSet: Set<string>
): AttributeNode | DirectiveNode { ): AttributeNode | DirectiveNode {
__DEV__ && assert(/^[^\t\r\n\f />]/.test(context.source)) __TEST__ && assert(/^[^\t\r\n\f />]/.test(context.source))
// Name. // Name.
const start = getCursor(context) const start = getCursor(context)
@ -725,7 +725,7 @@ function parseInterpolation(
mode: TextModes mode: TextModes
): InterpolationNode | undefined { ): InterpolationNode | undefined {
const [open, close] = context.options.delimiters const [open, close] = context.options.delimiters
__DEV__ && assert(startsWith(context.source, open)) __TEST__ && assert(startsWith(context.source, open))
const closeIndex = context.source.indexOf(close, open.length) const closeIndex = context.source.indexOf(close, open.length)
if (closeIndex === -1) { if (closeIndex === -1) {
@ -765,7 +765,7 @@ function parseInterpolation(
} }
function parseText(context: ParserContext, mode: TextModes): TextNode { function parseText(context: ParserContext, mode: TextModes): TextNode {
__DEV__ && assert(context.source.length > 0) __TEST__ && assert(context.source.length > 0)
const [open] = context.options.delimiters const [open] = context.options.delimiters
// TODO could probably use some perf optimization // TODO could probably use some perf optimization
@ -777,7 +777,7 @@ function parseText(context: ParserContext, mode: TextModes): TextNode {
context.source.length context.source.length
].filter(n => n !== -1) ].filter(n => n !== -1)
) )
__DEV__ && assert(endIndex > 0) __TEST__ && assert(endIndex > 0)
const start = getCursor(context) const start = getCursor(context)
const content = parseTextData(context, endIndex, mode) const content = parseTextData(context, endIndex, mode)
@ -951,7 +951,7 @@ function startsWith(source: string, searchString: string): boolean {
function advanceBy(context: ParserContext, numberOfCharacters: number): void { function advanceBy(context: ParserContext, numberOfCharacters: number): void {
const { source } = context const { source } = context
__DEV__ && assert(numberOfCharacters <= source.length) __TEST__ && assert(numberOfCharacters <= source.length)
advancePositionWithMutation(context, source, numberOfCharacters) advancePositionWithMutation(context, source, numberOfCharacters)
context.source = source.slice(numberOfCharacters) context.source = source.slice(numberOfCharacters)
} }

View File

@ -51,7 +51,7 @@ export const transformElement: NodeTransform = (node, context) => {
} }
// perform the work on exit, after all child expressions have been // perform the work on exit, after all child expressions have been
// processed and merged. // processed and merged.
return () => { return function postTransformElement() {
const { tag, tagType, props } = node const { tag, tagType, props } = node
const isPortal = tag === 'portal' || tag === 'Portal' const isPortal = tag === 'portal' || tag === 'Portal'
const isSuspense = tag === 'suspense' || tag === 'Suspense' const isSuspense = tag === 'suspense' || tag === 'Suspense'
@ -113,7 +113,7 @@ export const transformElement: NodeTransform = (node, context) => {
node, node,
context, context,
// skip reserved "is" prop <component is> // skip reserved "is" prop <component is>
node.props.filter(p => p !== isProp) isProp ? node.props.filter(p => p !== isProp) : node.props
) )
patchFlag = propsBuildResult.patchFlag patchFlag = propsBuildResult.patchFlag
dynamicPropNames = propsBuildResult.dynamicPropNames dynamicPropNames = propsBuildResult.dynamicPropNames
@ -177,9 +177,7 @@ export const transformElement: NodeTransform = (node, context) => {
args.push(patchFlag + '') args.push(patchFlag + '')
} }
if (dynamicPropNames && dynamicPropNames.length) { if (dynamicPropNames && dynamicPropNames.length) {
args.push( args.push(stringifyDynamicPropNames(dynamicPropNames))
`[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`
)
} }
} }
@ -204,6 +202,15 @@ export const transformElement: NodeTransform = (node, context) => {
} }
} }
function stringifyDynamicPropNames(props: string[]): string {
let propsNamesString = `[`
for (let i = 0, l = props.length; i < l; i++) {
propsNamesString += JSON.stringify(props[i])
if (i < l - 1) propsNamesString += ', '
}
return propsNamesString + `]`
}
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode
export function buildProps( export function buildProps(
@ -410,7 +417,7 @@ export function buildProps(
// - onXXX handlers / style: merge into array // - onXXX handlers / style: merge into array
// - class: merge into single expression with concatenation // - class: merge into single expression with concatenation
function dedupeProperties(properties: Property[]): Property[] { function dedupeProperties(properties: Property[]): Property[] {
const knownProps: Record<string, Property> = {} const knownProps: Map<string, Property> = new Map()
const deduped: Property[] = [] const deduped: Property[] = []
for (let i = 0; i < properties.length; i++) { for (let i = 0; i < properties.length; i++) {
const prop = properties[i] const prop = properties[i]
@ -420,7 +427,7 @@ function dedupeProperties(properties: Property[]): Property[] {
continue continue
} }
const name = prop.key.content const name = prop.key.content
const existing = knownProps[name] const existing = knownProps.get(name)
if (existing) { if (existing) {
if ( if (
name === 'style' || name === 'style' ||
@ -432,7 +439,7 @@ function dedupeProperties(properties: Property[]): Property[] {
} }
// unexpected duplicate, should have emitted error during parse // unexpected duplicate, should have emitted error during parse
} else { } else {
knownProps[name] = prop knownProps.set(name, prop)
deduped.push(prop) deduped.push(prop)
} }
} }

View File

@ -208,7 +208,7 @@ export function buildSlots(
// remove node // remove node
children.splice(i, 1) children.splice(i, 1)
i-- i--
__DEV__ && assert(dynamicSlots.length > 0) __TEST__ && assert(dynamicSlots.length > 0)
// attach this slot to previous conditional // attach this slot to previous conditional
let conditional = dynamicSlots[ let conditional = dynamicSlots[
dynamicSlots.length - 1 dynamicSlots.length - 1

View File

@ -77,7 +77,7 @@ export function getInnerRange(
offset: number, offset: number,
length?: number length?: number
): SourceLocation { ): SourceLocation {
__DEV__ && assert(offset <= loc.source.length) __TEST__ && assert(offset <= loc.source.length)
const source = loc.source.substr(offset, length) const source = loc.source.substr(offset, length)
const newLoc: SourceLocation = { const newLoc: SourceLocation = {
source, source,
@ -86,7 +86,7 @@ export function getInnerRange(
} }
if (length != null) { if (length != null) {
__DEV__ && assert(offset + length <= loc.source.length) __TEST__ && assert(offset + length <= loc.source.length)
newLoc.end = advancePositionWithClone( newLoc.end = advancePositionWithClone(
loc.start, loc.start,
loc.source, loc.source,