diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index b62a27a7557..cc3cbd480a5 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -623,7 +623,7 @@ describe('compiler: element transform', () => { test(`props merging: style`, () => { const { node } = parseWithElementTransform( - `
`, + `
`, { nodeTransforms: [transformStyle, transformElement], directiveTransforms: { @@ -646,7 +646,7 @@ describe('compiler: element transform', () => { elements: [ { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `{"color":"green"}`, isStatic: false }, { diff --git a/packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap b/packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap index b429387fd6d..40e14d51f18 100644 --- a/packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap +++ b/packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap @@ -2,9 +2,6 @@ exports[`compile should contain standard transforms 1`] = ` "const _Vue = Vue -const { createVNode: _createVNode } = _Vue - -const _hoisted_1 = {} return function render(_ctx, _cache) { with (_ctx) { @@ -14,7 +11,7 @@ return function render(_ctx, _cache) { _createVNode(\\"div\\", { textContent: text }, null, 8 /* PROPS */, [\\"textContent\\"]), _createVNode(\\"div\\", { innerHTML: html }, null, 8 /* PROPS */, [\\"innerHTML\\"]), _createVNode(\\"div\\", null, \\"test\\"), - _createVNode(\\"div\\", { style: _hoisted_1 }, \\"red\\"), + _createVNode(\\"div\\", { style: {\\"color\\":\\"red\\"} }, \\"red\\"), _createVNode(\\"div\\", { style: {color: 'green'} }, null, 4 /* STYLE */) ], 64 /* STABLE_FRAGMENT */)) } diff --git a/packages/compiler-dom/__tests__/index.spec.ts b/packages/compiler-dom/__tests__/index.spec.ts index d40bf36fe2c..db43ce905cf 100644 --- a/packages/compiler-dom/__tests__/index.spec.ts +++ b/packages/compiler-dom/__tests__/index.spec.ts @@ -5,7 +5,7 @@ describe('compile', () => { const { code } = compile(`
test
-
red
+
red
`) expect(code).toMatchSnapshot() diff --git a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts index d1095d3f425..cc8b53f245d 100644 --- a/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts @@ -77,8 +77,8 @@ describe('stringify static html', () => { test('serliazing constant bindings', () => { const { ast } = compileWithStringify( - `
${repeat( - `{{ 1 }} + {{ false }}`, + `
${repeat( + `{{ 1 }} + {{ false }}`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) @@ -89,8 +89,8 @@ describe('stringify static html', () => { callee: CREATE_STATIC, arguments: [ JSON.stringify( - `
${repeat( - `1 + false`, + `
${repeat( + `1 + false`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT )}
` ) diff --git a/packages/compiler-dom/__tests__/transforms/transformStyle.spec.ts b/packages/compiler-dom/__tests__/transforms/transformStyle.spec.ts index 89121c10a26..6eee9f8ba38 100644 --- a/packages/compiler-dom/__tests__/transforms/transformStyle.spec.ts +++ b/packages/compiler-dom/__tests__/transforms/transformStyle.spec.ts @@ -26,17 +26,8 @@ function transformWithStyleTransform( } describe('compiler: style transform', () => { - test('should transform into directive node and hoist value', () => { - const { root, node } = transformWithStyleTransform( - `
` - ) - expect(root.hoists).toMatchObject([ - { - type: NodeTypes.SIMPLE_EXPRESSION, - content: `{"color":"red"}`, - isStatic: false - } - ]) + test('should transform into directive node', () => { + const { node } = transformWithStyleTransform(`
`) expect(node.props[0]).toMatchObject({ type: NodeTypes.DIRECTIVE, name: `bind`, @@ -47,7 +38,7 @@ describe('compiler: style transform', () => { }, exp: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `{"color":"red"}`, isStatic: false } }) @@ -71,7 +62,7 @@ describe('compiler: style transform', () => { }, value: { type: NodeTypes.SIMPLE_EXPRESSION, - content: `_hoisted_1`, + content: `{"color":"red"}`, isStatic: false } } diff --git a/packages/compiler-dom/src/transforms/stringifyStatic.ts b/packages/compiler-dom/src/transforms/stringifyStatic.ts index a2efa56eec0..a4aa7745f8e 100644 --- a/packages/compiler-dom/src/transforms/stringifyStatic.ts +++ b/packages/compiler-dom/src/transforms/stringifyStatic.ts @@ -14,7 +14,10 @@ import { isString, isSymbol, escapeHtml, - toDisplayString + toDisplayString, + normalizeClass, + normalizeStyle, + stringifyStyle } from '@vue/shared' // Turn eligible hoisted static trees into stringied static nodes, e.g. @@ -84,8 +87,15 @@ function stringifyElement( } } else if (p.type === NodeTypes.DIRECTIVE && p.name === 'bind') { // constant v-bind, e.g. :foo="1" + let evaluated = evaluateConstant(p.exp as SimpleExpressionNode) + const arg = p.arg && (p.arg as SimpleExpressionNode).content + if (arg === 'class') { + evaluated = normalizeClass(evaluated) + } else if (arg === 'style') { + evaluated = stringifyStyle(normalizeStyle(evaluated)) + } res += ` ${(p.arg as SimpleExpressionNode).content}="${escapeHtml( - evaluateConstant(p.exp as ExpressionNode) + evaluated )}"` } } @@ -151,7 +161,7 @@ function evaluateConstant(exp: ExpressionNode): string { if (c.type === NodeTypes.TEXT) { res += c.content } else if (c.type === NodeTypes.INTERPOLATION) { - res += evaluateConstant(c.content) + res += toDisplayString(evaluateConstant(c.content)) } else { res += evaluateConstant(c) } diff --git a/packages/compiler-dom/src/transforms/transformStyle.ts b/packages/compiler-dom/src/transforms/transformStyle.ts index 3c232db4357..765fab778e9 100644 --- a/packages/compiler-dom/src/transforms/transformStyle.ts +++ b/packages/compiler-dom/src/transforms/transformStyle.ts @@ -17,12 +17,11 @@ export const transformStyle: NodeTransform = (node, context) => { node.props.forEach((p, i) => { if (p.type === NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) { // replace p with an expression node - const exp = context.hoist(parseInlineCSS(p.value.content, p.loc)) node.props[i] = { type: NodeTypes.DIRECTIVE, name: `bind`, arg: createSimpleExpression(`style`, true, p.loc), - exp, + exp: parseInlineCSS(p.value.content, p.loc), modifiers: [], loc: p.loc } @@ -45,5 +44,5 @@ function parseInlineCSS( tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim()) } }) - return createSimpleExpression(JSON.stringify(res), false, loc) + return createSimpleExpression(JSON.stringify(res), false, loc, true) } diff --git a/packages/compiler-ssr/__tests__/ssrElement.spec.ts b/packages/compiler-ssr/__tests__/ssrElement.spec.ts index c99d13c543a..c81d6ccb10e 100644 --- a/packages/compiler-ssr/__tests__/ssrElement.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrElement.spec.ts @@ -101,7 +101,7 @@ describe('ssr: element', () => { expect( getCompiledString(`
`) ).toMatchInlineSnapshot( - `"\`
\`"` + `"\`
\`"` ) }) @@ -184,7 +184,7 @@ describe('ssr: element', () => { ) ).toMatchInlineSnapshot(` "\`
\`" `) }) diff --git a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts index 2738bc22617..8a99a52c7d3 100644 --- a/packages/compiler-ssr/__tests__/ssrVShow.spec.ts +++ b/packages/compiler-ssr/__tests__/ssrVShow.spec.ts @@ -16,11 +16,9 @@ describe('ssr: v-show', () => { .toMatchInlineSnapshot(` "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") - const _hoisted_1 = {\\"color\\":\\"red\\"} - return function ssrRender(_ctx, _push, _parent) { _push(\`
\`) }" @@ -48,11 +46,9 @@ describe('ssr: v-show', () => { ).toMatchInlineSnapshot(` "const { ssrRenderStyle: _ssrRenderStyle } = require(\\"@vue/server-renderer\\") - const _hoisted_1 = {\\"color\\":\\"red\\"} - return function ssrRender(_ctx, _push, _parent) { _push(\`
\`) @@ -69,12 +65,10 @@ describe('ssr: v-show', () => { "const { mergeProps: _mergeProps } = require(\\"vue\\") const { ssrRenderAttrs: _ssrRenderAttrs } = require(\\"@vue/server-renderer\\") - const _hoisted_1 = {\\"color\\":\\"red\\"} - return function ssrRender(_ctx, _push, _parent) { _push(\` | undefined +): string { + let ret = '' + if (!styles) { + return ret + } + for (const key in styles) { + const value = styles[key] + const normalizedKey = key.indexOf(`--`) === 0 ? key : hyphenate(key) + if ( + isString(value) || + (typeof value === 'number' && isNoUnitNumericStyleProp(normalizedKey)) + ) { + // only render valid values + ret += `${normalizedKey}:${value};` + } + } + return ret +} + export function normalizeClass(value: unknown): string { let res = '' if (isString(value)) {