fix(webpack): add babelUpwardRootMode (#15061)
This commit is contained in:
parent
2011e29dc3
commit
5d54f71398
@ -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"],
|
||||
|
||||
@ -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": [],
|
||||
|
||||
@ -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`,
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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';
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,6 @@ import storiesGenerator from '../stories/stories';
|
||||
import {
|
||||
convertNxGenerator,
|
||||
ensurePackage,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
readProjectConfiguration,
|
||||
Tree,
|
||||
@ -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',
|
||||
|
||||
@ -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 = [
|
||||
{
|
||||
|
||||
@ -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": {}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"],
|
||||
|
||||
@ -9,4 +9,5 @@ export interface WebpackProjectGeneratorSchema {
|
||||
skipValidation?: boolean;
|
||||
target?: 'node' | 'web';
|
||||
webpackConfig?: string;
|
||||
babelConfig?: string;
|
||||
}
|
||||
|
||||
@ -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": []
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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();
|
||||
});
|
||||
});
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user