Skip to content

Commit 2b163d8

Browse files
Prepare for compiling Babel to native ESM (#13414)
* Move dynamic import in `@babel/core` to a CJS file * Allow compiling to ESM * Add `USE_ESM` compile-time flag * Fix `@babel/eslint-parser` * Provide CJS bundle of `@babel/parser` * Minor test fixes * Add CommonJS proxy to `@babel/core` for backward compat * Test ESM on CI * TODO: skip failing packages * Add missing `devDependency` to `@babel/helper-remap-async-to-generator` * Update contributing.md * Apply suggestions from self-review * Update Gulpfile.mjs * Prettier * Explicitly use node in makefile
1 parent ea99182 commit 2b163d8

File tree

28 files changed

+477
-82
lines changed

28 files changed

+477
-82
lines changed

.eslintrc.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ module.exports = {
5454
"guard-for-in": "error",
5555
"import/extensions": ["error", { json: "always", cjs: "always" }],
5656
},
57-
globals: { PACKAGE_JSON: "readonly" },
57+
globals: { PACKAGE_JSON: "readonly", USE_ESM: "readonly" },
5858
},
5959
{
6060
files: [

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ jobs:
6565
- name: Upload coverage report
6666
uses: codecov/codecov-action@v1
6767

68+
test-esm:
69+
name: Test ESM version
70+
needs: prepare-yarn-cache
71+
runs-on: ubuntu-latest
72+
steps:
73+
- name: Checkout code
74+
uses: actions/checkout@v3
75+
- name: Use Node.js latest
76+
uses: actions/setup-node@v3
77+
with:
78+
node-version: "*"
79+
cache: "yarn"
80+
- name: Use ESM and build
81+
run: make use-esm
82+
env:
83+
USE_ESM: true
84+
- name: Test
85+
# Hack: --color has supports-color@5 returned true for GitHub CI
86+
# Remove once `chalk` is bumped to 4.0.
87+
run: yarn jest --ci --color
88+
env:
89+
BABEL_ENV: test
90+
USE_ESM: true
91+
6892
build:
6993
name: Build Babel Artifacts
7094
needs: prepare-yarn-cache
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: E2E tests (esm)
2+
3+
on:
4+
push:
5+
pull_request:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
e2e-publish:
12+
name: Publish to local Verdaccio registry
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v3
17+
with:
18+
fetch-depth: 0
19+
- name: Use Node.js latest
20+
uses: actions/setup-node@v3
21+
with:
22+
node-version: "*"
23+
cache: "yarn"
24+
- name: Use ESM
25+
run: make use-esm
26+
- name: Publish
27+
run: ./scripts/integration-tests/publish-local.sh
28+
env:
29+
USE_ESM: true
30+
- uses: actions/upload-artifact@v3
31+
with:
32+
name: verdaccio-workspace
33+
path: /tmp/verdaccio-workspace
34+
35+
e2e-tests:
36+
name: Test
37+
needs: e2e-publish
38+
runs-on: ubuntu-latest
39+
strategy:
40+
fail-fast: false
41+
matrix:
42+
project:
43+
- create-react-app
44+
steps:
45+
- name: Get yarn1 cache directory path
46+
id: yarn1-cache-dir-path
47+
run: echo "::set-output name=dir::$(yarn cache dir)"
48+
- name: Checkout code
49+
uses: actions/checkout@v3
50+
- name: Use Node.js latest
51+
uses: actions/setup-node@v3
52+
with:
53+
node-version: "*"
54+
- name: Get yarn3 cache directory path
55+
id: yarn3-cache-dir-path
56+
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
57+
- name: Use yarn1 cache
58+
uses: actions/cache@v3
59+
id: yarn1-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
60+
with:
61+
path: ${{ steps.yarn1-cache-dir-path.outputs.dir }}
62+
key: ${{ runner.os }}-yarn1-e2e-breaking-${{ matrix.project }}-${{ hashFiles('**/yarn.lock') }}
63+
restore-keys: ${{ runner.os }}-yarn1-e2e-breaking-${{ matrix.project }}-
64+
- name: Use yarn3 cache
65+
uses: actions/cache@v3
66+
id: yarn3-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
67+
with:
68+
path: ${{ steps.yarn3-cache-dir-path.outputs.dir }}
69+
key: ${{ runner.os }}-yarn3-e2e-breaking-${{ matrix.project }}-${{ hashFiles('**/yarn.lock') }}
70+
restore-keys: ${{ runner.os }}-yarn3-e2e-breaking-${{ matrix.project }}-
71+
- name: Clean babel cache
72+
run: |
73+
rm -rf ${{ steps.yarn1-cache-dir-path.outputs.dir }}/*babel*
74+
rm -rf ${{ steps.yarn3-cache-dir-path.outputs.dir }}/*babel*
75+
- uses: actions/download-artifact@v3
76+
with:
77+
name: verdaccio-workspace
78+
path: /tmp/verdaccio-workspace
79+
- name: Test
80+
run: ./scripts/integration-tests/e2e-${{ matrix.project }}.sh
81+
env:
82+
USE_ESM: true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,5 @@ packages/babel-standalone/babel.min.js
8989

9090
/test/runtime-integration/*/output.js
9191
/test/runtime-integration/*/absolute-output.js
92+
93+
.module-type

CONTRIBUTING.md

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ If you wish to build a copy of Babel for distribution, then run:
8080
$ make build-dist
8181
```
8282

83+
## Develop compiling to CommonJS or to ECMAScript modules
84+
85+
Babel can currently be compiled both to CJS and to ESM. You can toggle between those two
86+
modes by running one of the following commands:
87+
```sh
88+
make use-esm
89+
```
90+
```sh
91+
make use-cjs
92+
```
93+
94+
Note that they need to recompile the whole monorepo, so please make sure to stop any running `make watch` process before running them.
95+
96+
If you never run a `make use-*` (or if you delete the `.module-type` file that they generate), our build process defaults to CJS.
97+
8398
### Running linting/tests
8499

85100
#### Lint
@@ -121,16 +136,17 @@ $ TEST_ONLY=babel-cli make test
121136
<summary>More options</summary>
122137
<code>TEST_ONLY</code> will also match substrings of the package name:
123138

124-
```sh
125-
# Run tests for the @babel/plugin-transform-classes package.
126-
$ TEST_ONLY=babel-plugin-transform-classes make test
127-
```
139+
```sh
140+
# Run tests for the @babel/plugin-transform-classes package.
141+
$ TEST_ONLY=babel-plugin-transform-classes make test
142+
```
128143

129-
Or you can use Yarn:
144+
Or you can use Yarn:
145+
146+
```sh
147+
$ yarn jest babel-cli
148+
```
130149

131-
```sh
132-
$ yarn jest babel-cli
133-
```
134150
</details>
135151
<br>
136152

@@ -145,16 +161,19 @@ $ TEST_GREP=transformation make test
145161
Substitute spaces for hyphens and forward slashes when targeting specific test names:
146162

147163
For example, for the following path:
164+
148165
```sh
149166
packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/destructuring-parameters
150167
```
151168

152169
You can use:
170+
153171
```sh
154172
$ TEST_GREP="arrow functions destructuring parameters" make test
155173
```
156174

157175
Or you can directly use Yarn:
176+
158177
```sh
159178
$ yarn jest -t "arrow functions destructuring parameters"
160179
```

Gulpfile.mjs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ import { resolve as importMetaResolve } from "import-meta-resolve";
2525
import rollupBabelSource from "./scripts/rollup-plugin-babel-source.js";
2626
import formatCode from "./scripts/utils/formatCode.js";
2727

28+
let USE_ESM = false;
29+
try {
30+
const type = fs
31+
.readFileSync(new URL(".module-type", import.meta.url), "utf-8")
32+
.trim();
33+
USE_ESM = type === "module";
34+
} catch {}
35+
2836
const require = createRequire(import.meta.url);
2937
const monorepoRoot = path.dirname(fileURLToPath(import.meta.url));
3038

@@ -480,10 +488,15 @@ const libBundles = [
480488
"packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression",
481489
].map(src => ({
482490
src,
483-
format: "cjs",
491+
format: USE_ESM ? "esm" : "cjs",
484492
dest: "lib",
485493
}));
486494

495+
const cjsBundles = [
496+
// This is used by Prettier, @babel/register and @babel/eslint-parser
497+
{ src: "packages/babel-parser" },
498+
];
499+
487500
const dtsBundles = ["packages/babel-types"];
488501

489502
const standaloneBundle = [
@@ -581,6 +594,45 @@ ${fs.readFileSync(path.join(path.dirname(input), "license"), "utf8")}*/
581594
);
582595
});
583596

597+
gulp.task("build-cjs-bundles", () => {
598+
if (!USE_ESM) {
599+
fancyLog(
600+
chalk.yellow(
601+
"Skipping CJS-compat bundles for ESM-based builds, because not compiling to ESM"
602+
)
603+
);
604+
return Promise.resolve();
605+
}
606+
return Promise.all(
607+
cjsBundles.map(async ({ src, external = [] }) => {
608+
const input = `./${src}/lib/index.js`;
609+
const output = `./${src}/lib/index.cjs`;
610+
611+
const bundle = await rollup({
612+
input,
613+
external,
614+
onwarn(warning, warn) {
615+
if (warning.code === "CIRCULAR_DEPENDENCY") return;
616+
warn(warning);
617+
},
618+
plugins: [
619+
rollupCommonJs({ defaultIsModuleExports: true }),
620+
rollupNodeResolve({
621+
extensions: [".js", ".mjs", ".cjs", ".json"],
622+
preferBuiltins: true,
623+
}),
624+
],
625+
});
626+
627+
await bundle.write({
628+
file: output,
629+
format: "cjs",
630+
sourcemap: false,
631+
});
632+
})
633+
);
634+
});
635+
584636
gulp.task(
585637
"build",
586638
gulp.series(
@@ -590,7 +642,7 @@ gulp.task(
590642
// rebuild @babel/types and @babel/helpers since
591643
// type-helpers and generated helpers may be changed
592644
"build-babel",
593-
"generate-standalone"
645+
gulp.parallel("generate-standalone", "build-cjs-bundles")
594646
)
595647
);
596648

@@ -612,7 +664,8 @@ gulp.task(
612664
gulp.series(
613665
"generate-type-helpers",
614666
// rebuild @babel/types since type-helpers may be changed
615-
"build-no-bundle"
667+
"build-no-bundle",
668+
"build-cjs-bundles"
616669
)
617670
)
618671
)
@@ -631,5 +684,11 @@ gulp.task(
631684
"./packages/babel-helpers/src/helpers/*.js",
632685
gulp.task("generate-runtime-helpers")
633686
);
687+
if (USE_ESM) {
688+
gulp.watch(
689+
cjsBundles.map(({ src }) => `./${src}/lib/**.js`),
690+
gulp.task("build-cjs-bundles")
691+
);
692+
}
634693
})
635694
);

Makefile

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ YARN := yarn
1616
NODE := $(YARN) node
1717

1818

19-
.PHONY: build build-dist watch lint fix clean test-clean test-only test test-ci publish bootstrap
19+
.PHONY: build build-dist watch lint fix clean test-clean test-only test test-ci publish bootstrap use-esm use-cjs
2020

2121
build: build-no-bundle
2222
ifneq ("$(BABEL_COVERAGE)", "true")
2323
$(MAKE) build-standalone
2424
endif
2525

2626
build-bundle: clean clean-lib
27+
node ./scripts/set-module-type.js
2728
$(YARN) gulp build
2829
$(MAKE) build-flow-typings
2930
$(MAKE) build-dist
@@ -34,6 +35,7 @@ build-no-bundle-ci: bootstrap-only
3435
$(MAKE) build-dist
3536

3637
build-no-bundle: clean clean-lib
38+
node ./scripts/set-module-type.js
3739
BABEL_ENV=development $(YARN) gulp build-dev
3840
$(MAKE) build-flow-typings
3941
$(MAKE) build-dist
@@ -186,6 +188,7 @@ prepublish:
186188
$(MAKE) bootstrap-only
187189
$(MAKE) prepublish-build
188190
IS_PUBLISH=true $(MAKE) test
191+
node ./scripts/set-module-type.js clean
189192

190193
new-version-checklist:
191194
# @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
@@ -221,6 +224,7 @@ ifneq ("$(I_AM_USING_VERDACCIO)", "I_AM_SURE")
221224
endif
222225
$(YARN) release-tool version $(VERSION) --all --yes --tag-version-prefix="version-e2e-test-"
223226
$(MAKE) prepublish-build
227+
node ./scripts/set-module-type.js clean
224228
YARN_NPM_PUBLISH_REGISTRY=http://localhost:4873 $(YARN) release-tool publish --yes --tag-version-prefix="version-e2e-test-"
225229
$(MAKE) clean
226230

@@ -230,6 +234,14 @@ bootstrap-only: clean-all
230234
bootstrap: bootstrap-only
231235
$(MAKE) generate-tsconfig build
232236

237+
use-cjs:
238+
node ./scripts/set-module-type.js script
239+
$(MAKE) bootstrap
240+
241+
use-esm:
242+
node ./scripts/set-module-type.js module
243+
$(MAKE) bootstrap
244+
233245
clean-lib:
234246
$(foreach source, $(SOURCES), \
235247
$(call clean-source-lib, $(source)))

0 commit comments

Comments
 (0)