From 6571dc3eb8361afd3c0f1d287ed5db36498f36e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 21 Aug 2023 16:08:26 +0200 Subject: [PATCH] Implement `import defer` proposal transform support --- .../babel-helpers/src/helpers-generated.ts | 4 + .../src/helpers/importDeferProxy.js | 31 +++++ .../.npmignore | 3 + .../README.md | 19 +++ .../package.json | 57 +++++++++ .../src/index.ts | 121 ++++++++++++++++++ .../integration/input.mjs | 7 + .../integration/options.json | 6 + .../integration/output.js | 18 +++ .../exec/get-own-property-names/dep.cjs | 4 + .../exec/get-own-property-names/exec.js | 14 ++ .../get-own-property-names/side-channel.cjs | 1 + .../test/fixtures/exec/not-referenced/dep.cjs | 1 + .../test/fixtures/exec/not-referenced/exec.js | 4 + .../exec/not-referenced/side-channel.cjs | 1 + .../test/fixtures/exec/options.json | 4 + .../exec/reference-plain-only/dep.cjs | 4 + .../exec/reference-plain-only/exec.js | 13 ++ .../reference-plain-only/side-channel.cjs | 1 + .../exec/reference-property-only/dep.cjs | 4 + .../exec/reference-property-only/exec.js | 9 ++ .../reference-property-only/side-channel.cjs | 1 + .../transform/not-referenced/input.mjs | 1 + .../transform/not-referenced/output.js | 1 + .../test/fixtures/transform/options.json | 3 + .../reference-plain-and-property/input.mjs | 6 + .../reference-plain-and-property/output.js | 7 + .../transform/reference-plain-only/input.mjs | 5 + .../transform/reference-plain-only/output.js | 6 + .../reference-property-and-plain/input.mjs | 6 + .../reference-property-and-plain/output.js | 7 + .../reference-property-only/input.mjs | 5 + .../reference-property-only/output.js | 10 ++ .../with-full-import-after/input.mjs | 7 + .../with-full-import-after/output.js | 8 ++ .../with-full-import-before/input.mjs | 7 + .../with-full-import-before/output.js | 8 ++ .../test/index.js | 3 + .../test/package.json | 1 + packages/babel-runtime-corejs2/package.json | 9 ++ packages/babel-runtime-corejs3/package.json | 9 ++ packages/babel-runtime/package.json | 9 ++ tsconfig.json | 4 + yarn.lock | 14 ++ 44 files changed, 463 insertions(+) create mode 100644 packages/babel-helpers/src/helpers/importDeferProxy.js create mode 100644 packages/babel-plugin-proposal-import-defer/.npmignore create mode 100644 packages/babel-plugin-proposal-import-defer/README.md create mode 100644 packages/babel-plugin-proposal-import-defer/package.json create mode 100644 packages/babel-plugin-proposal-import-defer/src/index.ts create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/options.json create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/dep.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/exec.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/side-channel.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/dep.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/exec.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/side-channel.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/options.json create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/dep.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/exec.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/side-channel.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/dep.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/exec.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/side-channel.cjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/options.json create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/input.mjs create mode 100644 packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/output.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/index.js create mode 100644 packages/babel-plugin-proposal-import-defer/test/package.json diff --git a/packages/babel-helpers/src/helpers-generated.ts b/packages/babel-helpers/src/helpers-generated.ts index a9c37f955b97..fb1f14d8d959 100644 --- a/packages/babel-helpers/src/helpers-generated.ts +++ b/packages/babel-helpers/src/helpers-generated.ts @@ -65,6 +65,10 @@ export default Object.freeze({ "7.22.0", 'function dispose_SuppressedError(r,e){return"undefined"!=typeof SuppressedError?dispose_SuppressedError=SuppressedError:(dispose_SuppressedError=function(r,e){this.suppressed=r,this.error=e,this.stack=(new Error).stack},dispose_SuppressedError.prototype=Object.create(Error.prototype,{constructor:{value:dispose_SuppressedError,writable:!0,configurable:!0}})),new dispose_SuppressedError(r,e)}export default function _dispose(r,e,s){function next(){for(;r.length>0;)try{var o=r.pop(),p=o.d.call(o.v);if(o.a)return Promise.resolve(p).then(next,err)}catch(r){return err(r)}if(s)throw e}function err(r){return e=s?new dispose_SuppressedError(r,e):r,s=!0,next()}return next()}', ), + importDeferProxy: helper( + "7.22.0", + "export default function _importDeferProxy(e){var t=null,constValue=function(e){return function(){return e}},proxy=function(r){return function(n,o,f){return null===t&&(t=e()),r(t,o,f)}};return new Proxy({},{defineProperty:constValue(!1),deleteProperty:constValue(!1),get:proxy(Reflect.get),getOwnPropertyDescriptor:proxy(Reflect.getOwnPropertyDescriptor),getPrototypeOf:constValue(null),isExtensible:constValue(!1),has:proxy(Reflect.has),ownKeys:proxy(Reflect.ownKeys),preventExtensions:constValue(!0),set:constValue(!1),setPrototypeOf:constValue(!1)})}", + ), iterableToArrayLimit: helper( "7.0.0-beta.0", 'export default function _iterableToArrayLimit(r,l){var t=null==r?null:"undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(null!=t){var e,n,i,u,a=[],f=!0,o=!1;try{if(i=(t=t.call(r)).next,0===l){if(Object(t)!==t)return;f=!1}else for(;!(f=(e=i.call(t)).done)&&(a.push(e.value),a.length!==l);f=!0);}catch(r){o=!0,n=r}finally{try{if(!f&&null!=t.return&&(u=t.return(),Object(u)!==u))return}finally{if(o)throw n}}return a}}', diff --git a/packages/babel-helpers/src/helpers/importDeferProxy.js b/packages/babel-helpers/src/helpers/importDeferProxy.js new file mode 100644 index 000000000000..d14b5e7776a3 --- /dev/null +++ b/packages/babel-helpers/src/helpers/importDeferProxy.js @@ -0,0 +1,31 @@ +/* @minVersion 7.22.0 */ +export default function _importDeferProxy(init) { + var ns = null; + var constValue = function (v) { + return function () { + return v; + }; + }; + var proxy = function (run) { + return function (arg1, arg2, arg3) { + if (ns === null) ns = init(); + return run(ns, arg2, arg3); + }; + }; + return new Proxy( + {}, + { + defineProperty: constValue(false), + deleteProperty: constValue(false), + get: proxy(Reflect.get), + getOwnPropertyDescriptor: proxy(Reflect.getOwnPropertyDescriptor), + getPrototypeOf: constValue(null), + isExtensible: constValue(false), + has: proxy(Reflect.has), + ownKeys: proxy(Reflect.ownKeys), + preventExtensions: constValue(true), + set: constValue(false), + setPrototypeOf: constValue(false), + } + ); +} diff --git a/packages/babel-plugin-proposal-import-defer/.npmignore b/packages/babel-plugin-proposal-import-defer/.npmignore new file mode 100644 index 000000000000..f9806945836e --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/.npmignore @@ -0,0 +1,3 @@ +src +test +*.log diff --git a/packages/babel-plugin-proposal-import-defer/README.md b/packages/babel-plugin-proposal-import-defer/README.md new file mode 100644 index 000000000000..fa338796e480 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/README.md @@ -0,0 +1,19 @@ +# @babel/plugin-proposal-import-defer + +> Support `import defer` when compiling to CommonJS + +See our website [@babel/plugin-proposal-import-defer](https://babeljs.io/docs/babel-plugin-proposal-import-defer) for more information. + +## Install + +Using npm: + +```sh +npm install --save-dev @babel/plugin-proposal-import-defer +``` + +or using yarn: + +```sh +yarn add @babel/plugin-proposal-import-defer --dev +``` diff --git a/packages/babel-plugin-proposal-import-defer/package.json b/packages/babel-plugin-proposal-import-defer/package.json new file mode 100644 index 000000000000..7acac2dfe69c --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/package.json @@ -0,0 +1,57 @@ +{ + "name": "@babel/plugin-proposal-import-defer", + "version": "7.22.5", + "description": "Support `import defer` when compiling to CommonJS", + "repository": { + "type": "git", + "url": "https://github.com/babel/babel.git", + "directory": "packages/babel-plugin-proposal-import-defer" + }, + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "main": "./lib/index.js", + "keywords": [ + "babel-plugin" + ], + "dependencies": { + "@babel/helper-plugin-utils": "workspace:^", + "@babel/plugin-syntax-import-defer": "workspace:^", + "@babel/plugin-transform-modules-commonjs": "workspace:^" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "devDependencies": { + "@babel/core": "workspace:^", + "@babel/helper-plugin-test-runner": "workspace:^" + }, + "engines": { + "node": ">=6.9.0" + }, + "author": "The Babel Team (https://babel.dev/team)", + "conditions": { + "BABEL_8_BREAKING": [ + { + "engines": { + "node": "^16.20.0 || ^18.16.0 || >=20.0.0" + } + }, + { + "exports": null + } + ], + "USE_ESM": [ + { + "type": "module" + }, + null + ] + }, + "exports": { + ".": "./lib/index.js", + "./package.json": "./package.json" + }, + "type": "commonjs" +} diff --git a/packages/babel-plugin-proposal-import-defer/src/index.ts b/packages/babel-plugin-proposal-import-defer/src/index.ts new file mode 100644 index 000000000000..3eb4e2988e92 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/src/index.ts @@ -0,0 +1,121 @@ +import { declare } from "@babel/helper-plugin-utils"; +import type { types as t } from "@babel/core"; +import type { Scope } from "@babel/traverse"; +import { defineCommonJSHook } from "@babel/plugin-transform-modules-commonjs"; + +import syntaxImportDefer from "@babel/plugin-syntax-import-defer"; + +export default declare(api => { + api.assertVersion(7); + // We need the explicit type annotation otherwise when using t.assert* ts + // reports that 'Assertions require every name in the call target to be + // declared with an explicit type annotation' + const t: typeof api.types = api.types; + const { template } = api; + + function allReferencesAreProps(scope: Scope, node: t.ImportDeclaration) { + const specifier = node.specifiers[0]; + t.assertImportNamespaceSpecifier(specifier); + + const binding = scope.getOwnBinding(specifier.local.name); + return !!binding?.referencePaths.every(path => + path.parentPath.isMemberExpression({ object: path.node }), + ); + } + + return { + name: "proposal-import-defer", + + inherits: syntaxImportDefer, + + pre() { + const { file } = this; + + defineCommonJSHook(file, { + name: PACKAGE_JSON.name, + version: PACKAGE_JSON.version, + getWrapperPayload(source, metadata, importNodes) { + let needsProxy = false; + for (const node of importNodes) { + if (!t.isImportDeclaration(node)) return null; + if (node.phase !== "defer") return null; + if (!allReferencesAreProps(file.scope, node)) needsProxy = true; + } + return needsProxy ? "defer/proxy" : "defer/function"; + }, + buildRequireWrapper(name, init, payload, referenced) { + if (payload === "defer/proxy") { + if (!referenced) return false; + return template.statement.ast` + var ${name} = ${file.addHelper("importDeferProxy")}( + () => ${init} + ) + `; + } + if (payload === "defer/function") { + if (!referenced) return false; + return template.statement.ast` + function ${name}() { + const data = ${init}; + ${name} = () => data; + return data; + } + `; + } + }, + wrapReference(ref, payload) { + if (payload === "defer/function") return t.callExpression(ref, []); + }, + }); + }, + + visitor: { + Program(path) { + if (this.file.get("@babel/plugin-transform-modules-*") !== "commonjs") { + throw new Error( + `@babel/plugin-proposal-import-defer can only be used when` + + ` transpiling modules to CommonJS.`, + ); + } + + // Move all deferred imports to the end, so that in case of + // import defer * as a from "a" + // import "b" + // import "a" + // we have the correct evaluation order + + const eagerImports = new Map(); + + for (const child of path.get("body")) { + if ( + (child.isImportDeclaration() && child.node.phase == null) || + (child.isExportNamedDeclaration() && child.node.source !== null) || + child.isExportAllDeclaration() + ) { + const specifier = child.node.source!.value; + if (!eagerImports.has(specifier)) { + eagerImports.set(specifier, child); + } + } + } + + const importsToPush = []; + for (const child of path.get("body")) { + if (child.isImportDeclaration({ phase: "defer" })) { + const specifier = child.node.source.value; + if (!eagerImports.has(specifier)) continue; + + child.node.phase = null; + importsToPush.push(child.node); + child.remove(); + } + } + if (importsToPush.length) { + path.pushContainer("body", importsToPush); + // Re-collect references to moved imports + path.scope.crawl(); + } + }, + }, + }; +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/input.mjs new file mode 100644 index 000000000000..ebdb14cadb74 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/input.mjs @@ -0,0 +1,7 @@ +import defer * as a from "a"; +import defer * as b from "b"; +import * as c from "lazy"; + +later(() => { + use(a.x, b, c); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/options.json b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/options.json new file mode 100644 index 000000000000..be5f10f7bf53 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "proposal-import-defer", + ["transform-modules-commonjs", { "lazy": ["lazy"] }] + ] +} diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/output.js new file mode 100644 index 000000000000..806451849bc3 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/output.js @@ -0,0 +1,18 @@ +"use strict"; + +function a() { + const data = babelHelpers.interopRequireWildcard(require("a")); + a = () => data; + return data; +} +var b = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("b"))); +function c() { + const data = babelHelpers.interopRequireWildcard(require("lazy")); + c = function () { + return data; + }; + return data; +} +later(() => { + use(a().x, b, c()); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/dep.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/dep.cjs new file mode 100644 index 000000000000..8c54d2a33bf4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/dep.cjs @@ -0,0 +1,4 @@ +require("./side-channel.cjs").executed = true; + +exports.__esModule = true; +exports.prop = 3; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/exec.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/exec.js new file mode 100644 index 000000000000..a02ccc444a2b --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/exec.js @@ -0,0 +1,14 @@ +import defer * as ns from "./dep.cjs"; +import sideChannel from "./side-channel.cjs"; + +expect(sideChannel.executed).toBe(false); + +// NOTE: In the current proposal, Object.getOwnPropertyNames does +// not trigger evaluation. However, this behavior is impossible +// to emulate given that we are importing a CommonJS module. +// In the proposal, Object.keys does tirgger evaluation because +// it internally performs .[[Get]] on the namespace object. + +const names = Object.getOwnPropertyNames(ns); +expect(sideChannel.executed).toBe(true); +expect(names).toEqual(["__esModule", "prop"]); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/side-channel.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/side-channel.cjs new file mode 100644 index 000000000000..175559f973c4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/side-channel.cjs @@ -0,0 +1 @@ +exports.executed = false; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/dep.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/dep.cjs new file mode 100644 index 000000000000..c0a7f229f3ba --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/dep.cjs @@ -0,0 +1 @@ +require("./side-channel.cjs").executed = true; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/exec.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/exec.js new file mode 100644 index 000000000000..9e94f0b5956c --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/exec.js @@ -0,0 +1,4 @@ +import defer * as ns from "./dep.cjs"; +import sideChannel from "./side-channel.cjs"; + +expect(sideChannel.executed).toBe(false); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/side-channel.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/side-channel.cjs new file mode 100644 index 000000000000..175559f973c4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/side-channel.cjs @@ -0,0 +1 @@ +exports.executed = false; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/options.json b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/options.json new file mode 100644 index 000000000000..f3112f15306b --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["proposal-import-defer", "transform-modules-commonjs"] +} diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/dep.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/dep.cjs new file mode 100644 index 000000000000..8c54d2a33bf4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/dep.cjs @@ -0,0 +1,4 @@ +require("./side-channel.cjs").executed = true; + +exports.__esModule = true; +exports.prop = 3; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/exec.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/exec.js new file mode 100644 index 000000000000..023d30684f8a --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/exec.js @@ -0,0 +1,13 @@ +import defer * as ns from "./dep.cjs"; +import sideChannel from "./side-channel.cjs"; + +expect(sideChannel.executed).toBe(false); + +const copy = ns; +expect(typeof copy).toBe("object"); +expect(sideChannel.executed).toBe(false); + +const val = Reflect.get(ns, "prop"); +expect(val).toBe(3); + +expect(sideChannel.executed).toBe(true); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/side-channel.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/side-channel.cjs new file mode 100644 index 000000000000..175559f973c4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/side-channel.cjs @@ -0,0 +1 @@ +exports.executed = false; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/dep.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/dep.cjs new file mode 100644 index 000000000000..8c54d2a33bf4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/dep.cjs @@ -0,0 +1,4 @@ +require("./side-channel.cjs").executed = true; + +exports.__esModule = true; +exports.prop = 3; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/exec.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/exec.js new file mode 100644 index 000000000000..8c03595de4b1 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/exec.js @@ -0,0 +1,9 @@ +import defer * as ns from "./dep.cjs"; +import sideChannel from "./side-channel.cjs"; + +expect(sideChannel.executed).toBe(false); + +const val = ns.prop; +expect(val).toBe(3); + +expect(sideChannel.executed).toBe(true); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/side-channel.cjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/side-channel.cjs new file mode 100644 index 000000000000..175559f973c4 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/side-channel.cjs @@ -0,0 +1 @@ +exports.executed = false; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/input.mjs new file mode 100644 index 000000000000..806ae2bb7690 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/input.mjs @@ -0,0 +1 @@ +import defer * as ns from "x"; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/output.js new file mode 100644 index 000000000000..3918c74e4463 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/output.js @@ -0,0 +1 @@ +"use strict"; diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/options.json b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/options.json new file mode 100644 index 000000000000..36c31a6bafe9 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-import-defer", "transform-modules-commonjs"] +} diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/input.mjs new file mode 100644 index 000000000000..1941f1f70683 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/input.mjs @@ -0,0 +1,6 @@ +import defer * as ns from "x"; + +later(() => { + use(ns); + ns.prop; +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/output.js new file mode 100644 index 000000000000..2758d4ab4c5e --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/output.js @@ -0,0 +1,7 @@ +"use strict"; + +var ns = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("x"))); +later(() => { + use(ns); + ns.prop; +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/input.mjs new file mode 100644 index 000000000000..fe4157905a95 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/input.mjs @@ -0,0 +1,5 @@ +import defer * as ns from "x"; + +later(() => { + use(ns); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/output.js new file mode 100644 index 000000000000..33ec4d205ea1 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/output.js @@ -0,0 +1,6 @@ +"use strict"; + +var ns = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("x"))); +later(() => { + use(ns); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/input.mjs new file mode 100644 index 000000000000..35c45201d2fc --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/input.mjs @@ -0,0 +1,6 @@ +import defer * as ns from "x"; + +later(() => { + ns.prop; + use(ns); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/output.js new file mode 100644 index 000000000000..90a7346d042e --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/output.js @@ -0,0 +1,7 @@ +"use strict"; + +var ns = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("x"))); +later(() => { + ns.prop; + use(ns); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/input.mjs new file mode 100644 index 000000000000..ed468db4a4d1 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/input.mjs @@ -0,0 +1,5 @@ +import defer * as ns from "x"; + +later(() => { + ns.prop; +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/output.js new file mode 100644 index 000000000000..8a34b3e11d75 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/reference-property-only/output.js @@ -0,0 +1,10 @@ +"use strict"; + +function ns() { + const data = babelHelpers.interopRequireWildcard(require("x")); + ns = () => data; + return data; +} +later(() => { + ns().prop; +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/input.mjs new file mode 100644 index 000000000000..0783441e664a --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/input.mjs @@ -0,0 +1,7 @@ +import defer * as x1 from "x"; +import * as y from "y"; +import * as x2 from "x"; + +later(() => { + use(x1, x2, y); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/output.js new file mode 100644 index 000000000000..268da2faaa1d --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-after/output.js @@ -0,0 +1,8 @@ +"use strict"; + +var y = babelHelpers.interopRequireWildcard(require("y")); +var x2 = babelHelpers.interopRequireWildcard(require("x")); +var x1 = x2; +later(() => { + use(x1, x2, y); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/input.mjs b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/input.mjs new file mode 100644 index 000000000000..464bbe629e01 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/input.mjs @@ -0,0 +1,7 @@ +import * as x1 from "x"; +import * as y from "y"; +import defer * as x2 from "x"; + +later(() => { + use(x1, x2, y); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/output.js b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/output.js new file mode 100644 index 000000000000..f0888785b98c --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/fixtures/transform/with-full-import-before/output.js @@ -0,0 +1,8 @@ +"use strict"; + +var x1 = babelHelpers.interopRequireWildcard(require("x")); +var x2 = x1; +var y = babelHelpers.interopRequireWildcard(require("y")); +later(() => { + use(x1, x2, y); +}); diff --git a/packages/babel-plugin-proposal-import-defer/test/index.js b/packages/babel-plugin-proposal-import-defer/test/index.js new file mode 100644 index 000000000000..21a55ce6b5e7 --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/index.js @@ -0,0 +1,3 @@ +import runner from "@babel/helper-plugin-test-runner"; + +runner(import.meta.url); diff --git a/packages/babel-plugin-proposal-import-defer/test/package.json b/packages/babel-plugin-proposal-import-defer/test/package.json new file mode 100644 index 000000000000..5ffd9800b97c --- /dev/null +++ b/packages/babel-plugin-proposal-import-defer/test/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/packages/babel-runtime-corejs2/package.json b/packages/babel-runtime-corejs2/package.json index d470f6a29f31..9fa2a5b36826 100644 --- a/packages/babel-runtime-corejs2/package.json +++ b/packages/babel-runtime-corejs2/package.json @@ -135,6 +135,15 @@ "./helpers/dispose.js" ], "./helpers/esm/dispose": "./helpers/esm/dispose.js", + "./helpers/importDeferProxy": [ + { + "node": "./helpers/importDeferProxy.js", + "import": "./helpers/esm/importDeferProxy.js", + "default": "./helpers/importDeferProxy.js" + }, + "./helpers/importDeferProxy.js" + ], + "./helpers/esm/importDeferProxy": "./helpers/esm/importDeferProxy.js", "./helpers/iterableToArrayLimit": [ { "node": "./helpers/iterableToArrayLimit.js", diff --git a/packages/babel-runtime-corejs3/package.json b/packages/babel-runtime-corejs3/package.json index 760b7ef1c2ed..6f8f142bd393 100644 --- a/packages/babel-runtime-corejs3/package.json +++ b/packages/babel-runtime-corejs3/package.json @@ -134,6 +134,15 @@ "./helpers/dispose.js" ], "./helpers/esm/dispose": "./helpers/esm/dispose.js", + "./helpers/importDeferProxy": [ + { + "node": "./helpers/importDeferProxy.js", + "import": "./helpers/esm/importDeferProxy.js", + "default": "./helpers/importDeferProxy.js" + }, + "./helpers/importDeferProxy.js" + ], + "./helpers/esm/importDeferProxy": "./helpers/esm/importDeferProxy.js", "./helpers/iterableToArrayLimit": [ { "node": "./helpers/iterableToArrayLimit.js", diff --git a/packages/babel-runtime/package.json b/packages/babel-runtime/package.json index b5b3a5c81b6a..7a759a5a3314 100644 --- a/packages/babel-runtime/package.json +++ b/packages/babel-runtime/package.json @@ -134,6 +134,15 @@ "./helpers/dispose.js" ], "./helpers/esm/dispose": "./helpers/esm/dispose.js", + "./helpers/importDeferProxy": [ + { + "node": "./helpers/importDeferProxy.js", + "import": "./helpers/esm/importDeferProxy.js", + "default": "./helpers/importDeferProxy.js" + }, + "./helpers/importDeferProxy.js" + ], + "./helpers/esm/importDeferProxy": "./helpers/esm/importDeferProxy.js", "./helpers/iterableToArrayLimit": [ { "node": "./helpers/iterableToArrayLimit.js", diff --git a/tsconfig.json b/tsconfig.json index b4616648f455..9145aa192015 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,6 +51,7 @@ "./packages/babel-plugin-proposal-function-bind/src/**/*.ts", "./packages/babel-plugin-proposal-function-sent/src/**/*.ts", "./packages/babel-plugin-proposal-import-attributes-to-assertions/src/**/*.ts", + "./packages/babel-plugin-proposal-import-defer/src/**/*.ts", "./packages/babel-plugin-proposal-partial-application/src/**/*.ts", "./packages/babel-plugin-proposal-pipeline-operator/src/**/*.ts", "./packages/babel-plugin-proposal-record-and-tuple/src/**/*.ts", @@ -324,6 +325,9 @@ "@babel/plugin-proposal-import-attributes-to-assertions": [ "./packages/babel-plugin-proposal-import-attributes-to-assertions/src" ], + "@babel/plugin-proposal-import-defer": [ + "./packages/babel-plugin-proposal-import-defer/src" + ], "@babel/plugin-proposal-partial-application": [ "./packages/babel-plugin-proposal-partial-application/src" ], diff --git a/yarn.lock b/yarn.lock index 5907cb7087c3..1d3d097eee21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1560,6 +1560,20 @@ __metadata: languageName: unknown linkType: soft +"@babel/plugin-proposal-import-defer@workspace:packages/babel-plugin-proposal-import-defer": + version: 0.0.0-use.local + resolution: "@babel/plugin-proposal-import-defer@workspace:packages/babel-plugin-proposal-import-defer" + dependencies: + "@babel/core": "workspace:^" + "@babel/helper-plugin-test-runner": "workspace:^" + "@babel/helper-plugin-utils": "workspace:^" + "@babel/plugin-syntax-import-defer": "workspace:^" + "@babel/plugin-transform-modules-commonjs": "workspace:^" + peerDependencies: + "@babel/core": ^7.0.0-0 + languageName: unknown + linkType: soft + "@babel/plugin-proposal-partial-application@workspace:packages/babel-plugin-proposal-partial-application": version: 0.0.0-use.local resolution: "@babel/plugin-proposal-partial-application@workspace:packages/babel-plugin-proposal-partial-application"