[babel 8] Move @babel/register transform to a separate worker (#14025)
This commit is contained in:
parent
d1cabf6bc8
commit
e77e3de402
@ -1 +1,3 @@
|
|||||||
console.log("foo");
|
// See https://github.com/babel/babel/pull/14025#issuecomment-986296424
|
||||||
|
// for the reason behind using setImmediate.
|
||||||
|
setImmediate(() => console.log("foo"));
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
console.log("foo");
|
// See https://github.com/babel/babel/pull/14025#issuecomment-986296424
|
||||||
|
// for the reason behind using setImmediate.
|
||||||
|
setImmediate(() => console.log("foo"));
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
console.log("foo");
|
// See https://github.com/babel/babel/pull/14025#issuecomment-986296424
|
||||||
|
// for the reason behind using setImmediate.
|
||||||
|
setImmediate(() => console.log("foo"));
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
console.log("foo");
|
// See https://github.com/babel/babel/pull/14025#issuecomment-986296424
|
||||||
|
// for the reason behind using setImmediate.
|
||||||
|
setImmediate(() => console.log("foo"));
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
src
|
src
|
||||||
test
|
test
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
experimental-worker.js
|
||||||
|
lib/experimental-worker.js
|
||||||
|
lib/is-in-register-worker.js
|
||||||
|
|||||||
1
packages/babel-register/experimental-worker.js
Normal file
1
packages/babel-register/experimental-worker.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = require("./lib/experimental-worker");
|
||||||
@ -12,9 +12,10 @@
|
|||||||
"directory": "packages/babel-register"
|
"directory": "packages/babel-register"
|
||||||
},
|
},
|
||||||
"author": "The Babel Team (https://babel.dev/team)",
|
"author": "The Babel Team (https://babel.dev/team)",
|
||||||
|
"type": "commonjs",
|
||||||
"main": "./lib/index.js",
|
"main": "./lib/index.js",
|
||||||
"browser": {
|
"browser": {
|
||||||
"./lib/nodeWrapper.js": "./lib/browser.js"
|
"./lib/index.js": "./lib/browser.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clone-deep": "^4.0.1",
|
"clone-deep": "^4.0.1",
|
||||||
@ -28,6 +29,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "workspace:^",
|
"@babel/core": "workspace:^",
|
||||||
|
"@babel/plugin-transform-arrow-functions": "workspace:^",
|
||||||
"@babel/plugin-transform-modules-commonjs": "workspace:^",
|
"@babel/plugin-transform-modules-commonjs": "workspace:^",
|
||||||
"browserify": "^16.5.2"
|
"browserify": "^16.5.2"
|
||||||
},
|
},
|
||||||
|
|||||||
10
packages/babel-register/src/browser.js
Normal file
10
packages/babel-register/src/browser.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// required to safely use babel/register within a browserify codebase
|
||||||
|
|
||||||
|
function register() {}
|
||||||
|
|
||||||
|
module.exports = Object.assign(register, {
|
||||||
|
default: register,
|
||||||
|
register,
|
||||||
|
revert: function revert() {},
|
||||||
|
__esModule: true,
|
||||||
|
});
|
||||||
@ -1,5 +0,0 @@
|
|||||||
// required to safely use babel/register within a browserify codebase
|
|
||||||
|
|
||||||
export default function register() {}
|
|
||||||
|
|
||||||
export function revert() {}
|
|
||||||
3
packages/babel-register/src/cache.js
Normal file
3
packages/babel-register/src/cache.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// File moved to ./worker/cache.js
|
||||||
|
// TODO: Remove this backward-compat "proxy file" in Babel 8
|
||||||
|
module.exports = require("./worker/cache");
|
||||||
26
packages/babel-register/src/experimental-worker.js
Normal file
26
packages/babel-register/src/experimental-worker.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// TODO: Move this file to index.js in Babel 8
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const [major, minor] = process.versions.node.split(".").map(Number);
|
||||||
|
|
||||||
|
if (major < 12 || (major === 12 && minor < 3)) {
|
||||||
|
throw new Error(
|
||||||
|
"@babel/register/experimental-worker requires Node.js >= 12.3.0",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hook = require("./hook");
|
||||||
|
const { WorkerClient } = require("./worker-client");
|
||||||
|
|
||||||
|
const register = hook.register.bind(null, new WorkerClient());
|
||||||
|
|
||||||
|
module.exports = Object.assign(register, {
|
||||||
|
revert: hook.revert,
|
||||||
|
default: register,
|
||||||
|
__esModule: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!require("./is-in-register-worker").isInRegisterWorker) {
|
||||||
|
register();
|
||||||
|
}
|
||||||
85
packages/babel-register/src/hook.js
Normal file
85
packages/babel-register/src/hook.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { addHook } = require("pirates");
|
||||||
|
const sourceMapSupport = require("source-map-support");
|
||||||
|
|
||||||
|
let piratesRevert;
|
||||||
|
const maps = Object.create(null);
|
||||||
|
|
||||||
|
function installSourceMapSupport() {
|
||||||
|
installSourceMapSupport = () => {}; // eslint-disable-line no-func-assign
|
||||||
|
|
||||||
|
sourceMapSupport.install({
|
||||||
|
handleUncaughtExceptions: false,
|
||||||
|
environment: "node",
|
||||||
|
retrieveSourceMap(filename) {
|
||||||
|
const map = maps?.[filename];
|
||||||
|
if (map) {
|
||||||
|
return { url: null, map: map };
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
// Babel 7 compiles files in the same thread where it hooks `require()`,
|
||||||
|
// so we must prevent mixing Babel plugin dependencies with the files
|
||||||
|
// to be compiled.
|
||||||
|
// All the `!process.env.BABEL_8_BREAKING` code in this file is for
|
||||||
|
// this purpose.
|
||||||
|
|
||||||
|
const Module = require("module");
|
||||||
|
|
||||||
|
let compiling = false;
|
||||||
|
const internalModuleCache = Module._cache;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var compileBabel7 = function compileBabel7(client, code, filename) {
|
||||||
|
if (!client.isLocalClient) return compile(client, code, filename);
|
||||||
|
|
||||||
|
if (compiling) return code;
|
||||||
|
|
||||||
|
const globalModuleCache = Module._cache;
|
||||||
|
try {
|
||||||
|
compiling = true;
|
||||||
|
Module._cache = internalModuleCache;
|
||||||
|
return compile(client, code, filename);
|
||||||
|
} finally {
|
||||||
|
compiling = false;
|
||||||
|
Module._cache = globalModuleCache;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function compile(client, inputCode, filename) {
|
||||||
|
const result = client.transform(inputCode, filename);
|
||||||
|
|
||||||
|
if (result === null) return inputCode;
|
||||||
|
|
||||||
|
const { code, map } = result;
|
||||||
|
if (map) {
|
||||||
|
maps[filename] = map;
|
||||||
|
installSourceMapSupport();
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.register = function register(client, opts = {}) {
|
||||||
|
if (piratesRevert) piratesRevert();
|
||||||
|
|
||||||
|
piratesRevert = addHook(
|
||||||
|
(process.env.BABEL_8_BREAKING ? compile : compileBabel7).bind(null, client),
|
||||||
|
{
|
||||||
|
exts: opts.extensions ?? client.getDefaultExtensions(),
|
||||||
|
ignoreNodeModules: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
client.setOptions(opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.revert = function revert() {
|
||||||
|
if (piratesRevert) piratesRevert();
|
||||||
|
};
|
||||||
@ -4,12 +4,16 @@
|
|||||||
* from a compiled Babel import.
|
* from a compiled Babel import.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
exports = module.exports = function (...args) {
|
if (process.env.BABEL_8_BREAKING) {
|
||||||
|
module.exports = require("./experimental-worker");
|
||||||
|
} else {
|
||||||
|
exports = module.exports = function (...args) {
|
||||||
return register(...args);
|
return register(...args);
|
||||||
};
|
};
|
||||||
exports.__esModule = true;
|
exports.__esModule = true;
|
||||||
|
|
||||||
const node = require("./nodeWrapper");
|
const node = require("./nodeWrapper");
|
||||||
const register = node.default;
|
const register = node.default;
|
||||||
|
|
||||||
Object.assign(exports, node);
|
Object.assign(exports, node);
|
||||||
|
}
|
||||||
|
|||||||
20
packages/babel-register/src/is-in-register-worker.js
Normal file
20
packages/babel-register/src/is-in-register-worker.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since workers inherit the exec options from the parent thread, we
|
||||||
|
* must be careful to avoid infite "@babel/register" setup loops.
|
||||||
|
*
|
||||||
|
* If @babel/register is imported using the -r/--require flag, the worker
|
||||||
|
* will have the same flag and we must avoid registering the @babel/register
|
||||||
|
* hook again.
|
||||||
|
*
|
||||||
|
* - markInRegisterWorker() can be used to mark a set of env vars (that will
|
||||||
|
* be forwarded to a worker) as being in the @babel/register worker.
|
||||||
|
* - isInRegisterWorker will be true in @babel/register workers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const envVarName = "___INTERNAL___IS_INSIDE_BABEL_REGISTER_WORKER___";
|
||||||
|
const envVarValue = "yes_I_am";
|
||||||
|
|
||||||
|
exports.markInRegisterWorker = env => ({ ...env, [envVarName]: envVarValue });
|
||||||
|
exports.isInRegisterWorker = process.env[envVarName] === envVarValue;
|
||||||
13
packages/babel-register/src/node.js
Normal file
13
packages/babel-register/src/node.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// TODO: Remove this file in Babel 8
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const hook = require("./hook");
|
||||||
|
const { LocalClient } = require("./worker-client");
|
||||||
|
|
||||||
|
const register = hook.register.bind(null, new LocalClient());
|
||||||
|
|
||||||
|
module.exports = Object.assign(register, {
|
||||||
|
revert: hook.revert,
|
||||||
|
default: register,
|
||||||
|
});
|
||||||
@ -1,176 +0,0 @@
|
|||||||
import cloneDeep from "clone-deep";
|
|
||||||
import sourceMapSupport from "source-map-support";
|
|
||||||
import * as registerCache from "./cache";
|
|
||||||
import * as babel from "@babel/core";
|
|
||||||
import { OptionManager, DEFAULT_EXTENSIONS } from "@babel/core";
|
|
||||||
import { addHook } from "pirates";
|
|
||||||
import fs from "fs";
|
|
||||||
import path from "path";
|
|
||||||
import Module from "module";
|
|
||||||
|
|
||||||
const maps = {};
|
|
||||||
let transformOpts: any = {};
|
|
||||||
let piratesRevert = null;
|
|
||||||
|
|
||||||
function installSourceMapSupport() {
|
|
||||||
sourceMapSupport.install({
|
|
||||||
handleUncaughtExceptions: false,
|
|
||||||
environment: "node",
|
|
||||||
retrieveSourceMap(source) {
|
|
||||||
const map = maps && maps[source];
|
|
||||||
if (map) {
|
|
||||||
return {
|
|
||||||
url: null,
|
|
||||||
map: map,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let cache;
|
|
||||||
|
|
||||||
function mtime(filename) {
|
|
||||||
return +fs.statSync(filename).mtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
function compile(code, filename) {
|
|
||||||
// merge in base options and resolve all the plugins and presets relative to this file
|
|
||||||
const opts = new OptionManager().init(
|
|
||||||
// sourceRoot can be overwritten
|
|
||||||
{
|
|
||||||
sourceRoot: path.dirname(filename) + path.sep,
|
|
||||||
...cloneDeep(transformOpts),
|
|
||||||
filename,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Bail out ASAP if the file has been ignored.
|
|
||||||
if (opts === null) return code;
|
|
||||||
|
|
||||||
let cacheKey = `${JSON.stringify(opts)}:${babel.version}`;
|
|
||||||
|
|
||||||
const env = babel.getEnv("");
|
|
||||||
|
|
||||||
if (env) cacheKey += `:${env}`;
|
|
||||||
|
|
||||||
let cached, fileMtime;
|
|
||||||
if (cache) {
|
|
||||||
cached = cache[cacheKey];
|
|
||||||
fileMtime = mtime(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cached || cached.mtime !== fileMtime) {
|
|
||||||
cached = babel.transform(code, {
|
|
||||||
...opts,
|
|
||||||
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
|
|
||||||
ast: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (cache) {
|
|
||||||
cache[cacheKey] = cached;
|
|
||||||
cached.mtime = fileMtime;
|
|
||||||
registerCache.setDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cached.map) {
|
|
||||||
if (Object.keys(maps).length === 0) {
|
|
||||||
installSourceMapSupport();
|
|
||||||
}
|
|
||||||
maps[filename] = cached.map;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cached.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
let compiling = false;
|
|
||||||
// @ts-expect-error field is missing in type definitions
|
|
||||||
const internalModuleCache = Module._cache;
|
|
||||||
|
|
||||||
function compileHook(code, filename) {
|
|
||||||
if (compiling) return code;
|
|
||||||
|
|
||||||
// @ts-expect-error field is missing in type definitions
|
|
||||||
const globalModuleCache = Module._cache;
|
|
||||||
try {
|
|
||||||
compiling = true;
|
|
||||||
// @ts-expect-error field is missing in type definitions
|
|
||||||
Module._cache = internalModuleCache;
|
|
||||||
return compile(code, filename);
|
|
||||||
} finally {
|
|
||||||
compiling = false;
|
|
||||||
// @ts-expect-error field is missing in type definitions
|
|
||||||
Module._cache = globalModuleCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hookExtensions(exts) {
|
|
||||||
if (piratesRevert) piratesRevert();
|
|
||||||
piratesRevert = addHook(compileHook, { exts, ignoreNodeModules: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function revert() {
|
|
||||||
if (piratesRevert) piratesRevert();
|
|
||||||
}
|
|
||||||
|
|
||||||
function escapeRegExp(string) {
|
|
||||||
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function register(opts: any = {}) {
|
|
||||||
// Clone to avoid mutating the arguments object with the 'delete's below.
|
|
||||||
opts = {
|
|
||||||
...opts,
|
|
||||||
};
|
|
||||||
hookExtensions(opts.extensions || DEFAULT_EXTENSIONS);
|
|
||||||
|
|
||||||
if (opts.cache === false && cache) {
|
|
||||||
registerCache.clear();
|
|
||||||
cache = null;
|
|
||||||
} else if (opts.cache !== false && !cache) {
|
|
||||||
registerCache.load();
|
|
||||||
cache = registerCache.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete opts.extensions;
|
|
||||||
delete opts.cache;
|
|
||||||
|
|
||||||
transformOpts = {
|
|
||||||
...opts,
|
|
||||||
caller: {
|
|
||||||
name: "@babel/register",
|
|
||||||
...(opts.caller || {}),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let { cwd = "." } = transformOpts;
|
|
||||||
|
|
||||||
// Ensure that the working directory is resolved up front so that
|
|
||||||
// things don't break if it changes later.
|
|
||||||
cwd = transformOpts.cwd = path.resolve(cwd);
|
|
||||||
|
|
||||||
if (transformOpts.ignore === undefined && transformOpts.only === undefined) {
|
|
||||||
transformOpts.only = [
|
|
||||||
// Only compile things inside the current working directory.
|
|
||||||
// $FlowIgnore
|
|
||||||
new RegExp("^" + escapeRegExp(cwd), "i"),
|
|
||||||
];
|
|
||||||
transformOpts.ignore = [
|
|
||||||
// Ignore any node_modules inside the current working directory.
|
|
||||||
new RegExp(
|
|
||||||
"^" +
|
|
||||||
// $FlowIgnore
|
|
||||||
escapeRegExp(cwd) +
|
|
||||||
"(?:" +
|
|
||||||
path.sep +
|
|
||||||
".*)?" +
|
|
||||||
// $FlowIgnore
|
|
||||||
escapeRegExp(path.sep + "node_modules" + path.sep),
|
|
||||||
"i",
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,7 +5,8 @@
|
|||||||
* and allows register to transform these modules if they are loaded externally.
|
* and allows register to transform these modules if they are loaded externally.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @ts-ignore todo(flow->ts) convert to esm
|
// TODO: Remove this file in Babel 8
|
||||||
|
|
||||||
const Module = require("module");
|
const Module = require("module");
|
||||||
|
|
||||||
const globalModuleCache = Module._cache;
|
const globalModuleCache = Module._cache;
|
||||||
110
packages/babel-register/src/worker-client.js
Normal file
110
packages/babel-register/src/worker-client.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const ACTIONS = {
|
||||||
|
GET_DEFAULT_EXTENSIONS: "GET_DEFAULT_EXTENSIONS",
|
||||||
|
SET_OPTIONS: "SET_OPTIONS",
|
||||||
|
TRANSFORM: "TRANSFORM",
|
||||||
|
TRANSFORM_SYNC: "TRANSFORM_SYNC",
|
||||||
|
};
|
||||||
|
|
||||||
|
class Client {
|
||||||
|
#send;
|
||||||
|
|
||||||
|
constructor(send) {
|
||||||
|
this.#send = send;
|
||||||
|
}
|
||||||
|
|
||||||
|
#eCache;
|
||||||
|
/** @return {string[]} */
|
||||||
|
getDefaultExtensions() {
|
||||||
|
return (this.#eCache ??= this.#send(
|
||||||
|
ACTIONS.GET_DEFAULT_EXTENSIONS,
|
||||||
|
undefined,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} options
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
setOptions(options) {
|
||||||
|
return this.#send(ACTIONS.SET_OPTIONS, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} code
|
||||||
|
* @param {string} filename
|
||||||
|
* @return {{ code: string, map: object } | null}
|
||||||
|
*/
|
||||||
|
transform(code, filename) {
|
||||||
|
return this.#send(ACTIONS.TRANSFORM, { code, filename });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to run Babel in a worker because require hooks must
|
||||||
|
// run synchronously, but many steps of Babel's config loading
|
||||||
|
// (which is done for each file) can be asynchronous
|
||||||
|
exports.WorkerClient = class WorkerClient extends Client {
|
||||||
|
// These two require() calls are in deferred so that they are not imported in
|
||||||
|
// older Node.js versions (which don't support workers).
|
||||||
|
// TODO: Hoist them in Babel 8.
|
||||||
|
|
||||||
|
/** @type {typeof import("worker_threads")} */
|
||||||
|
static get #worker_threads() {
|
||||||
|
return require("worker_threads");
|
||||||
|
}
|
||||||
|
|
||||||
|
static get #markInRegisterWorker() {
|
||||||
|
return require("./is-in-register-worker").markInRegisterWorker;
|
||||||
|
}
|
||||||
|
|
||||||
|
#worker = new WorkerClient.#worker_threads.Worker(
|
||||||
|
path.resolve(__dirname, "./worker/index.js"),
|
||||||
|
{ env: WorkerClient.#markInRegisterWorker(process.env) },
|
||||||
|
);
|
||||||
|
|
||||||
|
#signal = new Int32Array(new SharedArrayBuffer(4));
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super((action, payload) => {
|
||||||
|
this.#signal[0] = 0;
|
||||||
|
const subChannel = new WorkerClient.#worker_threads.MessageChannel();
|
||||||
|
|
||||||
|
this.#worker.postMessage(
|
||||||
|
{ signal: this.#signal, port: subChannel.port1, action, payload },
|
||||||
|
[subChannel.port1],
|
||||||
|
);
|
||||||
|
|
||||||
|
Atomics.wait(this.#signal, 0, 0);
|
||||||
|
const { message } = WorkerClient.#worker_threads.receiveMessageOnPort(
|
||||||
|
subChannel.port2,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (message.error) throw Object.assign(message.error, message.errorData);
|
||||||
|
else return message.result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// The worker will never exit by itself. Prevent it from keeping
|
||||||
|
// the main process alive.
|
||||||
|
this.#worker.unref();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
exports.LocalClient = class LocalClient extends Client {
|
||||||
|
isLocalClient = true;
|
||||||
|
|
||||||
|
static #handleMessage;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
LocalClient.#handleMessage ??= require("./worker/handle-message");
|
||||||
|
|
||||||
|
super((action, payload) => {
|
||||||
|
return LocalClient.#handleMessage(
|
||||||
|
action === ACTIONS.TRANSFORM ? ACTIONS.TRANSFORM_SYNC : action,
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
20
packages/babel-register/src/worker/babel-core.js
Normal file
20
packages/babel-register/src/worker/babel-core.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
function initialize(babel) {
|
||||||
|
exports.init = null;
|
||||||
|
exports.version = babel.version;
|
||||||
|
exports.DEFAULT_EXTENSIONS = babel.DEFAULT_EXTENSIONS;
|
||||||
|
exports.loadOptionsAsync = babel.loadOptionsAsync;
|
||||||
|
exports.transformAsync = babel.transformAsync;
|
||||||
|
exports.getEnv = babel.getEnv;
|
||||||
|
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
exports.loadOptionsSync = babel.loadOptionsSync;
|
||||||
|
exports.transformSync = babel.transformSync;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.BABEL_8_BREAKING) {
|
||||||
|
// @ts-expect-error CJS-ESM interop.
|
||||||
|
exports.init = import("@babel/core").then(ns => initialize(ns.default));
|
||||||
|
} else {
|
||||||
|
initialize(require("@babel/core"));
|
||||||
|
}
|
||||||
@ -1,8 +1,10 @@
|
|||||||
import path from "path";
|
"use strict";
|
||||||
import fs from "fs";
|
|
||||||
import os from "os";
|
const path = require("path");
|
||||||
import * as babel from "@babel/core";
|
const fs = require("fs");
|
||||||
import findCacheDir from "find-cache-dir";
|
const os = require("os");
|
||||||
|
const babel = require("@babel/core");
|
||||||
|
const findCacheDir = require("find-cache-dir");
|
||||||
|
|
||||||
const DEFAULT_CACHE_DIR =
|
const DEFAULT_CACHE_DIR =
|
||||||
findCacheDir({ name: "@babel/register" }) || os.homedir() || os.tmpdir();
|
findCacheDir({ name: "@babel/register" }) || os.homedir() || os.tmpdir();
|
||||||
@ -10,8 +12,9 @@ const DEFAULT_FILENAME = path.join(
|
|||||||
DEFAULT_CACHE_DIR,
|
DEFAULT_CACHE_DIR,
|
||||||
`.babel.${babel.version}.${babel.getEnv()}.json`,
|
`.babel.${babel.version}.${babel.getEnv()}.json`,
|
||||||
);
|
);
|
||||||
const FILENAME: string = process.env.BABEL_CACHE_PATH || DEFAULT_FILENAME;
|
|
||||||
let data: any = {};
|
const FILENAME = process.env.BABEL_CACHE_PATH || DEFAULT_FILENAME;
|
||||||
|
let data = {};
|
||||||
|
|
||||||
let cacheDirty = false;
|
let cacheDirty = false;
|
||||||
|
|
||||||
@ -20,15 +23,16 @@ let cacheDisabled = false;
|
|||||||
function isCacheDisabled() {
|
function isCacheDisabled() {
|
||||||
return process.env.BABEL_DISABLE_CACHE ?? cacheDisabled;
|
return process.env.BABEL_DISABLE_CACHE ?? cacheDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.save = save;
|
||||||
/**
|
/**
|
||||||
* Write stringified cache to disk.
|
* Write stringified cache to disk.
|
||||||
*/
|
*/
|
||||||
|
function save() {
|
||||||
export function save() {
|
|
||||||
if (isCacheDisabled() || !cacheDirty) return;
|
if (isCacheDisabled() || !cacheDirty) return;
|
||||||
cacheDirty = false;
|
cacheDirty = false;
|
||||||
|
|
||||||
let serialised: string = "{}";
|
let serialised = "{}";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serialised = JSON.stringify(data, null, " ");
|
serialised = JSON.stringify(data, null, " ");
|
||||||
@ -74,7 +78,7 @@ because it resides in a readonly filesystem. Cache is disabled.`,
|
|||||||
* Load cache from disk and parse.
|
* Load cache from disk and parse.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function load() {
|
exports.load = function load() {
|
||||||
if (isCacheDisabled()) {
|
if (isCacheDisabled()) {
|
||||||
data = {};
|
data = {};
|
||||||
return;
|
return;
|
||||||
@ -106,27 +110,25 @@ due to a permission issue. Cache is disabled.`,
|
|||||||
try {
|
try {
|
||||||
data = JSON.parse(cacheContent);
|
data = JSON.parse(cacheContent);
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve data from cache.
|
* Retrieve data from cache.
|
||||||
*/
|
*/
|
||||||
|
exports.get = function get() {
|
||||||
export function get(): any {
|
|
||||||
return data;
|
return data;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the cache dirty bit.
|
* Set the cache dirty bit.
|
||||||
*/
|
*/
|
||||||
export function setDirty() {
|
exports.setDirty = function setDirty() {
|
||||||
cacheDirty = true;
|
cacheDirty = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the cache object.
|
* Clear the cache object.
|
||||||
*/
|
*/
|
||||||
|
exports.clear = function clear() {
|
||||||
export function clear() {
|
|
||||||
data = {};
|
data = {};
|
||||||
}
|
};
|
||||||
20
packages/babel-register/src/worker/handle-message.js
Normal file
20
packages/babel-register/src/worker/handle-message.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
const babel = require("./babel-core");
|
||||||
|
const { setOptions, transform, transformSync } = require("./transform");
|
||||||
|
|
||||||
|
module.exports = function handleMessage(action, payload) {
|
||||||
|
switch (action) {
|
||||||
|
case "GET_DEFAULT_EXTENSIONS":
|
||||||
|
return babel.DEFAULT_EXTENSIONS;
|
||||||
|
case "SET_OPTIONS":
|
||||||
|
setOptions(payload);
|
||||||
|
return;
|
||||||
|
case "TRANSFORM":
|
||||||
|
return transform(payload.code, payload.filename);
|
||||||
|
case "TRANSFORM_SYNC":
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
return transformSync(payload.code, payload.filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unknown internal parser worker action: ${action}`);
|
||||||
|
};
|
||||||
28
packages/babel-register/src/worker/index.js
Normal file
28
packages/babel-register/src/worker/index.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const babel = require("./babel-core");
|
||||||
|
const handleMessage = require("./handle-message");
|
||||||
|
|
||||||
|
const { parentPort } = require("worker_threads");
|
||||||
|
|
||||||
|
parentPort.addListener("message", async ({ signal, port, action, payload }) => {
|
||||||
|
let response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (babel.init) await babel.init;
|
||||||
|
|
||||||
|
response = { result: await handleMessage(action, payload) };
|
||||||
|
} catch (error) {
|
||||||
|
response = { error, errorData: { ...error } };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
port.postMessage(response);
|
||||||
|
} catch {
|
||||||
|
port.postMessage({
|
||||||
|
error: new Error("Cannot serialize worker response"),
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
port.close();
|
||||||
|
Atomics.store(signal, 0, 1);
|
||||||
|
Atomics.notify(signal, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
128
packages/babel-register/src/worker/transform.js
Normal file
128
packages/babel-register/src/worker/transform.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const cloneDeep = require("clone-deep");
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
const babel = require("./babel-core");
|
||||||
|
const registerCache = require("../cache");
|
||||||
|
|
||||||
|
const nmRE = escapeRegExp(path.sep + "node_modules" + path.sep);
|
||||||
|
|
||||||
|
function escapeRegExp(string) {
|
||||||
|
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache;
|
||||||
|
let transformOpts;
|
||||||
|
exports.setOptions = function (opts) {
|
||||||
|
if (opts.cache === false && cache) {
|
||||||
|
registerCache.clear();
|
||||||
|
cache = null;
|
||||||
|
} else if (opts.cache !== false && !cache) {
|
||||||
|
registerCache.load();
|
||||||
|
cache = registerCache.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete opts.cache;
|
||||||
|
delete opts.extensions;
|
||||||
|
|
||||||
|
transformOpts = {
|
||||||
|
...opts,
|
||||||
|
caller: {
|
||||||
|
name: "@babel/register",
|
||||||
|
...(opts.caller || {}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let { cwd = "." } = transformOpts;
|
||||||
|
|
||||||
|
// Ensure that the working directory is resolved up front so that
|
||||||
|
// things don't break if it changes later.
|
||||||
|
cwd = transformOpts.cwd = path.resolve(cwd);
|
||||||
|
|
||||||
|
if (transformOpts.ignore === undefined && transformOpts.only === undefined) {
|
||||||
|
const cwdRE = escapeRegExp(cwd);
|
||||||
|
|
||||||
|
// Only compile things inside the current working directory.
|
||||||
|
transformOpts.only = [new RegExp("^" + cwdRE, "i")];
|
||||||
|
// Ignore any node_modules inside the current working directory.
|
||||||
|
transformOpts.ignore = [
|
||||||
|
new RegExp(`^${cwdRE}(?:${path.sep}.*)?${nmRE}`, "i"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.transform = async function (input, filename) {
|
||||||
|
const opts = await babel.loadOptionsAsync({
|
||||||
|
// sourceRoot can be overwritten
|
||||||
|
sourceRoot: path.dirname(filename) + path.sep,
|
||||||
|
...cloneDeep(transformOpts),
|
||||||
|
filename,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bail out ASAP if the file has been ignored.
|
||||||
|
if (opts === null) return null;
|
||||||
|
|
||||||
|
const { cached, store } = cacheLookup(opts, filename);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
const { code, map } = await babel.transformAsync(input, {
|
||||||
|
...opts,
|
||||||
|
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
|
||||||
|
ast: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return store({ code, map });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
exports.transformSync = function (input, filename) {
|
||||||
|
const opts = babel.loadOptionsSync({
|
||||||
|
// sourceRoot can be overwritten
|
||||||
|
sourceRoot: path.dirname(filename) + path.sep,
|
||||||
|
...cloneDeep(transformOpts),
|
||||||
|
filename,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bail out ASAP if the file has been ignored.
|
||||||
|
if (opts === null) return null;
|
||||||
|
|
||||||
|
const { cached, store } = cacheLookup(opts, filename);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
const { code, map } = babel.transformSync(input, {
|
||||||
|
...opts,
|
||||||
|
sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
|
||||||
|
ast: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return store({ code, map });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = value => value;
|
||||||
|
|
||||||
|
function cacheLookup(opts, filename) {
|
||||||
|
if (!cache) return { cached: null, store: id };
|
||||||
|
|
||||||
|
let cacheKey = `${JSON.stringify(opts)}:${babel.version}`;
|
||||||
|
|
||||||
|
const env = babel.getEnv();
|
||||||
|
if (env) cacheKey += `:${env}`;
|
||||||
|
|
||||||
|
const cached = cache[cacheKey];
|
||||||
|
const fileMtime = +fs.statSync(filename).mtime;
|
||||||
|
|
||||||
|
if (cached && cached.mtime === fileMtime) {
|
||||||
|
return { cached: cached.value, store: id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
cached: null,
|
||||||
|
store(value) {
|
||||||
|
cache[cacheKey] = { value, mtime: fileMtime };
|
||||||
|
return value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@babel/transform-modules-commonjs"
|
"@babel/transform-modules-commonjs",
|
||||||
|
"@babel/plugin-transform-arrow-functions"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
1
packages/babel-register/test/fixtures/babelrc/log.js
vendored
Normal file
1
packages/babel-register/test/fixtures/babelrc/log.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
console.log("It worked!", (() => {}).toString());
|
||||||
@ -1,23 +1,10 @@
|
|||||||
const register = require('../../..');
|
const register = require('../../..');
|
||||||
|
|
||||||
// Plugin to add '/* transformed */' comment to start of function bodies
|
|
||||||
const plugin = () => ( {
|
|
||||||
visitor: {
|
|
||||||
Function(path) {
|
|
||||||
const bodyNode = path.node.body;
|
|
||||||
(bodyNode.leadingComments || (bodyNode.leadingComments = [])).push( {
|
|
||||||
type: 'CommentBlock',
|
|
||||||
value: ' transformed '
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
|
|
||||||
register( {
|
register( {
|
||||||
ignore: [],
|
ignore: [],
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
configFile: false,
|
configFile: false,
|
||||||
plugins: [plugin]
|
plugins: [require.resolve("./plugin")]
|
||||||
} );
|
} );
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
|
|||||||
13
packages/babel-register/test/fixtures/internal-modules/plugin.js
vendored
Normal file
13
packages/babel-register/test/fixtures/internal-modules/plugin.js
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Plugin to add '/* transformed */' comment to start of function bodies
|
||||||
|
|
||||||
|
module.exports = () => ( {
|
||||||
|
visitor: {
|
||||||
|
Function(path) {
|
||||||
|
const bodyNode = path.node.body;
|
||||||
|
(bodyNode.leadingComments || (bodyNode.leadingComments = [])).push( {
|
||||||
|
type: 'CommentBlock',
|
||||||
|
value: ' transformed '
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} );
|
||||||
3
packages/babel-register/test/fixtures/mjs-babelrc/.babelrc.mjs
vendored
Normal file
3
packages/babel-register/test/fixtures/mjs-babelrc/.babelrc.mjs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
plugins: ["@babel/transform-modules-commonjs"],
|
||||||
|
};
|
||||||
1
packages/babel-register/test/fixtures/mjs-babelrc/es2015.js
vendored
Normal file
1
packages/babel-register/test/fixtures/mjs-babelrc/es2015.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
import "assert";
|
||||||
@ -7,10 +7,12 @@ import { fileURLToPath } from "url";
|
|||||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
const registerFile = require.resolve("../lib/index");
|
|
||||||
const testCacheFilename = path.join(dirname, ".index.babel");
|
const testCacheFilename = path.join(dirname, ".index.babel");
|
||||||
const testFile = require.resolve("./fixtures/babelrc/es2015");
|
const testFile = require.resolve("./fixtures/babelrc/es2015");
|
||||||
const testFileContent = fs.readFileSync(testFile);
|
const testFileLog = require.resolve("./fixtures/babelrc/log");
|
||||||
|
const testFileMjs = require.resolve("./fixtures/mjs-babelrc/es2015");
|
||||||
|
const testFileContent = fs.readFileSync(testFile, "utf-8");
|
||||||
|
const testFileMjsContent = fs.readFileSync(testFileMjs, "utf-8");
|
||||||
|
|
||||||
const piratesPath = require.resolve("pirates");
|
const piratesPath = require.resolve("pirates");
|
||||||
const smsPath = require.resolve("source-map-support");
|
const smsPath = require.resolve("source-map-support");
|
||||||
@ -57,48 +59,13 @@ describe("@babel/register", function () {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let babelRegister;
|
|
||||||
|
|
||||||
function setupRegister(config = { babelrc: false }) {
|
|
||||||
process.env.BABEL_CACHE_PATH = testCacheFilename;
|
|
||||||
config = {
|
|
||||||
cwd: path.dirname(testFile),
|
|
||||||
...config,
|
|
||||||
};
|
|
||||||
|
|
||||||
babelRegister = require(registerFile);
|
|
||||||
babelRegister.default(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
function revertRegister() {
|
|
||||||
if (babelRegister) {
|
|
||||||
babelRegister.revert();
|
|
||||||
delete require.cache[registerFile];
|
|
||||||
babelRegister = null;
|
|
||||||
}
|
|
||||||
cleanCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
currentHook = null;
|
currentHook = null;
|
||||||
currentOptions = null;
|
currentOptions = null;
|
||||||
sourceMapSupport = false;
|
sourceMapSupport = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async () => {
|
let originalRequireCacheDescriptor;
|
||||||
// @babel/register saves the cache on process.nextTick.
|
|
||||||
// We need to wait for at least one tick so that when jest
|
|
||||||
// tears down the testing environment @babel/register has
|
|
||||||
// already finished.
|
|
||||||
await new Promise(setImmediate);
|
|
||||||
|
|
||||||
revertRegister();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
resetCache();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (OLD_JEST_MOCKS) {
|
if (OLD_JEST_MOCKS) {
|
||||||
jest.doMock("pirates", () => mocks["pirates"]);
|
jest.doMock("pirates", () => mocks["pirates"]);
|
||||||
jest.doMock("source-map-support", () => mocks["source-map-support"]);
|
jest.doMock("source-map-support", () => mocks["source-map-support"]);
|
||||||
@ -107,7 +74,6 @@ describe("@babel/register", function () {
|
|||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let originalRequireCacheDescriptor;
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
originalRequireCacheDescriptor = Object.getOwnPropertyDescriptor(
|
originalRequireCacheDescriptor = Object.getOwnPropertyDescriptor(
|
||||||
Module,
|
Module,
|
||||||
@ -115,9 +81,18 @@ describe("@babel/register", function () {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
Object.defineProperty(Module, "_cache", originalRequireCacheDescriptor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.env.BABEL_8_BREAKING) {
|
||||||
|
describe("babel 7", () => {
|
||||||
|
if (!OLD_JEST_MOCKS) {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const isEmptyObj = obj =>
|
const isEmptyObj = obj =>
|
||||||
Object.getPrototypeOf(obj) === null && Object.keys(obj).length === 0;
|
Object.getPrototypeOf(obj) === null &&
|
||||||
|
Object.keys(obj).length === 0;
|
||||||
|
|
||||||
// This setter intercepts the Module._cache assignment in
|
// This setter intercepts the Module._cache assignment in
|
||||||
// packages/babel-register/src/nodeWrapper.js to install in the
|
// packages/babel-register/src/nodeWrapper.js to install in the
|
||||||
@ -141,12 +116,85 @@ describe("@babel/register", function () {
|
|||||||
configurable: originalRequireCacheDescriptor.configurable,
|
configurable: originalRequireCacheDescriptor.configurable,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
afterAll(() => {
|
buildTests(require.resolve(".."));
|
||||||
Object.defineProperty(Module, "_cache", originalRequireCacheDescriptor);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nodeGte12 = (fn, ...args) => {
|
||||||
|
// "minNodeVersion": "8.0.0" <-- For Ctrl+F when dropping node 6-8-10
|
||||||
|
const testFn = /v(?:6|8|10)\./.test(process.version) ? fn.skip : fn;
|
||||||
|
testFn(...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
nodeGte12(describe, "worker", () => {
|
||||||
|
if (!OLD_JEST_MOCKS) {
|
||||||
|
beforeEach(() => {
|
||||||
|
Object.defineProperty(Module, "_cache", {
|
||||||
|
...originalRequireCacheDescriptor,
|
||||||
|
value: {
|
||||||
|
[piratesPath]: { exports: mocks["pirates"] },
|
||||||
|
[smsPath]: { exports: mocks["source-map-support"] },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { setupRegister } = buildTests(
|
||||||
|
require.resolve("../experimental-worker"),
|
||||||
|
);
|
||||||
|
|
||||||
|
it("works with mjs config files", () => {
|
||||||
|
setupRegister({
|
||||||
|
babelrc: true,
|
||||||
|
sourceMaps: false,
|
||||||
|
cwd: path.dirname(testFileMjs),
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = currentHook(testFileMjsContent, testFileMjs);
|
||||||
|
|
||||||
|
expect(result).toBe('"use strict";\n\nrequire("assert");');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTests(registerFile) {
|
||||||
|
let babelRegister;
|
||||||
|
|
||||||
|
function setupRegister(config = { babelrc: false }) {
|
||||||
|
process.env.BABEL_CACHE_PATH = testCacheFilename;
|
||||||
|
config = {
|
||||||
|
cwd: path.dirname(testFile),
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
|
babelRegister = require(registerFile);
|
||||||
|
babelRegister.default(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function revertRegister() {
|
||||||
|
if (babelRegister) {
|
||||||
|
babelRegister.revert();
|
||||||
|
delete require.cache[registerFile];
|
||||||
|
babelRegister = null;
|
||||||
|
}
|
||||||
|
cleanCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// @babel/register saves the cache on process.nextTick.
|
||||||
|
// We need to wait for at least one tick so that when jest
|
||||||
|
// tears down the testing environment @babel/register has
|
||||||
|
// already finished.
|
||||||
|
await new Promise(setImmediate);
|
||||||
|
|
||||||
|
revertRegister();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
resetCache();
|
||||||
|
});
|
||||||
|
|
||||||
test("registers hook correctly", () => {
|
test("registers hook correctly", () => {
|
||||||
setupRegister();
|
setupRegister();
|
||||||
|
|
||||||
@ -192,6 +240,54 @@ describe("@babel/register", function () {
|
|||||||
expect(sourceMapSupport).toBe(false);
|
expect(sourceMapSupport).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("node auto-require", () => {
|
||||||
|
it("works with the -r flag", async () => {
|
||||||
|
const output = await spawnNodeAsync(
|
||||||
|
["-r", registerFile, testFileLog],
|
||||||
|
path.dirname(testFileLog),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output.trim()).toMatchInlineSnapshot(
|
||||||
|
`"It worked! function () {}"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with the --require flag", async () => {
|
||||||
|
const output = await spawnNodeAsync(
|
||||||
|
["--require", registerFile, testFileLog],
|
||||||
|
path.dirname(testFileLog),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output.trim()).toMatchInlineSnapshot(
|
||||||
|
`"It worked! function () {}"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with the -r flag in NODE_OPTIONS", async () => {
|
||||||
|
const output = await spawnNodeAsync(
|
||||||
|
[testFileLog],
|
||||||
|
path.dirname(testFileLog),
|
||||||
|
{ NODE_OPTIONS: `-r ${registerFile}` },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output.trim()).toMatchInlineSnapshot(
|
||||||
|
`"It worked! function () {}"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with the --require flag in NODE_OPTIONS", async () => {
|
||||||
|
const output = await spawnNodeAsync(
|
||||||
|
[testFileLog],
|
||||||
|
path.dirname(testFileLog),
|
||||||
|
{ NODE_OPTIONS: `--require ${registerFile}` },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output.trim()).toMatchInlineSnapshot(
|
||||||
|
`"It worked! function () {}"`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("returns concatenatable sourceRoot and sources", async () => {
|
it("returns concatenatable sourceRoot and sources", async () => {
|
||||||
// The Source Maps R3 standard https://sourcemaps.info/spec.html states
|
// The Source Maps R3 standard https://sourcemaps.info/spec.html states
|
||||||
// that `sourceRoot` is “prepended to the individual entries in the
|
// that `sourceRoot` is “prepended to the individual entries in the
|
||||||
@ -247,10 +343,13 @@ describe("@babel/register", function () {
|
|||||||
const { convertSourceMap } = JSON.parse(output);
|
const { convertSourceMap } = JSON.parse(output);
|
||||||
expect(convertSourceMap).toMatch("/* transformed */");
|
expect(convertSourceMap).toMatch("/* transformed */");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { setupRegister, revertRegister };
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function spawnNodeAsync(args) {
|
function spawnNodeAsync(args, cwd = dirname, env) {
|
||||||
const spawn = child.spawn(process.execPath, args, { cwd: dirname });
|
const spawn = child.spawn(process.execPath, args, { cwd, env });
|
||||||
|
|
||||||
let output = "";
|
let output = "";
|
||||||
let callback;
|
let callback;
|
||||||
|
|||||||
@ -3494,6 +3494,7 @@ __metadata:
|
|||||||
resolution: "@babel/register@workspace:packages/babel-register"
|
resolution: "@babel/register@workspace:packages/babel-register"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core": "workspace:^"
|
"@babel/core": "workspace:^"
|
||||||
|
"@babel/plugin-transform-arrow-functions": "workspace:^"
|
||||||
"@babel/plugin-transform-modules-commonjs": "workspace:^"
|
"@babel/plugin-transform-modules-commonjs": "workspace:^"
|
||||||
browserify: ^16.5.2
|
browserify: ^16.5.2
|
||||||
clone-deep: ^4.0.1
|
clone-deep: ^4.0.1
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user