diff --git a/packages/babel-plugin-transform-runtime/src/helpers.js b/packages/babel-plugin-transform-runtime/src/helpers.js index d9f90571efca..2a787745051a 100644 --- a/packages/babel-plugin-transform-runtime/src/helpers.js +++ b/packages/babel-plugin-transform-runtime/src/helpers.js @@ -1,4 +1,5 @@ import semver from "semver"; +import { types as t } from "@babel/core"; export function hasMinVersion(minVersion, runtimeVersion) { // If the range is unavailable, we're running the script during Babel's @@ -30,3 +31,16 @@ export function hasMinVersion(minVersion, runtimeVersion) { !semver.intersects(`>=8.0.0`, runtimeVersion) ); } + +// Note: We can't use NodePath#couldBeBaseType because it doesn't support arrays. +// Even if we added support for arrays, this package needs to be compatible with +// ^7.0.0 so we can't rely on it. +export function typeAnnotationToString(node) { + switch (node.type) { + case "GenericTypeAnnotation": + if (t.isIdentifier(node.id, { name: "Array" })) return "array"; + break; + case "StringTypeAnnotation": + return "string"; + } +} diff --git a/packages/babel-plugin-transform-runtime/src/index.js b/packages/babel-plugin-transform-runtime/src/index.js index 09d7a4fc6688..0d1f88571041 100644 --- a/packages/babel-plugin-transform-runtime/src/index.js +++ b/packages/babel-plugin-transform-runtime/src/index.js @@ -6,6 +6,7 @@ import { types as t } from "@babel/core"; import getCoreJS2Definitions from "./runtime-corejs2-definitions"; import getCoreJS3Definitions from "./runtime-corejs3-definitions"; +import { typeAnnotationToString } from "./helpers"; function resolveAbsoluteRuntime(moduleName: string, dirname: string) { try { @@ -112,6 +113,16 @@ export default declare((api, options, dirname) => { ); } + function maybeNeedsPolyfill(path, methods, name) { + if (!methods[name].types) return true; + + const typeAnnotation = path.get("object").getTypeAnnotation(); + const type = typeAnnotationToString(typeAnnotation); + if (!type) return true; + + return methods[name].types.some(name => name === type); + } + if (has(options, "useBuiltIns")) { if (options.useBuiltIns) { throw new Error( @@ -284,7 +295,14 @@ export default declare((api, options, dirname) => { // transform calling instance methods like `something.includes()` if (injectCoreJS3 && !hasStaticMapping(object.name, propertyName)) { - if (hasMapping(InstanceProperties, propertyName)) { + if ( + hasMapping(InstanceProperties, propertyName) && + maybeNeedsPolyfill( + path.get("callee"), + InstanceProperties, + propertyName, + ) + ) { let context1, context2; if (t.isIdentifier(object)) { context1 = object; @@ -381,7 +399,11 @@ export default declare((api, options, dirname) => { !hasStaticMapping(objectName, propertyName) ) { // transform getting of instance methods like `method = something.includes` - if (injectCoreJS3 && hasMapping(InstanceProperties, propertyName)) { + if ( + injectCoreJS3 && + hasMapping(InstanceProperties, propertyName) && + maybeNeedsPolyfill(path, InstanceProperties, propertyName) + ) { path.replaceWith( t.callExpression( this.addDefaultImport( diff --git a/packages/babel-plugin-transform-runtime/src/runtime-corejs3-definitions.js b/packages/babel-plugin-transform-runtime/src/runtime-corejs3-definitions.js index 4a68b0ab0e16..ab76a7eaaef7 100644 --- a/packages/babel-plugin-transform-runtime/src/runtime-corejs3-definitions.js +++ b/packages/babel-plugin-transform-runtime/src/runtime-corejs3-definitions.js @@ -180,12 +180,16 @@ export default () => { }, }, + // NOTE: You can specify the object types whose method needs to be polyfilled. + // e.g. concat: { types: ["array"] } + // See ./helpers.js@typeAnnotationToString for the supported types + InstanceProperties: { at: { stable: false, path: "at" }, bind: { stable: true, path: "bind" }, codePointAt: { stable: true, path: "code-point-at" }, codePoints: { stable: false, path: "code-points" }, - concat: { stable: true, path: "concat" }, + concat: { stable: true, path: "concat", types: ["array"] }, copyWithin: { stable: true, path: "copy-within" }, endsWith: { stable: true, path: "ends-with" }, entries: { stable: true, path: "entries" }, diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/input.js b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/input.js new file mode 100644 index 000000000000..e102e6fd7a2c --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/input.js @@ -0,0 +1 @@ +require(`./locale/${lan}`); \ No newline at end of file diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/options.json b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/options.json new file mode 100644 index 000000000000..1a7c4b5b6328 --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + ["transform-runtime", { "corejs": 3 }], + "transform-template-literals" + ] +} diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/output.js b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/output.js new file mode 100644 index 000000000000..57a591f39640 --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/regression/issue-9753-webpack-require-template-compatibility/output.js @@ -0,0 +1 @@ +require("./locale/".concat(lan)); diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/input.js b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/input.js new file mode 100644 index 000000000000..d1368df1566b --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/input.js @@ -0,0 +1,3 @@ +"".concat(b); +[].concat(b); +a.concat(b); diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/options.json b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/options.json new file mode 100644 index 000000000000..ea8bb9c3aa1c --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["transform-runtime", { "corejs": 3 }]] +} diff --git a/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/output.js b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/output.js new file mode 100644 index 000000000000..fe473d9f3f88 --- /dev/null +++ b/packages/babel-plugin-transform-runtime/test/fixtures/runtime-corejs3/instance-inference-optimization/output.js @@ -0,0 +1,9 @@ +var _concatInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/concat"); + +var _context; + +"".concat(b); + +_concatInstanceProperty(_context = []).call(_context, b); + +_concatInstanceProperty(a).call(a, b);