Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement
import defer
proposal transform support
- Loading branch information
1 parent
95b4b22
commit 6571dc3
Showing
44 changed files
with
463 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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), | ||
} | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
src | ||
test | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
121 changes: 121 additions & 0 deletions
121
packages/babel-plugin-proposal-import-defer/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
}, | ||
}, | ||
}; | ||
}); |
7 changes: 7 additions & 0 deletions
7
...bel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}); |
6 changes: 6 additions & 0 deletions
6
...-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/options.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"plugins": [ | ||
"proposal-import-defer", | ||
["transform-modules-commonjs", { "lazy": ["lazy"] }] | ||
] | ||
} |
18 changes: 18 additions & 0 deletions
18
...bel-plugin-proposal-import-defer/test/fixtures/esm-to-commonjs-lazy/integration/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()); | ||
}); |
4 changes: 4 additions & 0 deletions
4
...ages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/dep.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
require("./side-channel.cjs").executed = true; | ||
|
||
exports.__esModule = true; | ||
exports.prop = 3; |
14 changes: 14 additions & 0 deletions
14
...ages/babel-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/exec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"]); |
1 change: 1 addition & 0 deletions
1
...l-plugin-proposal-import-defer/test/fixtures/exec/get-own-property-names/side-channel.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.executed = false; |
1 change: 1 addition & 0 deletions
1
packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/dep.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
require("./side-channel.cjs").executed = true; |
4 changes: 4 additions & 0 deletions
4
packages/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/exec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import defer * as ns from "./dep.cjs"; | ||
import sideChannel from "./side-channel.cjs"; | ||
|
||
expect(sideChannel.executed).toBe(false); |
1 change: 1 addition & 0 deletions
1
...ges/babel-plugin-proposal-import-defer/test/fixtures/exec/not-referenced/side-channel.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.executed = false; |
4 changes: 4 additions & 0 deletions
4
packages/babel-plugin-proposal-import-defer/test/fixtures/exec/options.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"sourceType": "module", | ||
"plugins": ["proposal-import-defer", "transform-modules-commonjs"] | ||
} |
4 changes: 4 additions & 0 deletions
4
packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/dep.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
require("./side-channel.cjs").executed = true; | ||
|
||
exports.__esModule = true; | ||
exports.prop = 3; |
13 changes: 13 additions & 0 deletions
13
packages/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/exec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
1 change: 1 addition & 0 deletions
1
...bel-plugin-proposal-import-defer/test/fixtures/exec/reference-plain-only/side-channel.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.executed = false; |
4 changes: 4 additions & 0 deletions
4
...ges/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/dep.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
require("./side-channel.cjs").executed = true; | ||
|
||
exports.__esModule = true; | ||
exports.prop = 3; |
9 changes: 9 additions & 0 deletions
9
...ges/babel-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/exec.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); |
1 change: 1 addition & 0 deletions
1
...-plugin-proposal-import-defer/test/fixtures/exec/reference-property-only/side-channel.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
exports.executed = false; |
1 change: 1 addition & 0 deletions
1
packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import defer * as ns from "x"; |
1 change: 1 addition & 0 deletions
1
packages/babel-plugin-proposal-import-defer/test/fixtures/transform/not-referenced/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"use strict"; |
3 changes: 3 additions & 0 deletions
3
packages/babel-plugin-proposal-import-defer/test/fixtures/transform/options.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"plugins": ["proposal-import-defer", "transform-modules-commonjs"] | ||
} |
6 changes: 6 additions & 0 deletions
6
...ugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import defer * as ns from "x"; | ||
|
||
later(() => { | ||
use(ns); | ||
ns.prop; | ||
}); |
7 changes: 7 additions & 0 deletions
7
...ugin-proposal-import-defer/test/fixtures/transform/reference-plain-and-property/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
"use strict"; | ||
|
||
var ns = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("x"))); | ||
later(() => { | ||
use(ns); | ||
ns.prop; | ||
}); |
5 changes: 5 additions & 0 deletions
5
...babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import defer * as ns from "x"; | ||
|
||
later(() => { | ||
use(ns); | ||
}); |
6 changes: 6 additions & 0 deletions
6
...babel-plugin-proposal-import-defer/test/fixtures/transform/reference-plain-only/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
"use strict"; | ||
|
||
var ns = babelHelpers.importDeferProxy(() => babelHelpers.interopRequireWildcard(require("x"))); | ||
later(() => { | ||
use(ns); | ||
}); |
6 changes: 6 additions & 0 deletions
6
...ugin-proposal-import-defer/test/fixtures/transform/reference-property-and-plain/input.mjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import defer * as ns from "x"; | ||
|
||
later(() => { | ||
ns.prop; | ||
use(ns); | ||
}); |
Oops, something went wrong.