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

Resolve .babelrc files in a monorepo. #4132

Merged
merged 8 commits into from
Feb 25, 2020
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
17 changes: 17 additions & 0 deletions packages/core/integration-tests/test/babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,23 @@ describe('babel', function() {
assert(file.includes('hello there'));
});

it('should support merging .babelrc and babel.config.json in a monorepo', async function() {
await bundle(
path.join(
__dirname,
'/integration/babel-config-monorepo/packages/pkg-a/src/index.js',
),
);

let file = await outputFS.readFile(path.join(distDir, 'index.js'), 'utf8');
assert(!file.includes('REPLACE_ME'));
assert(file.includes('string from a plugin in babel.config.json'));
assert(!file.includes('ANOTHER_THING_TO_REPLACE'));
assert(file.includes('string from a plugin in .babelrc'));
assert(file.includes('SOMETHING ELSE'));
assert(!file.includes('string from a plugin from a different sub-package'));
});

describe('tests needing the real filesystem', () => {
beforeEach(async () => {
await fs.rimraf(inputDir);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = () => {
return {
visitor: {
StringLiteral(path, state) {
const opts = state.opts;

if (path.node.value === 'REPLACE_ME') {
path.node.value = 'string from a plugin in babel.config.json';
}
}
}
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"plugins": ["./babel-plugin-dummy-1"]
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "monorepo-babel-config",
"private": true,
"workspaces": ["pkg-a", "pkg-b"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"plugins": ["./babel-plugin-dummy-2"]
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = () => {
return {
visitor: {
StringLiteral(path, state) {
const opts = state.opts;

if (path.node.value === 'ANOTHER_THING_TO_REPLACE') {
path.node.value = 'string from a plugin in .babelrc';
}
}
}
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "pkg-a"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = function() {
const thing1 = "REPLACE_ME";
const thing2 = "ANOTHER_THING_TO_REPLACE"
const thing3 = "SOMETHING ELSE"
return thing1 + thing2 + thing3;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"plugins": ["./babel-plugin-dummy-3"]
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = () => {
return {
visitor: {
StringLiteral(path, state) {
const opts = state.opts;

if (path.node.value === 'ANOTHER_THING_TO_REPLACE') {
path.node.value = 'string from a plugin from a different sub-package';
}
}
}
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "pkg-b"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = function() {
const thing1 = "REPLACE_ME";
const thing2 = "ANOTHER_THING_TO_REPLACE"
const thing3 = "SOMETHING ELSE"
return thing1 + thing2 + thing3;
}
17 changes: 16 additions & 1 deletion packages/transformers/babel/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {PluginLogger} from '@parcel/logger';
import nullthrows from 'nullthrows';
import path from 'path';
import * as bundledBabelCore from '@babel/core';
import {md5FromObject} from '@parcel/utils';
import {md5FromObject, resolveConfig} from '@parcel/utils';

import getEnvOptions from './env';
import getJSXOptions from './jsx';
Expand All @@ -29,6 +29,20 @@ export async function load(
return buildDefaultBabelConfig(config);
}

// If we are in a monorepo, also find .babelrc configs in the sub packages.
let babelrcRoots = [options.projectRoot];
let packageJSONPath = await resolveConfig(
options.inputFS,
config.searchPath,
['package.json'],
);
if (packageJSONPath) {
let packageRoot = path.dirname(packageJSONPath);
if (packageRoot && packageRoot !== options.projectRoot) {
babelrcRoots.push(packageRoot);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably also need to track the package.json paths we searched as part of the config so it will be invalidated in the cache properly. Maybe a glob? cc. @padmaia

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, I guess that never got set. Easy to add though, it's just a call to config.setWatchGlob().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I fully understand how the cache invalidation works - could you elaborate on what you expect to happen (but isn't already), and how I might be able to test it?

In case it's relevant, one thing to note is that the sub-project babel config might be specified in a .babelrc/babelrc.json file in the sub-package directory, or as part of the babel property of the package.json file. Presumably, we'd want to make sure that the bundle will get regenerated if any of these change (and do whatever is necessary to keep the cache clean). Given this, are there any other tweaks you think might be necessary?

}
}

let babelCore = await options.packageManager.require(
'@babel/core',
config.searchPath,
Expand All @@ -38,6 +52,7 @@ export async function load(
filename: config.searchPath,
cwd: path.dirname(config.searchPath),
root: options.projectRoot,
babelrcRoots,
});

// loadPartialConfig returns null when the file should explicitly not be run through babel (ignore/exclude)
Expand Down