Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: replace @babel/register with esbuild-wasm #5180

Merged
merged 12 commits into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 11 additions & 29 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
"@babel/register": "^7.18.9",
"@types/jest": "^28.1.6",
"@types/node": "^18.11.11",
"@yarnpkg/cli": "workspace:^",
Expand All @@ -21,8 +20,10 @@
"@yarnpkg/libzip": "workspace:^",
"@yarnpkg/sdks": "workspace:^",
"clipanion": "^3.2.0-rc.10",
"esbuild-wasm": "0.17.5",
"eslint": "^8.2.0",
"jest": "^29.2.1",
"pirates": "^4.0.5",
"tslib": "^2.4.0",
"typescript": "5.0.0-beta"
},
Expand Down
149 changes: 128 additions & 21 deletions scripts/setup-ts-execution.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,134 @@
const crypto = require(`crypto`);
const esbuild = require(`esbuild-wasm`);
const fs = require(`fs`);
const path = require(`path`);
const babel = require(`@babel/core`);
const os = require(`os`);
const root = path.dirname(__dirname);
const pirates = require(`pirates`);
const v8 = require(`v8`);
const zlib = require(`zlib`);

// The cache in @babel/register never clears itself and will therefore grow
// forever causing massive slowdowns if left unchecked for a while
// this ensures a new cache key is generated every week
const weeksSinceUNIXEpoch = Math.floor(Date.now() / 604800000);
/**
* There is an issue on Windows with Node.js v14 (tested v14.19.2 and v14.21.2) where
* ```sh
* node esbuild-wasm\bin\esbuild --service=0.17.5 --ping
* ```
* uses up to 400% CPU and 3.62 GB RAM for a while when an ESM loader is enabled.
*
* ```console
* $ time NODE_OPTIONS="--require ./.pnp.cjs --loader ./.pnp.loader.mjs" node -p "require('esbuild-wasm').transformSync('let foo = 0;')"
* {
* warnings: [],
* code: 'let foo = 0;\n',
* map: '',
* mangleCache: undefined,
* legalComments: undefined
* }
*
* ________________________________________________________
* Executed in 54.99 secs fish external
* usr time 0.00 micros 0.00 micros 0.00 micros
* sys time 0.00 micros 0.00 micros 0.00 micros
* ```
*
* Reported upstream in https://github.com/evanw/esbuild/issues/2888 and seems to boil down to https://github.com/nodejs/node/issues/36616.
*
* To workaround this issue we remove the loader from the NODE_OPTIONS since it's not needed in this case.
*/

if (!process.env.BABEL_CACHE_PATH)
process.env.BABEL_CACHE_PATH = path.join(os.tmpdir(), `babel`, `.babel.${babel.version}.${babel.getEnv()}.${weeksSinceUNIXEpoch}.json`);
if (process.env.NODE_OPTIONS) {
const esmLoaderExpression = /\s*--experimental-loader\s+\S*\.pnp\.loader\.mjs\s*/;
process.env.NODE_OPTIONS = process.env.NODE_OPTIONS.replace(esmLoaderExpression, ` `);
}

require(`@babel/register`)({
root,
extensions: [`.tsx`, `.ts`, `.js`],
only: [
p => {
if (p?.endsWith(`.js`)) {
const normalizedP = p.replace(/\\/g, `/`);
return normalizedP.includes(`packages/yarnpkg-pnp/sources/node`) || normalizedP.endsWith(`packages/yarnpkg-pnp/sources/loader/node-options.js`);
}

return true;
// Needed by the worker spawned by esbuild
if (process.versions.pnp)
process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS || ``} -r ${JSON.stringify(require.resolve(`pnpapi`))}`;

const resolveVirtual = process.versions.pnp
? require(`pnpapi`).resolveVirtual
: undefined;

// esbuild only supports major.minor.patch, no pre-release (nightly) specifier is allowed
// so we reduce the version down to major.minor
const NODE_VERSION = process.versions.node.split(`.`, 2).join(`.`);

const cache = {
version: `${esbuild.version}\0${NODE_VERSION}`,
files: new Map(),
isDirty: false,
};

const cachePath = path.join(__dirname, `../node_modules/.cache/yarn/esbuild-transpile-cache.bin`);
try {
const cacheData = v8.deserialize(zlib.brotliDecompressSync(fs.readFileSync(cachePath)));
if (cacheData.version === cache.version) {
cache.files = cacheData.files;
}
} catch {}

function persistCache() {
if (!cache.isDirty)
return;

cache.isDirty = false;

const data = v8.serialize({
version: cache.version,
files: cache.files,
});

fs.mkdirSync(path.dirname(cachePath), {recursive: true});

const tmpPath = cachePath + crypto.randomBytes(8).toString(`hex`);
fs.writeFileSync(tmpPath, zlib.brotliCompressSync(data, {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 4,
},
}));

fs.renameSync(tmpPath, cachePath);
}

process.once(`exit`, persistCache);
process.nextTick(persistCache);

process.setSourceMapsEnabled?.(true);

function compileFile(sourceCode, filename) {
filename = resolveVirtual?.(filename) ?? filename;

const cacheEntry = cache.files.get(filename);
if (cacheEntry?.source === sourceCode)
return cacheEntry.code;

const res = esbuild.transformSync(sourceCode, {
target: `node${NODE_VERSION}`,
loader: path.extname(filename).slice(1),
sourcefile: filename,
sourcemap: `inline`,
platform: `node`,
format: `cjs`,
supported: {
'dynamic-import': false,
},
],
});

cache.isDirty = true;
cache.files.set(filename, {
source: sourceCode,
code: res.code,
});

return res.code;
}

pirates.addHook(compileFile, {
extensions: [`.tsx`, `.ts`, `.js`],
matcher(p) {
if (p?.endsWith(`.js`)) {
const normalizedP = p.replace(/\\/g, `/`);
return normalizedP.includes(`packages/yarnpkg-pnp/sources/node`) || normalizedP.endsWith(`packages/yarnpkg-pnp/sources/loader/node-options.js`);
}

return true;
},
});
33 changes: 14 additions & 19 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1751,21 +1751,6 @@ __metadata:
languageName: node
linkType: hard

"@babel/register@npm:^7.18.9":
version: 7.18.9
resolution: "@babel/register@npm:7.18.9"
dependencies:
clone-deep: "npm:^4.0.1"
find-cache-dir: "npm:^2.0.0"
make-dir: "npm:^2.1.0"
pirates: "npm:^4.0.5"
source-map-support: "npm:^0.5.16"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: e66100046daa1dee8bed8322d17f8374b47d3b30945accd3761303ca7bf93db406cea5edd530684b4964dbf969c1b5d0aaea07ecf5146ee68cf0fee6b1de88b5
languageName: node
linkType: hard

"@babel/runtime-corejs3@npm:^7.10.2, @babel/runtime-corejs3@npm:^7.18.6":
version: 7.19.1
resolution: "@babel/runtime-corejs3@npm:7.19.1"
Expand Down Expand Up @@ -7366,7 +7351,6 @@ __metadata:
"@babel/preset-env": "npm:^7.18.10"
"@babel/preset-react": "npm:^7.18.6"
"@babel/preset-typescript": "npm:^7.18.6"
"@babel/register": "npm:^7.18.9"
"@types/jest": "npm:^28.1.6"
"@types/node": "npm:^18.11.11"
"@yarnpkg/cli": "workspace:^"
Expand All @@ -7376,8 +7360,10 @@ __metadata:
"@yarnpkg/libzip": "workspace:^"
"@yarnpkg/sdks": "workspace:^"
clipanion: "npm:^3.2.0-rc.10"
esbuild-wasm: "npm:0.17.5"
eslint: "npm:^8.2.0"
jest: "npm:^29.2.1"
pirates: "npm:^4.0.5"
tslib: "npm:^2.4.0"
typescript: "npm:5.0.0-beta"
dependenciesMeta:
Expand Down Expand Up @@ -13160,6 +13146,15 @@ __metadata:
languageName: node
linkType: hard

"esbuild-wasm@npm:0.17.5":
version: 0.17.5
resolution: "esbuild-wasm@npm:0.17.5"
bin:
esbuild: bin/esbuild
checksum: 84a7e1774d9f31eef2ffe862616b9e08d4493598aed0087fc6a58d7bb2c31703455224af1ff02bf9a40119987d2897d94cdfa35a005cdf16d915e8a5da45a29d
languageName: node
linkType: hard

"esbuild-windows-32@npm:0.15.11":
version: 0.15.11
resolution: "esbuild-windows-32@npm:0.15.11"
Expand Down Expand Up @@ -14532,7 +14527,7 @@ __metadata:
languageName: node
linkType: hard

"find-cache-dir@npm:^2.0.0, find-cache-dir@npm:^2.1.0":
"find-cache-dir@npm:^2.1.0":
version: 2.1.0
resolution: "find-cache-dir@npm:2.1.0"
dependencies:
Expand Down Expand Up @@ -20369,7 +20364,7 @@ __metadata:
languageName: node
linkType: hard

"make-dir@npm:^2.0.0, make-dir@npm:^2.1.0":
"make-dir@npm:^2.0.0":
version: 2.1.0
resolution: "make-dir@npm:2.1.0"
dependencies:
Expand Down Expand Up @@ -27359,7 +27354,7 @@ pem@dexus/pem:
languageName: node
linkType: hard

"source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.17, source-map-support@npm:^0.5.19, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20":
"source-map-support@npm:^0.5.17, source-map-support@npm:^0.5.19, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20":
version: 0.5.20
resolution: "source-map-support@npm:0.5.20"
dependencies:
Expand Down