Skip to content

Commit

Permalink
feat(react): migrate webpack config (#14663)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Jan 27, 2023
1 parent 8bebf33 commit dba4a06
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 11 deletions.
6 changes: 6 additions & 0 deletions packages/react/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
"version": "15.3.0-beta.0",
"description": "Install new dependencies for React projects using Webpack or Rollup.",
"factory": "./src/migrations/update-15-3-0/install-webpack-rollup-dependencies"
},
"react-webpack-config-setup": {
"cli": "nx",
"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"
}
},
"packageJsonUpdates": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`15.6.3 migration (setup webpack.config file for React apps) should create webpack.config.js for React projects only 1`] = `
"
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Update the webpack config as needed here.
// e.g. config.plugins.push(new MyPlugin())
return config;
});
"
`;

exports[`15.6.3 migration (setup webpack.config file for React apps) should create webpack.config.js for React projects only 2`] = `
"
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Update the webpack config as needed here.
// e.g. config.plugins.push(new MyPlugin())
return config;
});
"
`;

exports[`15.6.3 migration (setup webpack.config file for React apps) should create webpack.config.js for React projects only 3`] = `
"
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Update the webpack config as needed here.
// e.g. config.plugins.push(new MyPlugin())
return config;
});
"
`;

exports[`15.6.3 migration (setup webpack.config file for React apps) should create webpack.config.js for React projects only 4`] = `
"
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Note: This was added by an Nx migration.
// You should consider inlining the logic into this file.
return require('./webpack.something.old.ts')(config, context);
});
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nrwl/devkit';
import webpackConfigSetup from './webpack-config-setup';

describe('15.6.3 migration (setup webpack.config file for React apps)', () => {
let tree: Tree;

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

addProjectConfiguration(tree, 'react1', {
root: 'apps/react1',
targets: {
build: {
executor: '@nrwl/webpack:webpack',
options: {
main: 'apps/react1/src/main.tsx',
webpackConfig: '@nrwl/react/plugins/webpack',
},
},
},
});
addProjectConfiguration(tree, 'react2', {
root: 'apps/react2',
targets: {
custom: {
executor: '@nrwl/webpack:webpack',
options: {
main: 'apps/react2/src/main.tsx',
},
},
},
});

addProjectConfiguration(tree, 'react3', {
root: 'apps/react3',
targets: {
custom: {
executor: '@nrwl/webpack:webpack',
options: {
webpackConfig: '@nrwl/react/plugins/webpack',
},
},
},
});

addProjectConfiguration(tree, 'react4', {
root: 'apps/react4',
targets: {
custom: {
executor: '@nrwl/webpack:webpack',
options: {
main: 'apps/react4/src/main.tsx',
webpackConfig: 'apps/react4/webpack.something.ts',
},
},
},
});
tree.write('apps/react4/webpack.something.ts', 'some content');

addProjectConfiguration(tree, 'app4', {
root: 'apps/app4',
targets: {
custom: {
executor: '@nrwl/webpack:webpack',
options: {
webpackConfig: 'some/random/path/webpack.something.ts',
},
},
},
});

tree.write('some/random/path/webpack.something.ts', 'some content');

addProjectConfiguration(tree, 'app5', {
root: 'apps/app5',
targets: {
custom: {
executor: '@nrwl/webpack:webpack',
options: {
isolatedConfig: true,
},
},
},
});

addProjectConfiguration(tree, 'app6', {
root: 'apps/app6',
targets: {
build: {
executor: '@nrwl/webpack:webpack',
options: {
main: 'apps/app6/src/main.ts',
},
},
},
});

await webpackConfigSetup(tree);
});

it('should create webpack.config.js for React projects only', () => {
expect(
tree.read('apps/react1/webpack.config.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('apps/react2/webpack.config.js', 'utf-8')
).toMatchSnapshot();
expect(
tree.read('apps/react3/webpack.config.js', 'utf-8')
).toMatchSnapshot();

expect(
tree.read('apps/react4/webpack.something.ts', 'utf-8')
).toMatchSnapshot();

expect(
tree.read('apps/react4/webpack.something.old.ts', 'utf-8')
).toMatchInlineSnapshot(`"some content"`);
});

it('should ignore non-react projects or isolatedConfig', () => {
expect(
tree.read('some/random/path/webpack.something.ts', 'utf-8')
).toMatchInlineSnapshot(`"some content"`);
expect(
tree.exists('some/random/path/webpack.something.old.ts')
).toBeFalsy();
expect(tree.exists('apps/app5/webpack.config.js')).toBeFalsy();
expect(tree.exists('apps/app6/webpack.config.js')).toBeFalsy();
});

it('should update the project configuration - executor options', () => {
expect(
readProjectConfiguration(tree, 'react1').targets.build.options
.webpackConfig
).toBe('apps/react1/webpack.config.js');
expect(
readProjectConfiguration(tree, 'react2').targets.custom.options
.webpackConfig
).toBe('apps/react2/webpack.config.js');

expect(
readProjectConfiguration(tree, 'react3').targets.custom.options
.webpackConfig
).toBe('apps/react3/webpack.config.js');

expect(
readProjectConfiguration(tree, 'react4').targets.custom.options
.webpackConfig
).toBe('apps/react4/webpack.something.ts');

expect(
readProjectConfiguration(tree, 'react1').targets.build.options
.isolatedConfig
).toBeTruthy();
expect(
readProjectConfiguration(tree, 'react2').targets.custom.options
.isolatedConfig
).toBeTruthy();

expect(
readProjectConfiguration(tree, 'react3').targets.custom.options
.isolatedConfig
).toBeTruthy();

expect(
readProjectConfiguration(tree, 'react4').targets.custom.options
.isolatedConfig
).toBeTruthy();
});
});
128 changes: 128 additions & 0 deletions packages/react/src/migrations/update-15-6-3/webpack-config-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import {
formatFiles,
logger,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { basename } from 'path';

export default async function (tree: Tree) {
forEachExecutorOptions(
tree,
'@nrwl/webpack:webpack',
(options: {}, projectName, targetName, _configurationName) => {
// If isolatedConfig is set, we don't need to do anything
// If it is NOT React, we don't need to do anything
if (
options?.['isolatedConfig'] ||
!(
options?.['main']?.match(/main\.(t|j)sx$/) ||
options?.['webpackConfig'] === '@nrwl/react/plugins/webpack'
)
) {
return;
}

// If webpackConfig is set, update it with the new options
// If webpackConfig is not set, we need to create a new
// webpack.config.js file and set the path to it in the
// executor options

if (
options?.['webpackConfig'] &&
options['webpackConfig'] !== '@nrwl/react/plugins/webpack'
) {
let oldName = options['webpackConfig'];
if (options['webpackConfig'].endsWith('.js')) {
oldName = options['webpackConfig'].replace('.js', '.old.js');
}
if (options['webpackConfig'].endsWith('.ts')) {
oldName = options['webpackConfig'].replace('.ts', '.old.ts');
}

renameFile(tree, options['webpackConfig'], oldName);

const justTheFileName = basename(oldName);
tree.write(
options['webpackConfig'],
`
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Note: This was added by an Nx migration.
// You should consider inlining the logic into this file.
return require('./${justTheFileName}')(config, context);
});
`
);

options['isolatedConfig'] = true;

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

logger.info(
`
${options['webpackConfig']} has been renamed to ${oldName} and a new ${options['webpackConfig']}
has been created for your project ${projectName}.
You should consider inlining the logic from ${oldName} into ${options['webpackConfig']}.
You can read our guide on how to do this here:
https://nx.dev/packages/webpack/documents/webpack-config-setup
`
);
} else {
const projectConfiguration = readProjectConfiguration(
tree,
projectName
);

if (!options) {
options = {};
}

options[
'webpackConfig'
] = `${projectConfiguration.root}/webpack.config.js`;
options['isolatedConfig'] = true;

tree.write(
options['webpackConfig'],
`
const { composePlugins, withNx } = require('@nrwl/webpack');
const { withReact } = require('@nrwl/react');
// Nx plugins for webpack.
module.exports = composePlugins(withNx(), withReact(), (config, { options, context }) => {
// Update the webpack config as needed here.
// e.g. config.plugins.push(new MyPlugin())
return config;
});
`
);

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

await formatFiles(tree);
}

function renameFile(tree: Tree, from: string, to: string) {
const buffer = tree.read(from);
if (!buffer) {
return;
}
tree.write(to, buffer);
tree.delete(from);
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ exports[`15.6.3 migration (setup webpack.config file) should rename existing web
module.exports = composePlugins(withNx(), (config, { options, context }) => {
// Note: This was added by an Nx migration.
// You should consider inlining the logic into this file.
return require('./webpack.config.js')(config, context);
return require('./webpack.config.old.js')(config, context);
});
"
`;
Expand All @@ -47,7 +47,7 @@ exports[`15.6.3 migration (setup webpack.config file) should rename existing web
module.exports = composePlugins(withNx(), (config, { options, context }) => {
// Note: This was added by an Nx migration.
// You should consider inlining the logic into this file.
return require('./webpack.something.ts')(config, context);
return require('./webpack.something.old.ts')(config, context);
});
"
`;

0 comments on commit dba4a06

Please sign in to comment.