weboptimizer 4.0.44 → 4.0.46

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "weboptimizer",
3
- "version": "4.0.44",
3
+ "version": "4.0.46",
4
4
  "description": "A generic web optimizer, (module) bundler and development environment.",
5
5
  "keywords": [
6
6
  "webpack",
@@ -77,7 +77,7 @@
77
77
  "lint:base": "eslint --no-warn-ignored *.ts */*.ts test/*/*.ts",
78
78
  "prepare": "yarn build",
79
79
  "prettify": "yarn lint:base --fix || true",
80
- "test": "yarn build:test && node --experimental-vm-modules node_modules/.bin/jest --config ./weboptimizerJest.json --root-dir './' --test-regex '/test/.+\\\\.js$' test/browser.js test/configurator.js test/ejsLoader.js test/helper.js test/stylelintConfigurator.js test/index.js test/webpackConfigurator.js",
80
+ "test": "yarn build:test && node --experimental-vm-modules node_modules/.bin/jest --config ./weboptimizerJest.json --noStackTrace --root-dir './' --test-regex '/test/.+\\\\.js$' test/browser.js test/configurator.js test/ejsLoader.js test/helper.js test/stylelintConfigurator.js test/index.js test/webpackConfigurator.js",
81
81
  "test:coverage": "yarn test --ci --coverage --coverageReporters=text --coverageReporters=text-summary --silent --testLocationInResults",
82
82
  "test:coverage:report": "yarn test:coverage --coverageDirectory=.coverage --coverageReporters=lcov --outputFile=lcov.info",
83
83
  "test:watch": "yarn test --watch",
@@ -94,7 +94,7 @@
94
94
  "babel-loader": "^10.1.1",
95
95
  "babel-plugin-polyfill-corejs3": "^1.0.0",
96
96
  "babel-plugin-transform-rewrite-imports": "^1.5.4",
97
- "clientnode": "4.0.1477",
97
+ "clientnode": "4.0.1480",
98
98
  "core-js": "^3.49.0",
99
99
  "ejs": "^6.0.1",
100
100
  "exports-loader": "^5.0.0",
@@ -108,8 +108,8 @@
108
108
  "rimraf": "^6.1.3",
109
109
  "script-loader": "^0.7.2",
110
110
  "typescript": "^6.0.3",
111
- "webpack": "^5.109.1",
112
- "webpack-cli": "^7.2.1",
111
+ "webpack": "^5.109.2",
112
+ "webpack-cli": "^7.2.2",
113
113
  "webpack-sources": "^3.5.1"
114
114
  },
115
115
  "devDependencies": {
@@ -132,7 +132,7 @@
132
132
  "cssnano": "^8.0.2",
133
133
  "eslint": "^10.8.0",
134
134
  "eslint-config-google": "^0.14.0",
135
- "eslint-plugin-jsdoc": "^63.3.1",
135
+ "eslint-plugin-jsdoc": "^63.3.2",
136
136
  "favicons": "^7.3.1",
137
137
  "favicons-webpack-plugin": "^6.0.1",
138
138
  "globals": "^17.8.0",
@@ -142,7 +142,7 @@
142
142
  "mini-css-extract-plugin": "^2.10.2",
143
143
  "mkdirp": "^3.0.1",
144
144
  "node-fetch": "^3.3.2",
145
- "postcss": "^8.5.23",
145
+ "postcss": "^8.5.25",
146
146
  "postcss-fontpath": "^1.0.0",
147
147
  "postcss-import": "^16.1.1",
148
148
  "postcss-loader": "^8.2.1",
@@ -157,7 +157,7 @@
157
157
  "terser-webpack-plugin": "^5.6.1",
158
158
  "typescript-eslint": "^8.65.0",
159
159
  "typescript-plugin-css-modules": "^5.2.0",
160
- "web-documentation": "^1.0.43",
160
+ "web-documentation": "^1.0.44",
161
161
  "workbox-webpack-plugin": "^7.4.1"
162
162
  },
163
163
  "peerDependencies": {
@@ -17,6 +17,7 @@
17
17
  */
18
18
  // region imports
19
19
  import { convertToValidVariableName, evaluate, escapeRegularExpressions, extend, importFilesystemAPI, isFileSync, isObject, isPlainObject, Logger, mask, optionalImport, represent, UTILITY_SCOPE } from 'clientnode';
20
+ import { rm, writeFile } from 'fs/promises';
20
21
  import { extname, join, relative, resolve } from 'path';
21
22
  import util from 'util';
22
23
  import webpack from 'webpack';
@@ -762,6 +763,60 @@ if (configuration.path.configuration.json) try {
762
763
  } catch {
763
764
  log.debug('Optional configuration file', `"${configuration.path.configuration.json}" not available.`);
764
765
  }
766
+
767
+ // region collapse multi-module ("multi-main") entry chunks into a barrel
768
+ /*
769
+ NOTE: Webpack awaits a single (async) entry module before completing the
770
+ startup evaluation but does NOT await async modules that are referenced as
771
+ part of an array ("multi-main") entry chunk. As a consequence any
772
+ top-level "await" (async module) reachable from such an entry - and every
773
+ side effect depending on it, like jest's synchronous "describe" / "test"
774
+ registration - would run only after the synchronous startup phase already
775
+ finished (leading for example to "Cannot nest a describe inside a test").
776
+
777
+ To keep evaluation deterministic we collapse every chunk which bundles
778
+ more than one module into a single generated barrel module which webpack
779
+ treats (and, when async, awaits) as a whole. Re-exporting via "export *"
780
+ preserves the (named) exports of all bundled modules while guaranteeing
781
+ each one is evaluated in the given order.
782
+ */
783
+ const generatedBarrelModuleFilePaths = [];
784
+ const normalizedEntryInjection = {};
785
+ for (const [chunkName, moduleIDs] of Object.entries(configuration.injection.entry.normalized)) if (Array.isArray(moduleIDs) && moduleIDs.length > 1) {
786
+ const barrelModuleFilePath = resolve(configuration.path.context, `.__${convertToValidVariableName(chunkName)}__.barrel.mjs`);
787
+ await writeFile(barrelModuleFilePath, moduleIDs.map(moduleID => {
788
+ const specifier = stripLoader(moduleID);
789
+ return `export * from ${JSON.stringify(specifier.startsWith('.') || specifier.startsWith('/') ? specifier : `./${specifier}`)}`;
790
+ }).join('\n') + '\n', {
791
+ encoding: configuration.encoding
792
+ });
793
+ generatedBarrelModuleFilePaths.push(barrelModuleFilePath);
794
+ normalizedEntryInjection[chunkName] = [`./${relative(configuration.path.context, barrelModuleFilePath)}`];
795
+ } else normalizedEntryInjection[chunkName] = moduleIDs;
796
+ if (generatedBarrelModuleFilePaths.length) pluginInstances.push({
797
+ apply: compiler => {
798
+ const removeGeneratedBarrelModules = async () => {
799
+ for (const filePath of generatedBarrelModuleFilePaths) try {
800
+ await rm(filePath, {
801
+ force: true
802
+ });
803
+ } catch (error) {
804
+ log.debug('Removing generated barrel entry module ' + `"${filePath}" failed:`, represent(error));
805
+ }
806
+ };
807
+
808
+ /*
809
+ NOTE: "shutdown" is an "AsyncSeriesHook" fired (and awaited) by
810
+ "compiler.close()" for both one-shot builds and watch-mode
811
+ teardown, so "tapPromise" guarantees the (async) removal finishes
812
+ before the process exits. "watchClose" would be a "SyncHook" which
813
+ cannot await a promise-based cleanup, hence it is not used here.
814
+ */
815
+ compiler.hooks.shutdown.tapPromise('WebOptimizerRemoveGeneratedBarrelModules', removeGeneratedBarrelModules);
816
+ }
817
+ });
818
+ // endregion
819
+
765
820
  export let webpackConfiguration = extend(true, {
766
821
  bail: !configuration.givenCommandLineArguments.includes('--watch'),
767
822
  context: configuration.path.context,
@@ -791,7 +846,7 @@ export let webpackConfiguration = extend(true, {
791
846
  typescript: false
792
847
  },
793
848
  // region input
794
- entry: configuration.injection.entry.normalized,
849
+ entry: normalizedEntryInjection,
795
850
  externals: configuration.injection.external.modules,
796
851
  resolve: {
797
852
  alias: module.aliases,