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

fix: babel-register transform internal dependencies #12665

Merged
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/babel-register/package.json
Expand Up @@ -14,7 +14,7 @@
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"main": "lib/index.js",
"browser": {
"./lib/node.js": "./lib/browser.js"
"./lib/nodeWrapper.js": "./lib/browser.js"
},
"dependencies": {
"find-cache-dir": "^2.0.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-register/src/index.js
Expand Up @@ -9,7 +9,7 @@ exports = module.exports = function (...args) {
};
exports.__esModule = true;

const node = require("./node");
const node = require("./nodeWrapper");
const register = node.default;

Object.assign(exports, node);
5 changes: 5 additions & 0 deletions packages/babel-register/src/node.js
Expand Up @@ -7,6 +7,7 @@ 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 = {};
Expand Down Expand Up @@ -82,15 +83,19 @@ function compile(code, filename) {
}

let compiling = false;
const internalModuleCache = Module._cache;

function compileHook(code, filename) {
if (compiling) return code;

const globalModuleCache = Module._cache;
try {
compiling = true;
Module._cache = internalModuleCache;
return compile(code, filename);
} finally {
compiling = false;
Module._cache = globalModuleCache;
}
}

Expand Down
21 changes: 21 additions & 0 deletions packages/babel-register/src/nodeWrapper.js
@@ -0,0 +1,21 @@
/**
* This file wraps the implementation of register so all modules `require()`-ed
* internally within register are stored in a separate module cache.
* This prevents un-transformed modules being stored in global module cache,
* and allows register to transform these modules if they are loaded externally.
*/

const Module = require("module");

const globalModuleCache = Module._cache;
const internalModuleCache = Object.create(null);

Module._cache = internalModuleCache;
const node = require("./node");
Module._cache = globalModuleCache;

// Add source-map-support to global cache as it's stateful
const smsPath = require.resolve("source-map-support");
globalModuleCache[smsPath] = internalModuleCache[smsPath];

module.exports = node;
28 changes: 28 additions & 0 deletions packages/babel-register/test/fixtures/internal-modules/index.js
@@ -0,0 +1,28 @@
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( {
ignore: [],
babelrc: false,
configFile: false,
plugins: [plugin]
} );

console.log(
JSON.stringify({
convertSourceMap: require('convert-source-map').fromObject.toString(),
isPlainObject: require('lodash/isPlainObject').toString()
})
);
54 changes: 41 additions & 13 deletions packages/babel-register/test/index.js
Expand Up @@ -6,14 +6,17 @@ let currentHook;
let currentOptions;
let sourceMapSupport = false;

const registerFile = require.resolve("../lib/node");
const registerFile = require.resolve("../lib/index");
const testCacheFilename = path.join(__dirname, ".babel");
const testFile = require.resolve("./fixtures/babelrc/es2015");
const testFileContent = fs.readFileSync(testFile);
const sourceMapTestFile = require.resolve("./fixtures/source-map/index");
const sourceMapNestedTestFile = require.resolve(
"./fixtures/source-map/foo/bar",
);
const internalModulesTestFile = require.resolve(
"./fixtures/internal-modules/index",
);

jest.mock("pirates", () => {
return {
Expand Down Expand Up @@ -152,18 +155,7 @@ describe("@babel/register", function () {
// that working inside a test, possibly because of jest’s mocking
// hooks, so we spawn a separate process.

const args = ["-r", registerFile, sourceMapTestFile];
const spawn = child.spawn(process.execPath, args, { cwd: __dirname });

let output = "";

for (const stream of [spawn.stderr, spawn.stdout]) {
stream.on("data", chunk => {
output += chunk;
});
}

spawn.on("close", function () {
spawnNode(["-r", registerFile, sourceMapTestFile], output => {
let err;

try {
Expand Down Expand Up @@ -201,4 +193,40 @@ describe("@babel/register", function () {

expect(result).toBe('"use strict";\n\nrequire("assert");');
});

test("transforms modules used within register", callback => {
// Need a clean environment without `convert-source-map`
// and `lodash/isPlainObject` already in the require cache,
// so we spawn a separate process

spawnNode([internalModulesTestFile], output => {
let err;

try {
const { convertSourceMap, isPlainObject } = JSON.parse(output);
expect(convertSourceMap).toMatch("/* transformed */");
expect(isPlainObject).toMatch("/* transformed */");
} catch (e) {
err = e;
}

callback(err);
});
});
});

function spawnNode(args, callback) {
const spawn = child.spawn(process.execPath, args, { cwd: __dirname });

let output = "";

for (const stream of [spawn.stderr, spawn.stdout]) {
stream.on("data", chunk => {
output += chunk;
});
}

spawn.on("close", function () {
callback(output);
});
}