diff --git a/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js b/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js index 1a627542c..f112b4ded 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js @@ -11,6 +11,7 @@ import { } from "dom-expressions/src/constants"; import VoidElements from "../VoidElements"; import { + evaluateAndInline, getTagName, isDynamic, isComponent, @@ -59,6 +60,13 @@ const alwaysClose = [ ]; export function transformElement(path, info) { + path + .get("openingElement") + .get("attributes") + .forEach(attr => { + evaluateAndInline(attr.node.value, attr.get("value")); + }); + let tagName = getTagName(path.node), config = getConfig(path), wrapSVG = info.topLevel && tagName != "svg" && SVGElements.has(tagName), diff --git a/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js b/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js index dff8a1a5a..0b5673d87 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/shared/utils.js @@ -104,7 +104,12 @@ export function isDynamic(path, { checkMember, checkTags, checkCallExpressions = return false; } - if (checkCallExpressions && (t.isCallExpression(expr) || t.isOptionalCallExpression(expr) || t.isTaggedTemplateExpression(expr))) { + if ( + checkCallExpressions && + (t.isCallExpression(expr) || + t.isOptionalCallExpression(expr) || + t.isTaggedTemplateExpression(expr)) + ) { return true; } @@ -442,3 +447,35 @@ const templateEscapes = new Map([ ["\u2028", "\\u2028"], ["\u2029", "\\u2029"] ]); + +export function evaluateAndInline(value, valueNode) { + if (t.isJSXExpressionContainer(value)) { + evaluateAndInline(value.expression, valueNode.get("expression")); + } else if (t.isObjectProperty(value)) { + evaluateAndInline(value.value, valueNode.get("value")); + } else if ( + t.isStringLiteral(value) || + t.isNumericLiteral(value) || + t.isBooleanLiteral(value) || + t.isNullLiteral(value) + ) { + // already native literal + } else if (t.isObjectExpression(value)) { + const properties = value.properties; + const propertiesNode = valueNode.get("properties"); + for (let i = 0; i < properties.length; i++) { + evaluateAndInline(properties[i], propertiesNode[i]); + } + } else { + const r = valueNode.evaluate(); + if (r.confident) { + if (typeof r.value === "string") { + valueNode.replaceWith(t.stringLiteral(r.value)); + } else if (typeof r.value === "number") { + valueNode.replaceWith(t.numericLiteral(r.value)); + } else if (typeof r.value === "boolean") { + valueNode.replaceWith(t.booleanLiteral(r.value)); + } + } + } +} diff --git a/packages/babel-plugin-jsx-dom-expressions/src/ssr/element.js b/packages/babel-plugin-jsx-dom-expressions/src/ssr/element.js index 285d7b099..dd01ab8ee 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/ssr/element.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/ssr/element.js @@ -8,6 +8,7 @@ import { } from "dom-expressions/src/constants"; import VoidElements from "../VoidElements"; import { + evaluateAndInline, getTagName, registerImportMethod, filterChildren, @@ -33,6 +34,13 @@ function appendToTemplate(template, value) { } export function transformElement(path, info) { + path + .get("openingElement") + .get("attributes") + .forEach(attr => { + evaluateAndInline(attr.node.value, attr.get("value")); + }); + const config = getConfig(path); const tagName = getTagName(path.node); if (tagName === "script" || tagName === "style") path.doNotEscape = true; diff --git a/packages/babel-plugin-jsx-dom-expressions/src/universal/element.js b/packages/babel-plugin-jsx-dom-expressions/src/universal/element.js index cff5d84ec..8a1a6772b 100644 --- a/packages/babel-plugin-jsx-dom-expressions/src/universal/element.js +++ b/packages/babel-plugin-jsx-dom-expressions/src/universal/element.js @@ -1,5 +1,6 @@ import * as t from "@babel/types"; import { + evaluateAndInline, getTagName, isDynamic, registerImportMethod, @@ -15,6 +16,13 @@ import { import { transformNode } from "../shared/transform"; export function transformElement(path, info) { + path + .get("openingElement") + .get("attributes") + .forEach(attr => { + evaluateAndInline(attr.node.value, attr.get("value")); + }); + let tagName = getTagName(path.node), results = { id: path.scope.generateUidIdentifier("el$"), @@ -101,9 +109,7 @@ function transformAttributes(path, results) { if (!isConstant && t.isLVal(value.expression)) { const refIdentifier = path.scope.generateUidIdentifier("_ref$"); results.exprs.unshift( - t.variableDeclaration("var", [ - t.variableDeclarator(refIdentifier, value.expression) - ]), + t.variableDeclaration("var", [t.variableDeclarator(refIdentifier, value.expression)]), t.expressionStatement( t.conditionalExpression( t.binaryExpression( @@ -139,9 +145,7 @@ function transformAttributes(path, results) { } else { const refIdentifier = path.scope.generateUidIdentifier("_ref$"); results.exprs.unshift( - t.variableDeclaration("var", [ - t.variableDeclarator(refIdentifier, value.expression) - ]), + t.variableDeclaration("var", [t.variableDeclarator(refIdentifier, value.expression)]), t.expressionStatement( t.logicalExpression( "&&", @@ -252,13 +256,19 @@ function transformChildren(path, results) { t.variableDeclarator( child.id, t.callExpression(createTextNode, [ - t.templateLiteral([t.templateElement({ raw: escapeStringForTemplate(child.template) })], []) + t.templateLiteral( + [t.templateElement({ raw: escapeStringForTemplate(child.template) })], + [] + ) ]) ) ); } else insert = t.callExpression(createTextNode, [ - t.templateLiteral([t.templateElement({ raw: escapeStringForTemplate(child.template) })], []) + t.templateLiteral( + [t.templateElement({ raw: escapeStringForTemplate(child.template) })], + [] + ) ]); } appends.push(t.expressionStatement(t.callExpression(insertNode, [results.id, insert]))); diff --git a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js index b2ece6cbf..a790c50de 100644 --- a/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js +++ b/packages/babel-plugin-jsx-dom-expressions/test/__dom_compatible_fixtures__/attributeExpressions/code.js @@ -275,4 +275,6 @@ const template90 =