From bb5ad3d1adaebb42514750b12d8f7470d66a7bd9 Mon Sep 17 00:00:00 2001 From: Andrew Stegmaier Date: Tue, 25 Feb 2020 00:24:03 -0800 Subject: [PATCH] Resolve .babelrc files in a monorepo. (#4132) * Resolve .babelrc files in a monorepo. * Resolve .babelrc files in a monorepo. * Add a unit test. Co-authored-by: Jasper De Moor --- packages/core/integration-tests/test/babel.js | 17 +++++++++++++++++ .../babel-plugin-dummy-1.js | 13 +++++++++++++ .../babel-config-monorepo/babel.config.json | 4 ++++ .../babel-config-monorepo/package.json | 5 +++++ .../packages/pkg-a/.babelrc | 4 ++++ .../packages/pkg-a/babel-plugin-dummy-2.js | 13 +++++++++++++ .../packages/pkg-a/package.json | 3 +++ .../packages/pkg-a/src/index.js | 6 ++++++ .../packages/pkg-b/.babelrc | 4 ++++ .../packages/pkg-b/babel-plugin-dummy-3.js | 13 +++++++++++++ .../packages/pkg-b/package.json | 3 +++ .../packages/pkg-b/src/index.js | 6 ++++++ .../integration/babel-config-monorepo/yarn.lock | 0 packages/transformers/babel/src/config.js | 17 ++++++++++++++++- 14 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/babel-plugin-dummy-1.js create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/babel.config.json create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/package.json create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/.babelrc create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/babel-plugin-dummy-2.js create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/package.json create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/src/index.js create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/.babelrc create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/babel-plugin-dummy-3.js create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/package.json create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/src/index.js create mode 100644 packages/core/integration-tests/test/integration/babel-config-monorepo/yarn.lock diff --git a/packages/core/integration-tests/test/babel.js b/packages/core/integration-tests/test/babel.js index 5e3cdb9fe56..ce7af718e7c 100644 --- a/packages/core/integration-tests/test/babel.js +++ b/packages/core/integration-tests/test/babel.js @@ -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); diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/babel-plugin-dummy-1.js b/packages/core/integration-tests/test/integration/babel-config-monorepo/babel-plugin-dummy-1.js new file mode 100644 index 00000000000..84a71046f9e --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/babel-plugin-dummy-1.js @@ -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'; + } + } + } + }; +}; diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/babel.config.json b/packages/core/integration-tests/test/integration/babel-config-monorepo/babel.config.json new file mode 100644 index 00000000000..c23544defb4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/babel.config.json @@ -0,0 +1,4 @@ +{ + "plugins": ["./babel-plugin-dummy-1"] +} + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/package.json b/packages/core/integration-tests/test/integration/babel-config-monorepo/package.json new file mode 100644 index 00000000000..9c4571efe3f --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/package.json @@ -0,0 +1,5 @@ +{ + "name": "monorepo-babel-config", + "private": true, + "workspaces": ["pkg-a", "pkg-b"] +} diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/.babelrc b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/.babelrc new file mode 100644 index 00000000000..a81743d9dc1 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/.babelrc @@ -0,0 +1,4 @@ +{ + "plugins": ["./babel-plugin-dummy-2"] +} + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/babel-plugin-dummy-2.js b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/babel-plugin-dummy-2.js new file mode 100644 index 00000000000..6515adf48e7 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/babel-plugin-dummy-2.js @@ -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'; + } + } + } + }; +}; diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/package.json b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/package.json new file mode 100644 index 00000000000..81099b949a4 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/package.json @@ -0,0 +1,3 @@ +{ + "name": "pkg-a" +} diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/src/index.js b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/src/index.js new file mode 100644 index 00000000000..6843dcf4b19 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-a/src/index.js @@ -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; +} diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/.babelrc b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/.babelrc new file mode 100644 index 00000000000..4cd6363f5e0 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/.babelrc @@ -0,0 +1,4 @@ +{ + "plugins": ["./babel-plugin-dummy-3"] +} + \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/babel-plugin-dummy-3.js b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/babel-plugin-dummy-3.js new file mode 100644 index 00000000000..a80a084a288 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/babel-plugin-dummy-3.js @@ -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'; + } + } + } + }; +}; diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/package.json b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/package.json new file mode 100644 index 00000000000..91f03c8d09c --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/package.json @@ -0,0 +1,3 @@ +{ + "name": "pkg-b" +} diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/src/index.js b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/src/index.js new file mode 100644 index 00000000000..6843dcf4b19 --- /dev/null +++ b/packages/core/integration-tests/test/integration/babel-config-monorepo/packages/pkg-b/src/index.js @@ -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; +} diff --git a/packages/core/integration-tests/test/integration/babel-config-monorepo/yarn.lock b/packages/core/integration-tests/test/integration/babel-config-monorepo/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/transformers/babel/src/config.js b/packages/transformers/babel/src/config.js index 57068ab2e9f..54cb94471b5 100644 --- a/packages/transformers/babel/src/config.js +++ b/packages/transformers/babel/src/config.js @@ -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'; @@ -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); + } + } + let babelCore = await options.packageManager.require( '@babel/core', config.searchPath, @@ -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)