import { compile, NodeTypes, CREATE_STATIC, createSimpleExpression } from '../../src' import { stringifyStatic, StringifyThresholds } from '../../src/transforms/stringifyStatic' describe('stringify static html', () => { function compileWithStringify(template: string) { return compile(template, { hoistStatic: true, prefixIdentifiers: true, transformHoist: stringifyStatic }) } function repeat(code: string, n: number): string { return new Array(n) .fill(0) .map(() => code) .join('') } test('should bail on non-eligible static trees', () => { const { ast } = compileWithStringify( `
hello
hello
` ) expect(ast.hoists.length).toBe(1) // should be a normal vnode call expect(ast.hoists[0]!.type).toBe(NodeTypes.VNODE_CALL) }) test('should work on eligible content (elements with binding > 5)', () => { const { ast } = compileWithStringify( `
${repeat( ``, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast.hoists.length).toBe(1) // should be optimized now expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.JS_CALL_EXPRESSION, callee: CREATE_STATIC, arguments: [ JSON.stringify( `
${repeat( ``, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ), '1' ] }) }) test('should work on eligible content (elements > 20)', () => { const { ast } = compileWithStringify( `
${repeat( ``, StringifyThresholds.NODE_COUNT )}
` ) expect(ast.hoists.length).toBe(1) // should be optimized now expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.JS_CALL_EXPRESSION, callee: CREATE_STATIC, arguments: [ JSON.stringify( `
${repeat( ``, StringifyThresholds.NODE_COUNT )}
` ), '1' ] }) }) test('should work for multiple adjacent nodes', () => { const { ast } = compileWithStringify( `
${repeat( ``, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) // should have 5 hoisted nodes, but the other 4 should be null expect(ast.hoists.length).toBe(5) for (let i = 1; i < 5; i++) { expect(ast.hoists[i]).toBe(null) } // should be optimized now expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.JS_CALL_EXPRESSION, callee: CREATE_STATIC, arguments: [ JSON.stringify( repeat( ``, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT ) ), '5' ] }) }) test('serializing constant bindings', () => { const { ast } = compileWithStringify( `
${repeat( `{{ 1 }} + {{ false }}`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast.hoists.length).toBe(1) // should be optimized now expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.JS_CALL_EXPRESSION, callee: CREATE_STATIC, arguments: [ JSON.stringify( `
${repeat( `1 + false`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ), '1' ] }) }) test('escape', () => { const { ast } = compileWithStringify( `
${repeat( `{{ 1 }} + {{ '<' }}` + `&`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast.hoists.length).toBe(1) // should be optimized now expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.JS_CALL_EXPRESSION, callee: CREATE_STATIC, arguments: [ JSON.stringify( `
${repeat( `1 + <` + `&`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ), '1' ] }) }) test('should bail on runtime constant v-bind bindings', () => { const { ast } = compile( `
${repeat( `foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
`, { hoistStatic: true, prefixIdentifiers: true, transformHoist: stringifyStatic, nodeTransforms: [ node => { if (node.type === NodeTypes.ELEMENT && node.tag === 'img') { const exp = createSimpleExpression( '_imports_0_', false, node.loc, true ) exp.isRuntimeConstant = true node.props[0] = { type: NodeTypes.DIRECTIVE, name: 'bind', arg: createSimpleExpression('src', true), exp, modifiers: [], loc: node.loc } } } ] } ) // the expression and the tree are still hoistable expect(ast.hoists.length).toBe(1) // ...but the hoisted tree should not be stringified expect(ast.hoists[0]).toMatchObject({ // if it's stringified it will be NodeTypes.CALL_EXPRESSION type: NodeTypes.VNODE_CALL }) }) // #1128 test('should bail on non attribute bindings', () => { const { ast } = compileWithStringify( `
${repeat( `foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast.hoists.length).toBe(1) expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION }) const { ast: ast2 } = compileWithStringify( `
${repeat( `foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast2.hoists.length).toBe(1) expect(ast2.hoists[0]).toMatchObject({ type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION }) }) test('should bail on non attribute bindings', () => { const { ast } = compileWithStringify( `
${repeat( `foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast.hoists.length).toBe(1) expect(ast.hoists[0]).toMatchObject({ type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION }) const { ast: ast2 } = compileWithStringify( `
${repeat( `foo`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) expect(ast2.hoists.length).toBe(1) expect(ast2.hoists[0]).toMatchObject({ type: NodeTypes.VNODE_CALL // not CALL_EXPRESSION }) }) })