@vue/server-renderer 3.2.45 → 3.2.46

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.
@@ -1,5 +1,5 @@
1
- import { ssrContextKey, warn as warn$1, Fragment, Static, Comment, Text, mergeProps, ssrUtils, createApp, createVNode, initDirectivesForSSR } from 'vue';
2
- import { makeMap, isOn, escapeHtml, normalizeClass, isSVGTag, propsToAttrMap, isBooleanAttr, includeBooleanAttr, isSSRSafeAttrName, isString, normalizeStyle, stringifyStyle, escapeHtmlComment, isVoidTag, isPromise, isArray, isFunction, NOOP, toDisplayString, isObject, looseEqual, looseIndexOf } from '@vue/shared';
1
+ import { createVNode, ssrContextKey, warn as warn$1, Fragment, Static, Comment, Text, mergeProps, ssrUtils, createApp, initDirectivesForSSR } from 'vue';
2
+ import { makeMap, isOn, isSVGTag, propsToAttrMap, isBooleanAttr, includeBooleanAttr, isSSRSafeAttrName, escapeHtml, normalizeClass, isString, normalizeStyle, stringifyStyle, isArray, toDisplayString, isFunction, isObject, looseEqual, looseIndexOf, isPromise, NOOP, escapeHtmlComment, isVoidTag } from '@vue/shared';
3
3
  export { includeBooleanAttr as ssrIncludeBooleanAttr } from '@vue/shared';
4
4
 
5
5
  // leading comma for empty string ""
@@ -73,13 +73,69 @@ function ssrRenderStyle(raw) {
73
73
  return escapeHtml(stringifyStyle(styles));
74
74
  }
75
75
 
76
- function ssrCompile(template, instance) {
77
- {
78
- throw new Error(`On-the-fly template compilation is not supported in the ESM build of ` +
79
- `@vue/server-renderer. All templates must be pre-compiled into ` +
80
- `render functions.`);
76
+ function ssrRenderComponent(comp, props = null, children = null, parentComponent = null, slotScopeId) {
77
+ return renderComponentVNode(createVNode(comp, props, children), parentComponent, slotScopeId);
78
+ }
79
+
80
+ function ssrRenderSlot(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId) {
81
+ // template-compiled slots are always rendered as fragments
82
+ push(`<!--[-->`);
83
+ ssrRenderSlotInner(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId);
84
+ push(`<!--]-->`);
85
+ }
86
+ function ssrRenderSlotInner(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId, transition) {
87
+ const slotFn = slots[slotName];
88
+ if (slotFn) {
89
+ const slotBuffer = [];
90
+ const bufferedPush = (item) => {
91
+ slotBuffer.push(item);
92
+ };
93
+ const ret = slotFn(slotProps, bufferedPush, parentComponent, slotScopeId ? ' ' + slotScopeId : '');
94
+ if (isArray(ret)) {
95
+ // normal slot
96
+ renderVNodeChildren(push, ret, parentComponent, slotScopeId);
97
+ }
98
+ else {
99
+ // ssr slot.
100
+ // check if the slot renders all comments, in which case use the fallback
101
+ let isEmptySlot = true;
102
+ if (transition) {
103
+ isEmptySlot = false;
104
+ }
105
+ else {
106
+ for (let i = 0; i < slotBuffer.length; i++) {
107
+ if (!isComment(slotBuffer[i])) {
108
+ isEmptySlot = false;
109
+ break;
110
+ }
111
+ }
112
+ }
113
+ if (isEmptySlot) {
114
+ if (fallbackRenderFn) {
115
+ fallbackRenderFn();
116
+ }
117
+ }
118
+ else {
119
+ for (let i = 0; i < slotBuffer.length; i++) {
120
+ push(slotBuffer[i]);
121
+ }
122
+ }
123
+ }
124
+ }
125
+ else if (fallbackRenderFn) {
126
+ fallbackRenderFn();
81
127
  }
82
128
  }
129
+ const commentTestRE = /^<!--.*-->$/s;
130
+ const commentRE = /<!--[^]*?-->/gm;
131
+ function isComment(item) {
132
+ if (typeof item !== 'string' || !commentTestRE.test(item))
133
+ return false;
134
+ // if item is '<!---->' or '<!--[-->' or '<!--]-->', return true directly
135
+ if (item.length <= 8)
136
+ return true;
137
+ return !item.replace(commentRE, '').trim();
138
+ }
83
139
 
84
140
  function ssrRenderTeleport(parentPush, contentRenderFn, target, disabled, parentComponent) {
85
141
  parentPush('<!--teleport start-->');
@@ -104,891 +160,852 @@ function ssrRenderTeleport(parentPush, contentRenderFn, target, disabled, parent
104
160
  parentPush('<!--teleport end-->');
105
161
  }
106
162
 
107
- const { createComponentInstance, setCurrentRenderingInstance, setupComponent, renderComponentRoot, normalizeVNode } = ssrUtils;
108
- // Each component has a buffer array.
109
- // A buffer array can contain one of the following:
110
- // - plain string
111
- // - A resolved buffer (recursive arrays of strings that can be unrolled
112
- // synchronously)
113
- // - An async buffer (a Promise that resolves to a resolved buffer)
114
- function createBuffer() {
115
- let appendable = false;
116
- const buffer = [];
117
- return {
118
- getBuffer() {
119
- // Return static buffer and await on items during unroll stage
120
- return buffer;
121
- },
122
- push(item) {
123
- const isStringItem = isString(item);
124
- if (appendable && isStringItem) {
125
- buffer[buffer.length - 1] += item;
126
- }
127
- else {
128
- buffer.push(item);
129
- }
130
- appendable = isStringItem;
131
- if (isPromise(item) || (isArray(item) && item.hasAsync)) {
132
- // promise, or child buffer with async, mark as async.
133
- // this allows skipping unnecessary await ticks during unroll stage
134
- buffer.hasAsync = true;
135
- }
136
- }
137
- };
163
+ function ssrInterpolate(value) {
164
+ return escapeHtml(toDisplayString(value));
138
165
  }
139
- function renderComponentVNode(vnode, parentComponent = null, slotScopeId) {
140
- const instance = createComponentInstance(vnode, parentComponent, null);
141
- const res = setupComponent(instance, true /* isSSR */);
142
- const hasAsyncSetup = isPromise(res);
143
- const prefetches = instance.sp; /* LifecycleHooks.SERVER_PREFETCH */
144
- if (hasAsyncSetup || prefetches) {
145
- let p = hasAsyncSetup
146
- ? res
147
- : Promise.resolve();
148
- if (prefetches) {
149
- p = p
150
- .then(() => Promise.all(prefetches.map(prefetch => prefetch.call(instance.proxy))))
151
- // Note: error display is already done by the wrapped lifecycle hook function.
152
- .catch(() => { });
153
- }
154
- return p.then(() => renderComponentSubTree(instance, slotScopeId));
166
+
167
+ Symbol((process.env.NODE_ENV !== 'production') ? 'iterate' : '');
168
+ Symbol((process.env.NODE_ENV !== 'production') ? 'Map key iterate' : '');
169
+ let shouldTrack = true;
170
+ const trackStack = [];
171
+ function pauseTracking() {
172
+ trackStack.push(shouldTrack);
173
+ shouldTrack = false;
174
+ }
175
+ function resetTracking() {
176
+ const last = trackStack.pop();
177
+ shouldTrack = last === undefined ? true : last;
178
+ }
179
+
180
+ function toRaw(observed) {
181
+ const raw = observed && observed["__v_raw" /* ReactiveFlags.RAW */];
182
+ return raw ? toRaw(raw) : observed;
183
+ }
184
+
185
+ function isRef(r) {
186
+ return !!(r && r.__v_isRef === true);
187
+ }
188
+
189
+ const stack = [];
190
+ function pushWarningContext(vnode) {
191
+ stack.push(vnode);
192
+ }
193
+ function popWarningContext() {
194
+ stack.pop();
195
+ }
196
+ function warn(msg, ...args) {
197
+ if (!(process.env.NODE_ENV !== 'production'))
198
+ return;
199
+ // avoid props formatting or warn handler tracking deps that might be mutated
200
+ // during patch, leading to infinite recursion.
201
+ pauseTracking();
202
+ const instance = stack.length ? stack[stack.length - 1].component : null;
203
+ const appWarnHandler = instance && instance.appContext.config.warnHandler;
204
+ const trace = getComponentTrace();
205
+ if (appWarnHandler) {
206
+ callWithErrorHandling(appWarnHandler, instance, 11 /* ErrorCodes.APP_WARN_HANDLER */, [
207
+ msg + args.join(''),
208
+ instance && instance.proxy,
209
+ trace
210
+ .map(({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`)
211
+ .join('\n'),
212
+ trace
213
+ ]);
155
214
  }
156
215
  else {
157
- return renderComponentSubTree(instance, slotScopeId);
216
+ const warnArgs = [`[Vue warn]: ${msg}`, ...args];
217
+ /* istanbul ignore if */
218
+ if (trace.length &&
219
+ // avoid spamming console during tests
220
+ !false) {
221
+ warnArgs.push(`\n`, ...formatTrace(trace));
222
+ }
223
+ console.warn(...warnArgs);
158
224
  }
225
+ resetTracking();
159
226
  }
160
- function renderComponentSubTree(instance, slotScopeId) {
161
- const comp = instance.type;
162
- const { getBuffer, push } = createBuffer();
163
- if (isFunction(comp)) {
164
- let root = renderComponentRoot(instance);
165
- // #5817 scope ID attrs not falling through if functional component doesn't
166
- // have props
167
- if (!comp.props) {
168
- for (const key in instance.attrs) {
169
- if (key.startsWith(`data-v-`)) {
170
- (root.props || (root.props = {}))[key] = ``;
171
- }
172
- }
173
- }
174
- renderVNode(push, (instance.subTree = root), instance, slotScopeId);
227
+ function getComponentTrace() {
228
+ let currentVNode = stack[stack.length - 1];
229
+ if (!currentVNode) {
230
+ return [];
175
231
  }
176
- else {
177
- if ((!instance.render || instance.render === NOOP) &&
178
- !instance.ssrRender &&
179
- !comp.ssrRender &&
180
- isString(comp.template)) {
181
- comp.ssrRender = ssrCompile(comp.template);
182
- }
183
- // perf: enable caching of computed getters during render
184
- // since there cannot be state mutations during render.
185
- for (const e of instance.scope.effects) {
186
- if (e.computed)
187
- e.computed._cacheable = true;
188
- }
189
- const ssrRender = instance.ssrRender || comp.ssrRender;
190
- if (ssrRender) {
191
- // optimized
192
- // resolve fallthrough attrs
193
- let attrs = instance.inheritAttrs !== false ? instance.attrs : undefined;
194
- let hasCloned = false;
195
- let cur = instance;
196
- while (true) {
197
- const scopeId = cur.vnode.scopeId;
198
- if (scopeId) {
199
- if (!hasCloned) {
200
- attrs = { ...attrs };
201
- hasCloned = true;
202
- }
203
- attrs[scopeId] = '';
204
- }
205
- const parent = cur.parent;
206
- if (parent && parent.subTree && parent.subTree === cur.vnode) {
207
- // parent is a non-SSR compiled component and is rendering this
208
- // component as root. inherit its scopeId if present.
209
- cur = parent;
210
- }
211
- else {
212
- break;
213
- }
214
- }
215
- if (slotScopeId) {
216
- if (!hasCloned)
217
- attrs = { ...attrs };
218
- attrs[slotScopeId.trim()] = '';
219
- }
220
- // set current rendering instance for asset resolution
221
- const prev = setCurrentRenderingInstance(instance);
222
- try {
223
- ssrRender(instance.proxy, push, instance, attrs,
224
- // compiler-optimized bindings
225
- instance.props, instance.setupState, instance.data, instance.ctx);
226
- }
227
- finally {
228
- setCurrentRenderingInstance(prev);
229
- }
230
- }
231
- else if (instance.render && instance.render !== NOOP) {
232
- renderVNode(push, (instance.subTree = renderComponentRoot(instance)), instance, slotScopeId);
232
+ // we can't just use the stack because it will be incomplete during updates
233
+ // that did not start from the root. Re-construct the parent chain using
234
+ // instance parent pointers.
235
+ const normalizedStack = [];
236
+ while (currentVNode) {
237
+ const last = normalizedStack[0];
238
+ if (last && last.vnode === currentVNode) {
239
+ last.recurseCount++;
233
240
  }
234
241
  else {
235
- const componentName = comp.name || comp.__file || `<Anonymous>`;
236
- warn$1(`Component ${componentName} is missing template or render function.`);
237
- push(`<!---->`);
242
+ normalizedStack.push({
243
+ vnode: currentVNode,
244
+ recurseCount: 0
245
+ });
238
246
  }
247
+ const parentInstance = currentVNode.component && currentVNode.component.parent;
248
+ currentVNode = parentInstance && parentInstance.vnode;
239
249
  }
240
- return getBuffer();
250
+ return normalizedStack;
241
251
  }
242
- function renderVNode(push, vnode, parentComponent, slotScopeId) {
243
- const { type, shapeFlag, children } = vnode;
244
- switch (type) {
245
- case Text:
246
- push(escapeHtml(children));
247
- break;
248
- case Comment:
249
- push(children ? `<!--${escapeHtmlComment(children)}-->` : `<!---->`);
250
- break;
251
- case Static:
252
- push(children);
253
- break;
254
- case Fragment:
255
- if (vnode.slotScopeIds) {
256
- slotScopeId =
257
- (slotScopeId ? slotScopeId + ' ' : '') + vnode.slotScopeIds.join(' ');
258
- }
259
- push(`<!--[-->`); // open
260
- renderVNodeChildren(push, children, parentComponent, slotScopeId);
261
- push(`<!--]-->`); // close
262
- break;
263
- default:
264
- if (shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
265
- renderElementVNode(push, vnode, parentComponent, slotScopeId);
266
- }
267
- else if (shapeFlag & 6 /* ShapeFlags.COMPONENT */) {
268
- push(renderComponentVNode(vnode, parentComponent, slotScopeId));
269
- }
270
- else if (shapeFlag & 64 /* ShapeFlags.TELEPORT */) {
271
- renderTeleportVNode(push, vnode, parentComponent, slotScopeId);
272
- }
273
- else if (shapeFlag & 128 /* ShapeFlags.SUSPENSE */) {
274
- renderVNode(push, vnode.ssContent, parentComponent, slotScopeId);
275
- }
276
- else {
277
- warn$1('[@vue/server-renderer] Invalid VNode type:', type, `(${typeof type})`);
278
- }
279
- }
252
+ /* istanbul ignore next */
253
+ function formatTrace(trace) {
254
+ const logs = [];
255
+ trace.forEach((entry, i) => {
256
+ logs.push(...(i === 0 ? [] : [`\n`]), ...formatTraceEntry(entry));
257
+ });
258
+ return logs;
280
259
  }
281
- function renderVNodeChildren(push, children, parentComponent, slotScopeId) {
282
- for (let i = 0; i < children.length; i++) {
283
- renderVNode(push, normalizeVNode(children[i]), parentComponent, slotScopeId);
260
+ function formatTraceEntry({ vnode, recurseCount }) {
261
+ const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;
262
+ const isRoot = vnode.component ? vnode.component.parent == null : false;
263
+ const open = ` at <${formatComponentName(vnode.component, vnode.type, isRoot)}`;
264
+ const close = `>` + postfix;
265
+ return vnode.props
266
+ ? [open, ...formatProps(vnode.props), close]
267
+ : [open + close];
268
+ }
269
+ /* istanbul ignore next */
270
+ function formatProps(props) {
271
+ const res = [];
272
+ const keys = Object.keys(props);
273
+ keys.slice(0, 3).forEach(key => {
274
+ res.push(...formatProp(key, props[key]));
275
+ });
276
+ if (keys.length > 3) {
277
+ res.push(` ...`);
284
278
  }
279
+ return res;
285
280
  }
286
- function renderElementVNode(push, vnode, parentComponent, slotScopeId) {
287
- const tag = vnode.type;
288
- let { props, children, shapeFlag, scopeId, dirs } = vnode;
289
- let openTag = `<${tag}`;
290
- if (dirs) {
291
- props = applySSRDirectives(vnode, props, dirs);
281
+ /* istanbul ignore next */
282
+ function formatProp(key, value, raw) {
283
+ if (isString(value)) {
284
+ value = JSON.stringify(value);
285
+ return raw ? value : [`${key}=${value}`];
292
286
  }
293
- if (props) {
294
- openTag += ssrRenderAttrs(props, tag);
287
+ else if (typeof value === 'number' ||
288
+ typeof value === 'boolean' ||
289
+ value == null) {
290
+ return raw ? value : [`${key}=${value}`];
295
291
  }
296
- if (scopeId) {
297
- openTag += ` ${scopeId}`;
292
+ else if (isRef(value)) {
293
+ value = formatProp(key, toRaw(value.value), true);
294
+ return raw ? value : [`${key}=Ref<`, value, `>`];
298
295
  }
299
- // inherit parent chain scope id if this is the root node
300
- let curParent = parentComponent;
301
- let curVnode = vnode;
302
- while (curParent && curVnode === curParent.subTree) {
303
- curVnode = curParent.vnode;
304
- if (curVnode.scopeId) {
305
- openTag += ` ${curVnode.scopeId}`;
306
- }
307
- curParent = curParent.parent;
296
+ else if (isFunction(value)) {
297
+ return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];
308
298
  }
309
- if (slotScopeId) {
310
- openTag += ` ${slotScopeId}`;
299
+ else {
300
+ value = toRaw(value);
301
+ return raw ? value : [`${key}=`, value];
311
302
  }
312
- push(openTag + `>`);
313
- if (!isVoidTag(tag)) {
314
- let hasChildrenOverride = false;
315
- if (props) {
316
- if (props.innerHTML) {
317
- hasChildrenOverride = true;
318
- push(props.innerHTML);
319
- }
320
- else if (props.textContent) {
321
- hasChildrenOverride = true;
322
- push(escapeHtml(props.textContent));
323
- }
324
- else if (tag === 'textarea' && props.value) {
325
- hasChildrenOverride = true;
326
- push(escapeHtml(props.value));
303
+ }
304
+
305
+ const ErrorTypeStrings = {
306
+ ["sp" /* LifecycleHooks.SERVER_PREFETCH */]: 'serverPrefetch hook',
307
+ ["bc" /* LifecycleHooks.BEFORE_CREATE */]: 'beforeCreate hook',
308
+ ["c" /* LifecycleHooks.CREATED */]: 'created hook',
309
+ ["bm" /* LifecycleHooks.BEFORE_MOUNT */]: 'beforeMount hook',
310
+ ["m" /* LifecycleHooks.MOUNTED */]: 'mounted hook',
311
+ ["bu" /* LifecycleHooks.BEFORE_UPDATE */]: 'beforeUpdate hook',
312
+ ["u" /* LifecycleHooks.UPDATED */]: 'updated',
313
+ ["bum" /* LifecycleHooks.BEFORE_UNMOUNT */]: 'beforeUnmount hook',
314
+ ["um" /* LifecycleHooks.UNMOUNTED */]: 'unmounted hook',
315
+ ["a" /* LifecycleHooks.ACTIVATED */]: 'activated hook',
316
+ ["da" /* LifecycleHooks.DEACTIVATED */]: 'deactivated hook',
317
+ ["ec" /* LifecycleHooks.ERROR_CAPTURED */]: 'errorCaptured hook',
318
+ ["rtc" /* LifecycleHooks.RENDER_TRACKED */]: 'renderTracked hook',
319
+ ["rtg" /* LifecycleHooks.RENDER_TRIGGERED */]: 'renderTriggered hook',
320
+ [0 /* ErrorCodes.SETUP_FUNCTION */]: 'setup function',
321
+ [1 /* ErrorCodes.RENDER_FUNCTION */]: 'render function',
322
+ [2 /* ErrorCodes.WATCH_GETTER */]: 'watcher getter',
323
+ [3 /* ErrorCodes.WATCH_CALLBACK */]: 'watcher callback',
324
+ [4 /* ErrorCodes.WATCH_CLEANUP */]: 'watcher cleanup function',
325
+ [5 /* ErrorCodes.NATIVE_EVENT_HANDLER */]: 'native event handler',
326
+ [6 /* ErrorCodes.COMPONENT_EVENT_HANDLER */]: 'component event handler',
327
+ [7 /* ErrorCodes.VNODE_HOOK */]: 'vnode hook',
328
+ [8 /* ErrorCodes.DIRECTIVE_HOOK */]: 'directive hook',
329
+ [9 /* ErrorCodes.TRANSITION_HOOK */]: 'transition hook',
330
+ [10 /* ErrorCodes.APP_ERROR_HANDLER */]: 'app errorHandler',
331
+ [11 /* ErrorCodes.APP_WARN_HANDLER */]: 'app warnHandler',
332
+ [12 /* ErrorCodes.FUNCTION_REF */]: 'ref function',
333
+ [13 /* ErrorCodes.ASYNC_COMPONENT_LOADER */]: 'async component loader',
334
+ [14 /* ErrorCodes.SCHEDULER */]: 'scheduler flush. This is likely a Vue internals bug. ' +
335
+ 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core'
336
+ };
337
+ function callWithErrorHandling(fn, instance, type, args) {
338
+ let res;
339
+ try {
340
+ res = args ? fn(...args) : fn();
341
+ }
342
+ catch (err) {
343
+ handleError(err, instance, type);
344
+ }
345
+ return res;
346
+ }
347
+ function handleError(err, instance, type, throwInDev = true) {
348
+ const contextVNode = instance ? instance.vnode : null;
349
+ if (instance) {
350
+ let cur = instance.parent;
351
+ // the exposed instance is the render proxy to keep it consistent with 2.x
352
+ const exposedInstance = instance.proxy;
353
+ // in production the hook receives only the error code
354
+ const errorInfo = (process.env.NODE_ENV !== 'production') ? ErrorTypeStrings[type] : type;
355
+ while (cur) {
356
+ const errorCapturedHooks = cur.ec;
357
+ if (errorCapturedHooks) {
358
+ for (let i = 0; i < errorCapturedHooks.length; i++) {
359
+ if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) {
360
+ return;
361
+ }
362
+ }
327
363
  }
364
+ cur = cur.parent;
328
365
  }
329
- if (!hasChildrenOverride) {
330
- if (shapeFlag & 8 /* ShapeFlags.TEXT_CHILDREN */) {
331
- push(escapeHtml(children));
332
- }
333
- else if (shapeFlag & 16 /* ShapeFlags.ARRAY_CHILDREN */) {
334
- renderVNodeChildren(push, children, parentComponent, slotScopeId);
335
- }
366
+ // app-level handling
367
+ const appErrorHandler = instance.appContext.config.errorHandler;
368
+ if (appErrorHandler) {
369
+ callWithErrorHandling(appErrorHandler, null, 10 /* ErrorCodes.APP_ERROR_HANDLER */, [err, exposedInstance, errorInfo]);
370
+ return;
336
371
  }
337
- push(`</${tag}>`);
338
372
  }
373
+ logError(err, type, contextVNode, throwInDev);
339
374
  }
340
- function applySSRDirectives(vnode, rawProps, dirs) {
341
- const toMerge = [];
342
- for (let i = 0; i < dirs.length; i++) {
343
- const binding = dirs[i];
344
- const { dir: { getSSRProps } } = binding;
345
- if (getSSRProps) {
346
- const props = getSSRProps(binding, vnode);
347
- if (props)
348
- toMerge.push(props);
375
+ function logError(err, type, contextVNode, throwInDev = true) {
376
+ if ((process.env.NODE_ENV !== 'production')) {
377
+ const info = ErrorTypeStrings[type];
378
+ if (contextVNode) {
379
+ pushWarningContext(contextVNode);
349
380
  }
350
- }
351
- return mergeProps(rawProps || {}, ...toMerge);
352
- }
353
- function renderTeleportVNode(push, vnode, parentComponent, slotScopeId) {
354
- const target = vnode.props && vnode.props.to;
355
- const disabled = vnode.props && vnode.props.disabled;
356
- if (!target) {
357
- if (!disabled) {
358
- warn$1(`[@vue/server-renderer] Teleport is missing target prop.`);
381
+ warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`);
382
+ if (contextVNode) {
383
+ popWarningContext();
359
384
  }
360
- return [];
361
- }
362
- if (!isString(target)) {
363
- warn$1(`[@vue/server-renderer] Teleport target must be a query selector string.`);
364
- return [];
365
- }
366
- ssrRenderTeleport(push, push => {
367
- renderVNodeChildren(push, vnode.children, parentComponent, slotScopeId);
368
- }, target, disabled || disabled === '', parentComponent);
369
- }
370
-
371
- const { isVNode } = ssrUtils;
372
- async function unrollBuffer(buffer) {
373
- if (buffer.hasAsync) {
374
- let ret = '';
375
- for (let i = 0; i < buffer.length; i++) {
376
- let item = buffer[i];
377
- if (isPromise(item)) {
378
- item = await item;
379
- }
380
- if (isString(item)) {
381
- ret += item;
382
- }
383
- else {
384
- ret += await unrollBuffer(item);
385
- }
385
+ // crash in dev by default so it's more noticeable
386
+ if (throwInDev) {
387
+ throw err;
388
+ }
389
+ else {
390
+ console.error(err);
386
391
  }
387
- return ret;
388
392
  }
389
393
  else {
390
- // sync buffer can be more efficiently unrolled without unnecessary await
391
- // ticks
392
- return unrollBufferSync(buffer);
394
+ // recover in prod to reduce the impact on end-user
395
+ console.error(err);
393
396
  }
394
397
  }
395
- function unrollBufferSync(buffer) {
396
- let ret = '';
397
- for (let i = 0; i < buffer.length; i++) {
398
- let item = buffer[i];
399
- if (isString(item)) {
400
- ret += item;
401
- }
402
- else {
403
- // since this is a sync buffer, child buffers are never promises
404
- ret += unrollBufferSync(item);
398
+
399
+ const classifyRE = /(?:^|[-_])(\w)/g;
400
+ const classify = (str) => str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '');
401
+ function getComponentName(Component, includeInferred = true) {
402
+ return isFunction(Component)
403
+ ? Component.displayName || Component.name
404
+ : Component.name || (includeInferred && Component.__name);
405
+ }
406
+ /* istanbul ignore next */
407
+ function formatComponentName(instance, Component, isRoot = false) {
408
+ let name = getComponentName(Component);
409
+ if (!name && Component.__file) {
410
+ const match = Component.__file.match(/([^/\\]+)\.\w+$/);
411
+ if (match) {
412
+ name = match[1];
405
413
  }
406
414
  }
407
- return ret;
408
- }
409
- async function renderToString(input, context = {}) {
410
- if (isVNode(input)) {
411
- // raw vnode, wrap with app (for context)
412
- return renderToString(createApp({ render: () => input }), context);
415
+ if (!name && instance && instance.parent) {
416
+ // try to infer the name based on reverse resolution
417
+ const inferFromRegistry = (registry) => {
418
+ for (const key in registry) {
419
+ if (registry[key] === Component) {
420
+ return key;
421
+ }
422
+ }
423
+ };
424
+ name =
425
+ inferFromRegistry(instance.components ||
426
+ instance.parent.type.components) || inferFromRegistry(instance.appContext.components);
413
427
  }
414
- // rendering an app
415
- const vnode = createVNode(input._component, input._props);
416
- vnode.appContext = input._context;
417
- // provide the ssr context to the tree
418
- input.provide(ssrContextKey, context);
419
- const buffer = await renderComponentVNode(vnode);
420
- const result = await unrollBuffer(buffer);
421
- await resolveTeleports(context);
422
- if (context.__watcherHandles) {
423
- for (const unwatch of context.__watcherHandles) {
424
- unwatch();
428
+ return name ? classify(name) : isRoot ? `App` : `Anonymous`;
429
+ }
430
+
431
+ function ssrRenderList(source, renderItem) {
432
+ if (isArray(source) || isString(source)) {
433
+ for (let i = 0, l = source.length; i < l; i++) {
434
+ renderItem(source[i], i);
425
435
  }
426
436
  }
427
- return result;
428
- }
429
- async function resolveTeleports(context) {
430
- if (context.__teleportBuffers) {
431
- context.teleports = context.teleports || {};
432
- for (const key in context.__teleportBuffers) {
433
- // note: it's OK to await sequentially here because the Promises were
434
- // created eagerly in parallel.
435
- context.teleports[key] = await unrollBuffer(await Promise.all([context.__teleportBuffers[key]]));
437
+ else if (typeof source === 'number') {
438
+ if ((process.env.NODE_ENV !== 'production') && !Number.isInteger(source)) {
439
+ warn(`The v-for range expect an integer value but got ${source}.`);
440
+ return;
441
+ }
442
+ for (let i = 0; i < source; i++) {
443
+ renderItem(i + 1, i);
436
444
  }
437
445
  }
438
- }
439
-
440
- const { isVNode: isVNode$1 } = ssrUtils;
441
- async function unrollBuffer$1(buffer, stream) {
442
- if (buffer.hasAsync) {
443
- for (let i = 0; i < buffer.length; i++) {
444
- let item = buffer[i];
445
- if (isPromise(item)) {
446
- item = await item;
447
- }
448
- if (isString(item)) {
449
- stream.push(item);
446
+ else if (isObject(source)) {
447
+ if (source[Symbol.iterator]) {
448
+ const arr = Array.from(source);
449
+ for (let i = 0, l = arr.length; i < l; i++) {
450
+ renderItem(arr[i], i);
450
451
  }
451
- else {
452
- await unrollBuffer$1(item, stream);
452
+ }
453
+ else {
454
+ const keys = Object.keys(source);
455
+ for (let i = 0, l = keys.length; i < l; i++) {
456
+ const key = keys[i];
457
+ renderItem(source[key], key, i);
453
458
  }
454
459
  }
455
460
  }
461
+ }
462
+
463
+ async function ssrRenderSuspense(push, { default: renderContent }) {
464
+ if (renderContent) {
465
+ renderContent();
466
+ }
456
467
  else {
457
- // sync buffer can be more efficiently unrolled without unnecessary await
458
- // ticks
459
- unrollBufferSync$1(buffer, stream);
468
+ push(`<!---->`);
460
469
  }
461
470
  }
462
- function unrollBufferSync$1(buffer, stream) {
463
- for (let i = 0; i < buffer.length; i++) {
464
- let item = buffer[i];
465
- if (isString(item)) {
466
- stream.push(item);
467
- }
468
- else {
469
- // since this is a sync buffer, child buffers are never promises
470
- unrollBufferSync$1(item, stream);
471
- }
471
+
472
+ function ssrGetDirectiveProps(instance, dir, value, arg, modifiers = {}) {
473
+ if (typeof dir !== 'function' && dir.getSSRProps) {
474
+ return (dir.getSSRProps({
475
+ dir,
476
+ instance,
477
+ value,
478
+ oldValue: undefined,
479
+ arg,
480
+ modifiers
481
+ }, null) || {});
472
482
  }
483
+ return {};
473
484
  }
474
- function renderToSimpleStream(input, context, stream) {
475
- if (isVNode$1(input)) {
476
- // raw vnode, wrap with app (for context)
477
- return renderToSimpleStream(createApp({ render: () => input }), context, stream);
485
+
486
+ const ssrLooseEqual = looseEqual;
487
+ function ssrLooseContain(arr, value) {
488
+ return looseIndexOf(arr, value) > -1;
489
+ }
490
+ // for <input :type="type" v-model="model" value="value">
491
+ function ssrRenderDynamicModel(type, model, value) {
492
+ switch (type) {
493
+ case 'radio':
494
+ return looseEqual(model, value) ? ' checked' : '';
495
+ case 'checkbox':
496
+ return (isArray(model) ? ssrLooseContain(model, value) : model)
497
+ ? ' checked'
498
+ : '';
499
+ default:
500
+ // text types
501
+ return ssrRenderAttr('value', model);
478
502
  }
479
- // rendering an app
480
- const vnode = createVNode(input._component, input._props);
481
- vnode.appContext = input._context;
482
- // provide the ssr context to the tree
483
- input.provide(ssrContextKey, context);
484
- Promise.resolve(renderComponentVNode(vnode))
485
- .then(buffer => unrollBuffer$1(buffer, stream))
486
- .then(() => resolveTeleports(context))
487
- .then(() => {
488
- if (context.__watcherHandles) {
489
- for (const unwatch of context.__watcherHandles) {
490
- unwatch();
491
- }
492
- }
493
- })
494
- .then(() => stream.push(null))
495
- .catch(error => {
496
- stream.destroy(error);
497
- });
498
- return stream;
499
503
  }
500
- /**
501
- * @deprecated
502
- */
503
- function renderToStream(input, context = {}) {
504
- console.warn(`[@vue/server-renderer] renderToStream is deprecated - use renderToNodeStream instead.`);
505
- return renderToNodeStream(input, context);
504
+ // for <input v-bind="obj" v-model="model">
505
+ function ssrGetDynamicModelProps(existingProps = {}, model) {
506
+ const { type, value } = existingProps;
507
+ switch (type) {
508
+ case 'radio':
509
+ return looseEqual(model, value) ? { checked: true } : null;
510
+ case 'checkbox':
511
+ return (isArray(model) ? ssrLooseContain(model, value) : model)
512
+ ? { checked: true }
513
+ : null;
514
+ default:
515
+ // text types
516
+ return { value: model };
517
+ }
506
518
  }
507
- function renderToNodeStream(input, context = {}) {
508
- const stream = null;
519
+
520
+ function ssrCompile(template, instance) {
521
+ // TODO: this branch should now work in ESM builds, enable it in a minor
509
522
  {
510
- throw new Error(`ESM build of renderToStream() does not support renderToNodeStream(). ` +
511
- `Use pipeToNodeWritable() with an existing Node.js Writable stream ` +
512
- `instance instead.`);
523
+ throw new Error(`On-the-fly template compilation is not supported in the ESM build of ` +
524
+ `@vue/server-renderer. All templates must be pre-compiled into ` +
525
+ `render functions.`);
513
526
  }
514
527
  }
515
- function pipeToNodeWritable(input, context = {}, writable) {
516
- renderToSimpleStream(input, context, {
517
- push(content) {
518
- if (content != null) {
519
- writable.write(content);
528
+
529
+ const { createComponentInstance, setCurrentRenderingInstance, setupComponent, renderComponentRoot, normalizeVNode } = ssrUtils;
530
+ // Each component has a buffer array.
531
+ // A buffer array can contain one of the following:
532
+ // - plain string
533
+ // - A resolved buffer (recursive arrays of strings that can be unrolled
534
+ // synchronously)
535
+ // - An async buffer (a Promise that resolves to a resolved buffer)
536
+ function createBuffer() {
537
+ let appendable = false;
538
+ const buffer = [];
539
+ return {
540
+ getBuffer() {
541
+ // Return static buffer and await on items during unroll stage
542
+ return buffer;
543
+ },
544
+ push(item) {
545
+ const isStringItem = isString(item);
546
+ if (appendable && isStringItem) {
547
+ buffer[buffer.length - 1] += item;
520
548
  }
521
549
  else {
522
- writable.end();
550
+ buffer.push(item);
551
+ }
552
+ appendable = isStringItem;
553
+ if (isPromise(item) || (isArray(item) && item.hasAsync)) {
554
+ // promise, or child buffer with async, mark as async.
555
+ // this allows skipping unnecessary await ticks during unroll stage
556
+ buffer.hasAsync = true;
523
557
  }
524
- },
525
- destroy(err) {
526
- writable.destroy(err);
527
558
  }
528
- });
559
+ };
529
560
  }
530
- function renderToWebStream(input, context = {}) {
531
- if (typeof ReadableStream !== 'function') {
532
- throw new Error(`ReadableStream constructor is not available in the global scope. ` +
533
- `If the target environment does support web streams, consider using ` +
534
- `pipeToWebWritable() with an existing WritableStream instance instead.`);
561
+ function renderComponentVNode(vnode, parentComponent = null, slotScopeId) {
562
+ const instance = createComponentInstance(vnode, parentComponent, null);
563
+ const res = setupComponent(instance, true /* isSSR */);
564
+ const hasAsyncSetup = isPromise(res);
565
+ const prefetches = instance.sp; /* LifecycleHooks.SERVER_PREFETCH */
566
+ if (hasAsyncSetup || prefetches) {
567
+ let p = hasAsyncSetup
568
+ ? res
569
+ : Promise.resolve();
570
+ if (prefetches) {
571
+ p = p
572
+ .then(() => Promise.all(prefetches.map(prefetch => prefetch.call(instance.proxy))))
573
+ // Note: error display is already done by the wrapped lifecycle hook function.
574
+ .catch(() => { });
575
+ }
576
+ return p.then(() => renderComponentSubTree(instance, slotScopeId));
535
577
  }
536
- const encoder = new TextEncoder();
537
- let cancelled = false;
538
- return new ReadableStream({
539
- start(controller) {
540
- renderToSimpleStream(input, context, {
541
- push(content) {
542
- if (cancelled)
543
- return;
544
- if (content != null) {
545
- controller.enqueue(encoder.encode(content));
546
- }
547
- else {
548
- controller.close();
549
- }
550
- },
551
- destroy(err) {
552
- controller.error(err);
578
+ else {
579
+ return renderComponentSubTree(instance, slotScopeId);
580
+ }
581
+ }
582
+ function renderComponentSubTree(instance, slotScopeId) {
583
+ const comp = instance.type;
584
+ const { getBuffer, push } = createBuffer();
585
+ if (isFunction(comp)) {
586
+ let root = renderComponentRoot(instance);
587
+ // #5817 scope ID attrs not falling through if functional component doesn't
588
+ // have props
589
+ if (!comp.props) {
590
+ for (const key in instance.attrs) {
591
+ if (key.startsWith(`data-v-`)) {
592
+ (root.props || (root.props = {}))[key] = ``;
553
593
  }
554
- });
555
- },
556
- cancel() {
557
- cancelled = true;
594
+ }
558
595
  }
559
- });
560
- }
561
- function pipeToWebWritable(input, context = {}, writable) {
562
- const writer = writable.getWriter();
563
- const encoder = new TextEncoder();
564
- // #4287 CloudFlare workers do not implement `ready` property
565
- let hasReady = false;
566
- try {
567
- hasReady = isPromise(writer.ready);
596
+ renderVNode(push, (instance.subTree = root), instance, slotScopeId);
568
597
  }
569
- catch (e) { }
570
- renderToSimpleStream(input, context, {
571
- async push(content) {
572
- if (hasReady) {
573
- await writer.ready;
598
+ else {
599
+ if ((!instance.render || instance.render === NOOP) &&
600
+ !instance.ssrRender &&
601
+ !comp.ssrRender &&
602
+ isString(comp.template)) {
603
+ comp.ssrRender = ssrCompile(comp.template);
604
+ }
605
+ // perf: enable caching of computed getters during render
606
+ // since there cannot be state mutations during render.
607
+ for (const e of instance.scope.effects) {
608
+ if (e.computed)
609
+ e.computed._cacheable = true;
610
+ }
611
+ const ssrRender = instance.ssrRender || comp.ssrRender;
612
+ if (ssrRender) {
613
+ // optimized
614
+ // resolve fallthrough attrs
615
+ let attrs = instance.inheritAttrs !== false ? instance.attrs : undefined;
616
+ let hasCloned = false;
617
+ let cur = instance;
618
+ while (true) {
619
+ const scopeId = cur.vnode.scopeId;
620
+ if (scopeId) {
621
+ if (!hasCloned) {
622
+ attrs = { ...attrs };
623
+ hasCloned = true;
624
+ }
625
+ attrs[scopeId] = '';
626
+ }
627
+ const parent = cur.parent;
628
+ if (parent && parent.subTree && parent.subTree === cur.vnode) {
629
+ // parent is a non-SSR compiled component and is rendering this
630
+ // component as root. inherit its scopeId if present.
631
+ cur = parent;
632
+ }
633
+ else {
634
+ break;
635
+ }
574
636
  }
575
- if (content != null) {
576
- return writer.write(encoder.encode(content));
637
+ if (slotScopeId) {
638
+ if (!hasCloned)
639
+ attrs = { ...attrs };
640
+ attrs[slotScopeId.trim()] = '';
577
641
  }
578
- else {
579
- return writer.close();
642
+ // set current rendering instance for asset resolution
643
+ const prev = setCurrentRenderingInstance(instance);
644
+ try {
645
+ ssrRender(instance.proxy, push, instance, attrs,
646
+ // compiler-optimized bindings
647
+ instance.props, instance.setupState, instance.data, instance.ctx);
648
+ }
649
+ finally {
650
+ setCurrentRenderingInstance(prev);
580
651
  }
581
- },
582
- destroy(err) {
583
- // TODO better error handling?
584
- console.log(err);
585
- writer.close();
586
652
  }
587
- });
588
- }
589
-
590
- function ssrRenderComponent(comp, props = null, children = null, parentComponent = null, slotScopeId) {
591
- return renderComponentVNode(createVNode(comp, props, children), parentComponent, slotScopeId);
592
- }
593
-
594
- function ssrRenderSlot(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId) {
595
- // template-compiled slots are always rendered as fragments
596
- push(`<!--[-->`);
597
- ssrRenderSlotInner(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId);
598
- push(`<!--]-->`);
599
- }
600
- function ssrRenderSlotInner(slots, slotName, slotProps, fallbackRenderFn, push, parentComponent, slotScopeId, transition) {
601
- const slotFn = slots[slotName];
602
- if (slotFn) {
603
- const slotBuffer = [];
604
- const bufferedPush = (item) => {
605
- slotBuffer.push(item);
606
- };
607
- const ret = slotFn(slotProps, bufferedPush, parentComponent, slotScopeId ? ' ' + slotScopeId : '');
608
- if (isArray(ret)) {
609
- // normal slot
610
- renderVNodeChildren(push, ret, parentComponent, slotScopeId);
653
+ else if (instance.render && instance.render !== NOOP) {
654
+ renderVNode(push, (instance.subTree = renderComponentRoot(instance)), instance, slotScopeId);
611
655
  }
612
656
  else {
613
- // ssr slot.
614
- // check if the slot renders all comments, in which case use the fallback
615
- let isEmptySlot = true;
616
- if (transition) {
617
- isEmptySlot = false;
657
+ const componentName = comp.name || comp.__file || `<Anonymous>`;
658
+ warn$1(`Component ${componentName} is missing template or render function.`);
659
+ push(`<!---->`);
660
+ }
661
+ }
662
+ return getBuffer();
663
+ }
664
+ function renderVNode(push, vnode, parentComponent, slotScopeId) {
665
+ const { type, shapeFlag, children } = vnode;
666
+ switch (type) {
667
+ case Text:
668
+ push(escapeHtml(children));
669
+ break;
670
+ case Comment:
671
+ push(children ? `<!--${escapeHtmlComment(children)}-->` : `<!---->`);
672
+ break;
673
+ case Static:
674
+ push(children);
675
+ break;
676
+ case Fragment:
677
+ if (vnode.slotScopeIds) {
678
+ slotScopeId =
679
+ (slotScopeId ? slotScopeId + ' ' : '') + vnode.slotScopeIds.join(' ');
618
680
  }
619
- else {
620
- for (let i = 0; i < slotBuffer.length; i++) {
621
- if (!isComment(slotBuffer[i])) {
622
- isEmptySlot = false;
623
- break;
624
- }
625
- }
681
+ push(`<!--[-->`); // open
682
+ renderVNodeChildren(push, children, parentComponent, slotScopeId);
683
+ push(`<!--]-->`); // close
684
+ break;
685
+ default:
686
+ if (shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
687
+ renderElementVNode(push, vnode, parentComponent, slotScopeId);
626
688
  }
627
- if (isEmptySlot) {
628
- if (fallbackRenderFn) {
629
- fallbackRenderFn();
630
- }
689
+ else if (shapeFlag & 6 /* ShapeFlags.COMPONENT */) {
690
+ push(renderComponentVNode(vnode, parentComponent, slotScopeId));
691
+ }
692
+ else if (shapeFlag & 64 /* ShapeFlags.TELEPORT */) {
693
+ renderTeleportVNode(push, vnode, parentComponent, slotScopeId);
694
+ }
695
+ else if (shapeFlag & 128 /* ShapeFlags.SUSPENSE */) {
696
+ renderVNode(push, vnode.ssContent, parentComponent, slotScopeId);
631
697
  }
632
698
  else {
633
- for (let i = 0; i < slotBuffer.length; i++) {
634
- push(slotBuffer[i]);
635
- }
699
+ warn$1('[@vue/server-renderer] Invalid VNode type:', type, `(${typeof type})`);
636
700
  }
637
- }
638
- }
639
- else if (fallbackRenderFn) {
640
- fallbackRenderFn();
641
701
  }
642
702
  }
643
- const commentTestRE = /^<!--.*-->$/s;
644
- const commentRE = /<!--[^]*?-->/gm;
645
- function isComment(item) {
646
- if (typeof item !== 'string' || !commentTestRE.test(item))
647
- return false;
648
- // if item is '<!---->' or '<!--[-->' or '<!--]-->', return true directly
649
- if (item.length <= 8)
650
- return true;
651
- return !item.replace(commentRE, '').trim();
652
- }
653
-
654
- function ssrInterpolate(value) {
655
- return escapeHtml(toDisplayString(value));
656
- }
657
-
658
- function toRaw(observed) {
659
- const raw = observed && observed["__v_raw" /* ReactiveFlags.RAW */];
660
- return raw ? toRaw(raw) : observed;
661
- }
662
-
663
- function isRef(r) {
664
- return !!(r && r.__v_isRef === true);
665
- }
666
-
667
- const stack = [];
668
- function pushWarningContext(vnode) {
669
- stack.push(vnode);
670
- }
671
- function popWarningContext() {
672
- stack.pop();
703
+ function renderVNodeChildren(push, children, parentComponent, slotScopeId) {
704
+ for (let i = 0; i < children.length; i++) {
705
+ renderVNode(push, normalizeVNode(children[i]), parentComponent, slotScopeId);
706
+ }
673
707
  }
674
- function warn(msg, ...args) {
675
- if (!(process.env.NODE_ENV !== 'production'))
676
- return;
677
- const instance = stack.length ? stack[stack.length - 1].component : null;
678
- const appWarnHandler = instance && instance.appContext.config.warnHandler;
679
- const trace = getComponentTrace();
680
- if (appWarnHandler) {
681
- callWithErrorHandling(appWarnHandler, instance, 11 /* ErrorCodes.APP_WARN_HANDLER */, [
682
- msg + args.join(''),
683
- instance && instance.proxy,
684
- trace
685
- .map(({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`)
686
- .join('\n'),
687
- trace
688
- ]);
708
+ function renderElementVNode(push, vnode, parentComponent, slotScopeId) {
709
+ const tag = vnode.type;
710
+ let { props, children, shapeFlag, scopeId, dirs } = vnode;
711
+ let openTag = `<${tag}`;
712
+ if (dirs) {
713
+ props = applySSRDirectives(vnode, props, dirs);
689
714
  }
690
- else {
691
- const warnArgs = [`[Vue warn]: ${msg}`, ...args];
692
- /* istanbul ignore if */
693
- if (trace.length &&
694
- // avoid spamming console during tests
695
- !false) {
696
- warnArgs.push(`\n`, ...formatTrace(trace));
715
+ if (props) {
716
+ openTag += ssrRenderAttrs(props, tag);
717
+ }
718
+ if (scopeId) {
719
+ openTag += ` ${scopeId}`;
720
+ }
721
+ // inherit parent chain scope id if this is the root node
722
+ let curParent = parentComponent;
723
+ let curVnode = vnode;
724
+ while (curParent && curVnode === curParent.subTree) {
725
+ curVnode = curParent.vnode;
726
+ if (curVnode.scopeId) {
727
+ openTag += ` ${curVnode.scopeId}`;
697
728
  }
698
- console.warn(...warnArgs);
729
+ curParent = curParent.parent;
699
730
  }
700
- }
701
- function getComponentTrace() {
702
- let currentVNode = stack[stack.length - 1];
703
- if (!currentVNode) {
704
- return [];
731
+ if (slotScopeId) {
732
+ openTag += ` ${slotScopeId}`;
705
733
  }
706
- // we can't just use the stack because it will be incomplete during updates
707
- // that did not start from the root. Re-construct the parent chain using
708
- // instance parent pointers.
709
- const normalizedStack = [];
710
- while (currentVNode) {
711
- const last = normalizedStack[0];
712
- if (last && last.vnode === currentVNode) {
713
- last.recurseCount++;
734
+ push(openTag + `>`);
735
+ if (!isVoidTag(tag)) {
736
+ let hasChildrenOverride = false;
737
+ if (props) {
738
+ if (props.innerHTML) {
739
+ hasChildrenOverride = true;
740
+ push(props.innerHTML);
741
+ }
742
+ else if (props.textContent) {
743
+ hasChildrenOverride = true;
744
+ push(escapeHtml(props.textContent));
745
+ }
746
+ else if (tag === 'textarea' && props.value) {
747
+ hasChildrenOverride = true;
748
+ push(escapeHtml(props.value));
749
+ }
714
750
  }
715
- else {
716
- normalizedStack.push({
717
- vnode: currentVNode,
718
- recurseCount: 0
719
- });
751
+ if (!hasChildrenOverride) {
752
+ if (shapeFlag & 8 /* ShapeFlags.TEXT_CHILDREN */) {
753
+ push(escapeHtml(children));
754
+ }
755
+ else if (shapeFlag & 16 /* ShapeFlags.ARRAY_CHILDREN */) {
756
+ renderVNodeChildren(push, children, parentComponent, slotScopeId);
757
+ }
720
758
  }
721
- const parentInstance = currentVNode.component && currentVNode.component.parent;
722
- currentVNode = parentInstance && parentInstance.vnode;
759
+ push(`</${tag}>`);
723
760
  }
724
- return normalizedStack;
725
761
  }
726
- /* istanbul ignore next */
727
- function formatTrace(trace) {
728
- const logs = [];
729
- trace.forEach((entry, i) => {
730
- logs.push(...(i === 0 ? [] : [`\n`]), ...formatTraceEntry(entry));
731
- });
732
- return logs;
733
- }
734
- function formatTraceEntry({ vnode, recurseCount }) {
735
- const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;
736
- const isRoot = vnode.component ? vnode.component.parent == null : false;
737
- const open = ` at <${formatComponentName(vnode.component, vnode.type, isRoot)}`;
738
- const close = `>` + postfix;
739
- return vnode.props
740
- ? [open, ...formatProps(vnode.props), close]
741
- : [open + close];
742
- }
743
- /* istanbul ignore next */
744
- function formatProps(props) {
745
- const res = [];
746
- const keys = Object.keys(props);
747
- keys.slice(0, 3).forEach(key => {
748
- res.push(...formatProp(key, props[key]));
749
- });
750
- if (keys.length > 3) {
751
- res.push(` ...`);
762
+ function applySSRDirectives(vnode, rawProps, dirs) {
763
+ const toMerge = [];
764
+ for (let i = 0; i < dirs.length; i++) {
765
+ const binding = dirs[i];
766
+ const { dir: { getSSRProps } } = binding;
767
+ if (getSSRProps) {
768
+ const props = getSSRProps(binding, vnode);
769
+ if (props)
770
+ toMerge.push(props);
771
+ }
752
772
  }
753
- return res;
773
+ return mergeProps(rawProps || {}, ...toMerge);
754
774
  }
755
- /* istanbul ignore next */
756
- function formatProp(key, value, raw) {
757
- if (isString(value)) {
758
- value = JSON.stringify(value);
759
- return raw ? value : [`${key}=${value}`];
760
- }
761
- else if (typeof value === 'number' ||
762
- typeof value === 'boolean' ||
763
- value == null) {
764
- return raw ? value : [`${key}=${value}`];
765
- }
766
- else if (isRef(value)) {
767
- value = formatProp(key, toRaw(value.value), true);
768
- return raw ? value : [`${key}=Ref<`, value, `>`];
769
- }
770
- else if (isFunction(value)) {
771
- return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];
775
+ function renderTeleportVNode(push, vnode, parentComponent, slotScopeId) {
776
+ const target = vnode.props && vnode.props.to;
777
+ const disabled = vnode.props && vnode.props.disabled;
778
+ if (!target) {
779
+ if (!disabled) {
780
+ warn$1(`[@vue/server-renderer] Teleport is missing target prop.`);
781
+ }
782
+ return [];
772
783
  }
773
- else {
774
- value = toRaw(value);
775
- return raw ? value : [`${key}=`, value];
784
+ if (!isString(target)) {
785
+ warn$1(`[@vue/server-renderer] Teleport target must be a query selector string.`);
786
+ return [];
776
787
  }
788
+ ssrRenderTeleport(push, push => {
789
+ renderVNodeChildren(push, vnode.children, parentComponent, slotScopeId);
790
+ }, target, disabled || disabled === '', parentComponent);
777
791
  }
778
792
 
779
- const ErrorTypeStrings = {
780
- ["sp" /* LifecycleHooks.SERVER_PREFETCH */]: 'serverPrefetch hook',
781
- ["bc" /* LifecycleHooks.BEFORE_CREATE */]: 'beforeCreate hook',
782
- ["c" /* LifecycleHooks.CREATED */]: 'created hook',
783
- ["bm" /* LifecycleHooks.BEFORE_MOUNT */]: 'beforeMount hook',
784
- ["m" /* LifecycleHooks.MOUNTED */]: 'mounted hook',
785
- ["bu" /* LifecycleHooks.BEFORE_UPDATE */]: 'beforeUpdate hook',
786
- ["u" /* LifecycleHooks.UPDATED */]: 'updated',
787
- ["bum" /* LifecycleHooks.BEFORE_UNMOUNT */]: 'beforeUnmount hook',
788
- ["um" /* LifecycleHooks.UNMOUNTED */]: 'unmounted hook',
789
- ["a" /* LifecycleHooks.ACTIVATED */]: 'activated hook',
790
- ["da" /* LifecycleHooks.DEACTIVATED */]: 'deactivated hook',
791
- ["ec" /* LifecycleHooks.ERROR_CAPTURED */]: 'errorCaptured hook',
792
- ["rtc" /* LifecycleHooks.RENDER_TRACKED */]: 'renderTracked hook',
793
- ["rtg" /* LifecycleHooks.RENDER_TRIGGERED */]: 'renderTriggered hook',
794
- [0 /* ErrorCodes.SETUP_FUNCTION */]: 'setup function',
795
- [1 /* ErrorCodes.RENDER_FUNCTION */]: 'render function',
796
- [2 /* ErrorCodes.WATCH_GETTER */]: 'watcher getter',
797
- [3 /* ErrorCodes.WATCH_CALLBACK */]: 'watcher callback',
798
- [4 /* ErrorCodes.WATCH_CLEANUP */]: 'watcher cleanup function',
799
- [5 /* ErrorCodes.NATIVE_EVENT_HANDLER */]: 'native event handler',
800
- [6 /* ErrorCodes.COMPONENT_EVENT_HANDLER */]: 'component event handler',
801
- [7 /* ErrorCodes.VNODE_HOOK */]: 'vnode hook',
802
- [8 /* ErrorCodes.DIRECTIVE_HOOK */]: 'directive hook',
803
- [9 /* ErrorCodes.TRANSITION_HOOK */]: 'transition hook',
804
- [10 /* ErrorCodes.APP_ERROR_HANDLER */]: 'app errorHandler',
805
- [11 /* ErrorCodes.APP_WARN_HANDLER */]: 'app warnHandler',
806
- [12 /* ErrorCodes.FUNCTION_REF */]: 'ref function',
807
- [13 /* ErrorCodes.ASYNC_COMPONENT_LOADER */]: 'async component loader',
808
- [14 /* ErrorCodes.SCHEDULER */]: 'scheduler flush. This is likely a Vue internals bug. ' +
809
- 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core'
810
- };
811
- function callWithErrorHandling(fn, instance, type, args) {
812
- let res;
813
- try {
814
- res = args ? fn(...args) : fn();
815
- }
816
- catch (err) {
817
- handleError(err, instance, type);
818
- }
819
- return res;
820
- }
821
- function handleError(err, instance, type, throwInDev = true) {
822
- const contextVNode = instance ? instance.vnode : null;
823
- if (instance) {
824
- let cur = instance.parent;
825
- // the exposed instance is the render proxy to keep it consistent with 2.x
826
- const exposedInstance = instance.proxy;
827
- // in production the hook receives only the error code
828
- const errorInfo = (process.env.NODE_ENV !== 'production') ? ErrorTypeStrings[type] : type;
829
- while (cur) {
830
- const errorCapturedHooks = cur.ec;
831
- if (errorCapturedHooks) {
832
- for (let i = 0; i < errorCapturedHooks.length; i++) {
833
- if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) {
834
- return;
835
- }
836
- }
793
+ const { isVNode: isVNode$1 } = ssrUtils;
794
+ async function unrollBuffer$1(buffer) {
795
+ if (buffer.hasAsync) {
796
+ let ret = '';
797
+ for (let i = 0; i < buffer.length; i++) {
798
+ let item = buffer[i];
799
+ if (isPromise(item)) {
800
+ item = await item;
801
+ }
802
+ if (isString(item)) {
803
+ ret += item;
804
+ }
805
+ else {
806
+ ret += await unrollBuffer$1(item);
837
807
  }
838
- cur = cur.parent;
839
- }
840
- // app-level handling
841
- const appErrorHandler = instance.appContext.config.errorHandler;
842
- if (appErrorHandler) {
843
- callWithErrorHandling(appErrorHandler, null, 10 /* ErrorCodes.APP_ERROR_HANDLER */, [err, exposedInstance, errorInfo]);
844
- return;
845
808
  }
809
+ return ret;
810
+ }
811
+ else {
812
+ // sync buffer can be more efficiently unrolled without unnecessary await
813
+ // ticks
814
+ return unrollBufferSync$1(buffer);
846
815
  }
847
- logError(err, type, contextVNode, throwInDev);
848
816
  }
849
- function logError(err, type, contextVNode, throwInDev = true) {
850
- if ((process.env.NODE_ENV !== 'production')) {
851
- const info = ErrorTypeStrings[type];
852
- if (contextVNode) {
853
- pushWarningContext(contextVNode);
854
- }
855
- warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`);
856
- if (contextVNode) {
857
- popWarningContext();
858
- }
859
- // crash in dev by default so it's more noticeable
860
- if (throwInDev) {
861
- throw err;
817
+ function unrollBufferSync$1(buffer) {
818
+ let ret = '';
819
+ for (let i = 0; i < buffer.length; i++) {
820
+ let item = buffer[i];
821
+ if (isString(item)) {
822
+ ret += item;
862
823
  }
863
824
  else {
864
- console.error(err);
825
+ // since this is a sync buffer, child buffers are never promises
826
+ ret += unrollBufferSync$1(item);
865
827
  }
866
828
  }
867
- else {
868
- // recover in prod to reduce the impact on end-user
869
- console.error(err);
870
- }
871
- }
872
-
873
- const classifyRE = /(?:^|[-_])(\w)/g;
874
- const classify = (str) => str.replace(classifyRE, c => c.toUpperCase()).replace(/[-_]/g, '');
875
- function getComponentName(Component, includeInferred = true) {
876
- return isFunction(Component)
877
- ? Component.displayName || Component.name
878
- : Component.name || (includeInferred && Component.__name);
829
+ return ret;
879
830
  }
880
- /* istanbul ignore next */
881
- function formatComponentName(instance, Component, isRoot = false) {
882
- let name = getComponentName(Component);
883
- if (!name && Component.__file) {
884
- const match = Component.__file.match(/([^/\\]+)\.\w+$/);
885
- if (match) {
886
- name = match[1];
831
+ async function renderToString(input, context = {}) {
832
+ if (isVNode$1(input)) {
833
+ // raw vnode, wrap with app (for context)
834
+ return renderToString(createApp({ render: () => input }), context);
835
+ }
836
+ // rendering an app
837
+ const vnode = createVNode(input._component, input._props);
838
+ vnode.appContext = input._context;
839
+ // provide the ssr context to the tree
840
+ input.provide(ssrContextKey, context);
841
+ const buffer = await renderComponentVNode(vnode);
842
+ const result = await unrollBuffer$1(buffer);
843
+ await resolveTeleports(context);
844
+ if (context.__watcherHandles) {
845
+ for (const unwatch of context.__watcherHandles) {
846
+ unwatch();
887
847
  }
888
848
  }
889
- if (!name && instance && instance.parent) {
890
- // try to infer the name based on reverse resolution
891
- const inferFromRegistry = (registry) => {
892
- for (const key in registry) {
893
- if (registry[key] === Component) {
894
- return key;
895
- }
896
- }
897
- };
898
- name =
899
- inferFromRegistry(instance.components ||
900
- instance.parent.type.components) || inferFromRegistry(instance.appContext.components);
849
+ return result;
850
+ }
851
+ async function resolveTeleports(context) {
852
+ if (context.__teleportBuffers) {
853
+ context.teleports = context.teleports || {};
854
+ for (const key in context.__teleportBuffers) {
855
+ // note: it's OK to await sequentially here because the Promises were
856
+ // created eagerly in parallel.
857
+ context.teleports[key] = await unrollBuffer$1(await Promise.all([context.__teleportBuffers[key]]));
858
+ }
901
859
  }
902
- return name ? classify(name) : isRoot ? `App` : `Anonymous`;
903
860
  }
904
861
 
905
- function ssrRenderList(source, renderItem) {
906
- if (isArray(source) || isString(source)) {
907
- for (let i = 0, l = source.length; i < l; i++) {
908
- renderItem(source[i], i);
862
+ const { isVNode } = ssrUtils;
863
+ async function unrollBuffer(buffer, stream) {
864
+ if (buffer.hasAsync) {
865
+ for (let i = 0; i < buffer.length; i++) {
866
+ let item = buffer[i];
867
+ if (isPromise(item)) {
868
+ item = await item;
869
+ }
870
+ if (isString(item)) {
871
+ stream.push(item);
872
+ }
873
+ else {
874
+ await unrollBuffer(item, stream);
875
+ }
909
876
  }
910
877
  }
911
- else if (typeof source === 'number') {
912
- if ((process.env.NODE_ENV !== 'production') && !Number.isInteger(source)) {
913
- warn(`The v-for range expect an integer value but got ${source}.`);
914
- return;
915
- }
916
- for (let i = 0; i < source; i++) {
917
- renderItem(i + 1, i);
918
- }
878
+ else {
879
+ // sync buffer can be more efficiently unrolled without unnecessary await
880
+ // ticks
881
+ unrollBufferSync(buffer, stream);
919
882
  }
920
- else if (isObject(source)) {
921
- if (source[Symbol.iterator]) {
922
- const arr = Array.from(source);
923
- for (let i = 0, l = arr.length; i < l; i++) {
924
- renderItem(arr[i], i);
925
- }
883
+ }
884
+ function unrollBufferSync(buffer, stream) {
885
+ for (let i = 0; i < buffer.length; i++) {
886
+ let item = buffer[i];
887
+ if (isString(item)) {
888
+ stream.push(item);
926
889
  }
927
890
  else {
928
- const keys = Object.keys(source);
929
- for (let i = 0, l = keys.length; i < l; i++) {
930
- const key = keys[i];
931
- renderItem(source[key], key, i);
932
- }
891
+ // since this is a sync buffer, child buffers are never promises
892
+ unrollBufferSync(item, stream);
933
893
  }
934
894
  }
935
895
  }
936
-
937
- async function ssrRenderSuspense(push, { default: renderContent }) {
938
- if (renderContent) {
939
- renderContent();
940
- }
941
- else {
942
- push(`<!---->`);
896
+ function renderToSimpleStream(input, context, stream) {
897
+ if (isVNode(input)) {
898
+ // raw vnode, wrap with app (for context)
899
+ return renderToSimpleStream(createApp({ render: () => input }), context, stream);
943
900
  }
901
+ // rendering an app
902
+ const vnode = createVNode(input._component, input._props);
903
+ vnode.appContext = input._context;
904
+ // provide the ssr context to the tree
905
+ input.provide(ssrContextKey, context);
906
+ Promise.resolve(renderComponentVNode(vnode))
907
+ .then(buffer => unrollBuffer(buffer, stream))
908
+ .then(() => resolveTeleports(context))
909
+ .then(() => {
910
+ if (context.__watcherHandles) {
911
+ for (const unwatch of context.__watcherHandles) {
912
+ unwatch();
913
+ }
914
+ }
915
+ })
916
+ .then(() => stream.push(null))
917
+ .catch(error => {
918
+ stream.destroy(error);
919
+ });
920
+ return stream;
944
921
  }
945
-
946
- function ssrGetDirectiveProps(instance, dir, value, arg, modifiers = {}) {
947
- if (typeof dir !== 'function' && dir.getSSRProps) {
948
- return (dir.getSSRProps({
949
- dir,
950
- instance,
951
- value,
952
- oldValue: undefined,
953
- arg,
954
- modifiers
955
- }, null) || {});
922
+ /**
923
+ * @deprecated
924
+ */
925
+ function renderToStream(input, context = {}) {
926
+ console.warn(`[@vue/server-renderer] renderToStream is deprecated - use renderToNodeStream instead.`);
927
+ return renderToNodeStream(input, context);
928
+ }
929
+ function renderToNodeStream(input, context = {}) {
930
+ {
931
+ throw new Error(`ESM build of renderToStream() does not support renderToNodeStream(). ` +
932
+ `Use pipeToNodeWritable() with an existing Node.js Writable stream ` +
933
+ `instance instead.`);
956
934
  }
957
- return {};
958
935
  }
959
-
960
- const ssrLooseEqual = looseEqual;
961
- function ssrLooseContain(arr, value) {
962
- return looseIndexOf(arr, value) > -1;
936
+ function pipeToNodeWritable(input, context = {}, writable) {
937
+ renderToSimpleStream(input, context, {
938
+ push(content) {
939
+ if (content != null) {
940
+ writable.write(content);
941
+ }
942
+ else {
943
+ writable.end();
944
+ }
945
+ },
946
+ destroy(err) {
947
+ writable.destroy(err);
948
+ }
949
+ });
963
950
  }
964
- // for <input :type="type" v-model="model" value="value">
965
- function ssrRenderDynamicModel(type, model, value) {
966
- switch (type) {
967
- case 'radio':
968
- return looseEqual(model, value) ? ' checked' : '';
969
- case 'checkbox':
970
- return (isArray(model) ? ssrLooseContain(model, value) : model)
971
- ? ' checked'
972
- : '';
973
- default:
974
- // text types
975
- return ssrRenderAttr('value', model);
951
+ function renderToWebStream(input, context = {}) {
952
+ if (typeof ReadableStream !== 'function') {
953
+ throw new Error(`ReadableStream constructor is not available in the global scope. ` +
954
+ `If the target environment does support web streams, consider using ` +
955
+ `pipeToWebWritable() with an existing WritableStream instance instead.`);
976
956
  }
957
+ const encoder = new TextEncoder();
958
+ let cancelled = false;
959
+ return new ReadableStream({
960
+ start(controller) {
961
+ renderToSimpleStream(input, context, {
962
+ push(content) {
963
+ if (cancelled)
964
+ return;
965
+ if (content != null) {
966
+ controller.enqueue(encoder.encode(content));
967
+ }
968
+ else {
969
+ controller.close();
970
+ }
971
+ },
972
+ destroy(err) {
973
+ controller.error(err);
974
+ }
975
+ });
976
+ },
977
+ cancel() {
978
+ cancelled = true;
979
+ }
980
+ });
977
981
  }
978
- // for <input v-bind="obj" v-model="model">
979
- function ssrGetDynamicModelProps(existingProps = {}, model) {
980
- const { type, value } = existingProps;
981
- switch (type) {
982
- case 'radio':
983
- return looseEqual(model, value) ? { checked: true } : null;
984
- case 'checkbox':
985
- return (isArray(model) ? ssrLooseContain(model, value) : model)
986
- ? { checked: true }
987
- : null;
988
- default:
989
- // text types
990
- return { value: model };
982
+ function pipeToWebWritable(input, context = {}, writable) {
983
+ const writer = writable.getWriter();
984
+ const encoder = new TextEncoder();
985
+ // #4287 CloudFlare workers do not implement `ready` property
986
+ let hasReady = false;
987
+ try {
988
+ hasReady = isPromise(writer.ready);
991
989
  }
990
+ catch (e) { }
991
+ renderToSimpleStream(input, context, {
992
+ async push(content) {
993
+ if (hasReady) {
994
+ await writer.ready;
995
+ }
996
+ if (content != null) {
997
+ return writer.write(encoder.encode(content));
998
+ }
999
+ else {
1000
+ return writer.close();
1001
+ }
1002
+ },
1003
+ destroy(err) {
1004
+ // TODO better error handling?
1005
+ console.log(err);
1006
+ writer.close();
1007
+ }
1008
+ });
992
1009
  }
993
1010
 
994
1011
  initDirectivesForSSR();