@openmrs/webpack-config 10.0.1-pre.5373 → 10.0.1-pre.5389

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.
package/dist/index.js CHANGED
@@ -49,7 +49,10 @@ const node_1 = require("browserslist/node");
49
49
  const browserslist_config_openmrs_1 = __importDefault(require("browserslist-config-openmrs"));
50
50
  const clean_webpack_plugin_1 = require("clean-webpack-plugin");
51
51
  const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
52
+ const css_minimizer_webpack_plugin_1 = __importDefault(require("css-minimizer-webpack-plugin"));
52
53
  const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
54
+ const lightningcss_1 = require("lightningcss");
55
+ const mini_css_extract_plugin_1 = __importDefault(require("mini-css-extract-plugin"));
53
56
  // eslint-disable-next-line no-restricted-imports
54
57
  const lodash_1 = require("lodash");
55
58
  const semver_1 = require("semver");
@@ -59,6 +62,7 @@ const browserslistTargetHandler_1 = __importDefault(require("webpack/lib/config/
59
62
  const webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
60
63
  const webpack_stats_plugin_1 = require("webpack-stats-plugin");
61
64
  const webpack_2 = require("@module-federation/enhanced/webpack");
65
+ const carbon_css_guard_1 = require("@openmrs/carbon-css-guard");
62
66
  const production = 'production';
63
67
  // Read from our own pin rather than `@module-federation/enhanced/package.json`, which its `exports` map
64
68
  // makes unreadable. `parse` rather than `coerce`, so that loosening the pin to a range disables the skew
@@ -277,14 +281,20 @@ exports.watchConfig = {};
277
281
  * This object will be merged with the webpack optimization
278
282
  * object.
279
283
  * Make sure to modify this object and not reassign it.
284
+ *
285
+ * Arrays here merge by index rather than replacing, so a `minimizer` set on this object lands on top of
286
+ * the defaults entry by entry instead of taking their place. Use `overrides.optimization` to replace
287
+ * them outright.
280
288
  */
281
289
  exports.optimizationConfig = {};
282
290
  exports.default = (env, argv = {}) => {
291
+ var _a;
283
292
  const root = process.cwd();
284
293
  // eslint-disable-next-line @typescript-eslint/no-require-imports
285
294
  const { name, version, peerDependencies, browser, main, types } = require((0, path_1.resolve)(root, 'package.json'));
286
295
  // this typing is provably incorrect, but actually works
287
296
  const mode = (argv.mode || process.env.NODE_ENV || 'development');
297
+ const isProd = mode === production;
288
298
  const filename = (0, path_1.basename)(browser || main);
289
299
  const outDir = (0, path_1.dirname)(browser || main);
290
300
  const srcFile = (0, path_1.resolve)(root, browser ? main : types);
@@ -299,20 +309,27 @@ exports.default = (env, argv = {}) => {
299
309
  // so this (hopefully) doesn't interfere with Webpack-specific exit codes
300
310
  process.exit(9819023573289);
301
311
  }
302
- const cssLoader = {
312
+ // These are factories rather than shared objects because `cssRuleConfig` and `scssRuleConfig` are
313
+ // merged into the rules with lodash `merge`, which mutates: one shared entry would let an override
314
+ // aimed at the CSS rule silently leak into the SCSS rule as well.
315
+ const cssLoader = () => ({
303
316
  loader: require.resolve('css-loader'),
304
317
  options: {
305
318
  modules: {
306
319
  localIdentName: `${ident}__[name]__[local]___[hash:base64:5]`,
307
320
  },
308
321
  },
309
- };
322
+ });
323
+ // Production emits real `.css` assets; development keeps `style-loader` for its better HMR story.
324
+ // See RFC 0033. The chunk-loading runtime resolves a chunk only once its stylesheet has loaded,
325
+ // so nothing mounts unstyled.
326
+ const styleLoader = () => isProd ? { loader: require.resolve(mini_css_extract_plugin_1.default.loader) } : { loader: require.resolve('style-loader') };
310
327
  const baseConfig = Object.assign({
311
328
  // The only `entry` in the application is the app shell. Everything else is
312
329
  // a Webpack Module Federation "remote." This ensures that there is always
313
330
  // only one container context--i.e., if we had an entry point per module,
314
331
  // WMF could get confused and not resolve shared dependencies correctly.
315
- output: {
332
+ entry: {}, output: {
316
333
  publicPath: 'auto',
317
334
  path: (0, path_1.resolve)(root, outDir),
318
335
  hashFunction: 'xxhash64',
@@ -335,13 +352,13 @@ exports.default = (env, argv = {}) => {
335
352
  }, exports.scriptRuleConfig),
336
353
  (0, lodash_1.merge)({
337
354
  test: /\.css$/,
338
- use: [require.resolve('style-loader'), cssLoader],
355
+ use: [styleLoader(), cssLoader()],
339
356
  }, exports.cssRuleConfig),
340
357
  (0, lodash_1.merge)({
341
358
  test: /\.s[ac]ss$/i,
342
359
  use: [
343
- require.resolve('style-loader'),
344
- cssLoader,
360
+ styleLoader(),
361
+ cssLoader(),
345
362
  {
346
363
  loader: require.resolve('sass-loader'),
347
364
  options: {
@@ -380,6 +397,17 @@ exports.default = (env, argv = {}) => {
380
397
  maxAsyncRequests: 3,
381
398
  maxInitialRequests: 1,
382
399
  },
400
+ // `'...'` keeps webpack's default JS minifier; naming any minimizer would otherwise replace it.
401
+ // Lightning CSS so that extracted stylesheets are minified the same way `@openmrs/rspack-config`
402
+ // minifies them. `targets` is passed explicitly because neither bundler's default consults the
403
+ // module's browserslist.
404
+ minimizer: [
405
+ '...',
406
+ new css_minimizer_webpack_plugin_1.default({
407
+ minify: css_minimizer_webpack_plugin_1.default.lightningCssMinify,
408
+ minimizerOptions: { targets: (0, lightningcss_1.browserslistToTargets)((0, browserslist_1.default)(browserTargets)) },
409
+ }),
410
+ ],
383
411
  }, exports.optimizationConfig), plugins: [
384
412
  browserslistWarnings.length > 0 && new BrowserslistWarningsPlugin(browserslistWarnings),
385
413
  new fork_ts_checker_webpack_plugin_1.default({
@@ -393,6 +421,12 @@ exports.default = (env, argv = {}) => {
393
421
  },
394
422
  }),
395
423
  new clean_webpack_plugin_1.CleanWebpackPlugin(),
424
+ isProd &&
425
+ new mini_css_extract_plugin_1.default({
426
+ // `ignoreOrder` because nearly every class here is uniquely scoped by CSS Modules, so the
427
+ // conflicting-order warnings this would otherwise emit across chunks are almost all noise.
428
+ ignoreOrder: true,
429
+ }),
396
430
  new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
397
431
  analyzerMode: env && env.analyze ? 'server' : 'disabled',
398
432
  }),
@@ -488,5 +522,12 @@ exports.default = (env, argv = {}) => {
488
522
  'lodash.throttle': 'lodash-es/throttle',
489
523
  },
490
524
  } }, exports.overrides);
491
- return (0, lodash_1.mergeWith)(baseConfig, exports.additionalConfig, mergeFunction);
525
+ const config = (0, lodash_1.mergeWith)(baseConfig, exports.additionalConfig, mergeFunction);
526
+ // Appended after the merge rather than listed above. `overrides` is spread over the config object, so
527
+ // an app setting `overrides.plugins` replaces the whole array — not a lodash merge, which would keep
528
+ // the entries — and would drop the guard without noticing. Same reasoning as the `ExternalsPlugin`
529
+ // block above, which avoids `externals` for the same reason.
530
+ // Production only: under `style-loader` there are no `.css` assets to check.
531
+ config.plugins = [...((_a = config.plugins) !== null && _a !== void 0 ? _a : []), ...(isProd ? [new carbon_css_guard_1.CarbonCssGuardPlugin(name)] : [])];
532
+ return config;
492
533
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/webpack-config",
3
- "version": "10.0.1-pre.5373",
3
+ "version": "10.0.1-pre.5389",
4
4
  "license": "MPL-2.0",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,14 +32,18 @@
32
32
  "homepage": "https://github.com/openmrs/openmrs-esm-core#readme",
33
33
  "dependencies": {
34
34
  "@module-federation/enhanced": "2.8.1",
35
+ "@openmrs/carbon-css-guard": "10.0.1-pre.5389",
35
36
  "@swc/core": "1.15.21",
36
37
  "browserslist": "4.28.9",
37
38
  "browserslist-config-openmrs": "^1.0.1",
38
39
  "clean-webpack-plugin": "4.0.0",
39
40
  "copy-webpack-plugin": "11.0.0",
40
41
  "css-loader": "5.2.7",
42
+ "css-minimizer-webpack-plugin": "7.0.2",
41
43
  "fork-ts-checker-webpack-plugin": "6.5.3",
44
+ "lightningcss": "1.32.0",
42
45
  "lodash": "4.17.21",
46
+ "mini-css-extract-plugin": "2.9.1",
43
47
  "sass-embedded": "1.89.2",
44
48
  "sass-loader": "16.0.5",
45
49
  "semver": "^7.7.3",
package/src/index.ts CHANGED
@@ -43,7 +43,10 @@ import { loadQueries } from 'browserslist/node';
43
43
  import defaultBrowserslistQueries from 'browserslist-config-openmrs';
44
44
  import { CleanWebpackPlugin } from 'clean-webpack-plugin';
45
45
  import CopyWebpackPlugin from 'copy-webpack-plugin';
46
+ import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
46
47
  import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
48
+ import { browserslistToTargets, type Targets } from 'lightningcss';
49
+ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
47
50
  // eslint-disable-next-line no-restricted-imports
48
51
  import { isArray, merge, mergeWith } from 'lodash';
49
52
  import { inc, parse } from 'semver';
@@ -62,6 +65,7 @@ import browserslistTargetHandler from 'webpack/lib/config/browserslistTargetHand
62
65
  import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
63
66
  import { StatsWriterPlugin } from 'webpack-stats-plugin';
64
67
  import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
68
+ import { CarbonCssGuardPlugin } from '@openmrs/carbon-css-guard';
65
69
 
66
70
  type OpenmrsWebpackConfig = Omit<Partial<WebpackConfiguration>, 'module' | 'output'> & {
67
71
  module: ModuleOptions;
@@ -341,6 +345,10 @@ export const watchConfig: Partial<WebpackConfiguration['watchOptions']> = {};
341
345
  * This object will be merged with the webpack optimization
342
346
  * object.
343
347
  * Make sure to modify this object and not reassign it.
348
+ *
349
+ * Arrays here merge by index rather than replacing, so a `minimizer` set on this object lands on top of
350
+ * the defaults entry by entry instead of taking their place. Use `overrides.optimization` to replace
351
+ * them outright.
344
352
  */
345
353
  export const optimizationConfig: Partial<WebpackConfiguration['optimization']> = {};
346
354
 
@@ -350,6 +358,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
350
358
  const { name, version, peerDependencies, browser, main, types } = require(resolve(root, 'package.json'));
351
359
  // this typing is provably incorrect, but actually works
352
360
  const mode = (argv.mode || process.env.NODE_ENV || 'development') as WebpackConfiguration['mode'];
361
+ const isProd = mode === production;
353
362
  const filename = basename(browser || main);
354
363
  const outDir = dirname(browser || main);
355
364
  const srcFile = resolve(root, browser ? main : types);
@@ -368,20 +377,30 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
368
377
  process.exit(9819023573289);
369
378
  }
370
379
 
371
- const cssLoader = {
380
+ // These are factories rather than shared objects because `cssRuleConfig` and `scssRuleConfig` are
381
+ // merged into the rules with lodash `merge`, which mutates: one shared entry would let an override
382
+ // aimed at the CSS rule silently leak into the SCSS rule as well.
383
+ const cssLoader = () => ({
372
384
  loader: require.resolve('css-loader'),
373
385
  options: {
374
386
  modules: {
375
387
  localIdentName: `${ident}__[name]__[local]___[hash:base64:5]`,
376
388
  },
377
389
  },
378
- };
390
+ });
391
+
392
+ // Production emits real `.css` assets; development keeps `style-loader` for its better HMR story.
393
+ // See RFC 0033. The chunk-loading runtime resolves a chunk only once its stylesheet has loaded,
394
+ // so nothing mounts unstyled.
395
+ const styleLoader = () =>
396
+ isProd ? { loader: require.resolve(MiniCssExtractPlugin.loader) } : { loader: require.resolve('style-loader') };
379
397
 
380
398
  const baseConfig: OpenmrsWebpackConfig = {
381
399
  // The only `entry` in the application is the app shell. Everything else is
382
400
  // a Webpack Module Federation "remote." This ensures that there is always
383
401
  // only one container context--i.e., if we had an entry point per module,
384
402
  // WMF could get confused and not resolve shared dependencies correctly.
403
+ entry: {},
385
404
  output: {
386
405
  publicPath: 'auto',
387
406
  path: resolve(root, outDir),
@@ -410,7 +429,7 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
410
429
  merge(
411
430
  {
412
431
  test: /\.css$/,
413
- use: [require.resolve('style-loader'), cssLoader],
432
+ use: [styleLoader(), cssLoader()],
414
433
  },
415
434
  cssRuleConfig,
416
435
  ),
@@ -418,8 +437,8 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
418
437
  {
419
438
  test: /\.s[ac]ss$/i,
420
439
  use: [
421
- require.resolve('style-loader'),
422
- cssLoader,
440
+ styleLoader(),
441
+ cssLoader(),
423
442
  {
424
443
  loader: require.resolve('sass-loader'),
425
444
  options: {
@@ -474,6 +493,17 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
474
493
  maxAsyncRequests: 3,
475
494
  maxInitialRequests: 1,
476
495
  },
496
+ // `'...'` keeps webpack's default JS minifier; naming any minimizer would otherwise replace it.
497
+ // Lightning CSS so that extracted stylesheets are minified the same way `@openmrs/rspack-config`
498
+ // minifies them. `targets` is passed explicitly because neither bundler's default consults the
499
+ // module's browserslist.
500
+ minimizer: [
501
+ '...',
502
+ new CssMinimizerPlugin<{ targets: Targets }>({
503
+ minify: CssMinimizerPlugin.lightningCssMinify,
504
+ minimizerOptions: { targets: browserslistToTargets(browserslist(browserTargets)) },
505
+ }),
506
+ ],
477
507
  },
478
508
  optimizationConfig,
479
509
  ),
@@ -490,6 +520,12 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
490
520
  },
491
521
  }),
492
522
  new CleanWebpackPlugin(),
523
+ isProd &&
524
+ new MiniCssExtractPlugin({
525
+ // `ignoreOrder` because nearly every class here is uniquely scoped by CSS Modules, so the
526
+ // conflicting-order warnings this would otherwise emit across chunks are almost all noise.
527
+ ignoreOrder: true,
528
+ }),
493
529
  new BundleAnalyzerPlugin({
494
530
  analyzerMode: env && env.analyze ? 'server' : 'disabled',
495
531
  }),
@@ -593,5 +629,14 @@ export default (env: Record<string, string>, argv: Record<string, string> = {})
593
629
  },
594
630
  ...overrides,
595
631
  };
596
- return mergeWith(baseConfig, additionalConfig, mergeFunction);
632
+ const config = mergeWith(baseConfig, additionalConfig, mergeFunction);
633
+
634
+ // Appended after the merge rather than listed above. `overrides` is spread over the config object, so
635
+ // an app setting `overrides.plugins` replaces the whole array — not a lodash merge, which would keep
636
+ // the entries — and would drop the guard without noticing. Same reasoning as the `ExternalsPlugin`
637
+ // block above, which avoids `externals` for the same reason.
638
+ // Production only: under `style-loader` there are no `.css` assets to check.
639
+ config.plugins = [...(config.plugins ?? []), ...(isProd ? [new CarbonCssGuardPlugin(name)] : [])];
640
+
641
+ return config;
597
642
  };