From 85606a45ea7e5affb886f2351163f015bb080352 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Thu, 26 Jan 2023 17:10:34 +0200 Subject: [PATCH] feat(webpack): migrate to webpack.config file (#14607) --- docs/generated/manifests/menus.json | 25 ++++ docs/generated/manifests/packages.json | 25 +++- docs/generated/packages-metadata.json | 25 +++- .../webpack/documents/webpack-config-setup.md | 108 ++++++++++++++ .../webpack/documents/webpack-plugins.md | 9 ++ .../packages/webpack/executors/webpack.json | 1 + docs/map.json | 19 +++ .../packages/webpack/webpack-config-setup.md | 108 ++++++++++++++ .../packages/webpack/webpack-plugins.md | 9 ++ .../docs/webpack-build-executor-examples.md | 90 ++++++++++++ packages/webpack/migrations.json | 18 ++- .../webpack/src/executors/webpack/schema.json | 3 +- .../webpack-config-setup.spec.ts.snap | 53 +++++++ .../webpack-config-setup.spec.ts | 139 ++++++++++++++++++ .../update-15-6-3/webpack-config-setup.ts | 123 ++++++++++++++++ 15 files changed, 746 insertions(+), 9 deletions(-) create mode 100644 docs/generated/packages/webpack/documents/webpack-config-setup.md create mode 100644 docs/generated/packages/webpack/documents/webpack-plugins.md create mode 100644 docs/shared/packages/webpack/webpack-config-setup.md create mode 100644 docs/shared/packages/webpack/webpack-plugins.md create mode 100644 packages/webpack/docs/webpack-build-executor-examples.md create mode 100644 packages/webpack/src/migrations/update-15-6-3/__snapshots__/webpack-config-setup.spec.ts.snap create mode 100644 packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.spec.ts create mode 100644 packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.ts diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index e9cfc816ba171..1017fe27a3480 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -6251,6 +6251,31 @@ "path": "/packages/webpack", "name": "webpack", "children": [ + { + "id": "documents", + "path": "/packages/webpack/documents", + "name": "documents", + "children": [ + { + "name": "Configure webpack on your Nx workspace", + "path": "/packages/webpack/documents/webpack-config-setup", + "id": "webpack-config-setup", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Webpack plugins", + "path": "/packages/webpack/documents/webpack-plugins", + "id": "webpack-plugins", + "isExternal": false, + "children": [], + "disableCollapsible": false + } + ], + "isExternal": false, + "disableCollapsible": false + }, { "id": "executors", "path": "/packages/webpack/executors", diff --git a/docs/generated/manifests/packages.json b/docs/generated/manifests/packages.json index 7e367e97b7c19..345772897257a 100644 --- a/docs/generated/manifests/packages.json +++ b/docs/generated/manifests/packages.json @@ -2813,7 +2813,30 @@ "name": "webpack", "packageName": "@nrwl/webpack", "description": "The Nx Plugin for Webpack contains executors and generators that support building applications using Webpack.", - "documents": {}, + "documents": { + "/packages/webpack/documents/webpack-config-setup": { + "id": "webpack-config-setup", + "name": "Configure webpack on your Nx workspace", + "description": "Configure webpack on your Nx workspace", + "file": "generated/packages/webpack/documents/webpack-config-setup", + "itemList": [], + "isExternal": false, + "path": "/packages/webpack/documents/webpack-config-setup", + "tags": [], + "originalFilePath": "shared/packages/webpack/webpack-config-setup" + }, + "/packages/webpack/documents/webpack-plugins": { + "id": "webpack-plugins", + "name": "Webpack plugins", + "description": "Webpack plugins", + "file": "generated/packages/webpack/documents/webpack-plugins", + "itemList": [], + "isExternal": false, + "path": "/packages/webpack/documents/webpack-plugins", + "tags": [], + "originalFilePath": "shared/packages/webpack/webpack-plugins" + } + }, "root": "/packages/webpack", "source": "/packages/webpack/src", "executors": { diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 68535b90dea19..3f1f6f97fa378 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -2782,7 +2782,30 @@ }, { "description": "The Nx Plugin for Webpack contains executors and generators that support building applications using Webpack.", - "documents": [], + "documents": [ + { + "id": "webpack-config-setup", + "name": "Configure webpack on your Nx workspace", + "description": "Configure webpack on your Nx workspace", + "file": "generated/packages/webpack/documents/webpack-config-setup", + "itemList": [], + "isExternal": false, + "path": "webpack/documents/webpack-config-setup", + "tags": [], + "originalFilePath": "shared/packages/webpack/webpack-config-setup" + }, + { + "id": "webpack-plugins", + "name": "Webpack plugins", + "description": "Webpack plugins", + "file": "generated/packages/webpack/documents/webpack-plugins", + "itemList": [], + "isExternal": false, + "path": "webpack/documents/webpack-plugins", + "tags": [], + "originalFilePath": "shared/packages/webpack/webpack-plugins" + } + ], "executors": [ { "description": "Run webpack build.", diff --git a/docs/generated/packages/webpack/documents/webpack-config-setup.md b/docs/generated/packages/webpack/documents/webpack-config-setup.md new file mode 100644 index 0000000000000..3e0d8972a5d70 --- /dev/null +++ b/docs/generated/packages/webpack/documents/webpack-config-setup.md @@ -0,0 +1,108 @@ +# Configure webpack on your Nx workspace + +You can configure Webpack using a `webpack.config.js` file in your project. You can set the path to this file in your `project.json` file, in the `build` target options: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js" + }, + "configurations": { + ... + } + }, + } +} +``` + +In that file, you can add the necessary configuration for Webpack. You can read more on how to configure webpack in the [Webpack documentation](https://webpack.js.org/concepts/configuration/). + +## Using webpack with `isolatedConfig` + +Setting `isolatedConfig` to `true` in your `project.json` file means that Nx will not apply the Nx webpack plugins automatically. In that case, the Nx plugins need to be applied in the project's `webpack.config.js` file (e.g. `withNx`, `withReact`, etc.). So don't forget to also specify the path to your webpack config file (using the `webpackConfig` option). + +Note that this is the new default setup for webpack in the latest version of Nx. + +Set `isolatedConfig` to `true` in your `project.json` file in the `build` target options like this: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js", + "isolatedConfig": true + }, + "configurations": { + ... + } + }, + } +} +``` + +Now, you need to manually add the Nx webpack plugins in your `webpack.config.js` file for Nx to work properly. Let's see how to do that. + +### Basic configuration for Nx + +You should start with a basic webpack configuration for Nx in your project, that looks like this: + +```ts +// apps/my-app/webpack.config.js +const { composePlugins, withNx } = require('@nrwl/webpack'); + +module.exports = composePlugins(withNx(), (config, { options, context }) => { + // customize webpack config here + return config; +}); +``` + +The `withNx()` plugin adds the necessary configuration for Nx to work with Webpack. The `composePlugins` function allows you to add other plugins to the configuration. + +#### The `composePlugins` function + +The `composePlugins` function takes a list of plugins and a function, and returns a webpack `Configuration` object. The `composePlugins` function is an enhanced version of the [webpack configuration function](https://webpack.js.org/configuration/configuration-types/#exporting-a-function), which allows you to add plugins to the configuration, and provides you with a function which accepts two arguments: + +1. `config`: The webpack configuration object. +2. An object with the following properties: + - `options`: The options passed to the `@nrwl/webpack:webpack` executor. + - `context`: The context passed of the `@nrwl/webpack:webpack` executor. + +This gives you the ability to customize the webpack configuration as needed, and make use of the options and context passed to the executor, as well. + +### Add configurations for other functionalities + +In addition to the basic configuration, you can add configurations for other frameworks or features. The `@nrwl/webpack` package provides plugins such as `withWeb` and `withReact`. This plugins provide features such as TS support, CSS support, JSX support, etc. You can read more about how these plugins work and how to use them in our [Webpack Plugins guide](/packages/webpack/documents/webpack-plugins). + +You may still reconfigure everything manually, without using the Nx plugins. However, these plugins ensure that you have the necessary configuration for Nx to work with your project. + +Here is an example of a configuration that uses the `withReact` plugin: + +```ts +// apps/my-react-app/webpack.config.js +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; + } +); +``` diff --git a/docs/generated/packages/webpack/documents/webpack-plugins.md b/docs/generated/packages/webpack/documents/webpack-plugins.md new file mode 100644 index 0000000000000..cb2c3d634cc98 --- /dev/null +++ b/docs/generated/packages/webpack/documents/webpack-plugins.md @@ -0,0 +1,9 @@ +# Webpack plugins + +Coming soon. + +## `withNx` + +## `withWeb` + +## `withReact` diff --git a/docs/generated/packages/webpack/executors/webpack.json b/docs/generated/packages/webpack/executors/webpack.json index bb6d7f013092f..2f5a8b17a5bdc 100644 --- a/docs/generated/packages/webpack/executors/webpack.json +++ b/docs/generated/packages/webpack/executors/webpack.json @@ -463,6 +463,7 @@ ] } }, + "examplesFile": "`project.json`:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"build\": {\n \"executor\": \"@nrwl/webpack:webpack\",\n //...\n //...\n \"options\": {\n ...\n },\n //...\n }\n },\n }\n}\n```\n\n```bash\nnx build my-app\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Add a path to your webpack.config.js file\" %}\n\nYou can configure Webpack using a `webpack.config.js` file. If you do so, you can set the path to this file in your `project.json` file, in the `build` target options:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"build\": {\n \"executor\": \"@nrwl/webpack:webpack\",\n //...\n \"options\": {\n //...\n \"webpackConfig\": \"apps/my-app/webpack.config.js\"\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\nRead more on how to configure Webpack in the [Nx Webpack configuration guide](/packages/webpack/documents/webpack-config-setup).\n\n{% /tab %}\n\n{% tab label=\"Run webpack with `isolatedConfig`\" %}\n\nSetting `isolatedConfig` to `true` in your `project.json` file means that Nx will not apply the Nx webpack plugins automatically. In that case, the Nx plugins need to be applied in the project's `webpack.config.js` file (e.g. `withNx`, `withReact`, etc.). So don't forget to also specify the path to your webpack config file (using the `webpackConfig` option).\n\nRead more on how to configure Webpack in our [Nx Webpack configuration guide](/packages/webpack/documents/webpack-config-setup) an in our [Webpack Plugins guide](/packages/webpack/documents/webpack-plugins).\n\nNote that this is the new default setup for webpack in the latest version of Nx.\n\nSet `isolatedConfig` to `true` in your `project.json` file in the `build` target options like this:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"build\": {\n \"executor\": \"@nrwl/webpack:webpack\",\n //...\n \"options\": {\n //...\n \"webpackConfig\": \"apps/my-app/webpack.config.js\",\n \"isolatedConfig\": true\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\n{% /tab %}\n\n{% /tabs %}\n", "presets": [] }, "description": "Run webpack build.", diff --git a/docs/map.json b/docs/map.json index fdfb437f039c5..d810fc4cad447 100644 --- a/docs/map.json +++ b/docs/map.json @@ -1609,6 +1609,25 @@ } ] }, + { + "name": "webpack", + "id": "webpack", + "description": "Webpack package.", + "itemList": [ + { + "name": "Configure webpack on your Nx workspace", + "id": "webpack-config-setup", + "description": "Configure webpack on your Nx workspace", + "file": "shared/packages/webpack/webpack-config-setup" + }, + { + "name": "Webpack plugins", + "id": "webpack-plugins", + "description": "Webpack plugins", + "file": "shared/packages/webpack/webpack-plugins" + } + ] + }, { "name": "angular", "id": "angular", diff --git a/docs/shared/packages/webpack/webpack-config-setup.md b/docs/shared/packages/webpack/webpack-config-setup.md new file mode 100644 index 0000000000000..3e0d8972a5d70 --- /dev/null +++ b/docs/shared/packages/webpack/webpack-config-setup.md @@ -0,0 +1,108 @@ +# Configure webpack on your Nx workspace + +You can configure Webpack using a `webpack.config.js` file in your project. You can set the path to this file in your `project.json` file, in the `build` target options: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js" + }, + "configurations": { + ... + } + }, + } +} +``` + +In that file, you can add the necessary configuration for Webpack. You can read more on how to configure webpack in the [Webpack documentation](https://webpack.js.org/concepts/configuration/). + +## Using webpack with `isolatedConfig` + +Setting `isolatedConfig` to `true` in your `project.json` file means that Nx will not apply the Nx webpack plugins automatically. In that case, the Nx plugins need to be applied in the project's `webpack.config.js` file (e.g. `withNx`, `withReact`, etc.). So don't forget to also specify the path to your webpack config file (using the `webpackConfig` option). + +Note that this is the new default setup for webpack in the latest version of Nx. + +Set `isolatedConfig` to `true` in your `project.json` file in the `build` target options like this: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js", + "isolatedConfig": true + }, + "configurations": { + ... + } + }, + } +} +``` + +Now, you need to manually add the Nx webpack plugins in your `webpack.config.js` file for Nx to work properly. Let's see how to do that. + +### Basic configuration for Nx + +You should start with a basic webpack configuration for Nx in your project, that looks like this: + +```ts +// apps/my-app/webpack.config.js +const { composePlugins, withNx } = require('@nrwl/webpack'); + +module.exports = composePlugins(withNx(), (config, { options, context }) => { + // customize webpack config here + return config; +}); +``` + +The `withNx()` plugin adds the necessary configuration for Nx to work with Webpack. The `composePlugins` function allows you to add other plugins to the configuration. + +#### The `composePlugins` function + +The `composePlugins` function takes a list of plugins and a function, and returns a webpack `Configuration` object. The `composePlugins` function is an enhanced version of the [webpack configuration function](https://webpack.js.org/configuration/configuration-types/#exporting-a-function), which allows you to add plugins to the configuration, and provides you with a function which accepts two arguments: + +1. `config`: The webpack configuration object. +2. An object with the following properties: + - `options`: The options passed to the `@nrwl/webpack:webpack` executor. + - `context`: The context passed of the `@nrwl/webpack:webpack` executor. + +This gives you the ability to customize the webpack configuration as needed, and make use of the options and context passed to the executor, as well. + +### Add configurations for other functionalities + +In addition to the basic configuration, you can add configurations for other frameworks or features. The `@nrwl/webpack` package provides plugins such as `withWeb` and `withReact`. This plugins provide features such as TS support, CSS support, JSX support, etc. You can read more about how these plugins work and how to use them in our [Webpack Plugins guide](/packages/webpack/documents/webpack-plugins). + +You may still reconfigure everything manually, without using the Nx plugins. However, these plugins ensure that you have the necessary configuration for Nx to work with your project. + +Here is an example of a configuration that uses the `withReact` plugin: + +```ts +// apps/my-react-app/webpack.config.js +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; + } +); +``` diff --git a/docs/shared/packages/webpack/webpack-plugins.md b/docs/shared/packages/webpack/webpack-plugins.md new file mode 100644 index 0000000000000..cb2c3d634cc98 --- /dev/null +++ b/docs/shared/packages/webpack/webpack-plugins.md @@ -0,0 +1,9 @@ +# Webpack plugins + +Coming soon. + +## `withNx` + +## `withWeb` + +## `withReact` diff --git a/packages/webpack/docs/webpack-build-executor-examples.md b/packages/webpack/docs/webpack-build-executor-examples.md new file mode 100644 index 0000000000000..d4f89596ff5e6 --- /dev/null +++ b/packages/webpack/docs/webpack-build-executor-examples.md @@ -0,0 +1,90 @@ +`project.json`: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + //... + "options": { + ... + }, + //... + } + }, + } +} +``` + +```bash +nx build my-app +``` + +## Examples + +{% tabs %} +{% tab label="Add a path to your webpack.config.js file" %} + +You can configure Webpack using a `webpack.config.js` file. If you do so, you can set the path to this file in your `project.json` file, in the `build` target options: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js" + }, + "configurations": { + ... + } + }, + } +} +``` + +Read more on how to configure Webpack in the [Nx Webpack configuration guide](/packages/webpack/documents/webpack-config-setup). + +{% /tab %} + +{% tab label="Run webpack with `isolatedConfig`" %} + +Setting `isolatedConfig` to `true` in your `project.json` file means that Nx will not apply the Nx webpack plugins automatically. In that case, the Nx plugins need to be applied in the project's `webpack.config.js` file (e.g. `withNx`, `withReact`, etc.). So don't forget to also specify the path to your webpack config file (using the `webpackConfig` option). + +Read more on how to configure Webpack in our [Nx Webpack configuration guide](/packages/webpack/documents/webpack-config-setup) an in our [Webpack Plugins guide](/packages/webpack/documents/webpack-plugins). + +Note that this is the new default setup for webpack in the latest version of Nx. + +Set `isolatedConfig` to `true` in your `project.json` file in the `build` target options like this: + +```json +//... +"my-app": { + "targets": { + //... + "build": { + "executor": "@nrwl/webpack:webpack", + //... + "options": { + //... + "webpackConfig": "apps/my-app/webpack.config.js", + "isolatedConfig": true + }, + "configurations": { + ... + } + }, + } +} +``` + +{% /tab %} + +{% /tabs %} diff --git a/packages/webpack/migrations.json b/packages/webpack/migrations.json index f8d499c14cae9..5d76975b1ce33 100644 --- a/packages/webpack/migrations.json +++ b/packages/webpack/migrations.json @@ -5,13 +5,19 @@ "version": "15.0.0-beta.0", "description": "Adds babel.config.json to the hash of all tasks", "factory": "./src/migrations/update-15-0-0/add-babel-inputs" + }, + "remove-es2015-polyfills-option": { + "cli": "nx", + "version": "15.4.5-beta.0", + "description": "Removes es2015Polyfills option since legacy browsers are no longer supported.", + "factory": "./src/migrations/update-15-4-5/remove-es2015-polyfills-option" + }, + "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" } }, - "remove-es2015-polyfills-option": { - "cli": "nx", - "version": "15.4.5-beta.0", - "description": "Removes es2015Polyfills option since legacy browsers are no longer supported.", - "factory": "./src/migrations/update-15-4-5/remove-es2015-polyfills-option" - }, "packageJsonUpdates": {} } diff --git a/packages/webpack/src/executors/webpack/schema.json b/packages/webpack/src/executors/webpack/schema.json index 335ec675fe767..ffa942bdd76fc 100644 --- a/packages/webpack/src/executors/webpack/schema.json +++ b/packages/webpack/src/executors/webpack/schema.json @@ -394,5 +394,6 @@ } ] } - } + }, + "examplesFile": "../../../docs/webpack-build-executor-examples.md" } diff --git a/packages/webpack/src/migrations/update-15-6-3/__snapshots__/webpack-config-setup.spec.ts.snap b/packages/webpack/src/migrations/update-15-6-3/__snapshots__/webpack-config-setup.spec.ts.snap new file mode 100644 index 0000000000000..815655ebf5064 --- /dev/null +++ b/packages/webpack/src/migrations/update-15-6-3/__snapshots__/webpack-config-setup.spec.ts.snap @@ -0,0 +1,53 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`15.6.3 migration (setup webpack.config file) should create webpack.config.js for projects that do not have one 1`] = ` +" + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + module.exports = composePlugins(withNx(), (config) => { + // 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) should create webpack.config.js for projects that do not have one 2`] = ` +" + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + module.exports = composePlugins(withNx(), (config) => { + // 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) should rename existing webpack.config file and create new one that requires it 1`] = ` +" + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + 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); + }); + " +`; + +exports[`15.6.3 migration (setup webpack.config file) should rename existing webpack.config file and create new one that requires it 3`] = ` +" + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + 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); + }); + " +`; diff --git a/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.spec.ts b/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.spec.ts new file mode 100644 index 0000000000000..a40a5795d70aa --- /dev/null +++ b/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.spec.ts @@ -0,0 +1,139 @@ +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)', () => { + let tree: Tree; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + + addProjectConfiguration(tree, 'app1', { + root: 'apps/app1', + targets: { + build: { + executor: '@nrwl/webpack:webpack', + options: {}, + }, + }, + }); + addProjectConfiguration(tree, 'app2', { + root: 'apps/app2', + targets: { + custom: { + executor: '@nrwl/webpack:webpack', + options: {}, + }, + }, + }); + + addProjectConfiguration(tree, 'app3', { + root: 'apps/app3', + targets: { + custom: { + executor: '@nrwl/webpack:webpack', + options: { + webpackConfig: 'apps/app3/webpack.config.js', + }, + }, + }, + }); + + tree.write('apps/app3/webpack.config.js', '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, + }, + }, + }, + }); + + await webpackConfigSetup(tree); + }); + + it('should create webpack.config.js for projects that do not have one', () => { + expect(tree.read('apps/app1/webpack.config.js', 'utf-8')).toMatchSnapshot(); + expect(tree.read('apps/app2/webpack.config.js', 'utf-8')).toMatchSnapshot(); + }); + + it('should rename existing webpack.config file and create new one that requires it', () => { + expect(tree.read('apps/app3/webpack.config.js', 'utf-8')).toMatchSnapshot(); + expect( + tree.read('apps/app3/webpack.config.old.js', 'utf-8') + ).toMatchInlineSnapshot(`"some content"`); + + expect( + tree.read('some/random/path/webpack.something.ts', 'utf-8') + ).toMatchSnapshot(); + + expect( + tree.read('some/random/path/webpack.something.old.ts', 'utf-8') + ).toMatchInlineSnapshot(`"some content"`); + }); + + it('should update the project configuration - executor options', () => { + expect( + readProjectConfiguration(tree, 'app1').targets.build.options.webpackConfig + ).toBe('apps/app1/webpack.config.js'); + expect( + readProjectConfiguration(tree, 'app2').targets.custom.options + .webpackConfig + ).toBe('apps/app2/webpack.config.js'); + + expect( + readProjectConfiguration(tree, 'app3').targets.custom.options + .webpackConfig + ).toBe('apps/app3/webpack.config.js'); + + expect( + readProjectConfiguration(tree, 'app4').targets.custom.options + .webpackConfig + ).toBe('some/random/path/webpack.something.ts'); + + expect( + readProjectConfiguration(tree, 'app1').targets.build.options + .isolatedConfig + ).toBeTruthy(); + expect( + readProjectConfiguration(tree, 'app2').targets.custom.options + .isolatedConfig + ).toBeTruthy(); + + expect( + readProjectConfiguration(tree, 'app3').targets.custom.options + .isolatedConfig + ).toBeTruthy(); + + expect( + readProjectConfiguration(tree, 'app4').targets.custom.options + .isolatedConfig + ).toBeTruthy(); + }); + + it('should not do anything if isolatedConfig is true', () => { + expect(tree.exists('apps/app5/webpack.config.js')).toBeFalsy(); + }); +}); diff --git a/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.ts b/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.ts new file mode 100644 index 0000000000000..024446adfff35 --- /dev/null +++ b/packages/webpack/src/migrations/update-15-6-3/webpack-config-setup.ts @@ -0,0 +1,123 @@ +import { + formatFiles, + logger, + readProjectConfiguration, + Tree, + updateProjectConfiguration, +} from '@nrwl/devkit'; +import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; +import { WebpackExecutorOptions } from '../../executors/webpack/schema'; +import { basename } from 'path'; + +export default async function (tree: Tree) { + forEachExecutorOptions( + tree, + '@nrwl/webpack:webpack', + ( + options: WebpackExecutorOptions, + projectName, + targetName, + _configurationName + ) => { + if (options?.['isolatedConfig']) { + 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) { + if (options.webpackConfig === '@nrwl/react/plugin/webpack') { + return; + } + + 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'); + } + + const justTheFileName = basename(options.webpackConfig); + renameFile(tree, options.webpackConfig, oldName); + + tree.write( + options.webpackConfig, + ` + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + 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('./${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 = {} as WebpackExecutorOptions; + } + + options.webpackConfig = `${projectConfiguration.root}/webpack.config.js`; + options['isolatedConfig'] = true; + + tree.write( + options.webpackConfig, + ` + const { composePlugins, withNx } = require('@nrwl/webpack'); + + // Nx plugins for webpack. + module.exports = composePlugins(withNx(), (config) => { + // 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); +}