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(webpack): add babelUpwardRootMode #15061

Merged
merged 1 commit into from
Feb 17, 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
10 changes: 10 additions & 0 deletions docs/generated/packages/webpack/executors/webpack.json
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,16 @@
"x-completion-type": "file",
"x-completion-glob": "webpack?(*)@(.js|.ts)",
"x-priority": "important"
},
"babelUpwardRootMode": {
"type": "boolean",
"description": "Whether to set rootmode to upward. See https://babeljs.io/docs/en/options#rootmode",
"default": false
},
"babelConfig": {
"type": "string",
"description": "Path to the babel configuration file of your project. If not provided, Nx will default to the .babelrc file at the root of your project. See https://babeljs.io/docs/en/config-files",
"x-completion-type": "file"
}
},
"required": ["tsConfig", "main"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
"type": "string",
"description": "Path relative to workspace root to a custom webpack file that takes a config object and returns an updated config.",
"x-priority": "internal"
},
"babelConfig": {
"type": "string",
"description": "Optionally specify a path relative to workspace root to the babel configuration file of your project.",
"x-completion-type": "file"
}
},
"required": [],
Expand Down
7 changes: 0 additions & 7 deletions e2e/js/src/js-tsc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ describe('js e2e', () => {
const libPackageJson = readJson(`libs/${lib}/package.json`);
expect(libPackageJson.scripts).toBeUndefined();

// Since `@nrwl/web` is installed in workspace, .babelrc and babel preset are needed for this lib
const babelRc = readJson(`libs/${lib}/.babelrc`);
expect(babelRc.plugins).toBeUndefined();
expect(babelRc.presets).toStrictEqual([
['@nrwl/js/babel', { useBuiltIns: 'usage' }],
]);

expect(runCLI(`build ${lib}`)).toContain('Done compiling TypeScript files');
checkFilesExist(
`dist/libs/${lib}/README.md`,
Expand Down
32 changes: 0 additions & 32 deletions packages/js/src/generators/library/library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -927,38 +927,6 @@ describe('lib', () => {
`);
});

it('should generate a .babelrc when flag is not set and there is a `@nrwl/web` package installed', async () => {
updateJson(tree, 'package.json', (json) => {
json.devDependencies = {
'@nrwl/web': '1.1.1',
'@nrwl/react': '1.1.1',
'@nrwl/next': '1.1.1',
};
return json;
});

await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
includeBabelRc: undefined,
});

expect(tree.exists('libs/my-lib/.babelrc')).toBeTruthy();

const babelRc = readJson(tree, 'libs/my-lib/.babelrc');
expect(babelRc).toMatchInlineSnapshot(`
Object {
"presets": Array [
Array [
"@nrwl/js/babel",
Object {
"useBuiltIns": "usage",
},
],
],
}
`);
});
it('should not generate a .babelrc when flag is not set and there is NOT a `@nrwl/web` package installed', async () => {
updateJson(tree, 'package.json', (json) => {
json.devDependencies = {
Expand Down
30 changes: 5 additions & 25 deletions packages/js/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ function addProject(
},
};

if (options.bundler === 'webpack') {
projectConfiguration.targets.build.options.babelUpwardRootMode = true;
}

if (options.compiler === 'swc' && options.skipTypeCheck) {
projectConfiguration.targets.build.options.skipTypeCheck = true;
}
Expand Down Expand Up @@ -234,30 +238,6 @@ function updateTsConfig(tree: Tree, options: NormalizedSchema) {
});
}

/**
* Currently `@nrwl/js:library` TypeScript files can be compiled by most NX applications scaffolded via the Plugin system. However, `@nrwl/react:app` is an exception that due to its babel configuration, won't transpile external TypeScript files from packages/libs that do not contain a .babelrc.
*
* If a user doesn't explicitly set the flag, to prevent breaking the experience (they see the application failing, and they need to manually add the babelrc themselves), we want to detect whether they have the `@nrwl/web` plugin installed, and generate it automatically for them (even when they do not explicity request it).
*
* You can find more details on why this is necessary here:
* https://github.com/nrwl/nx/pull/10055
*/
function shouldAddBabelRc(tree: Tree, options: NormalizedSchema) {
if (typeof options.includeBabelRc === 'undefined') {
const webPluginName = '@nrwl/web';

const packageJson = readJson(tree, 'package.json');

const hasNxWebPlugin = Object.keys(
packageJson.devDependencies as Record<string, string>
).includes(webPluginName);

return hasNxWebPlugin;
}

return options.includeBabelRc;
}

function addBabelRc(tree: Tree, options: NormalizedSchema) {
const filename = '.babelrc';

Expand Down Expand Up @@ -289,7 +269,7 @@ function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) {
if (options.compiler === 'swc') {
addSwcDependencies(tree);
addSwcConfig(tree, options.projectRoot);
} else if (shouldAddBabelRc(tree, options)) {
} else if (options.includeBabelRc) {
addBabelRc(tree, options);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import storiesGenerator from '../stories/stories';
import {
convertNxGenerator,
ensurePackage,
joinPathFragments,
logger,
readProjectConfiguration,
Tree,
Expand Down Expand Up @@ -54,42 +53,6 @@ export async function storybookConfigurationGenerator(
}
}

/**
* If it's library and there's no .babelrc file,
* we need to generate one if it's not using vite.
*
* The reason is that it will be using webpack for Storybook,
* and webpack needs the babelrc file to be present.
*
* The reason the babelrc file is not there in the first place,
* is because the vitest generator deletes it, since it
* does not need it.
* See:
* packages/react/src/generators/library/lib/create-files.ts#L42
*/

if (
bundler !== 'vite' &&
projectConfig.projectType === 'library' &&
!host.exists(joinPathFragments(projectConfig.root, '.babelrc'))
) {
host.write(
joinPathFragments(projectConfig.root, '.babelrc'),
JSON.stringify({
presets: [
[
'@nrwl/react/babel',
{
runtime: 'automatic',
useBuiltIns: 'usage',
},
],
],
plugins: [],
})
);
}

const installTask = await configurationGenerator(host, {
name: schema.name,
uiFramework: '@storybook/react',
Expand Down
4 changes: 4 additions & 0 deletions packages/web/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
buildOptions.styles = [
joinPathFragments(options.appProjectRoot, `src/styles.${options.style}`),
];
// We can delete that, because this projest is an application
// and applications have a .babelrc file in their root dir.
// So Nx will find it and use it
delete buildOptions.babelUpwardRootMode;
buildOptions.scripts = [];
prodConfig.fileReplacements = [
{
Expand Down
6 changes: 6 additions & 0 deletions packages/webpack/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
"version": "15.6.3-beta.0",
"description": "Creates or updates webpack.config.js file with the new options for webpack.",
"factory": "./src/migrations/update-15-6-3/webpack-config-setup"
},
"add-babelUpwardRootMode-flag": {
"cli": "nx",
"version": "15.7.2-beta.0",
"description": "Add the babelUpwardRootMode option to the build executor options.",
"factory": "./src/migrations/update-15-7-2/add-babelUpwardRootMode-flag"
}
},
"packageJsonUpdates": {}
Expand Down
2 changes: 2 additions & 0 deletions packages/webpack/src/executors/webpack/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export interface WebpackExecutorOptions {
verbose?: boolean;
watch?: boolean;
webpackConfig?: string;
babelConfig?: string;
babelUpwardRootMode?: boolean;
// TODO(jack): Also deprecate these in schema.json once we have migration from executor options to webpack.config.js file.
/** @deprecated Moved to withWeb options from `@nrwl/webpack` */
baseHref?: string;
Expand Down
10 changes: 10 additions & 0 deletions packages/webpack/src/executors/webpack/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,16 @@
"x-completion-type": "file",
"x-completion-glob": "webpack?(*)@(.js|.ts)",
"x-priority": "important"
},
"babelUpwardRootMode": {
"type": "boolean",
"description": "Whether to set rootmode to upward. See https://babeljs.io/docs/en/options#rootmode",
"default": false
},
"babelConfig": {
"type": "string",
"description": "Path to the babel configuration file of your project. If not provided, Nx will default to the .babelrc file at the root of your project. See https://babeljs.io/docs/en/config-files",
"x-completion-type": "file"
}
},
"required": ["tsConfig", "main"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export interface WebpackProjectGeneratorSchema {
skipValidation?: boolean;
target?: 'node' | 'web';
webpackConfig?: string;
babelConfig?: string;
}
5 changes: 5 additions & 0 deletions packages/webpack/src/generators/webpack-project/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
"type": "string",
"description": "Path relative to workspace root to a custom webpack file that takes a config object and returns an updated config.",
"x-priority": "internal"
},
"babelConfig": {
"type": "string",
"description": "Optionally specify a path relative to workspace root to the babel configuration file of your project.",
"x-completion-type": "file"
}
},
"required": []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ function addBuildTarget(tree: Tree, options: WebpackProjectGeneratorSchema) {
buildOptions.webpackConfig = options.webpackConfig;
}

if (options.babelConfig) {
buildOptions.babelConfig = options.babelConfig;
} else {
buildOptions.babelUpwardRootMode = true;
}

updateProjectConfiguration(tree, options.project, {
...project,
targets: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import addBabelUpwardRootModeFlag from './add-babelUpwardRootMode-flag';

describe('15.7.2 migration (add babelUpwardRootMode flag)', () => {
let tree: Tree;

beforeEach(async () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});

it('should add the babelUpwardRootMode flag to webpack projects', async () => {
addProjectConfiguration(tree, 'app1', {
root: 'apps/app1',
targets: {
build: {
executor: '@nrwl/webpack:webpack',
options: {},
},
},
});
addProjectConfiguration(tree, 'app2', {
root: 'apps/app2',
targets: {
build: {
executor: '@nrwl/webpack:webpack',
options: {
babelUpwardRootMode: false,
},
},
},
});

addProjectConfiguration(tree, 'app3', {
root: 'apps/app3',
targets: {
build: {
executor: '@nrwl/vite:build',
options: {},
},
},
});
await addBabelUpwardRootModeFlag(tree);

const app1 = readProjectConfiguration(tree, 'app1');
const app2 = readProjectConfiguration(tree, 'app2');
const app3 = readProjectConfiguration(tree, 'app3');

expect(app1.targets['build'].options.babelUpwardRootMode).toBeTruthy();
expect(app2.targets['build'].options.babelUpwardRootMode).toBeFalsy();
expect(app3.targets['build'].options.babelUpwardRootMode).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { WebpackExecutorOptions } from '../../executors/webpack/schema';

export default async function (tree: Tree) {
forEachExecutorOptions<WebpackExecutorOptions>(
tree,
'@nrwl/webpack:webpack',
(
options: WebpackExecutorOptions,
projectName,
targetName,
_configurationName
) => {
if (options.babelUpwardRootMode !== undefined) {
return;
}

const projectConfiguration = readProjectConfiguration(tree, projectName);
projectConfiguration.targets[targetName].options.babelUpwardRootMode =
true;
updateProjectConfiguration(tree, projectName, projectConfiguration);
}
);

await formatFiles(tree);
}
16 changes: 13 additions & 3 deletions packages/webpack/src/utils/with-nx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,21 +350,31 @@ export function createLoaderFromCompiler(
};
case 'babel':
const tsConfig = readTsConfig(options.tsConfig);
return {

const babelConfig = {
test: /\.([jt])sx?$/,
loader: path.join(__dirname, './web-babel-loader'),
exclude: /node_modules/,
options: {
rootMode: 'upward',
cwd: path.join(options.root, options.sourceRoot),
emitDecoratorMetadata: tsConfig.options.emitDecoratorMetadata,
isModern: true,
envName: process.env.NODE_ENV,
babelrc: true,
cacheDirectory: true,
cacheCompression: false,
},
};

if (options.babelUpwardRootMode) {
babelConfig.options['rootMode'] = 'upward';
babelConfig.options['babelrc'] = true;
} else {
babelConfig.options['configFile'] =
babelConfig.options?.['babelConfig'] ??
path.join(options.root, options.projectRoot, '.babelrc');
}

return babelConfig;
default:
return null;
}
Expand Down