@pixolith/webpack-sw6-config 12.0.2 → 12.0.4

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@pixolith/webpack-sw6-config",
3
3
  "public": true,
4
- "version": "12.0.2",
4
+ "version": "12.0.4",
5
5
  "description": "",
6
6
  "main": "src/index.js",
7
7
  "scripts": {},
@@ -21,7 +21,7 @@
21
21
  "url": "https://github.com/pixolith/webpack-plugins/issues"
22
22
  },
23
23
  "homepage": "https://github.com/pixolith/webpack-plugins/tree/master/packages/webpack-hook-plugin/#readme",
24
- "gitHead": "f97131a8656eaf93375ee9289067ccad56ecfdf4",
24
+ "gitHead": "fb56cf1e8eb854872b9576456bdb1fbe7c5343f4",
25
25
  "dependencies": {
26
26
  "@babel/cli": "7.25.9",
27
27
  "@babel/core": "^7.26.0",
@@ -35,9 +35,9 @@
35
35
  "@pixolith/webpack-assets-copy-plugin": "^12.0.0",
36
36
  "@pixolith/webpack-filename-linter-plugin": "^12.0.0",
37
37
  "@pixolith/webpack-hook-plugin": "^12.0.0",
38
- "@pixolith/webpack-sw6-plugin-map-emitter": "^12.0.0",
38
+ "@pixolith/webpack-sw6-plugin-map-emitter": "^12.0.3",
39
39
  "@pixolith/webpack-twig-assets-emitter-plugin": "^12.0.0",
40
- "@pixolith/webpack-watcher": "^12.0.0",
40
+ "@pixolith/webpack-watcher": "^12.0.3",
41
41
  "@swc/core": "^1.9.3",
42
42
  "autoprefixer": "^10.4.20",
43
43
  "babel-loader": "^9.2.1",
package/src/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const Path = require('path');
4
+ const Os = require('os');
4
5
 
5
6
  const config = {
6
7
  isProd: process.env.NODE_ENV === 'production',
@@ -27,7 +28,13 @@ const config = {
27
28
  jsFolder: process.env.JS_FOLDER || 'js',
28
29
  iconsFolder: process.env.ICONS_FOLDER || 'icons',
29
30
 
30
- spriteOrder: process.env.SPRITE_ORDER ?? ['pxsw/basic-theme', 'PxswBasicTheme', '**', 'pxsw/customer-theme', 'PxswCustomerTheme'],
31
+ spriteOrder: process.env.SPRITE_ORDER ?? [
32
+ 'pxsw/basic-theme',
33
+ 'PxswBasicTheme',
34
+ '**',
35
+ 'pxsw/customer-theme',
36
+ 'PxswCustomerTheme',
37
+ ],
31
38
  ignoreIcons: process.env.IGNORE_ICONS ?? [],
32
39
 
33
40
  mediaQueries: process.env.MEDIA_QUERIES || false,
@@ -40,12 +47,25 @@ const config = {
40
47
  pluginsPublicPath: Path.join(process.cwd(), 'public'),
41
48
  vendorPublicPath: Path.join(process.cwd(), 'public/bundles'),
42
49
 
43
- shopwareVendorPath: Path.join(process.cwd(), 'vendor/shopware/storefront/Resources/app/storefront/vendor'),
44
- shopwarePluginPath: Path.join(process.cwd(), 'vendor/shopware/storefront/Resources/app/storefront/src'),
50
+ shopwareVendorPath: Path.join(
51
+ process.cwd(),
52
+ 'vendor/shopware/storefront/Resources/app/storefront/vendor',
53
+ ),
54
+ shopwarePluginPath: Path.join(
55
+ process.cwd(),
56
+ 'vendor/shopware/storefront/Resources/app/storefront/src',
57
+ ),
45
58
 
46
59
  allowedExtensions: ['.ts', '.js', '.scss', '.css', '.svg'],
60
+
61
+ // Dev server connection settings (used for devServer config + output.publicPath in dev)
62
+ devServerHostname: process.env.DEV_SERVER_HOSTNAME || 'node.px-staging.de',
63
+ devServerPort: process.env.SHOPWARE_MODE === 'administration' ? 8080 : 8081,
64
+ devServerProtocol: process.env.DEV_SERVER_PROTOCOL || 'https',
47
65
  };
48
66
 
67
+ config.devServerPublicUrl = `${config.devServerProtocol}://${config.devServerHostname}:${config.devServerPort}/`;
68
+
49
69
  // PICKED_THEME: optional filter to build/watch a single theme from THEME_NAMES
50
70
  let pickedTheme = process.env.PICKED_THEME
51
71
  ? process.env.PICKED_THEME.trim()
@@ -53,7 +73,9 @@ let pickedTheme = process.env.PICKED_THEME
53
73
 
54
74
  if (pickedTheme && config.themeNames.indexOf(pickedTheme) === -1) {
55
75
  process.stderr.write(
56
- `PICKED_THEME "${pickedTheme}" is not in THEME_NAMES [${config.themeNames.join(', ')}].\n`,
76
+ `PICKED_THEME "${pickedTheme}" is not in THEME_NAMES [${config.themeNames.join(
77
+ ', ',
78
+ )}].\n`,
57
79
  );
58
80
  process.exit(1);
59
81
  }
@@ -62,6 +84,21 @@ if (pickedTheme && config.themeNames.indexOf(pickedTheme) === -1) {
62
84
  // themeNames stays as the full list (used for _global_resources exclusion)
63
85
  config.buildThemes = pickedTheme ? [pickedTheme] : config.themeNames;
64
86
 
87
+ // buildParallelism: how many per-theme compilers webpack's MultiCompiler runs
88
+ // concurrently. Default is webpack's `Infinity` (all themes at once) which is
89
+ // extremely memory-hungry with many themes. We cap it to a conservative,
90
+ // CPU-aware value. Override with BUILD_PARALLELISM=<n> (e.g. on big CI boxes).
91
+ // Peak memory ≈ buildParallelism × (memory of one theme compiler).
92
+ config.buildParallelism = (() => {
93
+ let raw = parseInt(process.env.BUILD_PARALLELISM, 10);
94
+ let value =
95
+ Number.isInteger(raw) && raw > 0
96
+ ? raw
97
+ : Math.max(2, Math.floor(Os.cpus().length / 4));
98
+ // Never exceed the number of themes actually being built.
99
+ return Math.max(1, Math.min(value, config.buildThemes.length || 1));
100
+ })();
101
+
65
102
  const pxEntryPath =
66
103
  process.env.PX_ENTRY_PATH ||
67
104
  (process.env.SHOPWARE_MODE === 'storefront'
@@ -74,12 +111,25 @@ const pxRouteSplitPath =
74
111
  : '');
75
112
 
76
113
  // Create a glob regex to match the plugin prefixes
77
- let prefixes = config.pluginPrefixes.split(',').map(p => `${p}*`).join('|');
114
+ let prefixes = config.pluginPrefixes
115
+ .split(',')
116
+ .map((p) => `${p}*`)
117
+ .join('|');
78
118
  const pluginSrcPath = Path.join(config.pluginsBasePath, `+(${prefixes})`);
79
- const vendorSrcPath = Path.join(config.vendorBasePath, `+(${config.pluginPrefixes.replace(',', '|').toLowerCase()})`, '*');
80
-
81
- const pluginMatch = new RegExp(`/plugins\/((${config.pluginPrefixes.replace(',', '|')})\\w*)\/`);
82
- const vendorMatch = new RegExp(`/(vendor\/(${config.pluginPrefixes.replace(',', '|').toLowerCase()})\/[\\w-]*)\/`);
119
+ const vendorSrcPath = Path.join(
120
+ config.vendorBasePath,
121
+ `+(${config.pluginPrefixes.replace(',', '|').toLowerCase()})`,
122
+ '*',
123
+ );
124
+
125
+ const pluginMatch = new RegExp(
126
+ `/plugins\/((${config.pluginPrefixes.replace(',', '|')})\\w*)\/`,
127
+ );
128
+ const vendorMatch = new RegExp(
129
+ `/(vendor\/(${config.pluginPrefixes
130
+ .replace(',', '|')
131
+ .toLowerCase()})\/[\\w-]*)\/`,
132
+ );
83
133
  const routeSplitMatch = new RegExp(`/scss-route-split\/([\\w-]*)`);
84
134
 
85
135
  module.exports = {
@@ -96,11 +146,31 @@ module.exports = {
96
146
  pluginMatch: pluginMatch,
97
147
  vendorMatch: vendorMatch,
98
148
 
99
- sharedScssPluginPath: Path.join(pluginSrcPath, pxEntryPath, config.pxSharedPath, config.scssFolder),
100
- sharedScssVendorPath: Path.join(vendorSrcPath, pxEntryPath, config.pxSharedPath, config.scssFolder),
101
-
102
- sharedIconPluginPath: Path.join(pluginSrcPath, pxEntryPath, config.pxSharedPath, config.iconsFolder),
103
- sharedIconVendorPath: Path.join(vendorSrcPath, pxEntryPath, config.pxSharedPath, config.iconsFolder),
149
+ sharedScssPluginPath: Path.join(
150
+ pluginSrcPath,
151
+ pxEntryPath,
152
+ config.pxSharedPath,
153
+ config.scssFolder,
154
+ ),
155
+ sharedScssVendorPath: Path.join(
156
+ vendorSrcPath,
157
+ pxEntryPath,
158
+ config.pxSharedPath,
159
+ config.scssFolder,
160
+ ),
161
+
162
+ sharedIconPluginPath: Path.join(
163
+ pluginSrcPath,
164
+ pxEntryPath,
165
+ config.pxSharedPath,
166
+ config.iconsFolder,
167
+ ),
168
+ sharedIconVendorPath: Path.join(
169
+ vendorSrcPath,
170
+ pxEntryPath,
171
+ config.pxSharedPath,
172
+ config.iconsFolder,
173
+ ),
104
174
 
105
175
  routeSplitMatch: routeSplitMatch,
106
176
  pluginRouteSplitPath: Path.join(pluginSrcPath, pxRouteSplitPath),
package/src/index.js CHANGED
@@ -35,6 +35,7 @@ const setup = () => {
35
35
  shopwareMode: config.shopwareMode,
36
36
  assetUrl: config.assetUrl,
37
37
  themeNames: config.themeNames.join(', ') + (config.buildThemes.length < config.themeNames.length ? ' (building: ' + config.buildThemes.join(', ') + ')' : ''),
38
+ parallelism: config.buildParallelism + ' / ' + config.buildThemes.length + ' themes',
38
39
  version: pkg.version,
39
40
  });
40
41
  }
@@ -125,7 +126,7 @@ const getResourcesPaths = (themeName, options) => {
125
126
  const createThemeConfigs = (options) => {
126
127
  setup();
127
128
 
128
- return config.buildThemes.map((themeName, index) => {
129
+ let themeConfigs = config.buildThemes.map((themeName, index) => {
129
130
  let resourcesPaths = getResourcesPaths(themeName, options);
130
131
  let themeSlug = ChangeCase.kebabCase(themeName);
131
132
  let themeOptions = {
@@ -157,6 +158,12 @@ const createThemeConfigs = (options) => {
157
158
 
158
159
  return merged;
159
160
  });
161
+
162
+ // Limit how many theme compilers run concurrently (webpack MultiCompiler).
163
+ // Without this webpack runs all of them in parallel in a single process.
164
+ themeConfigs.parallelism = config.buildParallelism;
165
+
166
+ return themeConfigs;
160
167
  };
161
168
 
162
169
  const setupAdministration = () => {
@@ -181,6 +188,7 @@ const setupAdministration = () => {
181
188
  shopwareMode: config.shopwareMode,
182
189
  assetUrl: config.assetUrl,
183
190
  themeNames: config.themeNames.join(', ') + (config.buildThemes.length < config.themeNames.length ? ' (building: ' + config.buildThemes.join(', ') + ')' : ''),
191
+ parallelism: config.buildParallelism + ' / ' + config.buildThemes.length + ' themes',
184
192
  version: pkg.version,
185
193
  });
186
194
  }
@@ -200,7 +208,7 @@ const setupAdministration = () => {
200
208
  const createAdminConfigs = (options) => {
201
209
  setupAdministration();
202
210
 
203
- return config.buildThemes.map((themeName, index) => {
211
+ let adminConfigs = config.buildThemes.map((themeName, index) => {
204
212
  let resourcesPaths = getResourcesPaths(themeName, options);
205
213
  let themeSlug = ChangeCase.kebabCase(themeName);
206
214
  let themeOptions = {
@@ -232,6 +240,11 @@ const createAdminConfigs = (options) => {
232
240
 
233
241
  return merged;
234
242
  });
243
+
244
+ // Limit how many theme compilers run concurrently (webpack MultiCompiler).
245
+ adminConfigs.parallelism = config.buildParallelism;
246
+
247
+ return adminConfigs;
235
248
  };
236
249
 
237
250
  module.exports = {
@@ -105,16 +105,14 @@ module.exports = function createDevConfig(themeOptions) {
105
105
  allowedHosts: 'all',
106
106
  client: {
107
107
  webSocketURL: {
108
- hostname: 'node.px-staging.de',
108
+ hostname: config.devServerHostname,
109
109
  protocol: 'wss',
110
- port:
111
- process.env.SHOPWARE_MODE === 'administration'
112
- ? 8080
113
- : 8081,
110
+ port: config.devServerPort,
114
111
  },
115
112
  overlay: {
116
113
  warnings: false,
117
114
  errors: true,
115
+ runtimeErrors: false,
118
116
  },
119
117
  },
120
118
  headers: {
@@ -124,7 +122,7 @@ module.exports = function createDevConfig(themeOptions) {
124
122
  'Access-Control-Allow-Headers':
125
123
  'X-Requested-With, content-type, Authorization',
126
124
  },
127
- port: process.env.SHOPWARE_MODE === 'administration' ? 8080 : 8081,
125
+ port: config.devServerPort,
128
126
  server: !config.isProd
129
127
  ? {
130
128
  type: 'https',
@@ -150,8 +148,9 @@ module.exports = function createDevConfig(themeOptions) {
150
148
  },
151
149
  }
152
150
  : 'http',
151
+ liveReload: false,
153
152
  devMiddleware: {
154
- writeToDisk: true,
153
+ writeToDisk: (filePath) => !filePath.includes('.hot-update.'),
155
154
  },
156
155
  setupMiddlewares: (middlewares, devServer) => {
157
156
  if (!devServer) {
@@ -197,5 +196,8 @@ module.exports = function createDevConfig(themeOptions) {
197
196
  : [],
198
197
  ),
199
198
  watch: false,
199
+ optimization: {
200
+ runtimeChunk: 'single',
201
+ },
200
202
  };
201
203
  };
@@ -14,7 +14,8 @@ module.exports = function createStorefrontConfig(themeOptions) {
14
14
 
15
15
  let outputConfig = {
16
16
  path: config.outputPath,
17
- publicPath: config.assetUrl,
17
+ publicPath: config.isProd ? config.assetUrl : config.devServerPublicUrl,
18
+ crossOriginLoading: config.isProd ? false : 'anonymous',
18
19
  chunkFilename: (chunkData) => {
19
20
  return `js/chunk[name]${config.isProd ? '.[contenthash]' : ''}.js`;
20
21
  },