@vue/compiler-ssr
Advanced tools
Comparing version
@@ -6,102 +6,4 @@ 'use strict'; | ||
var compilerDom = require('@vue/compiler-dom'); | ||
var shared = require('@vue/shared'); | ||
// Make a map and return a function for checking if a key | ||
// is in that map. | ||
// | ||
// IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/ | ||
// So that rollup can tree-shake them if necessary. | ||
function makeMap(str, expectsLowerCase) { | ||
const map = Object.create(null); | ||
const list = str.split(','); | ||
for (let i = 0; i < list.length; i++) { | ||
map[list[i]] = true; | ||
} | ||
return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; | ||
} | ||
// On the client we only need to offer special cases for boolean attributes that | ||
// have different names from their corresponding dom properties: | ||
// - itemscope -> N/A | ||
// - allowfullscreen -> allowFullscreen | ||
// - formnovalidate -> formNoValidate | ||
// - ismap -> isMap | ||
// - nomodule -> noModule | ||
// - novalidate -> noValidate | ||
// - readonly -> readOnly | ||
const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; | ||
// The full list is needed during SSR to produce the correct initial markup. | ||
const isBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs + | ||
`,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` + | ||
`loop,open,required,reversed,scoped,seamless,` + | ||
`checked,muted,multiple,selected`); | ||
const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/; | ||
const attrValidationCache = {}; | ||
function isSSRSafeAttrName(name) { | ||
if (attrValidationCache.hasOwnProperty(name)) { | ||
return attrValidationCache[name]; | ||
} | ||
const isUnsafe = unsafeAttrCharRE.test(name); | ||
if (isUnsafe) { | ||
console.error(`unsafe attribute name: ${name}`); | ||
} | ||
return (attrValidationCache[name] = !isUnsafe); | ||
} | ||
const propsToAttrMap = { | ||
acceptCharset: 'accept-charset', | ||
className: 'class', | ||
htmlFor: 'for', | ||
httpEquiv: 'http-equiv' | ||
}; | ||
const escapeRE = /["'&<>]/; | ||
function escapeHtml(string) { | ||
const str = '' + string; | ||
const match = escapeRE.exec(str); | ||
if (!match) { | ||
return str; | ||
} | ||
let html = ''; | ||
let escaped; | ||
let index; | ||
let lastIndex = 0; | ||
for (index = match.index; index < str.length; index++) { | ||
switch (str.charCodeAt(index)) { | ||
case 34: // " | ||
escaped = '"'; | ||
break; | ||
case 38: // & | ||
escaped = '&'; | ||
break; | ||
case 39: // ' | ||
escaped = '''; | ||
break; | ||
case 60: // < | ||
escaped = '<'; | ||
break; | ||
case 62: // > | ||
escaped = '>'; | ||
break; | ||
default: | ||
continue; | ||
} | ||
if (lastIndex !== index) { | ||
html += str.substring(lastIndex, index); | ||
} | ||
lastIndex = index + 1; | ||
html += escaped; | ||
} | ||
return lastIndex !== index ? html + str.substring(lastIndex, index) : html; | ||
} | ||
const EMPTY_OBJ = Object.freeze({}) | ||
; | ||
/** | ||
* Always return false. | ||
*/ | ||
const NO = () => false; | ||
const isArray = Array.isArray; | ||
const isString = (val) => typeof val === 'string'; | ||
const isSymbol = (val) => typeof val === 'symbol'; | ||
const isObject = (val) => val !== null && typeof val === 'object'; | ||
const SSR_INTERPOLATE = Symbol(`ssrInterpolate`); | ||
@@ -120,2 +22,3 @@ const SSR_RENDER_COMPONENT = Symbol(`ssrRenderComponent`); | ||
const SSR_GET_DYNAMIC_MODEL_PROPS = Symbol(`ssrGetDynamicModelProps`); | ||
const SSR_RENDER_PORTAL = Symbol(`ssrRenderPortal`); | ||
const ssrHelpers = { | ||
@@ -134,3 +37,4 @@ [SSR_INTERPOLATE]: `ssrInterpolate`, | ||
[SSR_RENDER_DYNAMIC_MODEL]: `ssrRenderDynamicModel`, | ||
[SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps` | ||
[SSR_GET_DYNAMIC_MODEL_PROPS]: `ssrGetDynamicModelProps`, | ||
[SSR_RENDER_PORTAL]: `ssrRenderPortal` | ||
}; | ||
@@ -147,3 +51,3 @@ // Note: these are helpers imported from @vue/server-renderer | ||
const [rootBranch] = node.branches; | ||
const ifStatement = compilerDom.createIfStatement(rootBranch.condition, processIfBranch(rootBranch, context)); | ||
const ifStatement = compilerDom.createIfStatement(rootBranch.condition, processChildrenAsStatement(rootBranch.children, context)); | ||
context.pushStatement(ifStatement); | ||
@@ -153,3 +57,3 @@ let currentIf = ifStatement; | ||
const branch = node.branches[i]; | ||
const branchBlockStatement = processIfBranch(branch, context); | ||
const branchBlockStatement = processChildrenAsStatement(branch.children, context); | ||
if (branch.condition) { | ||
@@ -170,9 +74,2 @@ // else-if | ||
} | ||
function processIfBranch(branch, context) { | ||
const { children } = branch; | ||
const needFragmentWrapper = (children.length !== 1 || children[0].type !== 1 /* ELEMENT */) && | ||
// optimize away nested fragments when the only child is a ForNode | ||
!(children.length === 1 && children[0].type === 11 /* FOR */); | ||
return processChildrenAsStatement(children, context, needFragmentWrapper); | ||
} | ||
@@ -184,7 +81,4 @@ // Plugin for the first transform pass, which simply constructs the AST node | ||
function ssrProcessFor(node, context) { | ||
const needFragmentWrapper = node.children.length !== 1 || node.children[0].type !== 1 /* ELEMENT */; | ||
const renderLoop = compilerDom.createFunctionExpression(compilerDom.createForLoopParams(node.parseResult)); | ||
renderLoop.body = processChildrenAsStatement(node.children, context, needFragmentWrapper); | ||
// v-for always renders a fragment | ||
context.pushStringPart(`<!---->`); | ||
renderLoop.body = processChildrenAsStatement(node.children, context); | ||
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_LIST), [ | ||
@@ -194,3 +88,2 @@ node.source, | ||
])); | ||
context.pushStringPart(`<!---->`); | ||
} | ||
@@ -223,2 +116,11 @@ | ||
function createSSRCompilerError(code, loc) { | ||
return compilerDom.createCompilerError(code, loc, SSRErrorMessages); | ||
} | ||
const SSRErrorMessages = { | ||
[65 /* X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM */]: `Custom directive is missing corresponding SSR transform and will be ignored.`, | ||
[66 /* X_SSR_UNSAFE_ATTR_NAME */]: `Unsafe attribute name for SSR.`, | ||
[67 /* X_SSR_NO_PORTAL_TARGET */]: `No target prop on portal element.` | ||
}; | ||
// We need to construct the slot functions in the 1st pass to ensure proper | ||
@@ -236,3 +138,3 @@ // scope tracking, but the children of each slot cannot be processed until | ||
const component = compilerDom.resolveComponentType(node, context, true /* ssr */); | ||
if (isSymbol(component)) { | ||
if (shared.isSymbol(component)) { | ||
componentTypeMap.set(node, component); | ||
@@ -250,2 +152,5 @@ return; // built-in component: fallthrough | ||
return function ssrPostTransformComponent() { | ||
// Using the cloned node, build the normal VNode-based branches (for | ||
// fallback in case the child is render-fn based). Store them in an array | ||
// for later use. | ||
compilerDom.buildSlots(clonedNode, context, (props, children) => { | ||
@@ -270,5 +175,3 @@ vnodeBranches.push(createVNodeSlotBranch(props, children, context)); | ||
children, | ||
// build the children using normal vnode-based transforms | ||
// TODO fixme: `children` here has already been mutated at this point | ||
// so the sub-transform runs into errors :/ | ||
// also collect the corresponding vnode branch built earlier | ||
vnodeBranch: vnodeBranches[wipEntries.length] | ||
@@ -290,7 +193,5 @@ }); | ||
if (component === compilerDom.PORTAL) { | ||
// TODO | ||
return; | ||
return ssrProcessPortal(node, context); | ||
} | ||
const needFragmentWrapper = component === compilerDom.SUSPENSE || component === compilerDom.TRANSITION_GROUP; | ||
processChildren(node.children, context, needFragmentWrapper); | ||
processChildren(node.children, context); | ||
} | ||
@@ -306,3 +207,3 @@ else { | ||
// is called by `_ssrRenderSlot`. | ||
fn.body = compilerDom.createIfStatement(compilerDom.createSimpleExpression(`_push`, false), processChildrenAsStatement(children, context, false, true /* withSlotScopeId */), vnodeBranch); | ||
fn.body = compilerDom.createIfStatement(compilerDom.createSimpleExpression(`_push`, false), processChildrenAsStatement(children, context, true /* withSlotScopeId */), vnodeBranch); | ||
} | ||
@@ -312,2 +213,30 @@ context.pushStatement(compilerDom.createCallExpression(`_push`, [node.ssrCodegenNode])); | ||
} | ||
function ssrProcessPortal(node, context) { | ||
const targetProp = compilerDom.findProp(node, 'target'); | ||
if (!targetProp) { | ||
context.onError(createSSRCompilerError(67 /* X_SSR_NO_PORTAL_TARGET */, node.loc)); | ||
return; | ||
} | ||
let target; | ||
if (targetProp.type === 6 /* ATTRIBUTE */ && targetProp.value) { | ||
target = compilerDom.createSimpleExpression(targetProp.value.content, true); | ||
} | ||
else if (targetProp.type === 7 /* DIRECTIVE */ && targetProp.exp) { | ||
target = targetProp.exp; | ||
} | ||
else { | ||
context.onError(createSSRCompilerError(67 /* X_SSR_NO_PORTAL_TARGET */, targetProp.loc)); | ||
return; | ||
} | ||
const contentRenderFn = compilerDom.createFunctionExpression([`_push`], undefined, // Body is added later | ||
true, // newline | ||
false, // isSlot | ||
node.loc); | ||
contentRenderFn.body = processChildrenAsStatement(node.children, context); | ||
context.pushStatement(compilerDom.createCallExpression(context.helper(SSR_RENDER_PORTAL), [ | ||
contentRenderFn, | ||
target, | ||
`_parent` | ||
])); | ||
} | ||
const rawOptionsMap = new WeakMap(); | ||
@@ -364,2 +293,5 @@ const [baseNodeTransforms, baseDirectiveTransforms] = compilerDom.getBaseTransformPreset(true); | ||
const childContext = compilerDom.createTransformContext(childRoot, options); | ||
// this sub transform is for vnode fallback branch so it should be handled | ||
// like normal render functions | ||
childContext.ssr = false; | ||
// inherit parent scope analysis state | ||
@@ -377,6 +309,6 @@ childContext.scopes = { ...parentContext.scopes }; | ||
function clone(v) { | ||
if (isArray(v)) { | ||
if (shared.isArray(v)) { | ||
return v.map(clone); | ||
} | ||
else if (isObject(v)) { | ||
else if (shared.isObject(v)) { | ||
const res = {}; | ||
@@ -393,10 +325,2 @@ for (const key in v) { | ||
function createSSRCompilerError(code, loc) { | ||
return compilerDom.createCompilerError(code, loc, SSRErrorMessages); | ||
} | ||
const SSRErrorMessages = { | ||
[65 /* X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM */]: `Custom directive is missing corresponding SSR transform and will be ignored.`, | ||
[66 /* X_SSR_UNSAFE_ATTR_NAME */]: `Unsafe attribute name for SSR.` | ||
}; | ||
// for directives with children overwrite (e.g. v-html & v-text), we need to | ||
@@ -513,7 +437,7 @@ // store the raw children so that they can be added in the 2nd pass. | ||
? attrName // preserve raw name on custom elements | ||
: propsToAttrMap[attrName] || attrName.toLowerCase(); | ||
if (isBooleanAttr(attrName)) { | ||
: shared.propsToAttrMap[attrName] || attrName.toLowerCase(); | ||
if (shared.isBooleanAttr(attrName)) { | ||
openTag.push(compilerDom.createConditionalExpression(value, compilerDom.createSimpleExpression(' ' + attrName, true), compilerDom.createSimpleExpression('', true), false /* no newline */)); | ||
} | ||
else if (isSSRSafeAttrName(attrName)) { | ||
else if (shared.isSSRSafeAttrName(attrName)) { | ||
openTag.push(compilerDom.createCallExpression(context.helper(SSR_RENDER_ATTR), [ | ||
@@ -542,3 +466,3 @@ key, | ||
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) { | ||
rawChildrenMap.set(node, escapeHtml(prop.value.content)); | ||
rawChildrenMap.set(node, shared.escapeHtml(prop.value.content)); | ||
} | ||
@@ -551,3 +475,3 @@ else if (!hasDynamicVBind) { | ||
openTag.push(` ${prop.name}` + | ||
(prop.value ? `="${escapeHtml(prop.value.content)}"` : ``)); | ||
(prop.value ? `="${shared.escapeHtml(prop.value.content)}"` : ``)); | ||
} | ||
@@ -592,3 +516,3 @@ } | ||
function ssrProcessElement(node, context) { | ||
const isVoidTag = context.options.isVoidTag || NO; | ||
const isVoidTag = context.options.isVoidTag || shared.NO; | ||
const elementsToAdd = node.ssrCodegenNode.elements; | ||
@@ -624,4 +548,3 @@ for (let j = 0; j < elementsToAdd.length; j++) { | ||
const context = createSSRTransformContext(ast, options); | ||
const isFragment = ast.children.length > 1 && ast.children.some(c => !compilerDom.isText(c)); | ||
processChildren(ast.children, context, isFragment); | ||
processChildren(ast.children, context); | ||
ast.codegenNode = compilerDom.createBlockStatement(context.body); | ||
@@ -645,2 +568,6 @@ // Finalize helpers. | ||
withSlotScopeId, | ||
onError: options.onError || | ||
(e => { | ||
throw e; | ||
}), | ||
helper(name) { | ||
@@ -659,3 +586,3 @@ helpers.add(name); | ||
const lastItem = bufferedElements[bufferedElements.length - 1]; | ||
if (isString(part) && isString(lastItem)) { | ||
if (shared.isString(part) && shared.isString(lastItem)) { | ||
bufferedElements[bufferedElements.length - 1] += part; | ||
@@ -678,6 +605,3 @@ } | ||
} | ||
function processChildren(children, context, asFragment = false) { | ||
if (asFragment) { | ||
context.pushStringPart(`<!---->`); | ||
} | ||
function processChildren(children, context) { | ||
for (let i = 0; i < children.length; i++) { | ||
@@ -697,3 +621,3 @@ const child = children[i]; | ||
else if (child.type === 2 /* TEXT */) { | ||
context.pushStringPart(escapeHtml(child.content)); | ||
context.pushStringPart(shared.escapeHtml(child.content)); | ||
} | ||
@@ -710,9 +634,6 @@ else if (child.type === 5 /* INTERPOLATION */) { | ||
} | ||
if (asFragment) { | ||
context.pushStringPart(`<!---->`); | ||
} | ||
} | ||
function processChildrenAsStatement(children, parentContext, asFragment = false, withSlotScopeId = parentContext.withSlotScopeId) { | ||
function processChildrenAsStatement(children, parentContext, withSlotScopeId = parentContext.withSlotScopeId) { | ||
const childContext = createChildContext(parentContext, withSlotScopeId); | ||
processChildren(children, childContext, asFragment); | ||
processChildren(children, childContext); | ||
return compilerDom.createBlockStatement(childContext.body); | ||
@@ -719,0 +640,0 @@ } |
{ | ||
"name": "@vue/compiler-ssr", | ||
"version": "3.0.0-alpha.7", | ||
"version": "3.0.0-alpha.8", | ||
"description": "@vue/compiler-ssr", | ||
@@ -18,3 +18,3 @@ "main": "dist/compiler-ssr.cjs.js", | ||
"type": "git", | ||
"url": "git+https://github.com/vuejs/vue.git" | ||
"url": "git+https://github.com/vuejs/vue-next.git" | ||
}, | ||
@@ -27,8 +27,9 @@ "keywords": [ | ||
"bugs": { | ||
"url": "https://github.com/vuejs/vue/issues" | ||
"url": "https://github.com/vuejs/vue-next/issues" | ||
}, | ||
"homepage": "https://github.com/vuejs/vue/tree/dev/packages/compiler-ssr#readme", | ||
"homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-ssr#readme", | ||
"dependencies": { | ||
"@vue/compiler-dom": "3.0.0-alpha.7" | ||
"@vue/shared": "3.0.0-alpha.8", | ||
"@vue/compiler-dom": "3.0.0-alpha.8" | ||
} | ||
} |
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
1
-50%36237
-6.65%2
100%755
-9.04%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed