@vue/compiler-ssr 3.2.40 → 3.2.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compiler-ssr.cjs.js +1232 -1231
- package/package.json +3 -3
package/dist/compiler-ssr.cjs.js
CHANGED
|
@@ -5,1267 +5,1268 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var compilerDom = require('@vue/compiler-dom');
|
|
6
6
|
var shared = require('@vue/shared');
|
|
7
7
|
|
|
8
|
-
const SSR_INTERPOLATE = Symbol(`ssrInterpolate`);
|
|
9
|
-
const SSR_RENDER_VNODE = Symbol(`ssrRenderVNode`);
|
|
10
|
-
const SSR_RENDER_COMPONENT = Symbol(`ssrRenderComponent`);
|
|
11
|
-
const SSR_RENDER_SLOT = Symbol(`ssrRenderSlot`);
|
|
12
|
-
const SSR_RENDER_SLOT_INNER = Symbol(`ssrRenderSlotInner`);
|
|
13
|
-
const SSR_RENDER_CLASS = Symbol(`ssrRenderClass`);
|
|
14
|
-
const SSR_RENDER_STYLE = Symbol(`ssrRenderStyle`);
|
|
15
|
-
const SSR_RENDER_ATTRS = Symbol(`ssrRenderAttrs`);
|
|
16
|
-
const SSR_RENDER_ATTR = Symbol(`ssrRenderAttr`);
|
|
17
|
-
const SSR_RENDER_DYNAMIC_ATTR = Symbol(`ssrRenderDynamicAttr`);
|
|
18
|
-
const SSR_RENDER_LIST = Symbol(`ssrRenderList`);
|
|
19
|
-
const SSR_INCLUDE_BOOLEAN_ATTR = Symbol(`ssrIncludeBooleanAttr`);
|
|
20
|
-
const SSR_LOOSE_EQUAL = Symbol(`ssrLooseEqual`);
|
|
21
|
-
const SSR_LOOSE_CONTAIN = Symbol(`ssrLooseContain`);
|
|
22
|
-
const SSR_RENDER_DYNAMIC_MODEL = Symbol(`ssrRenderDynamicModel`);
|
|
23
|
-
const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`);
|
|
24
|
-
const SSR_RENDER_TELEPORT = Symbol(`ssrRenderTeleport`);
|
|
25
|
-
const SSR_RENDER_SUSPENSE = Symbol(`ssrRenderSuspense`);
|
|
26
|
-
const SSR_GET_DIRECTIVE_PROPS = Symbol(`ssrGetDirectiveProps`);
|
|
27
|
-
const ssrHelpers = {
|
|
28
|
-
[SSR_INTERPOLATE]: `ssrInterpolate`,
|
|
29
|
-
[SSR_RENDER_VNODE]: `ssrRenderVNode`,
|
|
30
|
-
[SSR_RENDER_COMPONENT]: `ssrRenderComponent`,
|
|
31
|
-
[SSR_RENDER_SLOT]: `ssrRenderSlot`,
|
|
32
|
-
[SSR_RENDER_SLOT_INNER]: `ssrRenderSlotInner`,
|
|
33
|
-
[SSR_RENDER_CLASS]: `ssrRenderClass`,
|
|
34
|
-
[SSR_RENDER_STYLE]: `ssrRenderStyle`,
|
|
35
|
-
[SSR_RENDER_ATTRS]: `ssrRenderAttrs`,
|
|
36
|
-
[SSR_RENDER_ATTR]: `ssrRenderAttr`,
|
|
37
|
-
[SSR_RENDER_DYNAMIC_ATTR]: `ssrRenderDynamicAttr`,
|
|
38
|
-
[SSR_RENDER_LIST]: `ssrRenderList`,
|
|
39
|
-
[SSR_INCLUDE_BOOLEAN_ATTR]: `ssrIncludeBooleanAttr`,
|
|
40
|
-
[SSR_LOOSE_EQUAL]: `ssrLooseEqual`,
|
|
41
|
-
[SSR_LOOSE_CONTAIN]: `ssrLooseContain`,
|
|
42
|
-
[SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`,
|
|
43
|
-
[SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`,
|
|
44
|
-
[SSR_RENDER_TELEPORT]: `ssrRenderTeleport`,
|
|
45
|
-
[SSR_RENDER_SUSPENSE]: `ssrRenderSuspense`,
|
|
46
|
-
[SSR_GET_DIRECTIVE_PROPS]: `ssrGetDirectiveProps`
|
|
47
|
-
};
|
|
48
|
-
// Note: these are helpers imported from @vue/server-renderer
|
|
49
|
-
// make sure the names match!
|
|
8
|
+
const SSR_INTERPOLATE = Symbol(`ssrInterpolate`);
|
|
9
|
+
const SSR_RENDER_VNODE = Symbol(`ssrRenderVNode`);
|
|
10
|
+
const SSR_RENDER_COMPONENT = Symbol(`ssrRenderComponent`);
|
|
11
|
+
const SSR_RENDER_SLOT = Symbol(`ssrRenderSlot`);
|
|
12
|
+
const SSR_RENDER_SLOT_INNER = Symbol(`ssrRenderSlotInner`);
|
|
13
|
+
const SSR_RENDER_CLASS = Symbol(`ssrRenderClass`);
|
|
14
|
+
const SSR_RENDER_STYLE = Symbol(`ssrRenderStyle`);
|
|
15
|
+
const SSR_RENDER_ATTRS = Symbol(`ssrRenderAttrs`);
|
|
16
|
+
const SSR_RENDER_ATTR = Symbol(`ssrRenderAttr`);
|
|
17
|
+
const SSR_RENDER_DYNAMIC_ATTR = Symbol(`ssrRenderDynamicAttr`);
|
|
18
|
+
const SSR_RENDER_LIST = Symbol(`ssrRenderList`);
|
|
19
|
+
const SSR_INCLUDE_BOOLEAN_ATTR = Symbol(`ssrIncludeBooleanAttr`);
|
|
20
|
+
const SSR_LOOSE_EQUAL = Symbol(`ssrLooseEqual`);
|
|
21
|
+
const SSR_LOOSE_CONTAIN = Symbol(`ssrLooseContain`);
|
|
22
|
+
const SSR_RENDER_DYNAMIC_MODEL = Symbol(`ssrRenderDynamicModel`);
|
|
23
|
+
const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`);
|
|
24
|
+
const SSR_RENDER_TELEPORT = Symbol(`ssrRenderTeleport`);
|
|
25
|
+
const SSR_RENDER_SUSPENSE = Symbol(`ssrRenderSuspense`);
|
|
26
|
+
const SSR_GET_DIRECTIVE_PROPS = Symbol(`ssrGetDirectiveProps`);
|
|
27
|
+
const ssrHelpers = {
|
|
28
|
+
[SSR_INTERPOLATE]: `ssrInterpolate`,
|
|
29
|
+
[SSR_RENDER_VNODE]: `ssrRenderVNode`,
|
|
30
|
+
[SSR_RENDER_COMPONENT]: `ssrRenderComponent`,
|
|
31
|
+
[SSR_RENDER_SLOT]: `ssrRenderSlot`,
|
|
32
|
+
[SSR_RENDER_SLOT_INNER]: `ssrRenderSlotInner`,
|
|
33
|
+
[SSR_RENDER_CLASS]: `ssrRenderClass`,
|
|
34
|
+
[SSR_RENDER_STYLE]: `ssrRenderStyle`,
|
|
35
|
+
[SSR_RENDER_ATTRS]: `ssrRenderAttrs`,
|
|
36
|
+
[SSR_RENDER_ATTR]: `ssrRenderAttr`,
|
|
37
|
+
[SSR_RENDER_DYNAMIC_ATTR]: `ssrRenderDynamicAttr`,
|
|
38
|
+
[SSR_RENDER_LIST]: `ssrRenderList`,
|
|
39
|
+
[SSR_INCLUDE_BOOLEAN_ATTR]: `ssrIncludeBooleanAttr`,
|
|
40
|
+
[SSR_LOOSE_EQUAL]: `ssrLooseEqual`,
|
|
41
|
+
[SSR_LOOSE_CONTAIN]: `ssrLooseContain`,
|
|
42
|
+
[SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`,
|
|
43
|
+
[SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`,
|
|
44
|
+
[SSR_RENDER_TELEPORT]: `ssrRenderTeleport`,
|
|
45
|
+
[SSR_RENDER_SUSPENSE]: `ssrRenderSuspense`,
|
|
46
|
+
[SSR_GET_DIRECTIVE_PROPS]: `ssrGetDirectiveProps`
|
|
47
|
+
};
|
|
48
|
+
// Note: these are helpers imported from @vue/server-renderer
|
|
49
|
+
// make sure the names match!
|
|
50
50
|
compilerDom.registerRuntimeHelpers(ssrHelpers);
|
|
51
51
|
|
|
52
|
-
// Plugin for the first transform pass, which simply constructs the AST node
|
|
53
|
-
const ssrTransformIf = compilerDom.createStructuralDirectiveTransform(/^(if|else|else-if)$/, compilerDom.processIf);
|
|
54
|
-
// This is called during the 2nd transform pass to construct the SSR-specific
|
|
55
|
-
// codegen nodes.
|
|
56
|
-
function ssrProcessIf(node, context, disableNestedFragments = false) {
|
|
57
|
-
const [rootBranch] = node.branches;
|
|
58
|
-
const ifStatement = compilerDom.createIfStatement(rootBranch.condition, processIfBranch(rootBranch, context, disableNestedFragments));
|
|
59
|
-
context.pushStatement(ifStatement);
|
|
60
|
-
let currentIf = ifStatement;
|
|
61
|
-
for (let i = 1; i < node.branches.length; i++) {
|
|
62
|
-
const branch = node.branches[i];
|
|
63
|
-
const branchBlockStatement = processIfBranch(branch, context, disableNestedFragments);
|
|
64
|
-
if (branch.condition) {
|
|
65
|
-
// else-if
|
|
66
|
-
currentIf = currentIf.alternate = compilerDom.createIfStatement(branch.condition, branchBlockStatement);
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
// else
|
|
70
|
-
currentIf.alternate = branchBlockStatement;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (!currentIf.alternate) {
|
|
74
|
-
currentIf.alternate = compilerDom.createBlockStatement([
|
|
75
|
-
compilerDom.createCallExpression(`_push`, ['`<!---->`'])
|
|
76
|
-
]);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function processIfBranch(branch, context, disableNestedFragments = false) {
|
|
80
|
-
const { children } = branch;
|
|
81
|
-
const needFragmentWrapper = !disableNestedFragments &&
|
|
82
|
-
(children.length !== 1 || children[0].type !== 1 /* NodeTypes.ELEMENT */) &&
|
|
83
|
-
// optimize away nested fragments when the only child is a ForNode
|
|
84
|
-
!(children.length === 1 && children[0].type === 11 /* NodeTypes.FOR */);
|
|
85
|
-
return processChildrenAsStatement(branch, context, needFragmentWrapper);
|
|
52
|
+
// Plugin for the first transform pass, which simply constructs the AST node
|
|
53
|
+
const ssrTransformIf = compilerDom.createStructuralDirectiveTransform(/^(if|else|else-if)$/, compilerDom.processIf);
|
|
54
|
+
// This is called during the 2nd transform pass to construct the SSR-specific
|
|
55
|
+
// codegen nodes.
|
|
56
|
+
function ssrProcessIf(node, context, disableNestedFragments = false) {
|
|
57
|
+
const [rootBranch] = node.branches;
|
|
58
|
+
const ifStatement = compilerDom.createIfStatement(rootBranch.condition, processIfBranch(rootBranch, context, disableNestedFragments));
|
|
59
|
+
context.pushStatement(ifStatement);
|
|
60
|
+
let currentIf = ifStatement;
|
|
61
|
+
for (let i = 1; i < node.branches.length; i++) {
|
|
62
|
+
const branch = node.branches[i];
|
|
63
|
+
const branchBlockStatement = processIfBranch(branch, context, disableNestedFragments);
|
|
64
|
+
if (branch.condition) {
|
|
65
|
+
// else-if
|
|
66
|
+
currentIf = currentIf.alternate = compilerDom.createIfStatement(branch.condition, branchBlockStatement);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// else
|
|
70
|
+
currentIf.alternate = branchBlockStatement;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!currentIf.alternate) {
|
|
74
|
+
currentIf.alternate = compilerDom.createBlockStatement([
|
|
75
|
+
compilerDom.createCallExpression(`_push`, ['`<!---->`'])
|
|
76
|
+
]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function processIfBranch(branch, context, disableNestedFragments = false) {
|
|
80
|
+
const { children } = branch;
|
|
81
|
+
const needFragmentWrapper = !disableNestedFragments &&
|
|
82
|
+
(children.length !== 1 || children[0].type !== 1 /* NodeTypes.ELEMENT */) &&
|
|
83
|
+
// optimize away nested fragments when the only child is a ForNode
|
|
84
|
+
!(children.length === 1 && children[0].type === 11 /* NodeTypes.FOR */);
|
|
85
|
+
return processChildrenAsStatement(branch, context, needFragmentWrapper);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
// Plugin for the first transform pass, which simply constructs the AST node
|
|
89
|
-
const ssrTransformFor = compilerDom.createStructuralDirectiveTransform('for', compilerDom.processFor);
|
|
90
|
-
// This is called during the 2nd transform pass to construct the SSR-specific
|
|
91
|
-
// codegen nodes.
|
|
92
|
-
function ssrProcessFor(node, context, disableNestedFragments = false) {
|
|
93
|
-
const needFragmentWrapper = !disableNestedFragments &&
|
|
94
|
-
(node.children.length !== 1 || node.children[0].type !== 1 /* NodeTypes.ELEMENT */);
|
|
95
|
-
const renderLoop = compilerDom.createFunctionExpression(compilerDom.createForLoopParams(node.parseResult));
|
|
96
|
-
renderLoop.body = processChildrenAsStatement(node, context, needFragmentWrapper);
|
|
97
|
-
// v-for always renders a fragment unless explicitly disabled
|
|
98
|
-
if (!disableNestedFragments) {
|
|
99
|
-
context.pushStringPart(`<!--[-->`);
|
|
100
|
-
}
|
|
101
|
-
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_LIST), [
|
|
102
|
-
node.source,
|
|
103
|
-
renderLoop
|
|
104
|
-
]));
|
|
105
|
-
if (!disableNestedFragments) {
|
|
106
|
-
context.pushStringPart(`<!--]-->`);
|
|
107
|
-
}
|
|
88
|
+
// Plugin for the first transform pass, which simply constructs the AST node
|
|
89
|
+
const ssrTransformFor = compilerDom.createStructuralDirectiveTransform('for', compilerDom.processFor);
|
|
90
|
+
// This is called during the 2nd transform pass to construct the SSR-specific
|
|
91
|
+
// codegen nodes.
|
|
92
|
+
function ssrProcessFor(node, context, disableNestedFragments = false) {
|
|
93
|
+
const needFragmentWrapper = !disableNestedFragments &&
|
|
94
|
+
(node.children.length !== 1 || node.children[0].type !== 1 /* NodeTypes.ELEMENT */);
|
|
95
|
+
const renderLoop = compilerDom.createFunctionExpression(compilerDom.createForLoopParams(node.parseResult));
|
|
96
|
+
renderLoop.body = processChildrenAsStatement(node, context, needFragmentWrapper);
|
|
97
|
+
// v-for always renders a fragment unless explicitly disabled
|
|
98
|
+
if (!disableNestedFragments) {
|
|
99
|
+
context.pushStringPart(`<!--[-->`);
|
|
100
|
+
}
|
|
101
|
+
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_LIST), [
|
|
102
|
+
node.source,
|
|
103
|
+
renderLoop
|
|
104
|
+
]));
|
|
105
|
+
if (!disableNestedFragments) {
|
|
106
|
+
context.pushStringPart(`<!--]-->`);
|
|
107
|
+
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
const ssrTransformSlotOutlet = (node, context) => {
|
|
111
|
-
if (compilerDom.isSlotOutlet(node)) {
|
|
112
|
-
const { slotName, slotProps } = compilerDom.processSlotOutlet(node, context);
|
|
113
|
-
const args = [
|
|
114
|
-
`_ctx.$slots`,
|
|
115
|
-
slotName,
|
|
116
|
-
slotProps || `{}`,
|
|
117
|
-
// fallback content placeholder. will be replaced in the process phase
|
|
118
|
-
`null`,
|
|
119
|
-
`_push`,
|
|
120
|
-
`_parent`
|
|
121
|
-
];
|
|
122
|
-
// inject slot scope id if current template uses :slotted
|
|
123
|
-
if (context.scopeId && context.slotted !== false) {
|
|
124
|
-
args.push(`"${context.scopeId}-s"`);
|
|
125
|
-
}
|
|
126
|
-
let method = SSR_RENDER_SLOT;
|
|
127
|
-
// #3989
|
|
128
|
-
// check if this is a single slot inside a transition wrapper - since
|
|
129
|
-
// transition will unwrap the slot fragment into a single vnode at runtime,
|
|
130
|
-
// we need to avoid rendering the slot as a fragment.
|
|
131
|
-
const parent = context.parent;
|
|
132
|
-
if (parent &&
|
|
133
|
-
parent.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
134
|
-
parent.tagType === 1 /* ElementTypes.COMPONENT */ &&
|
|
135
|
-
compilerDom.resolveComponentType(parent, context, true) === compilerDom.TRANSITION &&
|
|
136
|
-
parent.children.filter(c => c.type === 1 /* NodeTypes.ELEMENT */).length === 1) {
|
|
137
|
-
method = SSR_RENDER_SLOT_INNER;
|
|
138
|
-
if (!(context.scopeId && context.slotted !== false)) {
|
|
139
|
-
args.push('null');
|
|
140
|
-
}
|
|
141
|
-
args.push('true');
|
|
142
|
-
}
|
|
143
|
-
node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(method), args);
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
function ssrProcessSlotOutlet(node, context) {
|
|
147
|
-
const renderCall = node.ssrCodegenNode;
|
|
148
|
-
// has fallback content
|
|
149
|
-
if (node.children.length) {
|
|
150
|
-
const fallbackRenderFn = compilerDom.createFunctionExpression([]);
|
|
151
|
-
fallbackRenderFn.body = processChildrenAsStatement(node, context);
|
|
152
|
-
// _renderSlot(slots, name, props, fallback, ...)
|
|
153
|
-
renderCall.arguments[3] = fallbackRenderFn;
|
|
154
|
-
}
|
|
155
|
-
// Forwarded <slot/>. Merge slot scope ids
|
|
156
|
-
if (context.withSlotScopeId) {
|
|
157
|
-
const slotScopeId = renderCall.arguments[6];
|
|
158
|
-
renderCall.arguments[6] = slotScopeId
|
|
159
|
-
? `${slotScopeId} + _scopeId`
|
|
160
|
-
: `_scopeId`;
|
|
161
|
-
}
|
|
162
|
-
context.pushStatement(node.ssrCodegenNode);
|
|
110
|
+
const ssrTransformSlotOutlet = (node, context) => {
|
|
111
|
+
if (compilerDom.isSlotOutlet(node)) {
|
|
112
|
+
const { slotName, slotProps } = compilerDom.processSlotOutlet(node, context);
|
|
113
|
+
const args = [
|
|
114
|
+
`_ctx.$slots`,
|
|
115
|
+
slotName,
|
|
116
|
+
slotProps || `{}`,
|
|
117
|
+
// fallback content placeholder. will be replaced in the process phase
|
|
118
|
+
`null`,
|
|
119
|
+
`_push`,
|
|
120
|
+
`_parent`
|
|
121
|
+
];
|
|
122
|
+
// inject slot scope id if current template uses :slotted
|
|
123
|
+
if (context.scopeId && context.slotted !== false) {
|
|
124
|
+
args.push(`"${context.scopeId}-s"`);
|
|
125
|
+
}
|
|
126
|
+
let method = SSR_RENDER_SLOT;
|
|
127
|
+
// #3989
|
|
128
|
+
// check if this is a single slot inside a transition wrapper - since
|
|
129
|
+
// transition will unwrap the slot fragment into a single vnode at runtime,
|
|
130
|
+
// we need to avoid rendering the slot as a fragment.
|
|
131
|
+
const parent = context.parent;
|
|
132
|
+
if (parent &&
|
|
133
|
+
parent.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
134
|
+
parent.tagType === 1 /* ElementTypes.COMPONENT */ &&
|
|
135
|
+
compilerDom.resolveComponentType(parent, context, true) === compilerDom.TRANSITION &&
|
|
136
|
+
parent.children.filter(c => c.type === 1 /* NodeTypes.ELEMENT */).length === 1) {
|
|
137
|
+
method = SSR_RENDER_SLOT_INNER;
|
|
138
|
+
if (!(context.scopeId && context.slotted !== false)) {
|
|
139
|
+
args.push('null');
|
|
140
|
+
}
|
|
141
|
+
args.push('true');
|
|
142
|
+
}
|
|
143
|
+
node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(method), args);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
function ssrProcessSlotOutlet(node, context) {
|
|
147
|
+
const renderCall = node.ssrCodegenNode;
|
|
148
|
+
// has fallback content
|
|
149
|
+
if (node.children.length) {
|
|
150
|
+
const fallbackRenderFn = compilerDom.createFunctionExpression([]);
|
|
151
|
+
fallbackRenderFn.body = processChildrenAsStatement(node, context);
|
|
152
|
+
// _renderSlot(slots, name, props, fallback, ...)
|
|
153
|
+
renderCall.arguments[3] = fallbackRenderFn;
|
|
154
|
+
}
|
|
155
|
+
// Forwarded <slot/>. Merge slot scope ids
|
|
156
|
+
if (context.withSlotScopeId) {
|
|
157
|
+
const slotScopeId = renderCall.arguments[6];
|
|
158
|
+
renderCall.arguments[6] = slotScopeId
|
|
159
|
+
? `${slotScopeId} + _scopeId`
|
|
160
|
+
: `_scopeId`;
|
|
161
|
+
}
|
|
162
|
+
context.pushStatement(node.ssrCodegenNode);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
function createSSRCompilerError(code, loc) {
|
|
166
|
-
return compilerDom.createCompilerError(code, loc, SSRErrorMessages);
|
|
167
|
-
}
|
|
168
|
-
const SSRErrorMessages = {
|
|
169
|
-
[61 /* SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME */]: `Unsafe attribute name for SSR.`,
|
|
170
|
-
[62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */]: `Missing the 'to' prop on teleport element.`,
|
|
171
|
-
[63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */]: `Invalid AST node during SSR transform.`
|
|
165
|
+
function createSSRCompilerError(code, loc) {
|
|
166
|
+
return compilerDom.createCompilerError(code, loc, SSRErrorMessages);
|
|
167
|
+
}
|
|
168
|
+
const SSRErrorMessages = {
|
|
169
|
+
[61 /* SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME */]: `Unsafe attribute name for SSR.`,
|
|
170
|
+
[62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */]: `Missing the 'to' prop on teleport element.`,
|
|
171
|
+
[63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */]: `Invalid AST node during SSR transform.`
|
|
172
172
|
};
|
|
173
173
|
|
|
174
|
-
// Note: this is a 2nd-pass codegen transform.
|
|
175
|
-
function ssrProcessTeleport(node, context) {
|
|
176
|
-
const targetProp = compilerDom.findProp(node, 'to');
|
|
177
|
-
if (!targetProp) {
|
|
178
|
-
context.onError(createSSRCompilerError(62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */, node.loc));
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
let target;
|
|
182
|
-
if (targetProp.type === 6 /* NodeTypes.ATTRIBUTE */) {
|
|
183
|
-
target =
|
|
184
|
-
targetProp.value && compilerDom.createSimpleExpression(targetProp.value.content, true);
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
target = targetProp.exp;
|
|
188
|
-
}
|
|
189
|
-
if (!target) {
|
|
190
|
-
context.onError(createSSRCompilerError(62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */, targetProp.loc));
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
const disabledProp = compilerDom.findProp(node, 'disabled', false, true /* allow empty */);
|
|
194
|
-
const disabled = disabledProp
|
|
195
|
-
? disabledProp.type === 6 /* NodeTypes.ATTRIBUTE */
|
|
196
|
-
? `true`
|
|
197
|
-
: disabledProp.exp || `false`
|
|
198
|
-
: `false`;
|
|
199
|
-
const contentRenderFn = compilerDom.createFunctionExpression([`_push`], undefined, // Body is added later
|
|
200
|
-
true, // newline
|
|
201
|
-
false, // isSlot
|
|
202
|
-
node.loc);
|
|
203
|
-
contentRenderFn.body = processChildrenAsStatement(node, context);
|
|
204
|
-
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_TELEPORT), [
|
|
205
|
-
`_push`,
|
|
206
|
-
contentRenderFn,
|
|
207
|
-
target,
|
|
208
|
-
disabled,
|
|
209
|
-
`_parent`
|
|
210
|
-
]));
|
|
174
|
+
// Note: this is a 2nd-pass codegen transform.
|
|
175
|
+
function ssrProcessTeleport(node, context) {
|
|
176
|
+
const targetProp = compilerDom.findProp(node, 'to');
|
|
177
|
+
if (!targetProp) {
|
|
178
|
+
context.onError(createSSRCompilerError(62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */, node.loc));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
let target;
|
|
182
|
+
if (targetProp.type === 6 /* NodeTypes.ATTRIBUTE */) {
|
|
183
|
+
target =
|
|
184
|
+
targetProp.value && compilerDom.createSimpleExpression(targetProp.value.content, true);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
target = targetProp.exp;
|
|
188
|
+
}
|
|
189
|
+
if (!target) {
|
|
190
|
+
context.onError(createSSRCompilerError(62 /* SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET */, targetProp.loc));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const disabledProp = compilerDom.findProp(node, 'disabled', false, true /* allow empty */);
|
|
194
|
+
const disabled = disabledProp
|
|
195
|
+
? disabledProp.type === 6 /* NodeTypes.ATTRIBUTE */
|
|
196
|
+
? `true`
|
|
197
|
+
: disabledProp.exp || `false`
|
|
198
|
+
: `false`;
|
|
199
|
+
const contentRenderFn = compilerDom.createFunctionExpression([`_push`], undefined, // Body is added later
|
|
200
|
+
true, // newline
|
|
201
|
+
false, // isSlot
|
|
202
|
+
node.loc);
|
|
203
|
+
contentRenderFn.body = processChildrenAsStatement(node, context);
|
|
204
|
+
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_TELEPORT), [
|
|
205
|
+
`_push`,
|
|
206
|
+
contentRenderFn,
|
|
207
|
+
target,
|
|
208
|
+
disabled,
|
|
209
|
+
`_parent`
|
|
210
|
+
]));
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
const wipMap = new WeakMap();
|
|
214
|
-
// phase 1
|
|
215
|
-
function ssrTransformSuspense(node, context) {
|
|
216
|
-
return () => {
|
|
217
|
-
if (node.children.length) {
|
|
218
|
-
const wipEntry = {
|
|
219
|
-
slotsExp: null,
|
|
220
|
-
wipSlots: []
|
|
221
|
-
};
|
|
222
|
-
wipMap.set(node, wipEntry);
|
|
223
|
-
wipEntry.slotsExp = compilerDom.buildSlots(node, context, (_props, children, loc) => {
|
|
224
|
-
const fn = compilerDom.createFunctionExpression([], undefined, // no return, assign body later
|
|
225
|
-
true, // newline
|
|
226
|
-
false, // suspense slots are not treated as normal slots
|
|
227
|
-
loc);
|
|
228
|
-
wipEntry.wipSlots.push({
|
|
229
|
-
fn,
|
|
230
|
-
children
|
|
231
|
-
});
|
|
232
|
-
return fn;
|
|
233
|
-
}).slots;
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
// phase 2
|
|
238
|
-
function ssrProcessSuspense(node, context) {
|
|
239
|
-
// complete wip slots with ssr code
|
|
240
|
-
const wipEntry = wipMap.get(node);
|
|
241
|
-
if (!wipEntry) {
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const { slotsExp, wipSlots } = wipEntry;
|
|
245
|
-
for (let i = 0; i < wipSlots.length; i++) {
|
|
246
|
-
const slot = wipSlots[i];
|
|
247
|
-
slot.fn.body = processChildrenAsStatement(slot, context);
|
|
248
|
-
}
|
|
249
|
-
// _push(ssrRenderSuspense(slots))
|
|
250
|
-
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_SUSPENSE), [
|
|
251
|
-
`_push`,
|
|
252
|
-
slotsExp
|
|
253
|
-
]));
|
|
213
|
+
const wipMap = new WeakMap();
|
|
214
|
+
// phase 1
|
|
215
|
+
function ssrTransformSuspense(node, context) {
|
|
216
|
+
return () => {
|
|
217
|
+
if (node.children.length) {
|
|
218
|
+
const wipEntry = {
|
|
219
|
+
slotsExp: null,
|
|
220
|
+
wipSlots: []
|
|
221
|
+
};
|
|
222
|
+
wipMap.set(node, wipEntry);
|
|
223
|
+
wipEntry.slotsExp = compilerDom.buildSlots(node, context, (_props, children, loc) => {
|
|
224
|
+
const fn = compilerDom.createFunctionExpression([], undefined, // no return, assign body later
|
|
225
|
+
true, // newline
|
|
226
|
+
false, // suspense slots are not treated as normal slots
|
|
227
|
+
loc);
|
|
228
|
+
wipEntry.wipSlots.push({
|
|
229
|
+
fn,
|
|
230
|
+
children
|
|
231
|
+
});
|
|
232
|
+
return fn;
|
|
233
|
+
}).slots;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
// phase 2
|
|
238
|
+
function ssrProcessSuspense(node, context) {
|
|
239
|
+
// complete wip slots with ssr code
|
|
240
|
+
const wipEntry = wipMap.get(node);
|
|
241
|
+
if (!wipEntry) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const { slotsExp, wipSlots } = wipEntry;
|
|
245
|
+
for (let i = 0; i < wipSlots.length; i++) {
|
|
246
|
+
const slot = wipSlots[i];
|
|
247
|
+
slot.fn.body = processChildrenAsStatement(slot, context);
|
|
248
|
+
}
|
|
249
|
+
// _push(ssrRenderSuspense(slots))
|
|
250
|
+
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_SUSPENSE), [
|
|
251
|
+
`_push`,
|
|
252
|
+
slotsExp
|
|
253
|
+
]));
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
// for directives with children overwrite (e.g. v-html & v-text), we need to
|
|
257
|
-
// store the raw children so that they can be added in the 2nd pass.
|
|
258
|
-
const rawChildrenMap = new WeakMap();
|
|
259
|
-
const ssrTransformElement = (node, context) => {
|
|
260
|
-
if (node.type !== 1 /* NodeTypes.ELEMENT */ ||
|
|
261
|
-
node.tagType !== 0 /* ElementTypes.ELEMENT */) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
return function ssrPostTransformElement() {
|
|
265
|
-
// element
|
|
266
|
-
// generate the template literal representing the open tag.
|
|
267
|
-
const openTag = [`<${node.tag}`];
|
|
268
|
-
// some tags need to be passed to runtime for special checks
|
|
269
|
-
const needTagForRuntime = node.tag === 'textarea' || node.tag.indexOf('-') > 0;
|
|
270
|
-
// v-bind="obj", v-bind:[key] and custom directives can potentially
|
|
271
|
-
// overwrite other static attrs and can affect final rendering result,
|
|
272
|
-
// so when they are present we need to bail out to full `renderAttrs`
|
|
273
|
-
const hasDynamicVBind = compilerDom.hasDynamicKeyVBind(node);
|
|
274
|
-
const hasCustomDir = node.props.some(p => p.type === 7 /* NodeTypes.DIRECTIVE */ && !shared.isBuiltInDirective(p.name));
|
|
275
|
-
const needMergeProps = hasDynamicVBind || hasCustomDir;
|
|
276
|
-
if (needMergeProps) {
|
|
277
|
-
const { props, directives } = compilerDom.buildProps(node, context, node.props, false /* isComponent */, false /* isDynamicComponent */, true /* ssr */);
|
|
278
|
-
if (props || directives.length) {
|
|
279
|
-
const mergedProps = buildSSRProps(props, directives, context);
|
|
280
|
-
const propsExp = compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTRS), [mergedProps]);
|
|
281
|
-
if (node.tag === 'textarea') {
|
|
282
|
-
const existingText = node.children[0];
|
|
283
|
-
// If interpolation, this is dynamic <textarea> content, potentially
|
|
284
|
-
// injected by v-model and takes higher priority than v-bind value
|
|
285
|
-
if (!existingText || existingText.type !== 5 /* NodeTypes.INTERPOLATION */) {
|
|
286
|
-
// <textarea> with dynamic v-bind. We don't know if the final props
|
|
287
|
-
// will contain .value, so we will have to do something special:
|
|
288
|
-
// assign the merged props to a temp variable, and check whether
|
|
289
|
-
// it contains value (if yes, render is as children).
|
|
290
|
-
const tempId = `_temp${context.temps++}`;
|
|
291
|
-
propsExp.arguments = [
|
|
292
|
-
compilerDom.createAssignmentExpression(compilerDom.createSimpleExpression(tempId, false), mergedProps)
|
|
293
|
-
];
|
|
294
|
-
rawChildrenMap.set(node, compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [
|
|
295
|
-
compilerDom.createConditionalExpression(compilerDom.createSimpleExpression(`"value" in ${tempId}`, false), compilerDom.createSimpleExpression(`${tempId}.value`, false), compilerDom.createSimpleExpression(existingText ? existingText.content : ``, true), false)
|
|
296
|
-
]));
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
else if (node.tag === 'input') {
|
|
300
|
-
// <input v-bind="obj" v-model>
|
|
301
|
-
// we need to determine the props to render for the dynamic v-model
|
|
302
|
-
// and merge it with the v-bind expression.
|
|
303
|
-
const vModel = findVModel(node);
|
|
304
|
-
if (vModel) {
|
|
305
|
-
// 1. save the props (san v-model) in a temp variable
|
|
306
|
-
const tempId = `_temp${context.temps++}`;
|
|
307
|
-
const tempExp = compilerDom.createSimpleExpression(tempId, false);
|
|
308
|
-
propsExp.arguments = [
|
|
309
|
-
compilerDom.createSequenceExpression([
|
|
310
|
-
compilerDom.createAssignmentExpression(tempExp, mergedProps),
|
|
311
|
-
compilerDom.createCallExpression(context.helper(compilerDom.MERGE_PROPS), [
|
|
312
|
-
tempExp,
|
|
313
|
-
compilerDom.createCallExpression(context.helper(SSR_GET_DYNAMIC_MODEL_PROPS), [
|
|
314
|
-
tempExp,
|
|
315
|
-
vModel.exp // model
|
|
316
|
-
])
|
|
317
|
-
])
|
|
318
|
-
])
|
|
319
|
-
];
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
if (needTagForRuntime) {
|
|
323
|
-
propsExp.arguments.push(`"${node.tag}"`);
|
|
324
|
-
}
|
|
325
|
-
openTag.push(propsExp);
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// book keeping static/dynamic class merging.
|
|
329
|
-
let dynamicClassBinding = undefined;
|
|
330
|
-
let staticClassBinding = undefined;
|
|
331
|
-
// all style bindings are converted to dynamic by transformStyle.
|
|
332
|
-
// but we need to make sure to merge them.
|
|
333
|
-
let dynamicStyleBinding = undefined;
|
|
334
|
-
for (let i = 0; i < node.props.length; i++) {
|
|
335
|
-
const prop = node.props[i];
|
|
336
|
-
// ignore true-value/false-value on input
|
|
337
|
-
if (node.tag === 'input' && isTrueFalseValue(prop)) {
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
|
-
// special cases with children override
|
|
341
|
-
if (prop.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
342
|
-
if (prop.name === 'html' && prop.exp) {
|
|
343
|
-
rawChildrenMap.set(node, prop.exp);
|
|
344
|
-
}
|
|
345
|
-
else if (prop.name === 'text' && prop.exp) {
|
|
346
|
-
node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
|
|
347
|
-
}
|
|
348
|
-
else if (prop.name === 'slot') {
|
|
349
|
-
context.onError(compilerDom.createCompilerError(40 /* ErrorCodes.X_V_SLOT_MISPLACED */, prop.loc));
|
|
350
|
-
}
|
|
351
|
-
else if (isTextareaWithValue(node, prop) && prop.exp) {
|
|
352
|
-
if (!needMergeProps) {
|
|
353
|
-
node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
else if (!needMergeProps && prop.name !== 'on') {
|
|
357
|
-
// Directive transforms.
|
|
358
|
-
const directiveTransform = context.directiveTransforms[prop.name];
|
|
359
|
-
if (directiveTransform) {
|
|
360
|
-
const { props, ssrTagParts } = directiveTransform(prop, node, context);
|
|
361
|
-
if (ssrTagParts) {
|
|
362
|
-
openTag.push(...ssrTagParts);
|
|
363
|
-
}
|
|
364
|
-
for (let j = 0; j < props.length; j++) {
|
|
365
|
-
const { key, value } = props[j];
|
|
366
|
-
if (compilerDom.isStaticExp(key)) {
|
|
367
|
-
let attrName = key.content;
|
|
368
|
-
// static key attr
|
|
369
|
-
if (attrName === 'key' || attrName === 'ref') {
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
if (attrName === 'class') {
|
|
373
|
-
openTag.push(` class="`, (dynamicClassBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_CLASS), [value])), `"`);
|
|
374
|
-
}
|
|
375
|
-
else if (attrName === 'style') {
|
|
376
|
-
if (dynamicStyleBinding) {
|
|
377
|
-
// already has style binding, merge into it.
|
|
378
|
-
mergeCall(dynamicStyleBinding, value);
|
|
379
|
-
}
|
|
380
|
-
else {
|
|
381
|
-
openTag.push(` style="`, (dynamicStyleBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_STYLE), [value])), `"`);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
else {
|
|
385
|
-
attrName =
|
|
386
|
-
node.tag.indexOf('-') > 0
|
|
387
|
-
? attrName // preserve raw name on custom elements
|
|
388
|
-
: shared.propsToAttrMap[attrName] || attrName.toLowerCase();
|
|
389
|
-
if (shared.isBooleanAttr(attrName)) {
|
|
390
|
-
openTag.push(compilerDom.createConditionalExpression(compilerDom.createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [value]), compilerDom.createSimpleExpression(' ' + attrName, true), compilerDom.createSimpleExpression('', true), false /* no newline */));
|
|
391
|
-
}
|
|
392
|
-
else if (shared.isSSRSafeAttrName(attrName)) {
|
|
393
|
-
openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTR), [
|
|
394
|
-
key,
|
|
395
|
-
value
|
|
396
|
-
]));
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
context.onError(createSSRCompilerError(61 /* SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME */, key.loc));
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
// dynamic key attr
|
|
405
|
-
// this branch is only encountered for custom directive
|
|
406
|
-
// transforms that returns properties with dynamic keys
|
|
407
|
-
const args = [key, value];
|
|
408
|
-
if (needTagForRuntime) {
|
|
409
|
-
args.push(`"${node.tag}"`);
|
|
410
|
-
}
|
|
411
|
-
openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_ATTR), args));
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
// special case: value on <textarea>
|
|
419
|
-
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
|
|
420
|
-
rawChildrenMap.set(node, shared.escapeHtml(prop.value.content));
|
|
421
|
-
}
|
|
422
|
-
else if (!needMergeProps) {
|
|
423
|
-
if (prop.name === 'key' || prop.name === 'ref') {
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
// static prop
|
|
427
|
-
if (prop.name === 'class' && prop.value) {
|
|
428
|
-
staticClassBinding = JSON.stringify(prop.value.content);
|
|
429
|
-
}
|
|
430
|
-
openTag.push(` ${prop.name}` +
|
|
431
|
-
(prop.value ? `="${shared.escapeHtml(prop.value.content)}"` : ``));
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
// handle co-existence of dynamic + static class bindings
|
|
436
|
-
if (dynamicClassBinding && staticClassBinding) {
|
|
437
|
-
mergeCall(dynamicClassBinding, staticClassBinding);
|
|
438
|
-
removeStaticBinding(openTag, 'class');
|
|
439
|
-
}
|
|
440
|
-
if (context.scopeId) {
|
|
441
|
-
openTag.push(` ${context.scopeId}`);
|
|
442
|
-
}
|
|
443
|
-
node.ssrCodegenNode = compilerDom.createTemplateLiteral(openTag);
|
|
444
|
-
};
|
|
445
|
-
};
|
|
446
|
-
function buildSSRProps(props, directives, context) {
|
|
447
|
-
let mergePropsArgs = [];
|
|
448
|
-
if (props) {
|
|
449
|
-
if (props.type === 14 /* NodeTypes.JS_CALL_EXPRESSION */) {
|
|
450
|
-
// already a mergeProps call
|
|
451
|
-
mergePropsArgs = props.arguments;
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
mergePropsArgs.push(props);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
if (directives.length) {
|
|
458
|
-
for (const dir of directives) {
|
|
459
|
-
mergePropsArgs.push(compilerDom.createCallExpression(context.helper(SSR_GET_DIRECTIVE_PROPS), [
|
|
460
|
-
`_ctx`,
|
|
461
|
-
...compilerDom.buildDirectiveArgs(dir, context).elements
|
|
462
|
-
]));
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return mergePropsArgs.length > 1
|
|
466
|
-
? compilerDom.createCallExpression(context.helper(compilerDom.MERGE_PROPS), mergePropsArgs)
|
|
467
|
-
: mergePropsArgs[0];
|
|
468
|
-
}
|
|
469
|
-
function isTrueFalseValue(prop) {
|
|
470
|
-
if (prop.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
471
|
-
return (prop.name === 'bind' &&
|
|
472
|
-
prop.arg &&
|
|
473
|
-
compilerDom.isStaticExp(prop.arg) &&
|
|
474
|
-
(prop.arg.content === 'true-value' || prop.arg.content === 'false-value'));
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
return prop.name === 'true-value' || prop.name === 'false-value';
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
function isTextareaWithValue(node, prop) {
|
|
481
|
-
return !!(node.tag === 'textarea' &&
|
|
482
|
-
prop.name === 'bind' &&
|
|
483
|
-
compilerDom.isStaticArgOf(prop.arg, 'value'));
|
|
484
|
-
}
|
|
485
|
-
function mergeCall(call, arg) {
|
|
486
|
-
const existing = call.arguments[0];
|
|
487
|
-
if (existing.type === 17 /* NodeTypes.JS_ARRAY_EXPRESSION */) {
|
|
488
|
-
existing.elements.push(arg);
|
|
489
|
-
}
|
|
490
|
-
else {
|
|
491
|
-
call.arguments[0] = compilerDom.createArrayExpression([existing, arg]);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
function removeStaticBinding(tag, binding) {
|
|
495
|
-
const regExp = new RegExp(`^ ${binding}=".+"$`);
|
|
496
|
-
const i = tag.findIndex(e => typeof e === 'string' && regExp.test(e));
|
|
497
|
-
if (i > -1) {
|
|
498
|
-
tag.splice(i, 1);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
function findVModel(node) {
|
|
502
|
-
return node.props.find(p => p.type === 7 /* NodeTypes.DIRECTIVE */ && p.name === 'model' && p.exp);
|
|
503
|
-
}
|
|
504
|
-
function ssrProcessElement(node, context) {
|
|
505
|
-
const isVoidTag = context.options.isVoidTag || shared.NO;
|
|
506
|
-
const elementsToAdd = node.ssrCodegenNode.elements;
|
|
507
|
-
for (let j = 0; j < elementsToAdd.length; j++) {
|
|
508
|
-
context.pushStringPart(elementsToAdd[j]);
|
|
509
|
-
}
|
|
510
|
-
// Handle slot scopeId
|
|
511
|
-
if (context.withSlotScopeId) {
|
|
512
|
-
context.pushStringPart(compilerDom.createSimpleExpression(`_scopeId`, false));
|
|
513
|
-
}
|
|
514
|
-
// close open tag
|
|
515
|
-
context.pushStringPart(`>`);
|
|
516
|
-
const rawChildren = rawChildrenMap.get(node);
|
|
517
|
-
if (rawChildren) {
|
|
518
|
-
context.pushStringPart(rawChildren);
|
|
519
|
-
}
|
|
520
|
-
else if (node.children.length) {
|
|
521
|
-
processChildren(node, context);
|
|
522
|
-
}
|
|
523
|
-
if (!isVoidTag(node.tag)) {
|
|
524
|
-
// push closing tag
|
|
525
|
-
context.pushStringPart(`</${node.tag}>`);
|
|
526
|
-
}
|
|
256
|
+
// for directives with children overwrite (e.g. v-html & v-text), we need to
|
|
257
|
+
// store the raw children so that they can be added in the 2nd pass.
|
|
258
|
+
const rawChildrenMap = new WeakMap();
|
|
259
|
+
const ssrTransformElement = (node, context) => {
|
|
260
|
+
if (node.type !== 1 /* NodeTypes.ELEMENT */ ||
|
|
261
|
+
node.tagType !== 0 /* ElementTypes.ELEMENT */) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
return function ssrPostTransformElement() {
|
|
265
|
+
// element
|
|
266
|
+
// generate the template literal representing the open tag.
|
|
267
|
+
const openTag = [`<${node.tag}`];
|
|
268
|
+
// some tags need to be passed to runtime for special checks
|
|
269
|
+
const needTagForRuntime = node.tag === 'textarea' || node.tag.indexOf('-') > 0;
|
|
270
|
+
// v-bind="obj", v-bind:[key] and custom directives can potentially
|
|
271
|
+
// overwrite other static attrs and can affect final rendering result,
|
|
272
|
+
// so when they are present we need to bail out to full `renderAttrs`
|
|
273
|
+
const hasDynamicVBind = compilerDom.hasDynamicKeyVBind(node);
|
|
274
|
+
const hasCustomDir = node.props.some(p => p.type === 7 /* NodeTypes.DIRECTIVE */ && !shared.isBuiltInDirective(p.name));
|
|
275
|
+
const needMergeProps = hasDynamicVBind || hasCustomDir;
|
|
276
|
+
if (needMergeProps) {
|
|
277
|
+
const { props, directives } = compilerDom.buildProps(node, context, node.props, false /* isComponent */, false /* isDynamicComponent */, true /* ssr */);
|
|
278
|
+
if (props || directives.length) {
|
|
279
|
+
const mergedProps = buildSSRProps(props, directives, context);
|
|
280
|
+
const propsExp = compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTRS), [mergedProps]);
|
|
281
|
+
if (node.tag === 'textarea') {
|
|
282
|
+
const existingText = node.children[0];
|
|
283
|
+
// If interpolation, this is dynamic <textarea> content, potentially
|
|
284
|
+
// injected by v-model and takes higher priority than v-bind value
|
|
285
|
+
if (!existingText || existingText.type !== 5 /* NodeTypes.INTERPOLATION */) {
|
|
286
|
+
// <textarea> with dynamic v-bind. We don't know if the final props
|
|
287
|
+
// will contain .value, so we will have to do something special:
|
|
288
|
+
// assign the merged props to a temp variable, and check whether
|
|
289
|
+
// it contains value (if yes, render is as children).
|
|
290
|
+
const tempId = `_temp${context.temps++}`;
|
|
291
|
+
propsExp.arguments = [
|
|
292
|
+
compilerDom.createAssignmentExpression(compilerDom.createSimpleExpression(tempId, false), mergedProps)
|
|
293
|
+
];
|
|
294
|
+
rawChildrenMap.set(node, compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [
|
|
295
|
+
compilerDom.createConditionalExpression(compilerDom.createSimpleExpression(`"value" in ${tempId}`, false), compilerDom.createSimpleExpression(`${tempId}.value`, false), compilerDom.createSimpleExpression(existingText ? existingText.content : ``, true), false)
|
|
296
|
+
]));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else if (node.tag === 'input') {
|
|
300
|
+
// <input v-bind="obj" v-model>
|
|
301
|
+
// we need to determine the props to render for the dynamic v-model
|
|
302
|
+
// and merge it with the v-bind expression.
|
|
303
|
+
const vModel = findVModel(node);
|
|
304
|
+
if (vModel) {
|
|
305
|
+
// 1. save the props (san v-model) in a temp variable
|
|
306
|
+
const tempId = `_temp${context.temps++}`;
|
|
307
|
+
const tempExp = compilerDom.createSimpleExpression(tempId, false);
|
|
308
|
+
propsExp.arguments = [
|
|
309
|
+
compilerDom.createSequenceExpression([
|
|
310
|
+
compilerDom.createAssignmentExpression(tempExp, mergedProps),
|
|
311
|
+
compilerDom.createCallExpression(context.helper(compilerDom.MERGE_PROPS), [
|
|
312
|
+
tempExp,
|
|
313
|
+
compilerDom.createCallExpression(context.helper(SSR_GET_DYNAMIC_MODEL_PROPS), [
|
|
314
|
+
tempExp,
|
|
315
|
+
vModel.exp // model
|
|
316
|
+
])
|
|
317
|
+
])
|
|
318
|
+
])
|
|
319
|
+
];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (needTagForRuntime) {
|
|
323
|
+
propsExp.arguments.push(`"${node.tag}"`);
|
|
324
|
+
}
|
|
325
|
+
openTag.push(propsExp);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// book keeping static/dynamic class merging.
|
|
329
|
+
let dynamicClassBinding = undefined;
|
|
330
|
+
let staticClassBinding = undefined;
|
|
331
|
+
// all style bindings are converted to dynamic by transformStyle.
|
|
332
|
+
// but we need to make sure to merge them.
|
|
333
|
+
let dynamicStyleBinding = undefined;
|
|
334
|
+
for (let i = 0; i < node.props.length; i++) {
|
|
335
|
+
const prop = node.props[i];
|
|
336
|
+
// ignore true-value/false-value on input
|
|
337
|
+
if (node.tag === 'input' && isTrueFalseValue(prop)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
// special cases with children override
|
|
341
|
+
if (prop.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
342
|
+
if (prop.name === 'html' && prop.exp) {
|
|
343
|
+
rawChildrenMap.set(node, prop.exp);
|
|
344
|
+
}
|
|
345
|
+
else if (prop.name === 'text' && prop.exp) {
|
|
346
|
+
node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
|
|
347
|
+
}
|
|
348
|
+
else if (prop.name === 'slot') {
|
|
349
|
+
context.onError(compilerDom.createCompilerError(40 /* ErrorCodes.X_V_SLOT_MISPLACED */, prop.loc));
|
|
350
|
+
}
|
|
351
|
+
else if (isTextareaWithValue(node, prop) && prop.exp) {
|
|
352
|
+
if (!needMergeProps) {
|
|
353
|
+
node.children = [compilerDom.createInterpolation(prop.exp, prop.loc)];
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else if (!needMergeProps && prop.name !== 'on') {
|
|
357
|
+
// Directive transforms.
|
|
358
|
+
const directiveTransform = context.directiveTransforms[prop.name];
|
|
359
|
+
if (directiveTransform) {
|
|
360
|
+
const { props, ssrTagParts } = directiveTransform(prop, node, context);
|
|
361
|
+
if (ssrTagParts) {
|
|
362
|
+
openTag.push(...ssrTagParts);
|
|
363
|
+
}
|
|
364
|
+
for (let j = 0; j < props.length; j++) {
|
|
365
|
+
const { key, value } = props[j];
|
|
366
|
+
if (compilerDom.isStaticExp(key)) {
|
|
367
|
+
let attrName = key.content;
|
|
368
|
+
// static key attr
|
|
369
|
+
if (attrName === 'key' || attrName === 'ref') {
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (attrName === 'class') {
|
|
373
|
+
openTag.push(` class="`, (dynamicClassBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_CLASS), [value])), `"`);
|
|
374
|
+
}
|
|
375
|
+
else if (attrName === 'style') {
|
|
376
|
+
if (dynamicStyleBinding) {
|
|
377
|
+
// already has style binding, merge into it.
|
|
378
|
+
mergeCall(dynamicStyleBinding, value);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
openTag.push(` style="`, (dynamicStyleBinding = compilerDom.createCallExpression(context.helper(SSR_RENDER_STYLE), [value])), `"`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
attrName =
|
|
386
|
+
node.tag.indexOf('-') > 0
|
|
387
|
+
? attrName // preserve raw name on custom elements
|
|
388
|
+
: shared.propsToAttrMap[attrName] || attrName.toLowerCase();
|
|
389
|
+
if (shared.isBooleanAttr(attrName)) {
|
|
390
|
+
openTag.push(compilerDom.createConditionalExpression(compilerDom.createCallExpression(context.helper(SSR_INCLUDE_BOOLEAN_ATTR), [value]), compilerDom.createSimpleExpression(' ' + attrName, true), compilerDom.createSimpleExpression('', true), false /* no newline */));
|
|
391
|
+
}
|
|
392
|
+
else if (shared.isSSRSafeAttrName(attrName)) {
|
|
393
|
+
openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTR), [
|
|
394
|
+
key,
|
|
395
|
+
value
|
|
396
|
+
]));
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
context.onError(createSSRCompilerError(61 /* SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME */, key.loc));
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
// dynamic key attr
|
|
405
|
+
// this branch is only encountered for custom directive
|
|
406
|
+
// transforms that returns properties with dynamic keys
|
|
407
|
+
const args = [key, value];
|
|
408
|
+
if (needTagForRuntime) {
|
|
409
|
+
args.push(`"${node.tag}"`);
|
|
410
|
+
}
|
|
411
|
+
openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_ATTR), args));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else {
|
|
418
|
+
// special case: value on <textarea>
|
|
419
|
+
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
|
|
420
|
+
rawChildrenMap.set(node, shared.escapeHtml(prop.value.content));
|
|
421
|
+
}
|
|
422
|
+
else if (!needMergeProps) {
|
|
423
|
+
if (prop.name === 'key' || prop.name === 'ref') {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
// static prop
|
|
427
|
+
if (prop.name === 'class' && prop.value) {
|
|
428
|
+
staticClassBinding = JSON.stringify(prop.value.content);
|
|
429
|
+
}
|
|
430
|
+
openTag.push(` ${prop.name}` +
|
|
431
|
+
(prop.value ? `="${shared.escapeHtml(prop.value.content)}"` : ``));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// handle co-existence of dynamic + static class bindings
|
|
436
|
+
if (dynamicClassBinding && staticClassBinding) {
|
|
437
|
+
mergeCall(dynamicClassBinding, staticClassBinding);
|
|
438
|
+
removeStaticBinding(openTag, 'class');
|
|
439
|
+
}
|
|
440
|
+
if (context.scopeId) {
|
|
441
|
+
openTag.push(` ${context.scopeId}`);
|
|
442
|
+
}
|
|
443
|
+
node.ssrCodegenNode = compilerDom.createTemplateLiteral(openTag);
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
function buildSSRProps(props, directives, context) {
|
|
447
|
+
let mergePropsArgs = [];
|
|
448
|
+
if (props) {
|
|
449
|
+
if (props.type === 14 /* NodeTypes.JS_CALL_EXPRESSION */) {
|
|
450
|
+
// already a mergeProps call
|
|
451
|
+
mergePropsArgs = props.arguments;
|
|
452
|
+
}
|
|
453
|
+
else {
|
|
454
|
+
mergePropsArgs.push(props);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (directives.length) {
|
|
458
|
+
for (const dir of directives) {
|
|
459
|
+
mergePropsArgs.push(compilerDom.createCallExpression(context.helper(SSR_GET_DIRECTIVE_PROPS), [
|
|
460
|
+
`_ctx`,
|
|
461
|
+
...compilerDom.buildDirectiveArgs(dir, context).elements
|
|
462
|
+
]));
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return mergePropsArgs.length > 1
|
|
466
|
+
? compilerDom.createCallExpression(context.helper(compilerDom.MERGE_PROPS), mergePropsArgs)
|
|
467
|
+
: mergePropsArgs[0];
|
|
468
|
+
}
|
|
469
|
+
function isTrueFalseValue(prop) {
|
|
470
|
+
if (prop.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
471
|
+
return (prop.name === 'bind' &&
|
|
472
|
+
prop.arg &&
|
|
473
|
+
compilerDom.isStaticExp(prop.arg) &&
|
|
474
|
+
(prop.arg.content === 'true-value' || prop.arg.content === 'false-value'));
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
return prop.name === 'true-value' || prop.name === 'false-value';
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
function isTextareaWithValue(node, prop) {
|
|
481
|
+
return !!(node.tag === 'textarea' &&
|
|
482
|
+
prop.name === 'bind' &&
|
|
483
|
+
compilerDom.isStaticArgOf(prop.arg, 'value'));
|
|
484
|
+
}
|
|
485
|
+
function mergeCall(call, arg) {
|
|
486
|
+
const existing = call.arguments[0];
|
|
487
|
+
if (existing.type === 17 /* NodeTypes.JS_ARRAY_EXPRESSION */) {
|
|
488
|
+
existing.elements.push(arg);
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
call.arguments[0] = compilerDom.createArrayExpression([existing, arg]);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function removeStaticBinding(tag, binding) {
|
|
495
|
+
const regExp = new RegExp(`^ ${binding}=".+"$`);
|
|
496
|
+
const i = tag.findIndex(e => typeof e === 'string' && regExp.test(e));
|
|
497
|
+
if (i > -1) {
|
|
498
|
+
tag.splice(i, 1);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
function findVModel(node) {
|
|
502
|
+
return node.props.find(p => p.type === 7 /* NodeTypes.DIRECTIVE */ && p.name === 'model' && p.exp);
|
|
503
|
+
}
|
|
504
|
+
function ssrProcessElement(node, context) {
|
|
505
|
+
const isVoidTag = context.options.isVoidTag || shared.NO;
|
|
506
|
+
const elementsToAdd = node.ssrCodegenNode.elements;
|
|
507
|
+
for (let j = 0; j < elementsToAdd.length; j++) {
|
|
508
|
+
context.pushStringPart(elementsToAdd[j]);
|
|
509
|
+
}
|
|
510
|
+
// Handle slot scopeId
|
|
511
|
+
if (context.withSlotScopeId) {
|
|
512
|
+
context.pushStringPart(compilerDom.createSimpleExpression(`_scopeId`, false));
|
|
513
|
+
}
|
|
514
|
+
// close open tag
|
|
515
|
+
context.pushStringPart(`>`);
|
|
516
|
+
const rawChildren = rawChildrenMap.get(node);
|
|
517
|
+
if (rawChildren) {
|
|
518
|
+
context.pushStringPart(rawChildren);
|
|
519
|
+
}
|
|
520
|
+
else if (node.children.length) {
|
|
521
|
+
processChildren(node, context);
|
|
522
|
+
}
|
|
523
|
+
if (!isVoidTag(node.tag)) {
|
|
524
|
+
// push closing tag
|
|
525
|
+
context.pushStringPart(`</${node.tag}>`);
|
|
526
|
+
}
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
-
const wipMap$1 = new WeakMap();
|
|
530
|
-
// phase 1: build props
|
|
531
|
-
function ssrTransformTransitionGroup(node, context) {
|
|
532
|
-
return () => {
|
|
533
|
-
const tag = compilerDom.findProp(node, 'tag');
|
|
534
|
-
if (tag) {
|
|
535
|
-
const otherProps = node.props.filter(p => p !== tag);
|
|
536
|
-
const { props, directives } = compilerDom.buildProps(node, context, otherProps, true
|
|
537
|
-
let propsExp = null;
|
|
538
|
-
if (props || directives.length) {
|
|
539
|
-
propsExp = compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTRS), [
|
|
540
|
-
buildSSRProps(props, directives, context)
|
|
541
|
-
]);
|
|
542
|
-
}
|
|
543
|
-
wipMap$1.set(node, {
|
|
544
|
-
tag,
|
|
545
|
-
propsExp
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
// phase 2: process children
|
|
551
|
-
function ssrProcessTransitionGroup(node, context) {
|
|
552
|
-
const entry = wipMap$1.get(node);
|
|
553
|
-
if (entry) {
|
|
554
|
-
const { tag, propsExp } = entry;
|
|
555
|
-
if (tag.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
556
|
-
// dynamic :tag
|
|
557
|
-
context.pushStringPart(`<`);
|
|
558
|
-
context.pushStringPart(tag.exp);
|
|
559
|
-
if (propsExp) {
|
|
560
|
-
context.pushStringPart(propsExp);
|
|
561
|
-
}
|
|
562
|
-
context.pushStringPart(`>`);
|
|
563
|
-
processChildren(node, context, false,
|
|
564
|
-
/**
|
|
565
|
-
* TransitionGroup has the special runtime behavior of flattening and
|
|
566
|
-
* concatenating all children into a single fragment (in order for them to
|
|
567
|
-
* be patched using the same key map) so we need to account for that here
|
|
568
|
-
* by disabling nested fragment wrappers from being generated.
|
|
569
|
-
*/
|
|
570
|
-
true);
|
|
571
|
-
context.pushStringPart(`</`);
|
|
572
|
-
context.pushStringPart(tag.exp);
|
|
573
|
-
context.pushStringPart(`>`);
|
|
574
|
-
}
|
|
575
|
-
else {
|
|
576
|
-
// static tag
|
|
577
|
-
context.pushStringPart(`<${tag.value.content}`);
|
|
578
|
-
if (propsExp) {
|
|
579
|
-
context.pushStringPart(propsExp);
|
|
580
|
-
}
|
|
581
|
-
context.pushStringPart(`>`);
|
|
582
|
-
processChildren(node, context, false, true);
|
|
583
|
-
context.pushStringPart(`</${tag.value.content}>`);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
else {
|
|
587
|
-
// fragment
|
|
588
|
-
processChildren(node, context, true, true);
|
|
589
|
-
}
|
|
529
|
+
const wipMap$1 = new WeakMap();
|
|
530
|
+
// phase 1: build props
|
|
531
|
+
function ssrTransformTransitionGroup(node, context) {
|
|
532
|
+
return () => {
|
|
533
|
+
const tag = compilerDom.findProp(node, 'tag');
|
|
534
|
+
if (tag) {
|
|
535
|
+
const otherProps = node.props.filter(p => p !== tag);
|
|
536
|
+
const { props, directives } = compilerDom.buildProps(node, context, otherProps, true /* isComponent */, false /* isDynamicComponent */, true /* ssr (skip event listeners) */);
|
|
537
|
+
let propsExp = null;
|
|
538
|
+
if (props || directives.length) {
|
|
539
|
+
propsExp = compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTRS), [
|
|
540
|
+
buildSSRProps(props, directives, context)
|
|
541
|
+
]);
|
|
542
|
+
}
|
|
543
|
+
wipMap$1.set(node, {
|
|
544
|
+
tag,
|
|
545
|
+
propsExp
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
// phase 2: process children
|
|
551
|
+
function ssrProcessTransitionGroup(node, context) {
|
|
552
|
+
const entry = wipMap$1.get(node);
|
|
553
|
+
if (entry) {
|
|
554
|
+
const { tag, propsExp } = entry;
|
|
555
|
+
if (tag.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
556
|
+
// dynamic :tag
|
|
557
|
+
context.pushStringPart(`<`);
|
|
558
|
+
context.pushStringPart(tag.exp);
|
|
559
|
+
if (propsExp) {
|
|
560
|
+
context.pushStringPart(propsExp);
|
|
561
|
+
}
|
|
562
|
+
context.pushStringPart(`>`);
|
|
563
|
+
processChildren(node, context, false,
|
|
564
|
+
/**
|
|
565
|
+
* TransitionGroup has the special runtime behavior of flattening and
|
|
566
|
+
* concatenating all children into a single fragment (in order for them to
|
|
567
|
+
* be patched using the same key map) so we need to account for that here
|
|
568
|
+
* by disabling nested fragment wrappers from being generated.
|
|
569
|
+
*/
|
|
570
|
+
true);
|
|
571
|
+
context.pushStringPart(`</`);
|
|
572
|
+
context.pushStringPart(tag.exp);
|
|
573
|
+
context.pushStringPart(`>`);
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
// static tag
|
|
577
|
+
context.pushStringPart(`<${tag.value.content}`);
|
|
578
|
+
if (propsExp) {
|
|
579
|
+
context.pushStringPart(propsExp);
|
|
580
|
+
}
|
|
581
|
+
context.pushStringPart(`>`);
|
|
582
|
+
processChildren(node, context, false, true);
|
|
583
|
+
context.pushStringPart(`</${tag.value.content}>`);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
// fragment
|
|
588
|
+
processChildren(node, context, true, true);
|
|
589
|
+
}
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
-
// We need to construct the slot functions in the 1st pass to ensure proper
|
|
593
|
-
// scope tracking, but the children of each slot cannot be processed until
|
|
594
|
-
// the 2nd pass, so we store the WIP slot functions in a weakMap during the 1st
|
|
595
|
-
// pass and complete them in the 2nd pass.
|
|
596
|
-
const wipMap$2 = new WeakMap();
|
|
597
|
-
const WIP_SLOT = Symbol();
|
|
598
|
-
const componentTypeMap = new WeakMap();
|
|
599
|
-
// ssr component transform is done in two phases:
|
|
600
|
-
// In phase 1. we use `buildSlot` to analyze the children of the component into
|
|
601
|
-
// WIP slot functions (it must be done in phase 1 because `buildSlot` relies on
|
|
602
|
-
// the core transform context).
|
|
603
|
-
// In phase 2. we convert the WIP slots from phase 1 into ssr-specific codegen
|
|
604
|
-
// nodes.
|
|
605
|
-
const ssrTransformComponent = (node, context) => {
|
|
606
|
-
if (node.type !== 1 /* NodeTypes.ELEMENT */ ||
|
|
607
|
-
node.tagType !== 1 /* ElementTypes.COMPONENT */) {
|
|
608
|
-
return;
|
|
609
|
-
}
|
|
610
|
-
const component = compilerDom.resolveComponentType(node, context, true /* ssr */);
|
|
611
|
-
const isDynamicComponent = shared.isObject(component) && component.callee === compilerDom.RESOLVE_DYNAMIC_COMPONENT;
|
|
612
|
-
componentTypeMap.set(node, component);
|
|
613
|
-
if (shared.isSymbol(component)) {
|
|
614
|
-
if (component === compilerDom.SUSPENSE) {
|
|
615
|
-
return ssrTransformSuspense(node, context);
|
|
616
|
-
}
|
|
617
|
-
if (component === compilerDom.TRANSITION_GROUP) {
|
|
618
|
-
return ssrTransformTransitionGroup(node, context);
|
|
619
|
-
}
|
|
620
|
-
return; // other built-in components: fallthrough
|
|
621
|
-
}
|
|
622
|
-
// Build the fallback vnode-based branch for the component's slots.
|
|
623
|
-
// We need to clone the node into a fresh copy and use the buildSlots' logic
|
|
624
|
-
// to get access to the children of each slot. We then compile them with
|
|
625
|
-
// a child transform pipeline using vnode-based transforms (instead of ssr-
|
|
626
|
-
// based ones), and save the result branch (a ReturnStatement) in an array.
|
|
627
|
-
// The branch is retrieved when processing slots again in ssr mode.
|
|
628
|
-
const vnodeBranches = [];
|
|
629
|
-
const clonedNode = clone(node);
|
|
630
|
-
return function ssrPostTransformComponent() {
|
|
631
|
-
// Using the cloned node, build the normal VNode-based branches (for
|
|
632
|
-
// fallback in case the child is render-fn based). Store them in an array
|
|
633
|
-
// for later use.
|
|
634
|
-
if (clonedNode.children.length) {
|
|
635
|
-
compilerDom.buildSlots(clonedNode, context, (props, children) => {
|
|
636
|
-
vnodeBranches.push(createVNodeSlotBranch(props, children, context));
|
|
637
|
-
return compilerDom.createFunctionExpression(undefined);
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
let propsExp = `null`;
|
|
641
|
-
if (node.props.length) {
|
|
642
|
-
// note we are not passing ssr: true here because for components, v-on
|
|
643
|
-
// handlers should still be passed
|
|
644
|
-
const { props, directives } = compilerDom.buildProps(node, context, undefined, true, isDynamicComponent);
|
|
645
|
-
if (props || directives.length) {
|
|
646
|
-
propsExp = buildSSRProps(props, directives, context);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
const wipEntries = [];
|
|
650
|
-
wipMap$2.set(node, wipEntries);
|
|
651
|
-
const buildSSRSlotFn = (props, children, loc) => {
|
|
652
|
-
const
|
|
653
|
-
|
|
654
|
-
true, //
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
//
|
|
671
|
-
//
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
//
|
|
703
|
-
//
|
|
704
|
-
//
|
|
705
|
-
//
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
//
|
|
723
|
-
//
|
|
724
|
-
// is
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
//
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
const
|
|
744
|
-
const
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
...
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
...
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
...
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
//
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
//
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
childContext.
|
|
799
|
-
childContext.
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
//
|
|
820
|
-
//
|
|
821
|
-
//
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
592
|
+
// We need to construct the slot functions in the 1st pass to ensure proper
|
|
593
|
+
// scope tracking, but the children of each slot cannot be processed until
|
|
594
|
+
// the 2nd pass, so we store the WIP slot functions in a weakMap during the 1st
|
|
595
|
+
// pass and complete them in the 2nd pass.
|
|
596
|
+
const wipMap$2 = new WeakMap();
|
|
597
|
+
const WIP_SLOT = Symbol();
|
|
598
|
+
const componentTypeMap = new WeakMap();
|
|
599
|
+
// ssr component transform is done in two phases:
|
|
600
|
+
// In phase 1. we use `buildSlot` to analyze the children of the component into
|
|
601
|
+
// WIP slot functions (it must be done in phase 1 because `buildSlot` relies on
|
|
602
|
+
// the core transform context).
|
|
603
|
+
// In phase 2. we convert the WIP slots from phase 1 into ssr-specific codegen
|
|
604
|
+
// nodes.
|
|
605
|
+
const ssrTransformComponent = (node, context) => {
|
|
606
|
+
if (node.type !== 1 /* NodeTypes.ELEMENT */ ||
|
|
607
|
+
node.tagType !== 1 /* ElementTypes.COMPONENT */) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const component = compilerDom.resolveComponentType(node, context, true /* ssr */);
|
|
611
|
+
const isDynamicComponent = shared.isObject(component) && component.callee === compilerDom.RESOLVE_DYNAMIC_COMPONENT;
|
|
612
|
+
componentTypeMap.set(node, component);
|
|
613
|
+
if (shared.isSymbol(component)) {
|
|
614
|
+
if (component === compilerDom.SUSPENSE) {
|
|
615
|
+
return ssrTransformSuspense(node, context);
|
|
616
|
+
}
|
|
617
|
+
if (component === compilerDom.TRANSITION_GROUP) {
|
|
618
|
+
return ssrTransformTransitionGroup(node, context);
|
|
619
|
+
}
|
|
620
|
+
return; // other built-in components: fallthrough
|
|
621
|
+
}
|
|
622
|
+
// Build the fallback vnode-based branch for the component's slots.
|
|
623
|
+
// We need to clone the node into a fresh copy and use the buildSlots' logic
|
|
624
|
+
// to get access to the children of each slot. We then compile them with
|
|
625
|
+
// a child transform pipeline using vnode-based transforms (instead of ssr-
|
|
626
|
+
// based ones), and save the result branch (a ReturnStatement) in an array.
|
|
627
|
+
// The branch is retrieved when processing slots again in ssr mode.
|
|
628
|
+
const vnodeBranches = [];
|
|
629
|
+
const clonedNode = clone(node);
|
|
630
|
+
return function ssrPostTransformComponent() {
|
|
631
|
+
// Using the cloned node, build the normal VNode-based branches (for
|
|
632
|
+
// fallback in case the child is render-fn based). Store them in an array
|
|
633
|
+
// for later use.
|
|
634
|
+
if (clonedNode.children.length) {
|
|
635
|
+
compilerDom.buildSlots(clonedNode, context, (props, children) => {
|
|
636
|
+
vnodeBranches.push(createVNodeSlotBranch(props, children, context));
|
|
637
|
+
return compilerDom.createFunctionExpression(undefined);
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
let propsExp = `null`;
|
|
641
|
+
if (node.props.length) {
|
|
642
|
+
// note we are not passing ssr: true here because for components, v-on
|
|
643
|
+
// handlers should still be passed
|
|
644
|
+
const { props, directives } = compilerDom.buildProps(node, context, undefined, true, isDynamicComponent);
|
|
645
|
+
if (props || directives.length) {
|
|
646
|
+
propsExp = buildSSRProps(props, directives, context);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const wipEntries = [];
|
|
650
|
+
wipMap$2.set(node, wipEntries);
|
|
651
|
+
const buildSSRSlotFn = (props, children, loc) => {
|
|
652
|
+
const param0 = (props && compilerDom.stringifyExpression(props)) || `_`;
|
|
653
|
+
const fn = compilerDom.createFunctionExpression([param0, `_push`, `_parent`, `_scopeId`], undefined, // no return, assign body later
|
|
654
|
+
true, // newline
|
|
655
|
+
true, // isSlot
|
|
656
|
+
loc);
|
|
657
|
+
wipEntries.push({
|
|
658
|
+
type: WIP_SLOT,
|
|
659
|
+
fn,
|
|
660
|
+
children,
|
|
661
|
+
// also collect the corresponding vnode branch built earlier
|
|
662
|
+
vnodeBranch: vnodeBranches[wipEntries.length]
|
|
663
|
+
});
|
|
664
|
+
return fn;
|
|
665
|
+
};
|
|
666
|
+
const slots = node.children.length
|
|
667
|
+
? compilerDom.buildSlots(node, context, buildSSRSlotFn).slots
|
|
668
|
+
: `null`;
|
|
669
|
+
if (typeof component !== 'string') {
|
|
670
|
+
// dynamic component that resolved to a `resolveDynamicComponent` call
|
|
671
|
+
// expression - since the resolved result may be a plain element (string)
|
|
672
|
+
// or a VNode, handle it with `renderVNode`.
|
|
673
|
+
node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(SSR_RENDER_VNODE), [
|
|
674
|
+
`_push`,
|
|
675
|
+
compilerDom.createCallExpression(context.helper(compilerDom.CREATE_VNODE), [
|
|
676
|
+
component,
|
|
677
|
+
propsExp,
|
|
678
|
+
slots
|
|
679
|
+
]),
|
|
680
|
+
`_parent`
|
|
681
|
+
]);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
node.ssrCodegenNode = compilerDom.createCallExpression(context.helper(SSR_RENDER_COMPONENT), [component, propsExp, slots, `_parent`]);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
};
|
|
688
|
+
function ssrProcessComponent(node, context, parent) {
|
|
689
|
+
const component = componentTypeMap.get(node);
|
|
690
|
+
if (!node.ssrCodegenNode) {
|
|
691
|
+
// this is a built-in component that fell-through.
|
|
692
|
+
if (component === compilerDom.TELEPORT) {
|
|
693
|
+
return ssrProcessTeleport(node, context);
|
|
694
|
+
}
|
|
695
|
+
else if (component === compilerDom.SUSPENSE) {
|
|
696
|
+
return ssrProcessSuspense(node, context);
|
|
697
|
+
}
|
|
698
|
+
else if (component === compilerDom.TRANSITION_GROUP) {
|
|
699
|
+
return ssrProcessTransitionGroup(node, context);
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
// real fall-through: Transition / KeepAlive
|
|
703
|
+
// just render its children.
|
|
704
|
+
// #5352: if is at root level of a slot, push an empty string.
|
|
705
|
+
// this does not affect the final output, but avoids all-comment slot
|
|
706
|
+
// content of being treated as empty by ssrRenderSlot().
|
|
707
|
+
if (parent.type === WIP_SLOT) {
|
|
708
|
+
context.pushStringPart(``);
|
|
709
|
+
}
|
|
710
|
+
// #5351: filter out comment children inside transition
|
|
711
|
+
if (component === compilerDom.TRANSITION) {
|
|
712
|
+
node.children = node.children.filter(c => c.type !== 3 /* NodeTypes.COMMENT */);
|
|
713
|
+
}
|
|
714
|
+
processChildren(node, context);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
else {
|
|
718
|
+
// finish up slot function expressions from the 1st pass.
|
|
719
|
+
const wipEntries = wipMap$2.get(node) || [];
|
|
720
|
+
for (let i = 0; i < wipEntries.length; i++) {
|
|
721
|
+
const { fn, vnodeBranch } = wipEntries[i];
|
|
722
|
+
// For each slot, we generate two branches: one SSR-optimized branch and
|
|
723
|
+
// one normal vnode-based branch. The branches are taken based on the
|
|
724
|
+
// presence of the 2nd `_push` argument (which is only present if the slot
|
|
725
|
+
// is called by `_ssrRenderSlot`.
|
|
726
|
+
fn.body = compilerDom.createIfStatement(compilerDom.createSimpleExpression(`_push`, false), processChildrenAsStatement(wipEntries[i], context, false, true /* withSlotScopeId */), vnodeBranch);
|
|
727
|
+
}
|
|
728
|
+
// component is inside a slot, inherit slot scope Id
|
|
729
|
+
if (context.withSlotScopeId) {
|
|
730
|
+
node.ssrCodegenNode.arguments.push(`_scopeId`);
|
|
731
|
+
}
|
|
732
|
+
if (typeof component === 'string') {
|
|
733
|
+
// static component
|
|
734
|
+
context.pushStatement(compilerDom.createCallExpression(`_push`, [node.ssrCodegenNode]));
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
// dynamic component (`resolveDynamicComponent` call)
|
|
738
|
+
// the codegen node is a `renderVNode` call
|
|
739
|
+
context.pushStatement(node.ssrCodegenNode);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
const rawOptionsMap = new WeakMap();
|
|
744
|
+
const [baseNodeTransforms, baseDirectiveTransforms] = compilerDom.getBaseTransformPreset(true);
|
|
745
|
+
const vnodeNodeTransforms = [...baseNodeTransforms, ...compilerDom.DOMNodeTransforms];
|
|
746
|
+
const vnodeDirectiveTransforms = {
|
|
747
|
+
...baseDirectiveTransforms,
|
|
748
|
+
...compilerDom.DOMDirectiveTransforms
|
|
749
|
+
};
|
|
750
|
+
function createVNodeSlotBranch(props, children, parentContext) {
|
|
751
|
+
// apply a sub-transform using vnode-based transforms.
|
|
752
|
+
const rawOptions = rawOptionsMap.get(parentContext.root);
|
|
753
|
+
const subOptions = {
|
|
754
|
+
...rawOptions,
|
|
755
|
+
// overwrite with vnode-based transforms
|
|
756
|
+
nodeTransforms: [
|
|
757
|
+
...vnodeNodeTransforms,
|
|
758
|
+
...(rawOptions.nodeTransforms || [])
|
|
759
|
+
],
|
|
760
|
+
directiveTransforms: {
|
|
761
|
+
...vnodeDirectiveTransforms,
|
|
762
|
+
...(rawOptions.directiveTransforms || {})
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
// wrap the children with a wrapper template for proper children treatment.
|
|
766
|
+
const wrapperNode = {
|
|
767
|
+
type: 1 /* NodeTypes.ELEMENT */,
|
|
768
|
+
ns: 0 /* Namespaces.HTML */,
|
|
769
|
+
tag: 'template',
|
|
770
|
+
tagType: 3 /* ElementTypes.TEMPLATE */,
|
|
771
|
+
isSelfClosing: false,
|
|
772
|
+
// important: provide v-slot="props" on the wrapper for proper
|
|
773
|
+
// scope analysis
|
|
774
|
+
props: [
|
|
775
|
+
{
|
|
776
|
+
type: 7 /* NodeTypes.DIRECTIVE */,
|
|
777
|
+
name: 'slot',
|
|
778
|
+
exp: props,
|
|
779
|
+
arg: undefined,
|
|
780
|
+
modifiers: [],
|
|
781
|
+
loc: compilerDom.locStub
|
|
782
|
+
}
|
|
783
|
+
],
|
|
784
|
+
children,
|
|
785
|
+
loc: compilerDom.locStub,
|
|
786
|
+
codegenNode: undefined
|
|
787
|
+
};
|
|
788
|
+
subTransform(wrapperNode, subOptions, parentContext);
|
|
789
|
+
return compilerDom.createReturnStatement(children);
|
|
790
|
+
}
|
|
791
|
+
function subTransform(node, options, parentContext) {
|
|
792
|
+
const childRoot = compilerDom.createRoot([node]);
|
|
793
|
+
const childContext = compilerDom.createTransformContext(childRoot, options);
|
|
794
|
+
// this sub transform is for vnode fallback branch so it should be handled
|
|
795
|
+
// like normal render functions
|
|
796
|
+
childContext.ssr = false;
|
|
797
|
+
// inherit parent scope analysis state
|
|
798
|
+
childContext.scopes = { ...parentContext.scopes };
|
|
799
|
+
childContext.identifiers = { ...parentContext.identifiers };
|
|
800
|
+
childContext.imports = parentContext.imports;
|
|
801
|
+
// traverse
|
|
802
|
+
compilerDom.traverseNode(childRoot, childContext);
|
|
803
|
+
['helpers', 'components', 'directives'].forEach(key => {
|
|
804
|
+
childContext[key].forEach((value, helperKey) => {
|
|
805
|
+
if (key === 'helpers') {
|
|
806
|
+
const parentCount = parentContext.helpers.get(helperKey);
|
|
807
|
+
if (parentCount === undefined) {
|
|
808
|
+
parentContext.helpers.set(helperKey, value);
|
|
809
|
+
}
|
|
810
|
+
else {
|
|
811
|
+
parentContext.helpers.set(helperKey, value + parentCount);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
parentContext[key].add(value);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
// imports/hoists are not merged because:
|
|
820
|
+
// - imports are only used for asset urls and should be consistent between
|
|
821
|
+
// node/client branches
|
|
822
|
+
// - hoists are not enabled for the client branch here
|
|
823
|
+
}
|
|
824
|
+
function clone(v) {
|
|
825
|
+
if (shared.isArray(v)) {
|
|
826
|
+
return v.map(clone);
|
|
827
|
+
}
|
|
828
|
+
else if (shared.isObject(v)) {
|
|
829
|
+
const res = {};
|
|
830
|
+
for (const key in v) {
|
|
831
|
+
res[key] = clone(v[key]);
|
|
832
|
+
}
|
|
833
|
+
return res;
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
return v;
|
|
837
|
+
}
|
|
837
838
|
}
|
|
838
839
|
|
|
839
|
-
// Because SSR codegen output is completely different from client-side output
|
|
840
|
-
// (e.g. multiple elements can be concatenated into a single template literal
|
|
841
|
-
// instead of each getting a corresponding call), we need to apply an extra
|
|
842
|
-
// transform pass to convert the template AST into a fresh JS AST before
|
|
843
|
-
// passing it to codegen.
|
|
844
|
-
function ssrCodegenTransform(ast, options) {
|
|
845
|
-
const context = createSSRTransformContext(ast, options);
|
|
846
|
-
// inject SFC <style> CSS variables
|
|
847
|
-
// we do this instead of inlining the expression to ensure the vars are
|
|
848
|
-
// only resolved once per render
|
|
849
|
-
if (options.ssrCssVars) {
|
|
850
|
-
const cssContext = compilerDom.createTransformContext(compilerDom.createRoot([]), options);
|
|
851
|
-
const varsExp = compilerDom.processExpression(compilerDom.createSimpleExpression(options.ssrCssVars, false), cssContext);
|
|
852
|
-
context.body.push(compilerDom.createCompoundExpression([`const _cssVars = { style: `, varsExp, `}`]));
|
|
853
|
-
Array.from(cssContext.helpers.keys()).forEach(helper => {
|
|
854
|
-
if (!ast.helpers.includes(helper))
|
|
855
|
-
ast.helpers.push(helper);
|
|
856
|
-
});
|
|
857
|
-
}
|
|
858
|
-
const isFragment = ast.children.length > 1 && ast.children.some(c => !compilerDom.isText(c));
|
|
859
|
-
processChildren(ast, context, isFragment);
|
|
860
|
-
ast.codegenNode = compilerDom.createBlockStatement(context.body);
|
|
861
|
-
// Finalize helpers.
|
|
862
|
-
// We need to separate helpers imported from 'vue' vs. '@vue/server-renderer'
|
|
863
|
-
ast.ssrHelpers = Array.from(new Set([...ast.helpers.filter(h => h in ssrHelpers), ...context.helpers]));
|
|
864
|
-
ast.helpers = ast.helpers.filter(h => !(h in ssrHelpers));
|
|
865
|
-
}
|
|
866
|
-
function createSSRTransformContext(root, options, helpers = new Set(), withSlotScopeId = false) {
|
|
867
|
-
const body = [];
|
|
868
|
-
let currentString = null;
|
|
869
|
-
return {
|
|
870
|
-
root,
|
|
871
|
-
options,
|
|
872
|
-
body,
|
|
873
|
-
helpers,
|
|
874
|
-
withSlotScopeId,
|
|
875
|
-
onError: options.onError ||
|
|
876
|
-
(e => {
|
|
877
|
-
throw e;
|
|
878
|
-
}),
|
|
879
|
-
helper(name) {
|
|
880
|
-
helpers.add(name);
|
|
881
|
-
return name;
|
|
882
|
-
},
|
|
883
|
-
pushStringPart(part) {
|
|
884
|
-
if (!currentString) {
|
|
885
|
-
const currentCall = compilerDom.createCallExpression(`_push`);
|
|
886
|
-
body.push(currentCall);
|
|
887
|
-
currentString = compilerDom.createTemplateLiteral([]);
|
|
888
|
-
currentCall.arguments.push(currentString);
|
|
889
|
-
}
|
|
890
|
-
const bufferedElements = currentString.elements;
|
|
891
|
-
const lastItem = bufferedElements[bufferedElements.length - 1];
|
|
892
|
-
if (shared.isString(part) && shared.isString(lastItem)) {
|
|
893
|
-
bufferedElements[bufferedElements.length - 1] += part;
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
bufferedElements.push(part);
|
|
897
|
-
}
|
|
898
|
-
},
|
|
899
|
-
pushStatement(statement) {
|
|
900
|
-
// close current string
|
|
901
|
-
currentString = null;
|
|
902
|
-
body.push(statement);
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
function createChildContext(parent, withSlotScopeId = parent.withSlotScopeId) {
|
|
907
|
-
// ensure child inherits parent helpers
|
|
908
|
-
return createSSRTransformContext(parent.root, parent.options, parent.helpers, withSlotScopeId);
|
|
909
|
-
}
|
|
910
|
-
function processChildren(parent, context, asFragment = false, disableNestedFragments = false) {
|
|
911
|
-
if (asFragment) {
|
|
912
|
-
context.pushStringPart(`<!--[-->`);
|
|
913
|
-
}
|
|
914
|
-
const { children } = parent;
|
|
915
|
-
for (let i = 0; i < children.length; i++) {
|
|
916
|
-
const child = children[i];
|
|
917
|
-
switch (child.type) {
|
|
918
|
-
case 1 /* NodeTypes.ELEMENT */:
|
|
919
|
-
switch (child.tagType) {
|
|
920
|
-
case 0 /* ElementTypes.ELEMENT */:
|
|
921
|
-
ssrProcessElement(child, context);
|
|
922
|
-
break;
|
|
923
|
-
case 1 /* ElementTypes.COMPONENT */:
|
|
924
|
-
ssrProcessComponent(child, context, parent);
|
|
925
|
-
break;
|
|
926
|
-
case 2 /* ElementTypes.SLOT */:
|
|
927
|
-
ssrProcessSlotOutlet(child, context);
|
|
928
|
-
break;
|
|
929
|
-
case 3 /* ElementTypes.TEMPLATE */:
|
|
930
|
-
// TODO
|
|
931
|
-
break;
|
|
932
|
-
default:
|
|
933
|
-
context.onError(createSSRCompilerError(63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */, child.loc));
|
|
934
|
-
// make sure we exhaust all possible types
|
|
935
|
-
const exhaustiveCheck = child;
|
|
936
|
-
return exhaustiveCheck;
|
|
937
|
-
}
|
|
938
|
-
break;
|
|
939
|
-
case 2 /* NodeTypes.TEXT */:
|
|
940
|
-
context.pushStringPart(shared.escapeHtml(child.content));
|
|
941
|
-
break;
|
|
942
|
-
case 3 /* NodeTypes.COMMENT */:
|
|
943
|
-
// no need to escape comment here because the AST can only
|
|
944
|
-
// contain valid comments.
|
|
945
|
-
context.pushStringPart(`<!--${child.content}-->`);
|
|
946
|
-
break;
|
|
947
|
-
case 5 /* NodeTypes.INTERPOLATION */:
|
|
948
|
-
context.pushStringPart(compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [child.content]));
|
|
949
|
-
break;
|
|
950
|
-
case 9 /* NodeTypes.IF */:
|
|
951
|
-
ssrProcessIf(child, context, disableNestedFragments);
|
|
952
|
-
break;
|
|
953
|
-
case 11 /* NodeTypes.FOR */:
|
|
954
|
-
ssrProcessFor(child, context, disableNestedFragments);
|
|
955
|
-
break;
|
|
956
|
-
case 10 /* NodeTypes.IF_BRANCH */:
|
|
957
|
-
// no-op - handled by ssrProcessIf
|
|
958
|
-
break;
|
|
959
|
-
case 12 /* NodeTypes.TEXT_CALL */:
|
|
960
|
-
case 8 /* NodeTypes.COMPOUND_EXPRESSION */:
|
|
961
|
-
// no-op - these two types can never appear as template child node since
|
|
962
|
-
// `transformText` is not used during SSR compile.
|
|
963
|
-
break;
|
|
964
|
-
default:
|
|
965
|
-
context.onError(createSSRCompilerError(63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */, child.loc));
|
|
966
|
-
// make sure we exhaust all possible types
|
|
967
|
-
const exhaustiveCheck = child;
|
|
968
|
-
return exhaustiveCheck;
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
if (asFragment) {
|
|
972
|
-
context.pushStringPart(`<!--]-->`);
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
function processChildrenAsStatement(parent, parentContext, asFragment = false, withSlotScopeId = parentContext.withSlotScopeId) {
|
|
976
|
-
const childContext = createChildContext(parentContext, withSlotScopeId);
|
|
977
|
-
processChildren(parent, childContext, asFragment);
|
|
978
|
-
return compilerDom.createBlockStatement(childContext.body);
|
|
840
|
+
// Because SSR codegen output is completely different from client-side output
|
|
841
|
+
// (e.g. multiple elements can be concatenated into a single template literal
|
|
842
|
+
// instead of each getting a corresponding call), we need to apply an extra
|
|
843
|
+
// transform pass to convert the template AST into a fresh JS AST before
|
|
844
|
+
// passing it to codegen.
|
|
845
|
+
function ssrCodegenTransform(ast, options) {
|
|
846
|
+
const context = createSSRTransformContext(ast, options);
|
|
847
|
+
// inject SFC <style> CSS variables
|
|
848
|
+
// we do this instead of inlining the expression to ensure the vars are
|
|
849
|
+
// only resolved once per render
|
|
850
|
+
if (options.ssrCssVars) {
|
|
851
|
+
const cssContext = compilerDom.createTransformContext(compilerDom.createRoot([]), options);
|
|
852
|
+
const varsExp = compilerDom.processExpression(compilerDom.createSimpleExpression(options.ssrCssVars, false), cssContext);
|
|
853
|
+
context.body.push(compilerDom.createCompoundExpression([`const _cssVars = { style: `, varsExp, `}`]));
|
|
854
|
+
Array.from(cssContext.helpers.keys()).forEach(helper => {
|
|
855
|
+
if (!ast.helpers.includes(helper))
|
|
856
|
+
ast.helpers.push(helper);
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
const isFragment = ast.children.length > 1 && ast.children.some(c => !compilerDom.isText(c));
|
|
860
|
+
processChildren(ast, context, isFragment);
|
|
861
|
+
ast.codegenNode = compilerDom.createBlockStatement(context.body);
|
|
862
|
+
// Finalize helpers.
|
|
863
|
+
// We need to separate helpers imported from 'vue' vs. '@vue/server-renderer'
|
|
864
|
+
ast.ssrHelpers = Array.from(new Set([...ast.helpers.filter(h => h in ssrHelpers), ...context.helpers]));
|
|
865
|
+
ast.helpers = ast.helpers.filter(h => !(h in ssrHelpers));
|
|
866
|
+
}
|
|
867
|
+
function createSSRTransformContext(root, options, helpers = new Set(), withSlotScopeId = false) {
|
|
868
|
+
const body = [];
|
|
869
|
+
let currentString = null;
|
|
870
|
+
return {
|
|
871
|
+
root,
|
|
872
|
+
options,
|
|
873
|
+
body,
|
|
874
|
+
helpers,
|
|
875
|
+
withSlotScopeId,
|
|
876
|
+
onError: options.onError ||
|
|
877
|
+
(e => {
|
|
878
|
+
throw e;
|
|
879
|
+
}),
|
|
880
|
+
helper(name) {
|
|
881
|
+
helpers.add(name);
|
|
882
|
+
return name;
|
|
883
|
+
},
|
|
884
|
+
pushStringPart(part) {
|
|
885
|
+
if (!currentString) {
|
|
886
|
+
const currentCall = compilerDom.createCallExpression(`_push`);
|
|
887
|
+
body.push(currentCall);
|
|
888
|
+
currentString = compilerDom.createTemplateLiteral([]);
|
|
889
|
+
currentCall.arguments.push(currentString);
|
|
890
|
+
}
|
|
891
|
+
const bufferedElements = currentString.elements;
|
|
892
|
+
const lastItem = bufferedElements[bufferedElements.length - 1];
|
|
893
|
+
if (shared.isString(part) && shared.isString(lastItem)) {
|
|
894
|
+
bufferedElements[bufferedElements.length - 1] += part;
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
bufferedElements.push(part);
|
|
898
|
+
}
|
|
899
|
+
},
|
|
900
|
+
pushStatement(statement) {
|
|
901
|
+
// close current string
|
|
902
|
+
currentString = null;
|
|
903
|
+
body.push(statement);
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
function createChildContext(parent, withSlotScopeId = parent.withSlotScopeId) {
|
|
908
|
+
// ensure child inherits parent helpers
|
|
909
|
+
return createSSRTransformContext(parent.root, parent.options, parent.helpers, withSlotScopeId);
|
|
910
|
+
}
|
|
911
|
+
function processChildren(parent, context, asFragment = false, disableNestedFragments = false) {
|
|
912
|
+
if (asFragment) {
|
|
913
|
+
context.pushStringPart(`<!--[-->`);
|
|
914
|
+
}
|
|
915
|
+
const { children } = parent;
|
|
916
|
+
for (let i = 0; i < children.length; i++) {
|
|
917
|
+
const child = children[i];
|
|
918
|
+
switch (child.type) {
|
|
919
|
+
case 1 /* NodeTypes.ELEMENT */:
|
|
920
|
+
switch (child.tagType) {
|
|
921
|
+
case 0 /* ElementTypes.ELEMENT */:
|
|
922
|
+
ssrProcessElement(child, context);
|
|
923
|
+
break;
|
|
924
|
+
case 1 /* ElementTypes.COMPONENT */:
|
|
925
|
+
ssrProcessComponent(child, context, parent);
|
|
926
|
+
break;
|
|
927
|
+
case 2 /* ElementTypes.SLOT */:
|
|
928
|
+
ssrProcessSlotOutlet(child, context);
|
|
929
|
+
break;
|
|
930
|
+
case 3 /* ElementTypes.TEMPLATE */:
|
|
931
|
+
// TODO
|
|
932
|
+
break;
|
|
933
|
+
default:
|
|
934
|
+
context.onError(createSSRCompilerError(63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */, child.loc));
|
|
935
|
+
// make sure we exhaust all possible types
|
|
936
|
+
const exhaustiveCheck = child;
|
|
937
|
+
return exhaustiveCheck;
|
|
938
|
+
}
|
|
939
|
+
break;
|
|
940
|
+
case 2 /* NodeTypes.TEXT */:
|
|
941
|
+
context.pushStringPart(shared.escapeHtml(child.content));
|
|
942
|
+
break;
|
|
943
|
+
case 3 /* NodeTypes.COMMENT */:
|
|
944
|
+
// no need to escape comment here because the AST can only
|
|
945
|
+
// contain valid comments.
|
|
946
|
+
context.pushStringPart(`<!--${child.content}-->`);
|
|
947
|
+
break;
|
|
948
|
+
case 5 /* NodeTypes.INTERPOLATION */:
|
|
949
|
+
context.pushStringPart(compilerDom.createCallExpression(context.helper(SSR_INTERPOLATE), [child.content]));
|
|
950
|
+
break;
|
|
951
|
+
case 9 /* NodeTypes.IF */:
|
|
952
|
+
ssrProcessIf(child, context, disableNestedFragments);
|
|
953
|
+
break;
|
|
954
|
+
case 11 /* NodeTypes.FOR */:
|
|
955
|
+
ssrProcessFor(child, context, disableNestedFragments);
|
|
956
|
+
break;
|
|
957
|
+
case 10 /* NodeTypes.IF_BRANCH */:
|
|
958
|
+
// no-op - handled by ssrProcessIf
|
|
959
|
+
break;
|
|
960
|
+
case 12 /* NodeTypes.TEXT_CALL */:
|
|
961
|
+
case 8 /* NodeTypes.COMPOUND_EXPRESSION */:
|
|
962
|
+
// no-op - these two types can never appear as template child node since
|
|
963
|
+
// `transformText` is not used during SSR compile.
|
|
964
|
+
break;
|
|
965
|
+
default:
|
|
966
|
+
context.onError(createSSRCompilerError(63 /* SSRErrorCodes.X_SSR_INVALID_AST_NODE */, child.loc));
|
|
967
|
+
// make sure we exhaust all possible types
|
|
968
|
+
const exhaustiveCheck = child;
|
|
969
|
+
return exhaustiveCheck;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (asFragment) {
|
|
973
|
+
context.pushStringPart(`<!--]-->`);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
function processChildrenAsStatement(parent, parentContext, asFragment = false, withSlotScopeId = parentContext.withSlotScopeId) {
|
|
977
|
+
const childContext = createChildContext(parentContext, withSlotScopeId);
|
|
978
|
+
processChildren(parent, childContext, asFragment);
|
|
979
|
+
return compilerDom.createBlockStatement(childContext.body);
|
|
979
980
|
}
|
|
980
981
|
|
|
981
|
-
const ssrTransformModel = (dir, node, context) => {
|
|
982
|
-
const model = dir.exp;
|
|
983
|
-
function checkDuplicatedValue() {
|
|
984
|
-
const value = compilerDom.findProp(node, 'value');
|
|
985
|
-
if (value) {
|
|
986
|
-
context.onError(compilerDom.createDOMCompilerError(57 /* DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE */, value.loc));
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
if (node.tagType === 0 /* ElementTypes.ELEMENT */) {
|
|
990
|
-
const res = { props: [] };
|
|
991
|
-
const defaultProps = [
|
|
992
|
-
// default value binding for text type inputs
|
|
993
|
-
compilerDom.createObjectProperty(`value`, model)
|
|
994
|
-
];
|
|
995
|
-
if (node.tag === 'input') {
|
|
996
|
-
const type = compilerDom.findProp(node, 'type');
|
|
997
|
-
if (type) {
|
|
998
|
-
const value = findValueBinding(node);
|
|
999
|
-
if (type.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
1000
|
-
// dynamic type
|
|
1001
|
-
res.ssrTagParts = [
|
|
1002
|
-
compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_MODEL), [
|
|
1003
|
-
type.exp,
|
|
1004
|
-
model,
|
|
1005
|
-
value
|
|
1006
|
-
])
|
|
1007
|
-
];
|
|
1008
|
-
}
|
|
1009
|
-
else if (type.value) {
|
|
1010
|
-
// static type
|
|
1011
|
-
switch (type.value.content) {
|
|
1012
|
-
case 'radio':
|
|
1013
|
-
res.props = [
|
|
1014
|
-
compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
|
|
1015
|
-
model,
|
|
1016
|
-
value
|
|
1017
|
-
]))
|
|
1018
|
-
];
|
|
1019
|
-
break;
|
|
1020
|
-
case 'checkbox':
|
|
1021
|
-
const trueValueBinding = compilerDom.findProp(node, 'true-value');
|
|
1022
|
-
if (trueValueBinding) {
|
|
1023
|
-
const trueValue = trueValueBinding.type === 6 /* NodeTypes.ATTRIBUTE */
|
|
1024
|
-
? JSON.stringify(trueValueBinding.value.content)
|
|
1025
|
-
: trueValueBinding.exp;
|
|
1026
|
-
res.props = [
|
|
1027
|
-
compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
|
|
1028
|
-
model,
|
|
1029
|
-
trueValue
|
|
1030
|
-
]))
|
|
1031
|
-
];
|
|
1032
|
-
}
|
|
1033
|
-
else {
|
|
1034
|
-
res.props = [
|
|
1035
|
-
compilerDom.createObjectProperty(`checked`, compilerDom.createConditionalExpression(compilerDom.createCallExpression(`Array.isArray`, [model]), compilerDom.createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
|
|
1036
|
-
model,
|
|
1037
|
-
value
|
|
1038
|
-
]), model))
|
|
1039
|
-
];
|
|
1040
|
-
}
|
|
1041
|
-
break;
|
|
1042
|
-
case 'file':
|
|
1043
|
-
context.onError(compilerDom.createDOMCompilerError(56 /* DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT */, dir.loc));
|
|
1044
|
-
break;
|
|
1045
|
-
default:
|
|
1046
|
-
checkDuplicatedValue();
|
|
1047
|
-
res.props = defaultProps;
|
|
1048
|
-
break;
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
else if (compilerDom.hasDynamicKeyVBind(node)) ;
|
|
1053
|
-
else {
|
|
1054
|
-
// text type
|
|
1055
|
-
checkDuplicatedValue();
|
|
1056
|
-
res.props = defaultProps;
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
else if (node.tag === 'textarea') {
|
|
1060
|
-
checkDuplicatedValue();
|
|
1061
|
-
node.children = [compilerDom.createInterpolation(model, model.loc)];
|
|
1062
|
-
}
|
|
1063
|
-
else if (node.tag === 'select') ;
|
|
1064
|
-
else {
|
|
1065
|
-
context.onError(compilerDom.createDOMCompilerError(54 /* DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT */, dir.loc));
|
|
1066
|
-
}
|
|
1067
|
-
return res;
|
|
1068
|
-
}
|
|
1069
|
-
else {
|
|
1070
|
-
// component v-model
|
|
1071
|
-
return compilerDom.transformModel(dir, node, context);
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
function findValueBinding(node) {
|
|
1075
|
-
const valueBinding = compilerDom.findProp(node, 'value');
|
|
1076
|
-
return valueBinding
|
|
1077
|
-
? valueBinding.type === 7 /* NodeTypes.DIRECTIVE */
|
|
1078
|
-
? valueBinding.exp
|
|
1079
|
-
: compilerDom.createSimpleExpression(valueBinding.value.content, true)
|
|
1080
|
-
: compilerDom.createSimpleExpression(`null`, false);
|
|
982
|
+
const ssrTransformModel = (dir, node, context) => {
|
|
983
|
+
const model = dir.exp;
|
|
984
|
+
function checkDuplicatedValue() {
|
|
985
|
+
const value = compilerDom.findProp(node, 'value');
|
|
986
|
+
if (value) {
|
|
987
|
+
context.onError(compilerDom.createDOMCompilerError(57 /* DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE */, value.loc));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (node.tagType === 0 /* ElementTypes.ELEMENT */) {
|
|
991
|
+
const res = { props: [] };
|
|
992
|
+
const defaultProps = [
|
|
993
|
+
// default value binding for text type inputs
|
|
994
|
+
compilerDom.createObjectProperty(`value`, model)
|
|
995
|
+
];
|
|
996
|
+
if (node.tag === 'input') {
|
|
997
|
+
const type = compilerDom.findProp(node, 'type');
|
|
998
|
+
if (type) {
|
|
999
|
+
const value = findValueBinding(node);
|
|
1000
|
+
if (type.type === 7 /* NodeTypes.DIRECTIVE */) {
|
|
1001
|
+
// dynamic type
|
|
1002
|
+
res.ssrTagParts = [
|
|
1003
|
+
compilerDom.createCallExpression(context.helper(SSR_RENDER_DYNAMIC_MODEL), [
|
|
1004
|
+
type.exp,
|
|
1005
|
+
model,
|
|
1006
|
+
value
|
|
1007
|
+
])
|
|
1008
|
+
];
|
|
1009
|
+
}
|
|
1010
|
+
else if (type.value) {
|
|
1011
|
+
// static type
|
|
1012
|
+
switch (type.value.content) {
|
|
1013
|
+
case 'radio':
|
|
1014
|
+
res.props = [
|
|
1015
|
+
compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
|
|
1016
|
+
model,
|
|
1017
|
+
value
|
|
1018
|
+
]))
|
|
1019
|
+
];
|
|
1020
|
+
break;
|
|
1021
|
+
case 'checkbox':
|
|
1022
|
+
const trueValueBinding = compilerDom.findProp(node, 'true-value');
|
|
1023
|
+
if (trueValueBinding) {
|
|
1024
|
+
const trueValue = trueValueBinding.type === 6 /* NodeTypes.ATTRIBUTE */
|
|
1025
|
+
? JSON.stringify(trueValueBinding.value.content)
|
|
1026
|
+
: trueValueBinding.exp;
|
|
1027
|
+
res.props = [
|
|
1028
|
+
compilerDom.createObjectProperty(`checked`, compilerDom.createCallExpression(context.helper(SSR_LOOSE_EQUAL), [
|
|
1029
|
+
model,
|
|
1030
|
+
trueValue
|
|
1031
|
+
]))
|
|
1032
|
+
];
|
|
1033
|
+
}
|
|
1034
|
+
else {
|
|
1035
|
+
res.props = [
|
|
1036
|
+
compilerDom.createObjectProperty(`checked`, compilerDom.createConditionalExpression(compilerDom.createCallExpression(`Array.isArray`, [model]), compilerDom.createCallExpression(context.helper(SSR_LOOSE_CONTAIN), [
|
|
1037
|
+
model,
|
|
1038
|
+
value
|
|
1039
|
+
]), model))
|
|
1040
|
+
];
|
|
1041
|
+
}
|
|
1042
|
+
break;
|
|
1043
|
+
case 'file':
|
|
1044
|
+
context.onError(compilerDom.createDOMCompilerError(56 /* DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT */, dir.loc));
|
|
1045
|
+
break;
|
|
1046
|
+
default:
|
|
1047
|
+
checkDuplicatedValue();
|
|
1048
|
+
res.props = defaultProps;
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
else if (compilerDom.hasDynamicKeyVBind(node)) ;
|
|
1054
|
+
else {
|
|
1055
|
+
// text type
|
|
1056
|
+
checkDuplicatedValue();
|
|
1057
|
+
res.props = defaultProps;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
else if (node.tag === 'textarea') {
|
|
1061
|
+
checkDuplicatedValue();
|
|
1062
|
+
node.children = [compilerDom.createInterpolation(model, model.loc)];
|
|
1063
|
+
}
|
|
1064
|
+
else if (node.tag === 'select') ;
|
|
1065
|
+
else {
|
|
1066
|
+
context.onError(compilerDom.createDOMCompilerError(54 /* DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT */, dir.loc));
|
|
1067
|
+
}
|
|
1068
|
+
return res;
|
|
1069
|
+
}
|
|
1070
|
+
else {
|
|
1071
|
+
// component v-model
|
|
1072
|
+
return compilerDom.transformModel(dir, node, context);
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
function findValueBinding(node) {
|
|
1076
|
+
const valueBinding = compilerDom.findProp(node, 'value');
|
|
1077
|
+
return valueBinding
|
|
1078
|
+
? valueBinding.type === 7 /* NodeTypes.DIRECTIVE */
|
|
1079
|
+
? valueBinding.exp
|
|
1080
|
+
: compilerDom.createSimpleExpression(valueBinding.value.content, true)
|
|
1081
|
+
: compilerDom.createSimpleExpression(`null`, false);
|
|
1081
1082
|
}
|
|
1082
1083
|
|
|
1083
|
-
const ssrTransformShow = (dir, node, context) => {
|
|
1084
|
-
if (!dir.exp) {
|
|
1085
|
-
context.onError(compilerDom.createDOMCompilerError(58 /* DOMErrorCodes.X_V_SHOW_NO_EXPRESSION */));
|
|
1086
|
-
}
|
|
1087
|
-
return {
|
|
1088
|
-
props: [
|
|
1089
|
-
compilerDom.createObjectProperty(`style`, compilerDom.createConditionalExpression(dir.exp, compilerDom.createSimpleExpression(`null`, false), compilerDom.createObjectExpression([
|
|
1090
|
-
compilerDom.createObjectProperty(`display`, compilerDom.createSimpleExpression(`none`, true))
|
|
1091
|
-
]), false /* no newline */))
|
|
1092
|
-
]
|
|
1093
|
-
};
|
|
1084
|
+
const ssrTransformShow = (dir, node, context) => {
|
|
1085
|
+
if (!dir.exp) {
|
|
1086
|
+
context.onError(compilerDom.createDOMCompilerError(58 /* DOMErrorCodes.X_V_SHOW_NO_EXPRESSION */));
|
|
1087
|
+
}
|
|
1088
|
+
return {
|
|
1089
|
+
props: [
|
|
1090
|
+
compilerDom.createObjectProperty(`style`, compilerDom.createConditionalExpression(dir.exp, compilerDom.createSimpleExpression(`null`, false), compilerDom.createObjectExpression([
|
|
1091
|
+
compilerDom.createObjectProperty(`display`, compilerDom.createSimpleExpression(`none`, true))
|
|
1092
|
+
]), false /* no newline */))
|
|
1093
|
+
]
|
|
1094
|
+
};
|
|
1094
1095
|
};
|
|
1095
1096
|
|
|
1096
|
-
const filterChild = (node) => node.children.filter(n => n.type !== 3 /* NodeTypes.COMMENT */);
|
|
1097
|
-
const hasSingleChild = (node) => filterChild(node).length === 1;
|
|
1098
|
-
const ssrInjectFallthroughAttrs = (node, context) => {
|
|
1099
|
-
// _attrs is provided as a function argument.
|
|
1100
|
-
// mark it as a known identifier so that it doesn't get prefixed by
|
|
1101
|
-
// transformExpression.
|
|
1102
|
-
if (node.type === 0 /* NodeTypes.ROOT */) {
|
|
1103
|
-
context.identifiers._attrs = 1;
|
|
1104
|
-
}
|
|
1105
|
-
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1106
|
-
node.tagType === 1 /* ElementTypes.COMPONENT */ &&
|
|
1107
|
-
(compilerDom.isBuiltInType(node.tag, 'Transition') ||
|
|
1108
|
-
compilerDom.isBuiltInType(node.tag, 'KeepAlive'))) {
|
|
1109
|
-
const rootChildren = filterChild(context.root);
|
|
1110
|
-
if (rootChildren.length === 1 && rootChildren[0] === node) {
|
|
1111
|
-
if (hasSingleChild(node)) {
|
|
1112
|
-
injectFallthroughAttrs(node.children[0]);
|
|
1113
|
-
}
|
|
1114
|
-
return;
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
const parent = context.parent;
|
|
1118
|
-
if (!parent || parent.type !== 0 /* NodeTypes.ROOT */) {
|
|
1119
|
-
return;
|
|
1120
|
-
}
|
|
1121
|
-
if (node.type === 10 /* NodeTypes.IF_BRANCH */ && hasSingleChild(node)) {
|
|
1122
|
-
// detect cases where the parent v-if is not the only root level node
|
|
1123
|
-
let hasEncounteredIf = false;
|
|
1124
|
-
for (const c of filterChild(parent)) {
|
|
1125
|
-
if (c.type === 9 /* NodeTypes.IF */ ||
|
|
1126
|
-
(c.type === 1 /* NodeTypes.ELEMENT */ && compilerDom.findDir(c, 'if'))) {
|
|
1127
|
-
// multiple root v-if
|
|
1128
|
-
if (hasEncounteredIf)
|
|
1129
|
-
return;
|
|
1130
|
-
hasEncounteredIf = true;
|
|
1131
|
-
}
|
|
1132
|
-
else if (
|
|
1133
|
-
// node before v-if
|
|
1134
|
-
!hasEncounteredIf ||
|
|
1135
|
-
// non else nodes
|
|
1136
|
-
!(c.type === 1 /* NodeTypes.ELEMENT */ && compilerDom.findDir(c, /else/, true))) {
|
|
1137
|
-
return;
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
injectFallthroughAttrs(node.children[0]);
|
|
1141
|
-
}
|
|
1142
|
-
else if (hasSingleChild(parent)) {
|
|
1143
|
-
injectFallthroughAttrs(node);
|
|
1144
|
-
}
|
|
1145
|
-
};
|
|
1146
|
-
function injectFallthroughAttrs(node) {
|
|
1147
|
-
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1148
|
-
(node.tagType === 0 /* ElementTypes.ELEMENT */ ||
|
|
1149
|
-
node.tagType === 1 /* ElementTypes.COMPONENT */) &&
|
|
1150
|
-
!compilerDom.findDir(node, 'for')) {
|
|
1151
|
-
node.props.push({
|
|
1152
|
-
type: 7 /* NodeTypes.DIRECTIVE */,
|
|
1153
|
-
name: 'bind',
|
|
1154
|
-
arg: undefined,
|
|
1155
|
-
exp: compilerDom.createSimpleExpression(`_attrs`, false),
|
|
1156
|
-
modifiers: [],
|
|
1157
|
-
loc: compilerDom.locStub
|
|
1158
|
-
});
|
|
1159
|
-
}
|
|
1097
|
+
const filterChild = (node) => node.children.filter(n => n.type !== 3 /* NodeTypes.COMMENT */);
|
|
1098
|
+
const hasSingleChild = (node) => filterChild(node).length === 1;
|
|
1099
|
+
const ssrInjectFallthroughAttrs = (node, context) => {
|
|
1100
|
+
// _attrs is provided as a function argument.
|
|
1101
|
+
// mark it as a known identifier so that it doesn't get prefixed by
|
|
1102
|
+
// transformExpression.
|
|
1103
|
+
if (node.type === 0 /* NodeTypes.ROOT */) {
|
|
1104
|
+
context.identifiers._attrs = 1;
|
|
1105
|
+
}
|
|
1106
|
+
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1107
|
+
node.tagType === 1 /* ElementTypes.COMPONENT */ &&
|
|
1108
|
+
(compilerDom.isBuiltInType(node.tag, 'Transition') ||
|
|
1109
|
+
compilerDom.isBuiltInType(node.tag, 'KeepAlive'))) {
|
|
1110
|
+
const rootChildren = filterChild(context.root);
|
|
1111
|
+
if (rootChildren.length === 1 && rootChildren[0] === node) {
|
|
1112
|
+
if (hasSingleChild(node)) {
|
|
1113
|
+
injectFallthroughAttrs(node.children[0]);
|
|
1114
|
+
}
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
const parent = context.parent;
|
|
1119
|
+
if (!parent || parent.type !== 0 /* NodeTypes.ROOT */) {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
if (node.type === 10 /* NodeTypes.IF_BRANCH */ && hasSingleChild(node)) {
|
|
1123
|
+
// detect cases where the parent v-if is not the only root level node
|
|
1124
|
+
let hasEncounteredIf = false;
|
|
1125
|
+
for (const c of filterChild(parent)) {
|
|
1126
|
+
if (c.type === 9 /* NodeTypes.IF */ ||
|
|
1127
|
+
(c.type === 1 /* NodeTypes.ELEMENT */ && compilerDom.findDir(c, 'if'))) {
|
|
1128
|
+
// multiple root v-if
|
|
1129
|
+
if (hasEncounteredIf)
|
|
1130
|
+
return;
|
|
1131
|
+
hasEncounteredIf = true;
|
|
1132
|
+
}
|
|
1133
|
+
else if (
|
|
1134
|
+
// node before v-if
|
|
1135
|
+
!hasEncounteredIf ||
|
|
1136
|
+
// non else nodes
|
|
1137
|
+
!(c.type === 1 /* NodeTypes.ELEMENT */ && compilerDom.findDir(c, /else/, true))) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
injectFallthroughAttrs(node.children[0]);
|
|
1142
|
+
}
|
|
1143
|
+
else if (hasSingleChild(parent)) {
|
|
1144
|
+
injectFallthroughAttrs(node);
|
|
1145
|
+
}
|
|
1146
|
+
};
|
|
1147
|
+
function injectFallthroughAttrs(node) {
|
|
1148
|
+
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1149
|
+
(node.tagType === 0 /* ElementTypes.ELEMENT */ ||
|
|
1150
|
+
node.tagType === 1 /* ElementTypes.COMPONENT */) &&
|
|
1151
|
+
!compilerDom.findDir(node, 'for')) {
|
|
1152
|
+
node.props.push({
|
|
1153
|
+
type: 7 /* NodeTypes.DIRECTIVE */,
|
|
1154
|
+
name: 'bind',
|
|
1155
|
+
arg: undefined,
|
|
1156
|
+
exp: compilerDom.createSimpleExpression(`_attrs`, false),
|
|
1157
|
+
modifiers: [],
|
|
1158
|
+
loc: compilerDom.locStub
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1160
1161
|
}
|
|
1161
1162
|
|
|
1162
|
-
const ssrInjectCssVars = (node, context) => {
|
|
1163
|
-
if (!context.ssrCssVars) {
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
// _cssVars is initialized once per render function
|
|
1167
|
-
// the code is injected in ssrCodegenTransform when creating the
|
|
1168
|
-
// ssr transform context
|
|
1169
|
-
if (node.type === 0 /* NodeTypes.ROOT */) {
|
|
1170
|
-
context.identifiers._cssVars = 1;
|
|
1171
|
-
}
|
|
1172
|
-
const parent = context.parent;
|
|
1173
|
-
if (!parent || parent.type !== 0 /* NodeTypes.ROOT */) {
|
|
1174
|
-
return;
|
|
1175
|
-
}
|
|
1176
|
-
if (node.type === 10 /* NodeTypes.IF_BRANCH */) {
|
|
1177
|
-
for (const child of node.children) {
|
|
1178
|
-
injectCssVars(child);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
else {
|
|
1182
|
-
injectCssVars(node);
|
|
1183
|
-
}
|
|
1184
|
-
};
|
|
1185
|
-
function injectCssVars(node) {
|
|
1186
|
-
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1187
|
-
(node.tagType === 0 /* ElementTypes.ELEMENT */ ||
|
|
1188
|
-
node.tagType === 1 /* ElementTypes.COMPONENT */) &&
|
|
1189
|
-
!compilerDom.findDir(node, 'for')) {
|
|
1190
|
-
if (compilerDom.isBuiltInType(node.tag, 'Suspense')) {
|
|
1191
|
-
for (const child of node.children) {
|
|
1192
|
-
if (child.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1193
|
-
child.tagType === 3 /* ElementTypes.TEMPLATE */) {
|
|
1194
|
-
// suspense slot
|
|
1195
|
-
child.children.forEach(injectCssVars);
|
|
1196
|
-
}
|
|
1197
|
-
else {
|
|
1198
|
-
injectCssVars(child);
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
else {
|
|
1203
|
-
node.props.push({
|
|
1204
|
-
type: 7 /* NodeTypes.DIRECTIVE */,
|
|
1205
|
-
name: 'bind',
|
|
1206
|
-
arg: undefined,
|
|
1207
|
-
exp: compilerDom.createSimpleExpression(`_cssVars`, false),
|
|
1208
|
-
modifiers: [],
|
|
1209
|
-
loc: compilerDom.locStub
|
|
1210
|
-
});
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1163
|
+
const ssrInjectCssVars = (node, context) => {
|
|
1164
|
+
if (!context.ssrCssVars) {
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
// _cssVars is initialized once per render function
|
|
1168
|
+
// the code is injected in ssrCodegenTransform when creating the
|
|
1169
|
+
// ssr transform context
|
|
1170
|
+
if (node.type === 0 /* NodeTypes.ROOT */) {
|
|
1171
|
+
context.identifiers._cssVars = 1;
|
|
1172
|
+
}
|
|
1173
|
+
const parent = context.parent;
|
|
1174
|
+
if (!parent || parent.type !== 0 /* NodeTypes.ROOT */) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
if (node.type === 10 /* NodeTypes.IF_BRANCH */) {
|
|
1178
|
+
for (const child of node.children) {
|
|
1179
|
+
injectCssVars(child);
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
injectCssVars(node);
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
function injectCssVars(node) {
|
|
1187
|
+
if (node.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1188
|
+
(node.tagType === 0 /* ElementTypes.ELEMENT */ ||
|
|
1189
|
+
node.tagType === 1 /* ElementTypes.COMPONENT */) &&
|
|
1190
|
+
!compilerDom.findDir(node, 'for')) {
|
|
1191
|
+
if (compilerDom.isBuiltInType(node.tag, 'Suspense')) {
|
|
1192
|
+
for (const child of node.children) {
|
|
1193
|
+
if (child.type === 1 /* NodeTypes.ELEMENT */ &&
|
|
1194
|
+
child.tagType === 3 /* ElementTypes.TEMPLATE */) {
|
|
1195
|
+
// suspense slot
|
|
1196
|
+
child.children.forEach(injectCssVars);
|
|
1197
|
+
}
|
|
1198
|
+
else {
|
|
1199
|
+
injectCssVars(child);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
else {
|
|
1204
|
+
node.props.push({
|
|
1205
|
+
type: 7 /* NodeTypes.DIRECTIVE */,
|
|
1206
|
+
name: 'bind',
|
|
1207
|
+
arg: undefined,
|
|
1208
|
+
exp: compilerDom.createSimpleExpression(`_cssVars`, false),
|
|
1209
|
+
modifiers: [],
|
|
1210
|
+
loc: compilerDom.locStub
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1213
1214
|
}
|
|
1214
1215
|
|
|
1215
|
-
function compile(template, options = {}) {
|
|
1216
|
-
options = {
|
|
1217
|
-
...options,
|
|
1218
|
-
// apply DOM-specific parsing options
|
|
1219
|
-
...compilerDom.parserOptions,
|
|
1220
|
-
ssr: true,
|
|
1221
|
-
inSSR: true,
|
|
1222
|
-
scopeId: options.mode === 'function' ? null : options.scopeId,
|
|
1223
|
-
// always prefix since compiler-ssr doesn't have size concern
|
|
1224
|
-
prefixIdentifiers: true,
|
|
1225
|
-
// disable optimizations that are unnecessary for ssr
|
|
1226
|
-
cacheHandlers: false,
|
|
1227
|
-
hoistStatic: false
|
|
1228
|
-
};
|
|
1229
|
-
const ast = compilerDom.baseParse(template, options);
|
|
1230
|
-
// Save raw options for AST. This is needed when performing sub-transforms
|
|
1231
|
-
// on slot vnode branches.
|
|
1232
|
-
rawOptionsMap.set(ast, options);
|
|
1233
|
-
compilerDom.transform(ast, {
|
|
1234
|
-
...options,
|
|
1235
|
-
hoistStatic: false,
|
|
1236
|
-
nodeTransforms: [
|
|
1237
|
-
ssrTransformIf,
|
|
1238
|
-
ssrTransformFor,
|
|
1239
|
-
compilerDom.trackVForSlotScopes,
|
|
1240
|
-
compilerDom.transformExpression,
|
|
1241
|
-
ssrTransformSlotOutlet,
|
|
1242
|
-
ssrInjectFallthroughAttrs,
|
|
1243
|
-
ssrInjectCssVars,
|
|
1244
|
-
ssrTransformElement,
|
|
1245
|
-
ssrTransformComponent,
|
|
1246
|
-
compilerDom.trackSlotScopes,
|
|
1247
|
-
compilerDom.transformStyle,
|
|
1248
|
-
...(options.nodeTransforms || []) // user transforms
|
|
1249
|
-
],
|
|
1250
|
-
directiveTransforms: {
|
|
1251
|
-
// reusing core v-bind
|
|
1252
|
-
bind: compilerDom.transformBind,
|
|
1253
|
-
on: compilerDom.transformOn,
|
|
1254
|
-
// model and show has dedicated SSR handling
|
|
1255
|
-
model: ssrTransformModel,
|
|
1256
|
-
show: ssrTransformShow,
|
|
1257
|
-
// the following are ignored during SSR
|
|
1258
|
-
// on: noopDirectiveTransform,
|
|
1259
|
-
cloak: compilerDom.noopDirectiveTransform,
|
|
1260
|
-
once: compilerDom.noopDirectiveTransform,
|
|
1261
|
-
memo: compilerDom.noopDirectiveTransform,
|
|
1262
|
-
...(options.directiveTransforms || {}) // user transforms
|
|
1263
|
-
}
|
|
1264
|
-
});
|
|
1265
|
-
// traverse the template AST and convert into SSR codegen AST
|
|
1266
|
-
// by replacing ast.codegenNode.
|
|
1267
|
-
ssrCodegenTransform(ast, options);
|
|
1268
|
-
return compilerDom.generate(ast, options);
|
|
1216
|
+
function compile(template, options = {}) {
|
|
1217
|
+
options = {
|
|
1218
|
+
...options,
|
|
1219
|
+
// apply DOM-specific parsing options
|
|
1220
|
+
...compilerDom.parserOptions,
|
|
1221
|
+
ssr: true,
|
|
1222
|
+
inSSR: true,
|
|
1223
|
+
scopeId: options.mode === 'function' ? null : options.scopeId,
|
|
1224
|
+
// always prefix since compiler-ssr doesn't have size concern
|
|
1225
|
+
prefixIdentifiers: true,
|
|
1226
|
+
// disable optimizations that are unnecessary for ssr
|
|
1227
|
+
cacheHandlers: false,
|
|
1228
|
+
hoistStatic: false
|
|
1229
|
+
};
|
|
1230
|
+
const ast = compilerDom.baseParse(template, options);
|
|
1231
|
+
// Save raw options for AST. This is needed when performing sub-transforms
|
|
1232
|
+
// on slot vnode branches.
|
|
1233
|
+
rawOptionsMap.set(ast, options);
|
|
1234
|
+
compilerDom.transform(ast, {
|
|
1235
|
+
...options,
|
|
1236
|
+
hoistStatic: false,
|
|
1237
|
+
nodeTransforms: [
|
|
1238
|
+
ssrTransformIf,
|
|
1239
|
+
ssrTransformFor,
|
|
1240
|
+
compilerDom.trackVForSlotScopes,
|
|
1241
|
+
compilerDom.transformExpression,
|
|
1242
|
+
ssrTransformSlotOutlet,
|
|
1243
|
+
ssrInjectFallthroughAttrs,
|
|
1244
|
+
ssrInjectCssVars,
|
|
1245
|
+
ssrTransformElement,
|
|
1246
|
+
ssrTransformComponent,
|
|
1247
|
+
compilerDom.trackSlotScopes,
|
|
1248
|
+
compilerDom.transformStyle,
|
|
1249
|
+
...(options.nodeTransforms || []) // user transforms
|
|
1250
|
+
],
|
|
1251
|
+
directiveTransforms: {
|
|
1252
|
+
// reusing core v-bind
|
|
1253
|
+
bind: compilerDom.transformBind,
|
|
1254
|
+
on: compilerDom.transformOn,
|
|
1255
|
+
// model and show has dedicated SSR handling
|
|
1256
|
+
model: ssrTransformModel,
|
|
1257
|
+
show: ssrTransformShow,
|
|
1258
|
+
// the following are ignored during SSR
|
|
1259
|
+
// on: noopDirectiveTransform,
|
|
1260
|
+
cloak: compilerDom.noopDirectiveTransform,
|
|
1261
|
+
once: compilerDom.noopDirectiveTransform,
|
|
1262
|
+
memo: compilerDom.noopDirectiveTransform,
|
|
1263
|
+
...(options.directiveTransforms || {}) // user transforms
|
|
1264
|
+
}
|
|
1265
|
+
});
|
|
1266
|
+
// traverse the template AST and convert into SSR codegen AST
|
|
1267
|
+
// by replacing ast.codegenNode.
|
|
1268
|
+
ssrCodegenTransform(ast, options);
|
|
1269
|
+
return compilerDom.generate(ast, options);
|
|
1269
1270
|
}
|
|
1270
1271
|
|
|
1271
1272
|
exports.compile = compile;
|