@nx/webpack 21.0.0-beta.1 → 21.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/index.d.ts +1 -1
  2. package/index.js +1 -2
  3. package/migrations.json +28 -6
  4. package/package.json +8 -7
  5. package/src/executors/dev-server/schema.json +1 -0
  6. package/src/executors/ssr-dev-server/schema.json +1 -0
  7. package/src/executors/webpack/lib/normalize-options.js +1 -0
  8. package/src/executors/webpack/schema.d.ts +1 -3
  9. package/src/executors/webpack/schema.json +6 -6
  10. package/src/executors/webpack/webpack.impl.js +1 -10
  11. package/src/generators/convert-to-inferred/utils/build-post-target-transformer.js +0 -8
  12. package/src/generators/convert-to-inferred/utils/serve-post-target-transformer.js +4 -1
  13. package/src/generators/init/init.js +1 -1
  14. package/src/migrations/update-21-0-0/remove-isolated-config.js +41 -0
  15. package/src/plugins/nx-typescript-webpack-plugin/nx-tsconfig-paths-webpack-plugin.d.ts +1 -1
  16. package/src/plugins/nx-typescript-webpack-plugin/nx-tsconfig-paths-webpack-plugin.js +3 -1
  17. package/src/plugins/nx-webpack-plugin/lib/apply-base-config.js +39 -3
  18. package/src/plugins/nx-webpack-plugin/lib/apply-web-config.js +22 -4
  19. package/src/plugins/nx-webpack-plugin/lib/compiler-loaders.d.ts +2 -0
  20. package/src/plugins/nx-webpack-plugin/lib/compiler-loaders.js +2 -0
  21. package/src/plugins/nx-webpack-plugin/lib/normalize-options.js +6 -1
  22. package/src/plugins/nx-webpack-plugin/lib/stylesheet-loaders.js +1 -1
  23. package/src/plugins/nx-webpack-plugin/lib/utils.d.ts +7 -0
  24. package/src/plugins/nx-webpack-plugin/lib/utils.js +48 -0
  25. package/src/plugins/nx-webpack-plugin/nx-app-webpack-plugin-options.d.ts +16 -2
  26. package/src/plugins/nx-webpack-plugin/nx-app-webpack-plugin.js +4 -0
  27. package/src/plugins/plugin.js +3 -0
  28. package/src/plugins/webpack-nx-build-coordination-plugin.d.ts +10 -0
  29. package/src/plugins/webpack-nx-build-coordination-plugin.js +14 -9
  30. package/src/utils/with-web.d.ts +6 -1
  31. package/src/migrations/update-17-2-1/webpack-config-setup.js +0 -31
  32. /package/src/migrations/{update-17-2-1/webpack-config-setup.d.ts → update-21-0-0/remove-isolated-config.d.ts} +0 -0
package/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { useLegacyNxPlugin } from './src/plugins/use-legacy-nx-plugin/use-legacy
6
6
  export { configurationGenerator, convertConfigToWebpackPluginGenerator, useLegacyNxPlugin, };
7
7
  /** @deprecated Use `configurationGenerator` instead. */
8
8
  export declare const webpackProjectGenerator: typeof configurationGenerator;
9
- /** @deprecated Use NxAppWebpackPlugin from `@nx/webpack/app-plugin` instead. */
9
+ /** @deprecated Use NxAppWebpackPlugin from `@nx/webpack/app-plugin` instead, which can improve graph creation by 150-200ms per file. */
10
10
  export declare const NxWebpackPlugin: typeof NxAppWebpackPlugin;
11
11
  /** @deprecated Use NxTsconfigPathsWebpackPlugin from `@nx/webpack/tsconfig-paths-plugin` instead. */
12
12
  export declare const NxTsconfigPathsWebpackPlugin: typeof _NxTsconfigPathsWebpackPlugin;
package/index.js CHANGED
@@ -13,8 +13,7 @@ Object.defineProperty(exports, "useLegacyNxPlugin", { enumerable: true, get: fun
13
13
  // Exported for backwards compatibility in case a plugin is using the old name.
14
14
  /** @deprecated Use `configurationGenerator` instead. */
15
15
  exports.webpackProjectGenerator = configuration_1.configurationGenerator;
16
- // TODO(v21): Remove this in favor of deep imports in order to load configs faster (150-200ms faster).
17
- /** @deprecated Use NxAppWebpackPlugin from `@nx/webpack/app-plugin` instead. */
16
+ /** @deprecated Use NxAppWebpackPlugin from `@nx/webpack/app-plugin` instead, which can improve graph creation by 150-200ms per file. */
18
17
  exports.NxWebpackPlugin = nx_app_webpack_plugin_1.NxAppWebpackPlugin;
19
18
  /** @deprecated Use NxTsconfigPathsWebpackPlugin from `@nx/webpack/tsconfig-paths-plugin` instead. */
20
19
  exports.NxTsconfigPathsWebpackPlugin = nx_tsconfig_paths_webpack_plugin_1.NxTsconfigPathsWebpackPlugin;
package/migrations.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "generators": {
3
- "update-17-2-1-webpack-config-setup": {
4
- "cli": "nx",
5
- "version": "17.2.1-beta.0",
6
- "description": "Add webpack.config.js file when webpackConfig is not defined",
7
- "implementation": "./src/migrations/update-17-2-1/webpack-config-setup"
8
- },
9
3
  "update-19-6-3-proxy-config": {
10
4
  "cli": "nx",
11
5
  "version": "19.6.3-beta.0",
12
6
  "description": "Migrate proxy config files to match new format from webpack-dev-server v5.",
13
7
  "implementation": "./src/migrations/update-19-6-3/proxy-config"
8
+ },
9
+ "update-21-0-0-remove-isolated-config": {
10
+ "cli": "nx",
11
+ "version": "21.0.0-beta.11",
12
+ "description": "Remove isolatedConfig option for @nx/webpack:webpack",
13
+ "implementation": "./src/migrations/update-21-0-0/remove-isolated-config"
14
14
  }
15
15
  },
16
16
  "packageJsonUpdates": {
@@ -35,6 +35,28 @@
35
35
  "alwaysAddToPackageJson": false
36
36
  }
37
37
  }
38
+ },
39
+ "20.5.0": {
40
+ "version": "20.5.0-beta.3",
41
+ "packages": {
42
+ "sass-loader": {
43
+ "version": "^16.0.4",
44
+ "alwaysAddToPackageJson": false
45
+ }
46
+ }
47
+ },
48
+ "20.7.1": {
49
+ "version": "20.7.1-beta.0",
50
+ "packages": {
51
+ "webpack": {
52
+ "version": "5.98.0",
53
+ "alwaysAddToPackageJson": false
54
+ },
55
+ "webpack-dev-server": {
56
+ "version": "^5.2.1",
57
+ "alwaysAddToPackageJson": false
58
+ }
59
+ }
38
60
  }
39
61
  }
40
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/webpack",
3
- "version": "21.0.0-beta.1",
3
+ "version": "21.0.0-beta.11",
4
4
  "private": false,
5
5
  "description": "The Nx Plugin for Webpack contains executors and generators that support building applications using Webpack.",
6
6
  "repository": {
@@ -51,8 +51,9 @@
51
51
  "postcss-import": "~14.1.0",
52
52
  "postcss-loader": "^6.1.1",
53
53
  "rxjs": "^7.8.0",
54
- "sass": "^1.42.1",
55
- "sass-loader": "^12.2.0",
54
+ "sass": "^1.85.0",
55
+ "sass-embedded": "^1.83.4",
56
+ "sass-loader": "^16.0.4",
56
57
  "source-map-loader": "^5.0.0",
57
58
  "style-loader": "^3.3.0",
58
59
  "stylus": "^0.64.0",
@@ -61,12 +62,12 @@
61
62
  "ts-loader": "^9.3.1",
62
63
  "tsconfig-paths-webpack-plugin": "4.0.0",
63
64
  "tslib": "^2.3.0",
64
- "webpack": "^5.80.0",
65
- "webpack-dev-server": "^5.0.4",
65
+ "webpack": "5.98.0",
66
+ "webpack-dev-server": "^5.2.1",
66
67
  "webpack-node-externals": "^3.0.0",
67
68
  "webpack-subresource-integrity": "^5.1.0",
68
- "@nx/devkit": "21.0.0-beta.1",
69
- "@nx/js": "21.0.0-beta.1"
69
+ "@nx/devkit": "21.0.0-beta.11",
70
+ "@nx/js": "21.0.0-beta.11"
70
71
  },
71
72
  "publishConfig": {
72
73
  "access": "public"
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "version": 2,
3
+ "continuous": true,
3
4
  "outputCapture": "direct-nodejs",
4
5
  "title": "Webpack dev server",
5
6
  "description": "Serve an application using webpack.",
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "version": 2,
3
+ "continuous": true,
3
4
  "outputCapture": "direct-nodejs",
4
5
  "title": "Webpack SSR Dev Server",
5
6
  "description": "Serve a SSR application using webpack.",
@@ -16,6 +16,7 @@ function normalizeOptions(options, root, projectRoot, sourceRoot) {
16
16
  outputFileName: options.outputFileName ?? 'main.js',
17
17
  webpackConfig: normalizePluginPath(options.webpackConfig, root),
18
18
  fileReplacements: (0, normalize_options_1.normalizeFileReplacements)(root, options.fileReplacements),
19
+ sassImplementation: options.sassImplementation ?? 'sass',
19
20
  optimization: typeof options.optimization !== 'object'
20
21
  ? {
21
22
  scripts: options.optimization,
@@ -47,9 +47,6 @@ export interface WebpackExecutorOptions {
47
47
  extractLicenses?: boolean;
48
48
  fileReplacements?: FileReplacement[];
49
49
  generatePackageJson?: boolean;
50
- // TODO(v21): Remove this option
51
- /** @deprecated set webpackConfig and provide an explicit webpack.config.js file (See: https://nx.dev/recipes/webpack/webpack-config-setup) */
52
- isolatedConfig?: boolean;
53
50
  standardWebpackConfigFunction?: boolean;
54
51
  main?: string;
55
52
  memoryLimit?: number;
@@ -81,6 +78,7 @@ export interface WebpackExecutorOptions {
81
78
  index?: string;
82
79
  postcssConfig?: string;
83
80
  scripts?: Array<ExtraEntryPointClass | string>;
81
+ sassImplementation?: 'sass' | 'sass-embedded';
84
82
  stylePreprocessorOptions?: any;
85
83
  styles?: Array<ExtraEntryPointClass | string>;
86
84
  subresourceIntegrity?: boolean;
@@ -144,6 +144,12 @@
144
144
  },
145
145
  "additionalProperties": false
146
146
  },
147
+ "sassImplementation": {
148
+ "type": "string",
149
+ "description": "The implementation of the SASS compiler to use. Can be either `sass` or `sass-embedded`. Defaults to `sass-embedded`.",
150
+ "enum": ["sass", "sass-embedded"],
151
+ "default": "sass"
152
+ },
147
153
  "optimization": {
148
154
  "description": "Enables optimization of the build output.",
149
155
  "oneOf": [
@@ -248,12 +254,6 @@
248
254
  "type": "boolean",
249
255
  "description": "Generates a 'stats.json' file which can be analyzed using tools such as: 'webpack-bundle-analyzer' or `<https://webpack.github.io/analyse>`."
250
256
  },
251
- "isolatedConfig": {
252
- "type": "boolean",
253
- "description": "Do not apply Nx webpack plugins automatically. Plugins need to be applied in the project's webpack.config.js file (e.g. withNx, withReact, etc.).",
254
- "default": true,
255
- "x-deprecated": "Automatic configuration of Webpack is deprecated in favor of an explicit 'webpack.config.js' file. This option will be removed in Nx 20. See https://nx.dev/recipes/webpack/webpack-config-setup."
256
- },
257
257
  "standardWebpackConfigFunction": {
258
258
  "type": "boolean",
259
259
  "description": "Set to true if the webpack config exports a standard webpack function, not an Nx-specific one. See: https://webpack.js.org/configuration/configuration-types/#exporting-a-function",
@@ -11,13 +11,8 @@ const fs_1 = require("../../utils/fs");
11
11
  const resolve_user_defined_webpack_config_1 = require("../../utils/webpack/resolve-user-defined-webpack-config");
12
12
  const normalize_options_1 = require("./lib/normalize-options");
13
13
  const config_1 = require("../../utils/config");
14
- const with_nx_1 = require("../../utils/with-nx");
15
14
  const js_1 = require("@nx/js");
16
- const with_web_1 = require("../../utils/with-web");
17
15
  async function getWebpackConfigs(options, context) {
18
- if (options.isolatedConfig && !options.webpackConfig) {
19
- throw new Error(`Using "isolatedConfig" without a "webpackConfig" is not supported.`);
20
- }
21
16
  let userDefinedWebpackConfig = null;
22
17
  if (options.webpackConfig) {
23
18
  userDefinedWebpackConfig = (0, resolve_user_defined_webpack_config_1.resolveUserDefinedWebpackConfig)(options.webpackConfig, (0, js_1.getRootTsConfigPath)());
@@ -25,11 +20,7 @@ async function getWebpackConfigs(options, context) {
25
20
  userDefinedWebpackConfig = await userDefinedWebpackConfig;
26
21
  }
27
22
  }
28
- const config = options.isolatedConfig
29
- ? {}
30
- : (options.target === 'web'
31
- ? (0, config_1.composePluginsSync)((0, with_nx_1.withNx)(options), (0, with_web_1.withWeb)(options))
32
- : (0, with_nx_1.withNx)(options))({}, { options, context });
23
+ const config = {};
33
24
  if (typeof userDefinedWebpackConfig === 'function' &&
34
25
  ((0, config_1.isNxWebpackComposablePlugin)(userDefinedWebpackConfig) ||
35
26
  !options.standardWebpackConfigFunction)) {
@@ -90,14 +90,6 @@ function extractPluginOptions(options, context, configName) {
90
90
  }
91
91
  delete options.memoryLimit;
92
92
  }
93
- else if (key === 'isolatedConfig') {
94
- context.logger.addLog({
95
- executorName: '@nx/webpack:webpack',
96
- log: `The 'isolatedConfig' option is deprecated and not supported by the NxAppWebpackPlugin. It was removed from your project configuration.`,
97
- project: context.projectName,
98
- });
99
- delete options.isolatedConfig;
100
- }
101
93
  else if (key === 'standardWebpackConfigFunction') {
102
94
  delete options.standardWebpackConfigFunction;
103
95
  }
@@ -156,7 +156,10 @@ function extractDevServerOptions(options, context) {
156
156
  return devServerOptions;
157
157
  }
158
158
  function applyDefaults(options, buildOptions) {
159
- if (options.port === undefined) {
159
+ if (!options) {
160
+ options = {};
161
+ }
162
+ if (options?.port === undefined) {
160
163
  options.port = 4200;
161
164
  }
162
165
  options.headers = { 'Access-Control-Allow-Origin': '*' };
@@ -15,7 +15,7 @@ async function webpackInitGeneratorInternal(tree, schema) {
15
15
  nxJson.useInferencePlugins !== false;
16
16
  schema.addPlugin ??= addPluginDefault;
17
17
  if (schema.addPlugin) {
18
- await (0, add_plugin_1.addPluginV1)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/webpack/plugin', plugin_1.createNodes, {
18
+ await (0, add_plugin_1.addPlugin)(tree, await (0, devkit_1.createProjectGraphAsync)(), '@nx/webpack/plugin', plugin_1.createNodesV2, {
19
19
  buildTargetName: [
20
20
  'build',
21
21
  'webpack:build',
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
6
+ async function default_1(tree) {
7
+ (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/webpack:webpack', (options, projectName, targetName, configurationName) => {
8
+ // Only handle webpack config for default configuration
9
+ if (configurationName)
10
+ return;
11
+ const projectConfiguration = (0, devkit_1.readProjectConfiguration)(tree, projectName);
12
+ if (!options.webpackConfig) {
13
+ delete options['isolatedConfig'];
14
+ options.webpackConfig = `${projectConfiguration.root}/webpack.config.js`;
15
+ tree.write(options.webpackConfig, options.target === 'web'
16
+ ? `
17
+ const { composePlugins, withNx, withWeb } = require('@nx/webpack');
18
+
19
+ // Nx plugins for webpack.
20
+ module.exports = composePlugins(withNx(), withWeb(), (config) => {
21
+ // Note: This was added by an Nx migration. Webpack builds are required to have a corresponding Webpack config file.
22
+ // See: https://nx.dev/recipes/webpack/webpack-config-setup
23
+ return config;
24
+ });
25
+ `
26
+ : `
27
+ const { composePlugins, withNx } = require('@nx/webpack');
28
+
29
+ // Nx plugins for webpack.
30
+ module.exports = composePlugins(withNx(), (config) => {
31
+ // Note: This was added by an Nx migration. Webpack builds are required to have a corresponding Webpack config file.
32
+ // See: https://nx.dev/recipes/webpack/webpack-config-setup
33
+ return config;
34
+ });
35
+ `);
36
+ projectConfiguration.targets[targetName].options = options;
37
+ (0, devkit_1.updateProjectConfiguration)(tree, projectName, projectConfiguration);
38
+ }
39
+ });
40
+ await (0, devkit_1.formatFiles)(tree);
41
+ }
@@ -4,5 +4,5 @@ export declare class NxTsconfigPathsWebpackPlugin {
4
4
  private options;
5
5
  constructor(options: NormalizedNxAppWebpackPluginOptions);
6
6
  apply(compiler: Compiler): void;
7
- handleBuildLibsFromSource(config: Partial<WebpackOptionsNormalized | Configuration>, options: any): void;
7
+ handleBuildLibsFromSource(config: Partial<WebpackOptionsNormalized | Configuration>, options: NormalizedNxAppWebpackPluginOptions): void;
8
8
  }
@@ -42,7 +42,9 @@ class NxTsconfigPathsWebpackPlugin {
42
42
  .map((dependency) => dependency.node.name)
43
43
  .join(',');
44
44
  const buildCommand = `nx run-many --target=build --projects=${buildableDependencies}`;
45
- config.plugins.push(new webpack_nx_build_coordination_plugin_1.WebpackNxBuildCoordinationPlugin(buildCommand));
45
+ config.plugins.push(new webpack_nx_build_coordination_plugin_1.WebpackNxBuildCoordinationPlugin(buildCommand, {
46
+ skipWatchingDeps: options.watchDependencies === false,
47
+ }));
46
48
  }
47
49
  }
48
50
  }
@@ -15,10 +15,15 @@ const compiler_loaders_1 = require("./compiler-loaders");
15
15
  const TerserPlugin = require("terser-webpack-plugin");
16
16
  const nodeExternals = require("webpack-node-externals");
17
17
  const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
18
+ const utils_1 = require("./utils");
18
19
  const IGNORED_WEBPACK_WARNINGS = [
19
20
  /The comment file/i,
20
21
  /could not find any license/i,
21
22
  ];
23
+ const extensionAlias = {
24
+ '.js': ['.ts', '.js'],
25
+ '.mjs': ['.mts', '.mjs'],
26
+ };
22
27
  const extensions = ['.ts', '.tsx', '.mjs', '.js', '.jsx'];
23
28
  const mainFields = ['module', 'main'];
24
29
  function applyBaseConfig(options, config = {}, { useNormalizedEntry, } = {}) {
@@ -183,8 +188,11 @@ function applyNxDependentConfig(options, config, { useNormalizedEntry } = {}) {
183
188
  if (options.useTsconfigPaths) {
184
189
  plugins.push(new nx_tsconfig_paths_webpack_plugin_1.NxTsconfigPathsWebpackPlugin({ ...options, tsConfig }));
185
190
  }
186
- // New TS Solution already has a typecheck target
187
- if (!options?.skipTypeChecking && !isUsingTsSolution) {
191
+ // New TS Solution already has a typecheck target but allow it to run during serve
192
+ if ((!options?.skipTypeChecking && !isUsingTsSolution) ||
193
+ (isUsingTsSolution &&
194
+ options?.skipTypeChecking === false &&
195
+ process.env['WEBPACK_SERVE'])) {
188
196
  const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
189
197
  plugins.push(new ForkTsCheckerWebpackPlugin({
190
198
  typescript: {
@@ -271,7 +279,31 @@ function applyNxDependentConfig(options, config, { useNormalizedEntry } = {}) {
271
279
  const externals = [];
272
280
  if (options.target === 'node' && options.externalDependencies === 'all') {
273
281
  const modulesDir = `${options.root}/node_modules`;
274
- externals.push(nodeExternals({ modulesDir }));
282
+ const graph = options.projectGraph;
283
+ const projectName = options.projectName;
284
+ const deps = graph?.dependencies?.[projectName] ?? [];
285
+ // Collect non-buildable TS project references so that they are bundled
286
+ // in the final output. This is needed for projects that are not buildable
287
+ // but are referenced by buildable projects. This is needed for the new TS
288
+ // solution setup.
289
+ const nonBuildableWorkspaceLibs = isUsingTsSolution
290
+ ? deps
291
+ .filter((dep) => {
292
+ const node = graph.nodes?.[dep.target];
293
+ if (!node || node.type !== 'lib')
294
+ return false;
295
+ const hasBuildTarget = 'build' in (node.data?.targets ?? {});
296
+ if (hasBuildTarget) {
297
+ return false;
298
+ }
299
+ // If there is no build target we check the package exports to see if they reference
300
+ // source files
301
+ return !(0, utils_1.isBuildableLibrary)(node);
302
+ })
303
+ .map((dep) => graph.nodes?.[dep.target]?.data?.metadata?.js?.packageName)
304
+ .filter((name) => !!name)
305
+ : [];
306
+ externals.push(nodeExternals({ modulesDir, allowlist: nonBuildableWorkspaceLibs }));
275
307
  }
276
308
  else if (Array.isArray(options.externalDependencies)) {
277
309
  externals.push(function (ctx, callback) {
@@ -286,6 +318,10 @@ function applyNxDependentConfig(options, config, { useNormalizedEntry } = {}) {
286
318
  config.resolve = {
287
319
  ...config.resolve,
288
320
  extensions: [...(config?.resolve?.extensions ?? []), ...extensions],
321
+ extensionAlias: {
322
+ ...(config.resolve?.extensionAlias ?? {}),
323
+ ...extensionAlias,
324
+ },
289
325
  alias: {
290
326
  ...(config.resolve?.alias ?? {}),
291
327
  ...(options.fileReplacements?.reduce((aliases, replacement) => ({
@@ -34,7 +34,7 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
34
34
  sri: options.subresourceIntegrity,
35
35
  outputPath: path.basename(options.index),
36
36
  indexPath: path.join(options.root, options.index),
37
- baseHref: options.baseHref,
37
+ baseHref: options.baseHref !== false ? options.baseHref : undefined,
38
38
  deployUrl: options.deployUrl,
39
39
  scripts: options.scripts,
40
40
  styles: options.styles,
@@ -56,6 +56,8 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
56
56
  const globalStylePaths = [];
57
57
  // Determine hashing format.
58
58
  const hashFormat = (0, hash_format_1.getOutputHashFormat)(options.outputHashing);
59
+ const sassOptions = options.stylePreprocessorOptions?.sassOptions;
60
+ const lessOptions = options.stylePreprocessorOptions?.lessOptions;
59
61
  const includePaths = [];
60
62
  if (options?.stylePreprocessorOptions?.includePaths?.length > 0) {
61
63
  options.stylePreprocessorOptions.includePaths.forEach((includePath) => includePaths.push(path.resolve(options.root, includePath)));
@@ -97,11 +99,15 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
97
99
  {
98
100
  loader: require.resolve('sass-loader'),
99
101
  options: {
100
- implementation: require('sass'),
102
+ api: 'modern-compiler',
103
+ implementation: options.sassImplementation === 'sass'
104
+ ? require.resolve('sass')
105
+ : require.resolve('sass-embedded'),
101
106
  sassOptions: {
102
107
  fiber: false,
103
108
  precision: 8,
104
109
  includePaths,
110
+ ...(sassOptions ?? {}),
105
111
  },
106
112
  },
107
113
  },
@@ -117,6 +123,7 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
117
123
  options: {
118
124
  lessOptions: {
119
125
  paths: includePaths,
126
+ ...(lessOptions ?? {}),
120
127
  },
121
128
  },
122
129
  },
@@ -152,13 +159,17 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
152
159
  {
153
160
  loader: require.resolve('sass-loader'),
154
161
  options: {
155
- implementation: require('sass'),
162
+ api: 'modern-compiler',
163
+ implementation: options.sassImplementation === 'sass'
164
+ ? require.resolve('sass')
165
+ : require.resolve('sass-embedded'),
156
166
  sourceMap: !!options.sourceMap,
157
167
  sassOptions: {
158
168
  fiber: false,
159
169
  // bootstrap-sass requires a minimum precision of 8
160
170
  precision: 8,
161
171
  includePaths,
172
+ ...(sassOptions ?? {}),
162
173
  },
163
174
  },
164
175
  },
@@ -176,6 +187,7 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
176
187
  lessOptions: {
177
188
  javascriptEnabled: true,
178
189
  ...lessPathOptions,
190
+ ...(lessOptions ?? {}),
179
191
  },
180
192
  },
181
193
  },
@@ -212,13 +224,17 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
212
224
  {
213
225
  loader: require.resolve('sass-loader'),
214
226
  options: {
215
- implementation: require('sass'),
227
+ api: 'modern-compiler',
228
+ implementation: options.sassImplementation === 'sass'
229
+ ? require.resolve('sass')
230
+ : require.resolve('sass-embedded'),
216
231
  sourceMap: !!options.sourceMap,
217
232
  sassOptions: {
218
233
  fiber: false,
219
234
  // bootstrap-sass requires a minimum precision of 8
220
235
  precision: 8,
221
236
  includePaths,
237
+ ...(sassOptions ?? {}),
222
238
  },
223
239
  },
224
240
  },
@@ -236,6 +252,7 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
236
252
  lessOptions: {
237
253
  javascriptEnabled: true,
238
254
  ...lessPathOptions,
255
+ ...(lessOptions ?? {}),
239
256
  },
240
257
  },
241
258
  },
@@ -342,6 +359,7 @@ function applyWebConfig(options, config = {}, { useNormalizedEntry, } = {}) {
342
359
  },
343
360
  },
344
361
  },
362
+ // TODO(v22): Remove this but provide a migration in `@nx/react` to add @svgr/webpack in userland webpack config
345
363
  // SVG: same as image but we need to separate it so it can be swapped for SVGR in the React plugin.
346
364
  {
347
365
  test: /\.svg$/,
@@ -24,6 +24,8 @@ export declare function createLoaderFromCompiler(options: NormalizedNxAppWebpack
24
24
  tsx: boolean;
25
25
  };
26
26
  transform: {
27
+ legacyDecorator: boolean;
28
+ decoratorMetadata: boolean;
27
29
  react: {
28
30
  runtime: string;
29
31
  };
@@ -18,6 +18,8 @@ function createLoaderFromCompiler(options) {
18
18
  tsx: true,
19
19
  },
20
20
  transform: {
21
+ legacyDecorator: true,
22
+ decoratorMetadata: true,
21
23
  react: {
22
24
  runtime: 'automatic',
23
25
  },
@@ -48,7 +48,10 @@ function normalizeOptions(options) {
48
48
  // executor options take precedence (especially for overriding with CLI args)
49
49
  originalTargetOptions);
50
50
  }
51
- const sourceRoot = projectNode.data.sourceRoot ?? projectNode.data.root;
51
+ const sourceRoot = projectNode.data.sourceRoot ??
52
+ ((0, fs_1.existsSync)((0, path_1.join)(devkit_1.workspaceRoot, projectNode.data.root, 'src'))
53
+ ? (0, path_1.join)(projectNode.data.root, 'src')
54
+ : projectNode.data.root);
52
55
  if (!combinedPluginAndMaybeExecutorOptions.main) {
53
56
  throw new Error(`Missing "main" option for the entry file. Set this option in your Nx webpack plugin.`);
54
57
  }
@@ -85,6 +88,8 @@ function normalizeOptions(options) {
85
88
  target: combinedPluginAndMaybeExecutorOptions.target,
86
89
  targetName,
87
90
  vendorChunk: combinedPluginAndMaybeExecutorOptions.vendorChunk ?? !isProd,
91
+ sassImplementation: combinedPluginAndMaybeExecutorOptions.sassImplementation ??
92
+ 'sass-embedded',
88
93
  };
89
94
  }
90
95
  function normalizeAssets(assets, root, sourceRoot, projectRoot, resolveRelativePathsToProjectRoot = true) {
@@ -98,7 +98,7 @@ function postcssOptionsCreator(options, { includePaths, forCssModules = false, }
98
98
  ? []
99
99
  : [
100
100
  (0, postcss_cli_resources_1.PostcssCliResources)({
101
- baseHref: options.baseHref,
101
+ baseHref: options.baseHref ? options.baseHref : undefined,
102
102
  deployUrl: options.deployUrl,
103
103
  loader,
104
104
  filename: `[name]${hashFormat.file}.[ext]`,
@@ -0,0 +1,7 @@
1
+ import { type ProjectGraphProjectNode } from '@nx/devkit';
2
+ /**
3
+ * Check if the library is buildable.
4
+ * @param node from the project graph
5
+ * @returns boolean
6
+ */
7
+ export declare function isBuildableLibrary(node: ProjectGraphProjectNode): boolean;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isBuildableLibrary = isBuildableLibrary;
4
+ function isSourceFile(path) {
5
+ return ['.ts', '.tsx', '.mts', '.cts'].some((ext) => path.endsWith(ext));
6
+ }
7
+ function isBuildableExportMap(packageExports) {
8
+ if (!packageExports || Object.keys(packageExports).length === 0) {
9
+ return false; // exports = {} → not buildable
10
+ }
11
+ const isCompiledExport = (value) => {
12
+ if (typeof value === 'string') {
13
+ return !isSourceFile(value);
14
+ }
15
+ if (typeof value === 'object' && value !== null) {
16
+ return Object.entries(value).some(([key, subValue]) => {
17
+ if (key === 'types' ||
18
+ key === 'development' ||
19
+ key === './package.json')
20
+ return false;
21
+ return typeof subValue === 'string' && !isSourceFile(subValue);
22
+ });
23
+ }
24
+ return false;
25
+ };
26
+ if (packageExports['.']) {
27
+ return isCompiledExport(packageExports['.']);
28
+ }
29
+ return Object.entries(packageExports).some(([key, value]) => key !== '.' && isCompiledExport(value));
30
+ }
31
+ /**
32
+ * Check if the library is buildable.
33
+ * @param node from the project graph
34
+ * @returns boolean
35
+ */
36
+ function isBuildableLibrary(node) {
37
+ if (!node.data.metadata?.js) {
38
+ return false;
39
+ }
40
+ const { packageExports, packageMain } = node.data.metadata.js;
41
+ // if we have exports only check this else fallback to packageMain
42
+ if (packageExports) {
43
+ return isBuildableExportMap(packageExports);
44
+ }
45
+ return (typeof packageMain === 'string' &&
46
+ packageMain !== '' &&
47
+ !isSourceFile(packageMain));
48
+ }
@@ -57,7 +57,7 @@ export interface NxAppWebpackPluginOptions {
57
57
  /**
58
58
  * Set <base href> for the resulting index.html.
59
59
  */
60
- baseHref?: string;
60
+ baseHref?: string | false;
61
61
  /**
62
62
  * Build the libraries from source. Default is `true`.
63
63
  */
@@ -73,6 +73,7 @@ export interface NxAppWebpackPluginOptions {
73
73
  crossOrigin?: 'none' | 'anonymous' | 'use-credentials';
74
74
  /**
75
75
  * Delete the output path before building.
76
+ * @deprecated Use the `output.clean` option in Webpack. https://webpack.js.org/guides/output-management/#cleaning-up-the-dist-folder
76
77
  */
77
78
  deleteOutputPath?: boolean;
78
79
  /**
@@ -185,7 +186,11 @@ export interface NxAppWebpackPluginOptions {
185
186
  /**
186
187
  * Options for the style preprocessor. e.g. `{ "includePaths": [] }` for SASS.
187
188
  */
188
- stylePreprocessorOptions?: any;
189
+ stylePreprocessorOptions?: {
190
+ includePaths?: string[];
191
+ sassOptions?: Record<string, any>;
192
+ lessOptions?: Record<string, any>;
193
+ };
189
194
  /**
190
195
  * External stylesheets that will be included with the application.
191
196
  */
@@ -206,6 +211,11 @@ export interface NxAppWebpackPluginOptions {
206
211
  * Use tsconfig-paths-webpack-plugin to resolve modules using paths in the tsconfig file.
207
212
  */
208
213
  useTsconfigPaths?: boolean;
214
+ /**
215
+ * The implementation of the SASS compiler to use. Can be either `sass` or `sass-embedded`. Defaults to `sass-embedded`.
216
+ * @deprecated Sass option will be removed in Nx 22. This option will also be removed in Nx 22 as it is no longer needed.
217
+ */
218
+ sassImplementation?: 'sass' | 'sass-embedded';
209
219
  /**
210
220
  * Generate a separate vendor chunk for 3rd party packages.
211
221
  */
@@ -226,6 +236,10 @@ export interface NxAppWebpackPluginOptions {
226
236
  * Whether to rebase absolute path for assets in postcss cli resources.
227
237
  */
228
238
  rebaseRootRelative?: boolean;
239
+ /**
240
+ * Watch buildable dependencies and rebuild when they change.
241
+ */
242
+ watchDependencies?: boolean;
229
243
  }
230
244
  export interface NormalizedNxAppWebpackPluginOptions extends NxAppWebpackPluginOptions {
231
245
  projectName: string;
@@ -29,6 +29,10 @@ class NxAppWebpackPlugin {
29
29
  if (typeof target === 'string') {
30
30
  this.options.target = target;
31
31
  }
32
+ // Prefer `clean` option from Webpack config over our own.
33
+ if (typeof compiler.options.output?.clean !== 'undefined') {
34
+ this.options.deleteOutputPath = false;
35
+ }
32
36
  (0, apply_base_config_1.applyBaseConfig)(this.options, compiler.options, {
33
37
  useNormalizedEntry: true,
34
38
  });
@@ -120,6 +120,7 @@ async function createWebpackTargets(configFilePath, projectRoot, options, contex
120
120
  },
121
121
  };
122
122
  targets[options.serveTargetName] = {
123
+ continuous: true,
123
124
  command: `webpack-cli serve`,
124
125
  options: {
125
126
  cwd: projectRoot,
@@ -139,6 +140,7 @@ async function createWebpackTargets(configFilePath, projectRoot, options, contex
139
140
  },
140
141
  };
141
142
  targets[options.previewTargetName] = {
143
+ continuous: true,
142
144
  command: `webpack-cli serve`,
143
145
  options: {
144
146
  cwd: projectRoot,
@@ -158,6 +160,7 @@ async function createWebpackTargets(configFilePath, projectRoot, options, contex
158
160
  },
159
161
  };
160
162
  targets[options.serveStaticTargetName] = {
163
+ continuous: true,
161
164
  dependsOn: [options.buildTargetName],
162
165
  executor: '@nx/web:file-server',
163
166
  options: {
@@ -1,11 +1,21 @@
1
1
  import type { Compiler } from 'webpack';
2
+ type PluginOptions = {
3
+ skipInitialBuild?: boolean;
4
+ skipWatchingDeps?: boolean;
5
+ };
2
6
  export declare class WebpackNxBuildCoordinationPlugin {
3
7
  private readonly buildCmd;
4
8
  private currentlyRunning;
5
9
  private buildCmdProcess;
10
+ constructor(buildCmd: string);
11
+ /**
12
+ * @deprecated Use the constructor with the `options` parameter instead.
13
+ */
6
14
  constructor(buildCmd: string, skipInitialBuild?: boolean);
15
+ constructor(buildCmd: string, options?: PluginOptions);
7
16
  apply(compiler: Compiler): void;
8
17
  startWatchingBuildableLibs(): Promise<void>;
9
18
  buildChangedProjects(): Promise<void>;
10
19
  private createFileWatcher;
11
20
  }
21
+ export {};
@@ -6,20 +6,25 @@ const client_1 = require("nx/src/daemon/client/client");
6
6
  const watch_1 = require("nx/src/command-line/watch/watch");
7
7
  const output_1 = require("nx/src/utils/output");
8
8
  class WebpackNxBuildCoordinationPlugin {
9
- constructor(buildCmd, skipInitialBuild) {
9
+ constructor(buildCmd, skipInitialBuildOrOptions) {
10
10
  this.buildCmd = buildCmd;
11
11
  this.currentlyRunning = 'none';
12
12
  this.buildCmdProcess = null;
13
- if (!skipInitialBuild) {
13
+ const options = typeof skipInitialBuildOrOptions === 'boolean'
14
+ ? { skipInitialBuild: skipInitialBuildOrOptions }
15
+ : skipInitialBuildOrOptions;
16
+ if (!options?.skipInitialBuild) {
14
17
  this.buildChangedProjects();
15
18
  }
16
- if ((0, client_1.isDaemonEnabled)()) {
17
- this.startWatchingBuildableLibs();
18
- }
19
- else {
20
- output_1.output.warn({
21
- title: 'Nx Daemon is not enabled. Buildable libs will not be rebuilt on file changes.',
22
- });
19
+ if (!options?.skipWatchingDeps) {
20
+ if ((0, client_1.isDaemonEnabled)()) {
21
+ this.startWatchingBuildableLibs();
22
+ }
23
+ else {
24
+ output_1.output.warn({
25
+ title: 'Nx Daemon is not enabled. Buildable libs will not be rebuilt on file changes.',
26
+ });
27
+ }
23
28
  }
24
29
  }
25
30
  apply(compiler) {
@@ -8,8 +8,13 @@ export interface WithWebOptions {
8
8
  generateIndexHtml?: boolean;
9
9
  index?: string;
10
10
  postcssConfig?: string;
11
+ sassImplementation?: 'sass' | 'sass-embedded';
11
12
  scripts?: Array<ExtraEntryPointClass | string>;
12
- stylePreprocessorOptions?: any;
13
+ stylePreprocessorOptions?: {
14
+ includePaths?: string[];
15
+ sassOptions?: Record<string, any>;
16
+ lessOptions?: Record<string, any>;
17
+ };
13
18
  styles?: Array<ExtraEntryPointClass | string>;
14
19
  subresourceIntegrity?: boolean;
15
20
  ssr?: boolean;
@@ -1,31 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = default_1;
4
- const devkit_1 = require("@nx/devkit");
5
- const executor_options_utils_1 = require("@nx/devkit/src/generators/executor-options-utils");
6
- async function default_1(tree) {
7
- const update = (options, projectName, targetName, configurationName) => {
8
- // Only handle webpack config for default configuration
9
- if (configurationName)
10
- return;
11
- const projectConfiguration = (0, devkit_1.readProjectConfiguration)(tree, projectName);
12
- if (!options.webpackConfig && options.isolatedConfig !== false) {
13
- options.webpackConfig = `${projectConfiguration.root}/webpack.config.js`;
14
- tree.write(options.webpackConfig, `
15
- const { composePlugins, withNx } = require('@nx/webpack');
16
-
17
- // Nx plugins for webpack.
18
- module.exports = composePlugins(withNx(), (config) => {
19
- // Note: This was added by an Nx migration. Webpack builds are required to have a corresponding Webpack config file.
20
- // See: https://nx.dev/recipes/webpack/webpack-config-setup
21
- return config;
22
- });
23
- `);
24
- projectConfiguration.targets[targetName].options = options;
25
- (0, devkit_1.updateProjectConfiguration)(tree, projectName, projectConfiguration);
26
- }
27
- };
28
- (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nx/webpack:webpack', update);
29
- (0, executor_options_utils_1.forEachExecutorOptions)(tree, '@nrwl/webpack:webpack', update);
30
- await (0, devkit_1.formatFiles)(tree);
31
- }