}
}"
`;
+
+exports[`compiler: codegen temps 1`] = `
+"
+return function render() {
+ with (this) {
+ let _temp0, _temp1, _temp2
+ return null
+ }
+}"
+`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
"offset": 0,
},
},
+ "temps": 0,
"type": 0,
}
`;
createCacheExpression,
createTemplateLiteral,
createBlockStatement,
- createIfStatement
+ createIfStatement,
+ createAssignmentExpression
} from '../src'
import {
CREATE_VNODE,
imports: [],
hoists: [],
cached: 0,
+ temps: 0,
codegenNode: createSimpleExpression(`null`, false),
loc: locStub,
...options
expect(code).toMatchSnapshot()
})
+ test('temps', () => {
+ const root = createRoot({
+ temps: 3
+ })
+ const { code } = generate(root)
+ expect(code).toMatch(`let _temp0, _temp1, _temp2`)
+ expect(code).toMatchSnapshot()
+ })
+
test('prefixIdentifiers: true should inject _ctx statement', () => {
const { code } = generate(createRoot(), { prefixIdentifiers: true })
expect(code).toMatch(`const _ctx = this\n`)
`)
})
})
+
+ test('AssignmentExpression', () => {
+ const { code } = generate(
+ createRoot({
+ codegenNode: createAssignmentExpression(
+ createSimpleExpression(`foo`, false),
+ createSimpleExpression(`bar`, false)
+ )
+ })
+ )
+ expect(code).toMatchInlineSnapshot(`
+ "
+ return function render() {
+ with (this) {
+ return (foo = bar)
+ }
+ }"
+ `)
+ })
})
// ssr codegen
JS_BLOCK_STATEMENT,
JS_TEMPLATE_LITERAL,
- JS_IF_STATEMENT
+ JS_IF_STATEMENT,
+ JS_ASSIGNMENT_EXPRESSION
}
export const enum ElementTypes {
hoists: JSChildNode[]
imports: ImportItem[]
cached: number
- codegenNode?: TemplateChildNode | JSChildNode | BlockStatement | undefined
+ temps: number
ssrHelpers?: symbol[]
+ codegenNode?: TemplateChildNode | JSChildNode | BlockStatement | undefined
}
export type ElementNode =
| ConditionalExpression
| SequenceExpression
| CacheExpression
+ | AssignmentExpression
export interface CallExpression extends Node {
type: NodeTypes.JS_CALL_EXPRESSION
alternate: IfStatement | BlockStatement | undefined
}
+export interface AssignmentExpression extends Node {
+ type: NodeTypes.JS_ASSIGNMENT_EXPRESSION
+ left: SimpleExpressionNode
+ right: JSChildNode
+}
+
// Codegen Node Types ----------------------------------------------------------
// createVNode(...)
loc: locStub
}
}
+
+export function createAssignmentExpression(
+ left: AssignmentExpression['left'],
+ right: AssignmentExpression['right']
+): AssignmentExpression {
+ return {
+ type: NodeTypes.JS_ASSIGNMENT_EXPRESSION,
+ left,
+ right,
+ loc: locStub
+ }
+}
locStub,
SSRCodegenNode,
TemplateLiteral,
- IfStatement
+ IfStatement,
+ AssignmentExpression
} from './ast'
import { SourceMapGenerator, RawSourceMap } from 'source-map'
import {
if (ast.directives.length) {
genAssets(ast.directives, 'directive', context)
}
- if (ast.components.length || ast.directives.length) {
+ if (ast.temps > 0) {
+ push(`let `)
+ for (let i = 0; i < ast.temps; i++) {
+ push(`${i > 0 ? `, ` : ``}_temp${i}`)
+ }
+ newline()
+ }
+ if (ast.components.length || ast.directives.length || ast.temps) {
newline()
}
case NodeTypes.JS_IF_STATEMENT:
!__BROWSER__ && genIfStatement(node, context)
break
+ case NodeTypes.JS_ASSIGNMENT_EXPRESSION:
+ !__BROWSER__ && genAssignmentExpression(node, context)
+ break
/* istanbul ignore next */
default:
}
}
}
+
+function genAssignmentExpression(
+ node: AssignmentExpression,
+ context: CodegenContext
+) {
+ genNode(node.left, context)
+ context.push(` = `)
+ genNode(node.right, context)
+}
hoists: [],
imports: [],
cached: 0,
+ temps: 0,
codegenNode: undefined,
loc: getSelection(context, start)
}
components: Set<string>
directives: Set<string>
hoists: JSChildNode[]
+ temps: number
imports: Set<ImportItem>
cached: number
identifiers: { [name: string]: number | undefined }
components: new Set(),
directives: new Set(),
hoists: [],
+ temps: 0,
imports: new Set(),
cached: 0,
identifiers: {},
root.directives = [...context.directives]
root.imports = [...context.imports]
root.hoists = context.hoists
+ root.temps = context.temps
root.cached = context.cached
}
import { getCompiledString } from './utils'
+import { compile } from '../src'
describe('ssr: element', () => {
test('basic elements', () => {
})
test('<textarea> with dynamic v-bind', () => {
- // TODO
+ expect(compile(`<textarea v-bind="obj">fallback</textarea>`).code)
+ .toMatchInlineSnapshot(`
+ "const { _renderAttrs, _interpolate } = require(\\"vue\\")
+
+ return function ssrRender(_ctx, _push, _parent) {
+ let _temp0
+
+ _push(\`<textarea\${
+ _renderAttrs(_temp0 = _ctx.obj)
+ }>\${
+ _interpolate((\\"value\\" in _temp0) ? _temp0.value : \\"fallback\\")
+ }</textarea>\`)
+ }"
+ `)
})
})
expect(
getCompiledString(`<input type="checkbox" :checked="checked">`)
).toMatchInlineSnapshot(
- `"\`<input type=\\"checkbox\\"\${(_ctx.checked)? \\" checked\\": \\"\\"}>\`"`
+ `"\`<input type=\\"checkbox\\"\${(_ctx.checked) ? \\" checked\\" : \\"\\"}>\`"`
)
})
createArrayExpression,
ExpressionNode,
JSChildNode,
- ArrayExpression
+ ArrayExpression,
+ createAssignmentExpression,
+ TextNode
} from '@vue/compiler-dom'
import { escapeHtml, isBooleanAttr, isSSRSafeAttrName } from '@vue/shared'
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
SSR_RENDER_CLASS,
SSR_RENDER_STYLE,
SSR_RENDER_DYNAMIC_ATTR,
- SSR_RENDER_ATTRS
+ SSR_RENDER_ATTRS,
+ SSR_INTERPOLATE
} from '../runtimeHelpers'
export const ssrTransformElement: NodeTransform = (node, context) => {
if (hasDynamicVBind) {
const { props } = buildProps(node, context, node.props, true /* ssr */)
if (props) {
- openTag.push(
- createCallExpression(context.helper(SSR_RENDER_ATTRS), [props])
+ const propsExp = createCallExpression(
+ context.helper(SSR_RENDER_ATTRS),
+ [props]
)
+ if (node.tag === 'textarea') {
+ // <textarea> with dynamic v-bind. We don't know if the final props
+ // will contain .value, so we will have to do something special:
+ // assign the merged props to a temp variable, and check whether
+ // it contains value (if yes, render is as children).
+ const tempId = `_temp${context.temps++}`
+ propsExp.arguments[0] = createAssignmentExpression(
+ createSimpleExpression(tempId, false),
+ props
+ )
+ const existingText = node.children[0] as TextNode | undefined
+ node.children = []
+ rawChildren = createCallExpression(
+ context.helper(SSR_INTERPOLATE),
+ [
+ createConditionalExpression(
+ createSimpleExpression(`"value" in ${tempId}`, false),
+ createSimpleExpression(`${tempId}.value`, false),
+ createSimpleExpression(
+ existingText ? existingText.content : ``,
+ true
+ ),
+ false
+ )
+ ]
+ )
+ }
+ openTag.push(propsExp)
}
}
} else if (isTextareaWithValue(node, prop) && prop.exp) {
if (!hasDynamicVBind) {
node.children = [createInterpolation(prop.exp, prop.loc)]
- } else {
- // TODO handle <textrea> with dynamic v-bind
}
} else {
// Directive transforms.