@pixolith/webpack-sw6-config 11.0.8 → 12.0.0
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 +11 -11
- package/src/config.js +46 -6
- package/src/index.js +205 -7
- package/src/webpack.config.administration.js +92 -160
- package/src/webpack.config.dev.js +162 -167
- package/src/webpack.config.storefront.js +170 -129
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixolith/webpack-sw6-config",
|
|
3
3
|
"public": true,
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "12.0.0",
|
|
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": "
|
|
24
|
+
"gitHead": "5c29b0a4c1b2e0876f25a05f517100c83fc9a36c",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@babel/cli": "7.25.9",
|
|
27
27
|
"@babel/core": "^7.26.0",
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
"@babel/plugin-proposal-decorators": "7.25.9",
|
|
30
30
|
"@babel/preset-env": "7.26.0",
|
|
31
31
|
"@babel/preset-typescript": "7.26.0",
|
|
32
|
-
"@pixolith/eslint-config-sw6": "^
|
|
33
|
-
"@pixolith/external-svg-sprite-loader": "^
|
|
34
|
-
"@pixolith/stylelint-config-standard": "^
|
|
35
|
-
"@pixolith/webpack-assets-copy-plugin": "^
|
|
36
|
-
"@pixolith/webpack-filename-linter-plugin": "^
|
|
37
|
-
"@pixolith/webpack-hook-plugin": "^
|
|
38
|
-
"@pixolith/webpack-sw6-plugin-map-emitter": "^
|
|
39
|
-
"@pixolith/webpack-twig-assets-emitter-plugin": "^
|
|
40
|
-
"@pixolith/webpack-watcher": "^
|
|
32
|
+
"@pixolith/eslint-config-sw6": "^12.0.0",
|
|
33
|
+
"@pixolith/external-svg-sprite-loader": "^12.0.0",
|
|
34
|
+
"@pixolith/stylelint-config-standard": "^12.0.0",
|
|
35
|
+
"@pixolith/webpack-assets-copy-plugin": "^12.0.0",
|
|
36
|
+
"@pixolith/webpack-filename-linter-plugin": "^12.0.0",
|
|
37
|
+
"@pixolith/webpack-hook-plugin": "^12.0.0",
|
|
38
|
+
"@pixolith/webpack-sw6-plugin-map-emitter": "^12.0.0",
|
|
39
|
+
"@pixolith/webpack-twig-assets-emitter-plugin": "^12.0.0",
|
|
40
|
+
"@pixolith/webpack-watcher": "^12.0.0",
|
|
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
|
@@ -6,11 +6,22 @@ const config = {
|
|
|
6
6
|
isProd: process.env.NODE_ENV === 'production',
|
|
7
7
|
isDebug: !!process.env.DEBUG || false,
|
|
8
8
|
shopwareMode: process.env.SHOPWARE_MODE,
|
|
9
|
-
shopwareVersion: process.env.SHOPWARE_VERSION || '6.6',
|
|
10
9
|
|
|
11
10
|
assetUrl: process.env.ASSET_URL || '/',
|
|
12
11
|
pluginPrefixes: process.env.PLUGIN_PREFIXES || 'Pxsw',
|
|
13
12
|
|
|
13
|
+
// Multi-theme build configuration (mandatory in v12+)
|
|
14
|
+
themeNames: process.env.THEME_NAMES
|
|
15
|
+
? process.env.THEME_NAMES.split(',')
|
|
16
|
+
.map((s) => s.trim())
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
: [],
|
|
19
|
+
skipPlugins: process.env.SKIP_PLUGINS
|
|
20
|
+
? process.env.SKIP_PLUGINS.split(',')
|
|
21
|
+
.map((s) => s.trim())
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
: [],
|
|
24
|
+
|
|
14
25
|
pxSharedPath: process.env.SHARED_SCSS_PATH || '../../shared',
|
|
15
26
|
scssFolder: process.env.SCSS_FOLDER || 'scss',
|
|
16
27
|
jsFolder: process.env.JS_FOLDER || 'js',
|
|
@@ -32,11 +43,35 @@ const config = {
|
|
|
32
43
|
shopwareVendorPath: Path.join(process.cwd(), 'vendor/shopware/storefront/Resources/app/storefront/vendor'),
|
|
33
44
|
shopwarePluginPath: Path.join(process.cwd(), 'vendor/shopware/storefront/Resources/app/storefront/src'),
|
|
34
45
|
|
|
35
|
-
allowedExtensions: ['.ts', '.js', '.scss', '.css', '.svg']
|
|
46
|
+
allowedExtensions: ['.ts', '.js', '.scss', '.css', '.svg'],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// PICKED_THEME: optional filter to build/watch a single theme from THEME_NAMES
|
|
50
|
+
let pickedTheme = process.env.PICKED_THEME
|
|
51
|
+
? process.env.PICKED_THEME.trim()
|
|
52
|
+
: '';
|
|
53
|
+
|
|
54
|
+
if (pickedTheme && config.themeNames.indexOf(pickedTheme) === -1) {
|
|
55
|
+
process.stderr.write(
|
|
56
|
+
`PICKED_THEME "${pickedTheme}" is not in THEME_NAMES [${config.themeNames.join(', ')}].\n`,
|
|
57
|
+
);
|
|
58
|
+
process.exit(1);
|
|
36
59
|
}
|
|
37
60
|
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
// buildThemes: the subset of themeNames that actually get compiled
|
|
62
|
+
// themeNames stays as the full list (used for _global_resources exclusion)
|
|
63
|
+
config.buildThemes = pickedTheme ? [pickedTheme] : config.themeNames;
|
|
64
|
+
|
|
65
|
+
const pxEntryPath =
|
|
66
|
+
process.env.PX_ENTRY_PATH ||
|
|
67
|
+
(process.env.SHOPWARE_MODE === 'storefront'
|
|
68
|
+
? 'src/Resources/app/storefront/private'
|
|
69
|
+
: 'src/Resources/app/administration/src');
|
|
70
|
+
const pxRouteSplitPath =
|
|
71
|
+
process.env.PX_ROUTE_SPLIT_PATH ||
|
|
72
|
+
(process.env.SHOPWARE_MODE === 'storefront'
|
|
73
|
+
? 'src/Resources/app/storefront/private/scss-route-split/*'
|
|
74
|
+
: '');
|
|
40
75
|
|
|
41
76
|
// Create a glob regex to match the plugin prefixes
|
|
42
77
|
let prefixes = config.pluginPrefixes.split(',').map(p => `${p}*`).join('|');
|
|
@@ -49,6 +84,7 @@ const routeSplitMatch = new RegExp(`/scss-route-split\/([\\w-]*)`);
|
|
|
49
84
|
|
|
50
85
|
module.exports = {
|
|
51
86
|
...config,
|
|
87
|
+
|
|
52
88
|
pluginSrcPath: Path.join(pluginSrcPath, pxEntryPath),
|
|
53
89
|
pluginScssPath: Path.join(pluginSrcPath, pxEntryPath, config.scssFolder),
|
|
54
90
|
pluginJsPath: Path.join(pluginSrcPath, pxEntryPath, config.jsFolder),
|
|
@@ -70,5 +106,9 @@ module.exports = {
|
|
|
70
106
|
pluginRouteSplitPath: Path.join(pluginSrcPath, pxRouteSplitPath),
|
|
71
107
|
vendorRouteSplitPath: Path.join(vendorSrcPath, pxRouteSplitPath),
|
|
72
108
|
|
|
73
|
-
|
|
74
|
-
|
|
109
|
+
// Raw glob base paths for multi-theme resource resolution
|
|
110
|
+
pluginGlobBase: pluginSrcPath,
|
|
111
|
+
vendorGlobBase: vendorSrcPath,
|
|
112
|
+
pxEntryPath: pxEntryPath,
|
|
113
|
+
resourcesPath: process.env.RESOURCES_PATHS,
|
|
114
|
+
};
|
package/src/index.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
const Fs = require('fs');
|
|
2
|
+
const Glob = require('glob');
|
|
1
3
|
const config = require('./config');
|
|
2
4
|
const production = require('./webpack.config.production');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
5
|
+
const createStorefrontConfig = require('./webpack.config.storefront');
|
|
6
|
+
const createDevConfig = require('./webpack.config.dev');
|
|
7
|
+
const createAdministrationConfig = require('./webpack.config.administration');
|
|
6
8
|
const pkg = require('./../package.json');
|
|
7
9
|
const watcher = require('@pixolith/webpack-watcher');
|
|
8
10
|
const { merge } = require('webpack-merge');
|
|
11
|
+
const ChangeCase = require('change-case');
|
|
9
12
|
|
|
10
13
|
const setup = () => {
|
|
11
14
|
watcher.clean(config);
|
|
12
|
-
|
|
15
|
+
config.buildThemes.forEach((themeName) => {
|
|
16
|
+
watcher.compileTheme(themeName, config);
|
|
17
|
+
});
|
|
13
18
|
|
|
14
19
|
if (config.isDebug) {
|
|
15
20
|
console.table({
|
|
@@ -29,14 +34,207 @@ const setup = () => {
|
|
|
29
34
|
isProd: config.isProd,
|
|
30
35
|
shopwareMode: config.shopwareMode,
|
|
31
36
|
assetUrl: config.assetUrl,
|
|
37
|
+
themeNames: config.themeNames.join(', ') + (config.buildThemes.length < config.themeNames.length ? ' (building: ' + config.buildThemes.join(', ') + ')' : ''),
|
|
32
38
|
version: pkg.version,
|
|
33
39
|
});
|
|
34
40
|
}
|
|
35
41
|
};
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Build per-theme resource paths for sass-resources-loader.
|
|
45
|
+
*
|
|
46
|
+
* Each theme gets:
|
|
47
|
+
* 1. uses.scss (shared vendor utilities)
|
|
48
|
+
* 2. vendor global resources (vendor/pxsw/...)
|
|
49
|
+
* 3. all non-theme plugin _global_resources (custom/plugins + custom/static-plugins
|
|
50
|
+
* that are NOT in THEME_NAMES)
|
|
51
|
+
* 4. this theme's _global_resources (overrides everything)
|
|
52
|
+
*
|
|
53
|
+
* Other themes' global resources are excluded to prevent style bleeding.
|
|
54
|
+
*
|
|
55
|
+
* @param {string} themeName - Theme name (e.g. 'PxswEbertTheme')
|
|
56
|
+
* @param {Object} options
|
|
57
|
+
* @param {string[]} options.uses - Paths to shared vendor uses.scss
|
|
58
|
+
* @param {string[]} options.sharedVendorResourcePaths - Paths to shared vendor _global_resources
|
|
59
|
+
* @returns {string[]} Array of SCSS resource paths
|
|
60
|
+
*/
|
|
61
|
+
const getResourcesPaths = (themeName, options) => {
|
|
62
|
+
let uses = options.uses || [];
|
|
63
|
+
let sharedVendorResourcePaths = options.sharedVendorResourcePaths || [];
|
|
64
|
+
let paths = [].concat(uses, sharedVendorResourcePaths);
|
|
65
|
+
let globalResourcesSuffix = '/src/Resources/app/_global_resources';
|
|
66
|
+
let scssGlob = '/**/*.scss';
|
|
67
|
+
|
|
68
|
+
// Collect base plugin global resources (plugins NOT in THEME_NAMES)
|
|
69
|
+
let pluginDirs = ['custom/plugins', 'custom/static-plugins'];
|
|
70
|
+
pluginDirs.forEach((dir) => {
|
|
71
|
+
if (!Fs.existsSync(dir)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let entries = Fs.readdirSync(dir).filter((name) => {
|
|
76
|
+
// Must match plugin prefix pattern
|
|
77
|
+
let prefixes = (config.pluginPrefixes || 'Pxsw').split(',');
|
|
78
|
+
let matchesPrefix = prefixes.some((p) =>
|
|
79
|
+
name.startsWith(p.trim()),
|
|
80
|
+
);
|
|
81
|
+
if (!matchesPrefix) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
// Exclude ALL themes from base pool — prevents style bleeding
|
|
85
|
+
let isTheme = config.themeNames.some(
|
|
86
|
+
(t) => name.indexOf(t) !== -1,
|
|
87
|
+
);
|
|
88
|
+
return !isTheme;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
entries.forEach((name) => {
|
|
92
|
+
let glob = dir + '/' + name + globalResourcesSuffix + scssGlob;
|
|
93
|
+
if (Glob.sync(glob).length) {
|
|
94
|
+
paths.push(glob);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Add this theme's global resources LAST (overrides base)
|
|
100
|
+
pluginDirs.forEach((dir) => {
|
|
101
|
+
if (!Fs.existsSync(dir)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let themeGlob =
|
|
106
|
+
dir + '/*' + themeName + '*' + globalResourcesSuffix + scssGlob;
|
|
107
|
+
if (Glob.sync(themeGlob).length) {
|
|
108
|
+
paths.push(themeGlob);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return paths;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create an array of webpack configs, one per theme.
|
|
117
|
+
* Each theme gets its own dev config (with per-theme resourcesPaths for
|
|
118
|
+
* sass-resources-loader) and its own storefront config (with per-theme entry).
|
|
119
|
+
*
|
|
120
|
+
* @param {Object} options
|
|
121
|
+
* @param {string[]} options.uses - Paths to shared vendor uses.scss
|
|
122
|
+
* @param {string[]} options.sharedVendorResourcePaths - Paths to shared vendor _global_resources
|
|
123
|
+
* @returns {Object[]} Array of webpack config objects (one per theme)
|
|
124
|
+
*/
|
|
125
|
+
const createThemeConfigs = (options) => {
|
|
126
|
+
setup();
|
|
127
|
+
|
|
128
|
+
return config.buildThemes.map((themeName, index) => {
|
|
129
|
+
let resourcesPaths = getResourcesPaths(themeName, options);
|
|
130
|
+
let themeSlug = ChangeCase.kebabCase(themeName);
|
|
131
|
+
let themeOptions = {
|
|
132
|
+
themeName: themeName,
|
|
133
|
+
resourcesPaths: resourcesPaths,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
let devCfg = createDevConfig(themeOptions);
|
|
137
|
+
let storefrontCfg = createStorefrontConfig(themeOptions);
|
|
138
|
+
let merged = merge(
|
|
139
|
+
devCfg,
|
|
140
|
+
storefrontCfg,
|
|
141
|
+
config.isProd ? production : {},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Only the first compiler should have devServer (webpack multi-compiler limitation)
|
|
145
|
+
if (index > 0) {
|
|
146
|
+
delete merged.devServer;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Per-theme filesystem cache to avoid collisions between compilers
|
|
150
|
+
merged.cache = {
|
|
151
|
+
type: 'filesystem',
|
|
152
|
+
name: themeSlug,
|
|
153
|
+
buildDependencies: {
|
|
154
|
+
config: [__filename],
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return merged;
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const setupAdministration = () => {
|
|
163
|
+
watcher.clean(config);
|
|
164
|
+
config.buildThemes.forEach((themeName) => {
|
|
165
|
+
watcher.compileAdministration(themeName, config);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (config.isDebug) {
|
|
169
|
+
console.table({
|
|
170
|
+
...config,
|
|
171
|
+
|
|
172
|
+
version: pkg.version,
|
|
173
|
+
|
|
174
|
+
pluginMatch: config.pluginMatch.toString(),
|
|
175
|
+
vendorMatch: config.vendorMatch.toString(),
|
|
176
|
+
allowedExtensions: config.allowedExtensions.toString(),
|
|
177
|
+
});
|
|
178
|
+
} else {
|
|
179
|
+
console.table({
|
|
180
|
+
isProd: config.isProd,
|
|
181
|
+
shopwareMode: config.shopwareMode,
|
|
182
|
+
assetUrl: config.assetUrl,
|
|
183
|
+
themeNames: config.themeNames.join(', ') + (config.buildThemes.length < config.themeNames.length ? ' (building: ' + config.buildThemes.join(', ') + ')' : ''),
|
|
184
|
+
version: pkg.version,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create an array of webpack configs for administration, one per theme.
|
|
191
|
+
* Each theme gets its own dev config (with per-theme resourcesPaths for
|
|
192
|
+
* sass-resources-loader) and its own administration config (with per-theme
|
|
193
|
+
* SCSS entries for theme-specific styling).
|
|
194
|
+
*
|
|
195
|
+
* @param {Object} options
|
|
196
|
+
* @param {string[]} options.uses - Paths to shared vendor uses.scss
|
|
197
|
+
* @param {string[]} options.sharedVendorResourcePaths - Paths to shared vendor _global_resources
|
|
198
|
+
* @returns {Object[]} Array of webpack config objects (one per theme)
|
|
199
|
+
*/
|
|
200
|
+
const createAdminConfigs = (options) => {
|
|
201
|
+
setupAdministration();
|
|
202
|
+
|
|
203
|
+
return config.buildThemes.map((themeName, index) => {
|
|
204
|
+
let resourcesPaths = getResourcesPaths(themeName, options);
|
|
205
|
+
let themeSlug = ChangeCase.kebabCase(themeName);
|
|
206
|
+
let themeOptions = {
|
|
207
|
+
themeName: themeName,
|
|
208
|
+
resourcesPaths: resourcesPaths,
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
let devCfg = createDevConfig(themeOptions);
|
|
212
|
+
let adminCfg = createAdministrationConfig(themeOptions);
|
|
213
|
+
let merged = merge(
|
|
214
|
+
devCfg,
|
|
215
|
+
adminCfg,
|
|
216
|
+
config.isProd ? production : {},
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Only the first compiler should have devServer (webpack multi-compiler limitation)
|
|
220
|
+
if (index > 0) {
|
|
221
|
+
delete merged.devServer;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Per-theme filesystem cache to avoid collisions between compilers
|
|
225
|
+
merged.cache = {
|
|
226
|
+
type: 'filesystem',
|
|
227
|
+
name: themeSlug + '-admin',
|
|
228
|
+
buildDependencies: {
|
|
229
|
+
config: [__filename],
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return merged;
|
|
234
|
+
});
|
|
235
|
+
};
|
|
38
236
|
|
|
39
237
|
module.exports = {
|
|
40
|
-
|
|
41
|
-
|
|
238
|
+
createThemeConfigs: createThemeConfigs,
|
|
239
|
+
createAdminConfigs: createAdminConfigs,
|
|
42
240
|
};
|
|
@@ -5,178 +5,110 @@ const Path = require('path'),
|
|
|
5
5
|
Entry = require('webpack-glob-entry'),
|
|
6
6
|
ChangeCase = require('change-case'),
|
|
7
7
|
MiniCssExtractPlugin = require('mini-css-extract-plugin'),
|
|
8
|
-
Consola = require('consola')
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
Consola = require('consola');
|
|
9
|
+
|
|
10
|
+
module.exports = function createAdministrationConfig(themeOptions) {
|
|
11
|
+
let themeName = themeOptions && themeOptions.themeName;
|
|
12
|
+
let themeSlug = themeName
|
|
13
|
+
? ChangeCase.kebabCase(themeName)
|
|
14
|
+
: 'administration';
|
|
15
|
+
|
|
16
|
+
let outputConfig = {
|
|
13
17
|
path: config.outputPath,
|
|
14
|
-
publicPath: config.
|
|
15
|
-
filename: (chunkData) => {
|
|
16
|
-
let pluginName = chunkData.chunk.name.toLowerCase().replace('pxsw-pxsw-', 'pxsw-');
|
|
17
|
-
pluginName = config.shopwareVersion === '6.6' ? pluginName.replace('vendor-', '') : pluginName;
|
|
18
|
-
return config.shopwareVersion === '6.6' ?
|
|
19
|
-
`${pluginName.replace(/-/g, '',)}/administration/js/${pluginName}.js` :
|
|
20
|
-
`js/${chunkData.chunk.name.toLowerCase()}${
|
|
21
|
-
config.isProd ? '.admin.[contenthash]' : ''
|
|
22
|
-
}.js`;
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
miniCssChunksConfig = {
|
|
18
|
+
publicPath: config.assetUrl,
|
|
26
19
|
filename: (chunkData) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}.css`;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
20
|
+
return `js/${chunkData.chunk.name.toLowerCase()}${
|
|
21
|
+
config.isProd ? '.admin.[contenthash]' : ''
|
|
22
|
+
}.js`;
|
|
23
|
+
},
|
|
24
|
+
uniqueName: themeSlug + '-admin',
|
|
25
|
+
};
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Path.join(config.pluginSrcPath, 'index.js'),
|
|
45
|
-
);
|
|
27
|
+
let miniCssChunksConfig = {
|
|
28
|
+
filename: (chunkData) => {
|
|
29
|
+
return `css/[name]${
|
|
30
|
+
config.isProd ? '.admin.[contenthash]' : ''
|
|
31
|
+
}.css`;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
35
|
+
return {
|
|
36
|
+
name: themeSlug + '-admin',
|
|
37
|
+
entry: () => {
|
|
38
|
+
let entriesPlugins = Entry(
|
|
39
|
+
(filePath) =>
|
|
40
|
+
ChangeCase.kebabCase(filePath.match(config.pluginMatch)[2]),
|
|
41
|
+
Path.join(config.pluginSrcPath, 'index.js'),
|
|
42
|
+
);
|
|
54
43
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
let entriesVendor = Entry(
|
|
45
|
+
(filePath) =>
|
|
46
|
+
ChangeCase.kebabCase(filePath.match(config.vendorMatch)[1]),
|
|
47
|
+
Path.resolve(config.vendorSrcPath, 'index.js'),
|
|
48
|
+
);
|
|
59
49
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
test: /\.(jpe?g|png|gif|ico)(\?v=\d+\.\d+\.\d+)?$/,
|
|
74
|
-
type: 'asset/resource',
|
|
75
|
-
generator: {
|
|
76
|
-
filename: config.shopwareVersion === '6.6' ? '../img/[name][ext]' : 'img/[name][ext]'
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
test: /\.(eot|ttf|woff2?)(\?v=\d+\.\d+\.\d+)?$/,
|
|
81
|
-
type: 'asset/resource',
|
|
82
|
-
generator: {
|
|
83
|
-
filename: config.shopwareVersion === '6.6' ? '../fonts/[name][ext]' : 'fonts/[name][ext]'
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
test: /\.svg$/,
|
|
88
|
-
use: [
|
|
89
|
-
{
|
|
90
|
-
loader: SvgStorePlugin.loader,
|
|
91
|
-
options: {
|
|
92
|
-
name: 'sprite/sprite.svg',
|
|
93
|
-
iconName: '[name]',
|
|
94
|
-
overrideOrder: config.spriteOrder,
|
|
95
|
-
ignoreIconsByName: config.ignoreIcons,
|
|
96
|
-
onlySymbols: true,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
loader: 'svgo-loader',
|
|
101
|
-
options: {
|
|
102
|
-
plugins: [
|
|
103
|
-
'cleanupAttrs',
|
|
104
|
-
'removeDoctype',
|
|
105
|
-
'removeXMLProcInst',
|
|
106
|
-
'cleanupEnableBackground',
|
|
107
|
-
'convertStyleToAttrs',
|
|
108
|
-
'convertPathData',
|
|
109
|
-
'cleanupIds',
|
|
110
|
-
'minifyStyles',
|
|
111
|
-
'removeUselessDefs',
|
|
112
|
-
'convertShapeToPath',
|
|
113
|
-
'removeUnusedNS',
|
|
114
|
-
'removeDimensions',
|
|
115
|
-
'convertTransform',
|
|
116
|
-
'collapseGroups',
|
|
117
|
-
'removeComments',
|
|
118
|
-
'removeEditorsNSData',
|
|
119
|
-
'removeUnknownsAndDefaults',
|
|
120
|
-
],
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
},
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
output: outputConfig,
|
|
128
|
-
plugins: [
|
|
129
|
-
new SvgStorePlugin(),
|
|
130
|
-
new MiniCssExtractPlugin(miniCssChunksConfig),
|
|
131
|
-
].concat(
|
|
132
|
-
config.isProd && config.shopwareVersion === '6.6' ?
|
|
133
|
-
new AssetsCopyPlugin({
|
|
134
|
-
includes: ['js', 'css'],
|
|
135
|
-
ignoreFiles: [/[-\w.]*.hot-update.js/],
|
|
136
|
-
files: [
|
|
137
|
-
{
|
|
138
|
-
from: config.outputPath,
|
|
139
|
-
to: '$pluginPath/$plugin/src/Resources/public',
|
|
140
|
-
replace: async (fromPath, toPath) => {
|
|
141
|
-
let composerPluginName = Path.basename(fromPath).replace(
|
|
142
|
-
Path.extname(fromPath),
|
|
143
|
-
'',
|
|
144
|
-
).replace('pxsw-', ''),
|
|
145
|
-
pluginName = 'Pxsw' + ChangeCase.pascalCase(composerPluginName);
|
|
50
|
+
// Discover the consolidated admin SCSS entry from .theme-entries/{theme-slug}/
|
|
51
|
+
let scssEntries = {};
|
|
52
|
+
let scssEntryDir = Path.join(
|
|
53
|
+
config.outputPath,
|
|
54
|
+
'.theme-entries',
|
|
55
|
+
themeSlug,
|
|
56
|
+
);
|
|
57
|
+
let scssEntryFile = Path.join(
|
|
58
|
+
scssEntryDir,
|
|
59
|
+
themeSlug + '-admin.scss',
|
|
60
|
+
);
|
|
146
61
|
|
|
147
|
-
|
|
148
|
-
|
|
62
|
+
if (Fs.existsSync(scssEntryFile)) {
|
|
63
|
+
scssEntries[themeSlug + '-admin-scss'] = scssEntryFile;
|
|
64
|
+
}
|
|
149
65
|
|
|
150
|
-
|
|
66
|
+
let allEntries = {
|
|
67
|
+
...entriesPlugins,
|
|
68
|
+
...entriesVendor,
|
|
69
|
+
...scssEntries,
|
|
70
|
+
};
|
|
151
71
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
72
|
+
if (config.isDebug) {
|
|
73
|
+
Consola.info(
|
|
74
|
+
`[${themeName || themeSlug}] Administration webpack entry points:`,
|
|
75
|
+
);
|
|
76
|
+
console.table(allEntries);
|
|
77
|
+
}
|
|
159
78
|
|
|
160
|
-
|
|
161
|
-
|
|
79
|
+
return allEntries;
|
|
80
|
+
},
|
|
81
|
+
module: {
|
|
82
|
+
rules: [
|
|
83
|
+
{
|
|
84
|
+
test: /\.js$/,
|
|
85
|
+
exclude: (file) => /node_modules/.test(file),
|
|
86
|
+
loader: 'babel-loader',
|
|
87
|
+
options: {
|
|
88
|
+
configFile: Path.resolve(__dirname, 'babel.config.js'),
|
|
162
89
|
},
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
test: /\.(jpe?g|png|gif|ico)(\?v=\d+\.\d+\.\d+)?$/,
|
|
93
|
+
type: 'asset/resource',
|
|
94
|
+
generator: {
|
|
95
|
+
filename: 'img/[name][ext]',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
test: /\.(eot|ttf|woff2?)(\?v=\d+\.\d+\.\d+)?$/,
|
|
100
|
+
type: 'asset/resource',
|
|
101
|
+
generator: {
|
|
102
|
+
filename: 'fonts/[name][ext]',
|
|
174
103
|
},
|
|
175
104
|
},
|
|
176
|
-
|
|
177
|
-
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
output: outputConfig,
|
|
108
|
+
plugins: [new MiniCssExtractPlugin(miniCssChunksConfig)],
|
|
178
109
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
110
|
+
optimization: {
|
|
111
|
+
splitChunks: false,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
182
114
|
};
|
|
@@ -13,188 +13,183 @@ const webpack = require('webpack'),
|
|
|
13
13
|
Sass = require('sass'),
|
|
14
14
|
TimeFixPlugin = require('time-fix-plugin');
|
|
15
15
|
|
|
16
|
-
module.exports = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
module.exports = function createDevConfig(themeOptions) {
|
|
17
|
+
let resourcesPaths =
|
|
18
|
+
themeOptions && themeOptions.resourcesPaths
|
|
19
|
+
? themeOptions.resourcesPaths
|
|
20
|
+
: JSON.parse(process.env.RESOURCES_PATHS || '[]');
|
|
21
|
+
|
|
22
|
+
let resolvedResources = resourcesPaths.filter((path) => {
|
|
23
|
+
return Glob.sync(path).length > 0;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
target: 'web',
|
|
28
|
+
mode: 'development',
|
|
29
|
+
resolve: {
|
|
30
|
+
modules: ['node_modules', Path.resolve(config.shopwareVendorPath)],
|
|
31
|
+
alias: {
|
|
32
|
+
src: Path.resolve(config.shopwarePluginPath),
|
|
33
|
+
vendor: Path.resolve(config.shopwareVendorPath),
|
|
34
|
+
},
|
|
27
35
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
devtool: 'inline-cheap-module-source-map',
|
|
37
|
+
module: {
|
|
38
|
+
rules: [
|
|
39
|
+
{
|
|
40
|
+
test: /(\.scss|\.css)$/,
|
|
41
|
+
use: [
|
|
42
|
+
config.isProd
|
|
43
|
+
? MiniCssExtractPlugin.loader
|
|
44
|
+
: 'style-loader',
|
|
45
|
+
{
|
|
46
|
+
loader: 'css-loader',
|
|
47
|
+
options: {
|
|
48
|
+
importLoaders: 1,
|
|
49
|
+
sourceMap: !config.isProd,
|
|
50
|
+
},
|
|
41
51
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
config.isProd && config.mediaQueries
|
|
53
|
+
? MediaQueryPlugin.loader
|
|
54
|
+
: '',
|
|
55
|
+
{
|
|
56
|
+
loader: 'postcss-loader',
|
|
57
|
+
options: {
|
|
58
|
+
sourceMap: !config.isProd,
|
|
59
|
+
postcssOptions: {
|
|
60
|
+
config: Path.resolve(
|
|
61
|
+
__dirname,
|
|
62
|
+
'postcss.config.js',
|
|
63
|
+
),
|
|
64
|
+
},
|
|
50
65
|
},
|
|
51
66
|
},
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
{
|
|
68
|
+
loader: 'sass-loader',
|
|
69
|
+
options: {
|
|
70
|
+
sourceMap: !config.isProd,
|
|
71
|
+
additionalData: `$asset_url: '${config.assetUrl}';`,
|
|
72
|
+
sassOptions: {
|
|
73
|
+
quietDeps: true,
|
|
74
|
+
logger: Sass.Logger.silent,
|
|
75
|
+
},
|
|
61
76
|
},
|
|
62
77
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
).filter((path) => {
|
|
70
|
-
return Glob.sync(path).length > 0;
|
|
71
|
-
}),
|
|
72
|
-
hoistUseStatements: true
|
|
78
|
+
{
|
|
79
|
+
loader: 'sass-resources-loader',
|
|
80
|
+
options: {
|
|
81
|
+
resources: resolvedResources,
|
|
82
|
+
hoistUseStatements: true,
|
|
83
|
+
},
|
|
73
84
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
test: /\.(html|twig)$/,
|
|
89
|
+
use: [
|
|
90
|
+
{
|
|
91
|
+
loader: 'html-loader',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
stats: 'errors-warnings',
|
|
98
|
+
devServer: {
|
|
99
|
+
allowedHosts: 'all',
|
|
100
|
+
client: {
|
|
101
|
+
webSocketURL: {
|
|
102
|
+
hostname: 'node.px-staging.de',
|
|
103
|
+
protocol: 'wss',
|
|
104
|
+
port:
|
|
105
|
+
process.env.SHOPWARE_MODE === 'administration'
|
|
106
|
+
? 8080
|
|
107
|
+
: 8081,
|
|
108
|
+
},
|
|
109
|
+
overlay: {
|
|
110
|
+
warnings: false,
|
|
111
|
+
errors: true,
|
|
112
|
+
},
|
|
84
113
|
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
webSocketURL: {
|
|
92
|
-
hostname: 'node.px-staging.de',
|
|
93
|
-
protocol: 'wss',
|
|
94
|
-
port: process.env.SHOPWARE_MODE === 'administration' ? 8080 : 8081,
|
|
114
|
+
headers: {
|
|
115
|
+
'Access-Control-Allow-Origin': '*',
|
|
116
|
+
'Access-Control-Allow-Methods':
|
|
117
|
+
'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
|
118
|
+
'Access-Control-Allow-Headers':
|
|
119
|
+
'X-Requested-With, content-type, Authorization',
|
|
95
120
|
},
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
port: process.env.SHOPWARE_MODE === 'administration' ? 8080 : 8081,
|
|
122
|
+
server: !config.isProd
|
|
123
|
+
? {
|
|
124
|
+
type: 'https',
|
|
125
|
+
options: {
|
|
126
|
+
ca: Fs.readFileSync(
|
|
127
|
+
Path.join(
|
|
128
|
+
process.cwd() +
|
|
129
|
+
'/.ddev/ssl/_wildcard.px-staging.de+1-client.pem',
|
|
130
|
+
),
|
|
131
|
+
),
|
|
132
|
+
key: Fs.readFileSync(
|
|
133
|
+
Path.join(
|
|
134
|
+
process.cwd() +
|
|
135
|
+
'/.ddev/ssl/_wildcard.px-staging.de+1-key.pem',
|
|
136
|
+
),
|
|
137
|
+
),
|
|
138
|
+
cert: Fs.readFileSync(
|
|
139
|
+
Path.join(
|
|
140
|
+
process.cwd() +
|
|
141
|
+
'/.ddev/ssl/_wildcard.px-staging.de+1.pem',
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
},
|
|
145
|
+
}
|
|
146
|
+
: 'http',
|
|
147
|
+
devMiddleware: {
|
|
148
|
+
writeToDisk: true,
|
|
99
149
|
},
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
'Access-Control-Allow-Methods':
|
|
104
|
-
'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
|
105
|
-
'Access-Control-Allow-Headers':
|
|
106
|
-
'X-Requested-With, content-type, Authorization',
|
|
107
|
-
},
|
|
108
|
-
port: process.env.SHOPWARE_MODE === 'administration' ? 8080 : 8081,
|
|
109
|
-
server: !config.isProd
|
|
110
|
-
? {
|
|
111
|
-
type: 'https',
|
|
112
|
-
options: {
|
|
113
|
-
ca: Fs.readFileSync(
|
|
114
|
-
Path.join(
|
|
115
|
-
process.cwd() +
|
|
116
|
-
'/.ddev/ssl/_wildcard.px-staging.de+1-client.pem',
|
|
117
|
-
),
|
|
118
|
-
),
|
|
119
|
-
key: Fs.readFileSync(
|
|
120
|
-
Path.join(
|
|
121
|
-
process.cwd() +
|
|
122
|
-
'/.ddev/ssl/_wildcard.px-staging.de+1-key.pem',
|
|
123
|
-
),
|
|
124
|
-
),
|
|
125
|
-
cert: Fs.readFileSync(
|
|
126
|
-
Path.join(
|
|
127
|
-
process.cwd() +
|
|
128
|
-
'/.ddev/ssl/_wildcard.px-staging.de+1.pem',
|
|
129
|
-
),
|
|
130
|
-
),
|
|
150
|
+
setupMiddlewares: (middlewares, devServer) => {
|
|
151
|
+
if (!devServer) {
|
|
152
|
+
throw new Error('webpack-dev-server is not defined');
|
|
131
153
|
}
|
|
132
|
-
}
|
|
133
|
-
: 'http',
|
|
134
|
-
devMiddleware: {
|
|
135
|
-
writeToDisk: true,
|
|
136
|
-
},
|
|
137
|
-
setupMiddlewares: (middlewares, devServer) => {
|
|
138
|
-
if (!devServer) {
|
|
139
|
-
throw new Error("webpack-dev-server is not defined")
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
Consola.success(
|
|
143
|
-
`Starting webpack in [${process.env.NODE_ENV}] with [${process.env.SHOPWARE_MODE}]`,
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
watcher.watch(config);
|
|
147
154
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
plugins: [
|
|
152
|
-
new ESLintPlugin({
|
|
153
|
-
exclude: [
|
|
154
|
-
'**/node_modules/**',
|
|
155
|
-
'vendor'
|
|
156
|
-
]
|
|
157
|
-
}),
|
|
158
|
-
new HookPlugin({
|
|
159
|
-
beforeCompile(compiler, callback) {
|
|
160
|
-
let path = Path.join(config.outputPath, 'sprite'),
|
|
161
|
-
filename = 'sprite.svg',
|
|
162
|
-
exists = Fs.existsSync(path);
|
|
155
|
+
Consola.success(
|
|
156
|
+
`Starting webpack in [${process.env.NODE_ENV}] with [${process.env.SHOPWARE_MODE}]`,
|
|
157
|
+
);
|
|
163
158
|
|
|
164
|
-
|
|
165
|
-
Fs.mkdirSync(path, {
|
|
166
|
-
recursive: true,
|
|
167
|
-
});
|
|
168
|
-
Fs.appendFile(Path.join(path, filename), '#', (err) => {
|
|
169
|
-
if (err) {
|
|
170
|
-
throw err;
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
159
|
+
watcher.watch(config);
|
|
174
160
|
|
|
175
|
-
|
|
161
|
+
return middlewares;
|
|
176
162
|
},
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
163
|
+
},
|
|
164
|
+
plugins: [
|
|
165
|
+
new ESLintPlugin({
|
|
166
|
+
exclude: ['**/node_modules/**', 'vendor'],
|
|
167
|
+
}),
|
|
168
|
+
new HookPlugin({
|
|
169
|
+
failed() {
|
|
170
|
+
watcher.onFileChange(null, config);
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
181
173
|
|
|
182
|
-
|
|
174
|
+
new TimeFixPlugin(),
|
|
183
175
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
176
|
+
new webpack.DefinePlugin({
|
|
177
|
+
'process.env.NODE_ENV': JSON.stringify(
|
|
178
|
+
process.env.NODE_ENV || 'development',
|
|
179
|
+
),
|
|
180
|
+
'process.env.ASSET_URL': JSON.stringify(config.assetUrl),
|
|
181
|
+
'process.env.RESOURCES_PATHS': JSON.stringify(
|
|
182
|
+
JSON.stringify(resourcesPaths),
|
|
183
|
+
),
|
|
184
|
+
}),
|
|
185
|
+
].concat(
|
|
186
|
+
config.isProd && config.mediaQueries
|
|
187
|
+
? new MediaQueryPlugin({
|
|
188
|
+
include: true,
|
|
189
|
+
queries: JSON.parse(config.mediaQueries),
|
|
190
|
+
})
|
|
191
|
+
: [],
|
|
192
|
+
),
|
|
193
|
+
watch: false,
|
|
194
|
+
};
|
|
200
195
|
};
|
|
@@ -1,166 +1,207 @@
|
|
|
1
1
|
const config = require('./config');
|
|
2
2
|
|
|
3
3
|
const Path = require('path'),
|
|
4
|
+
Fs = require('fs'),
|
|
4
5
|
MiniCssExtractPlugin = require('mini-css-extract-plugin'),
|
|
5
6
|
ChangeCase = require('change-case'),
|
|
6
7
|
Consola = require('consola'),
|
|
7
8
|
Sw6PluginMapEmitterPlugin = require('@pixolith/webpack-sw6-plugin-map-emitter'),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
SvgStorePlugin = require('@pixolith/external-svg-sprite-loader');
|
|
10
|
+
|
|
11
|
+
module.exports = function createStorefrontConfig(themeOptions) {
|
|
12
|
+
let themeName = themeOptions && themeOptions.themeName;
|
|
13
|
+
let themeSlug = themeName ? ChangeCase.kebabCase(themeName) : 'storefront';
|
|
14
|
+
|
|
15
|
+
let outputConfig = {
|
|
11
16
|
path: config.outputPath,
|
|
12
17
|
publicPath: config.assetUrl,
|
|
13
18
|
chunkFilename: (chunkData) => {
|
|
14
|
-
return `js/chunk[name]${
|
|
15
|
-
config.isProd ? '.[contenthash]' : ''
|
|
16
|
-
}.js`;
|
|
19
|
+
return `js/chunk[name]${config.isProd ? '.[contenthash]' : ''}.js`;
|
|
17
20
|
},
|
|
18
21
|
filename: (chunkData) => {
|
|
19
22
|
return `js/${chunkData.chunk.name.toLowerCase()}${
|
|
20
23
|
config.isProd ? `.[contenthash]` : ''
|
|
21
24
|
}.js`;
|
|
22
25
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}.css`,
|
|
26
|
+
uniqueName: themeSlug,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let miniCssChunksConfig = {
|
|
30
|
+
filename: `css/[name]${config.isProd ? '.[contenthash]' : ''}.css`,
|
|
28
31
|
chunkFilename: `css/[name].vendor${
|
|
29
32
|
config.isProd ? '.[contenthash]' : ''
|
|
30
|
-
}.css
|
|
33
|
+
}.css`,
|
|
31
34
|
};
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let entriesPlugins = Entry(
|
|
36
|
-
(filePath) =>
|
|
37
|
-
ChangeCase.kebabCase(
|
|
38
|
-
filePath.match(config.pluginMatch)[1],
|
|
39
|
-
),
|
|
40
|
-
Path.resolve(config.pluginSrcPath, 'index.js'),
|
|
41
|
-
);
|
|
36
|
+
// Per-theme sprite path to avoid collisions between compilers
|
|
37
|
+
let spritePath = `sprite/${themeSlug}-sprite.svg`;
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Path.resolve(config.vendorSrcPath, 'index.js'),
|
|
39
|
+
let entryFn = () => {
|
|
40
|
+
let entryDir = Path.join(
|
|
41
|
+
config.outputPath,
|
|
42
|
+
'.theme-entries',
|
|
43
|
+
themeSlug,
|
|
49
44
|
);
|
|
50
45
|
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
let entries = {};
|
|
47
|
+
|
|
48
|
+
// Main theme entry
|
|
49
|
+
let mainEntry = Path.join(entryDir, 'index.js');
|
|
50
|
+
if (Fs.existsSync(mainEntry)) {
|
|
51
|
+
entries[themeSlug] = mainEntry;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Route-split SCSS entries
|
|
55
|
+
let routeSplitFiles = Fs.existsSync(entryDir)
|
|
56
|
+
? Fs.readdirSync(entryDir).filter(
|
|
57
|
+
(f) => f.endsWith('.index.scss') && f !== 'index.scss',
|
|
58
|
+
)
|
|
59
|
+
: [];
|
|
60
|
+
|
|
61
|
+
routeSplitFiles.forEach((file) => {
|
|
62
|
+
let routeName = file.replace('.index.scss', '');
|
|
63
|
+
let entryName = themeSlug + '_' + routeName;
|
|
64
|
+
entries[entryName] = Path.join(entryDir, file);
|
|
65
|
+
});
|
|
59
66
|
|
|
60
67
|
if (config.isDebug) {
|
|
61
|
-
Consola.info(
|
|
62
|
-
console.table(
|
|
68
|
+
Consola.info(`[${themeName || themeSlug}] Webpack entry points:`);
|
|
69
|
+
console.table(entries);
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
return entries;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
name: themeSlug,
|
|
77
|
+
entry: entryFn,
|
|
78
|
+
// -.- hardcoded fix for zbar-wasm and issue https://github.com/webpack/webpack/issues/16878
|
|
79
|
+
resolve: {
|
|
80
|
+
conditionNames: [
|
|
81
|
+
'zbar-inlined',
|
|
82
|
+
'browser',
|
|
83
|
+
'import',
|
|
84
|
+
'require',
|
|
85
|
+
'default',
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
module: {
|
|
90
|
+
rules: [
|
|
91
|
+
{
|
|
92
|
+
// -.- hardcoded fix for zbar-wasm and issue https://github.com/webpack/webpack/issues/16878
|
|
93
|
+
test: /\.m?js$/,
|
|
94
|
+
include: /node_modules[\\/]@undecaf[\\/]zbar-wasm/,
|
|
95
|
+
enforce: 'pre',
|
|
96
|
+
use: [
|
|
97
|
+
{
|
|
98
|
+
loader: 'string-replace-loader',
|
|
99
|
+
options: {
|
|
100
|
+
search: 'new URL("./",import.meta.url)',
|
|
101
|
+
replace: '"/"',
|
|
85
102
|
},
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
test: /\.js$/,
|
|
108
|
+
exclude: (file) => {
|
|
109
|
+
return /node_modules/.test(file);
|
|
110
|
+
},
|
|
111
|
+
use: [
|
|
112
|
+
{
|
|
113
|
+
loader: 'swc-loader',
|
|
114
|
+
options: {
|
|
115
|
+
env: {
|
|
116
|
+
mode: 'entry',
|
|
117
|
+
coreJs: '3.34.0',
|
|
118
|
+
// .browserlist settings are not found by swc-loader, so we load it manually: https://github.com/swc-project/swc/issues/3365
|
|
119
|
+
targets: require('browserslist').loadConfig(
|
|
120
|
+
{
|
|
121
|
+
config: './package.json',
|
|
122
|
+
},
|
|
123
|
+
),
|
|
89
124
|
},
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
125
|
+
jsc: {
|
|
126
|
+
parser: {
|
|
127
|
+
syntax: 'typescript',
|
|
128
|
+
},
|
|
129
|
+
transform: {
|
|
130
|
+
// NEXT-30535 - Restore babel option to not use defineProperty for class fields.
|
|
131
|
+
// Previously (in v6.5.x) this was done by `@babel/preset-typescript` automatically.
|
|
132
|
+
useDefineForClassFields: false,
|
|
133
|
+
},
|
|
94
134
|
},
|
|
95
135
|
},
|
|
96
136
|
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
test: /\.(jpe?g|png|gif|ico)(\?v=\d+\.\d+\.\d+)?$/,
|
|
141
|
+
type: 'asset/resource',
|
|
142
|
+
generator: {
|
|
143
|
+
filename: 'img/[name][ext]',
|
|
97
144
|
},
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
filename: 'img/[name][ext]'
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
test: /\.(eot|ttf|woff2?)(\?v=\d+\.\d+\.\d+)?$/,
|
|
109
|
-
type: 'asset/resource',
|
|
110
|
-
generator: {
|
|
111
|
-
filename: 'fonts/[name][ext]'
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
test: /\.svg$/,
|
|
116
|
-
use: [
|
|
117
|
-
{
|
|
118
|
-
loader: SvgStorePlugin.loader,
|
|
119
|
-
options: {
|
|
120
|
-
name: 'sprite/sprite.svg',
|
|
121
|
-
iconName: '[name]',
|
|
122
|
-
overrideOrder: config.spriteOrder,
|
|
123
|
-
ignoreIconsByName: config.ignoreIcons,
|
|
124
|
-
onlySymbols: true,
|
|
125
|
-
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
test: /\.(eot|ttf|woff2?)(\?v=\d+\.\d+\.\d+)?$/,
|
|
148
|
+
type: 'asset/resource',
|
|
149
|
+
generator: {
|
|
150
|
+
filename: 'fonts/[name][ext]',
|
|
126
151
|
},
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
'
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
'convertShapeToPath',
|
|
141
|
-
'removeUnusedNS',
|
|
142
|
-
'removeDimensions',
|
|
143
|
-
'convertTransform',
|
|
144
|
-
'collapseGroups',
|
|
145
|
-
'removeComments',
|
|
146
|
-
'removeEditorsNSData',
|
|
147
|
-
'removeUnknownsAndDefaults',
|
|
148
|
-
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
test: /\.svg$/,
|
|
155
|
+
use: [
|
|
156
|
+
{
|
|
157
|
+
loader: SvgStorePlugin.loader,
|
|
158
|
+
options: {
|
|
159
|
+
name: spritePath,
|
|
160
|
+
iconName: '[name]',
|
|
161
|
+
overrideOrder: config.spriteOrder,
|
|
162
|
+
ignoreIconsByName: config.ignoreIcons,
|
|
163
|
+
onlySymbols: true,
|
|
164
|
+
},
|
|
149
165
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
166
|
+
{
|
|
167
|
+
loader: 'svgo-loader',
|
|
168
|
+
options: {
|
|
169
|
+
plugins: [
|
|
170
|
+
'cleanupAttrs',
|
|
171
|
+
'removeDoctype',
|
|
172
|
+
'removeXMLProcInst',
|
|
173
|
+
'cleanupEnableBackground',
|
|
174
|
+
'convertStyleToAttrs',
|
|
175
|
+
'convertPathData',
|
|
176
|
+
'cleanupIds',
|
|
177
|
+
'minifyStyles',
|
|
178
|
+
'removeUselessDefs',
|
|
179
|
+
'convertShapeToPath',
|
|
180
|
+
'removeUnusedNS',
|
|
181
|
+
'removeDimensions',
|
|
182
|
+
'convertTransform',
|
|
183
|
+
'collapseGroups',
|
|
184
|
+
'removeComments',
|
|
185
|
+
'removeEditorsNSData',
|
|
186
|
+
'removeUnknownsAndDefaults',
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
output: outputConfig,
|
|
195
|
+
plugins: [
|
|
196
|
+
new Sw6PluginMapEmitterPlugin({
|
|
197
|
+
includes: ['js', 'css'],
|
|
198
|
+
ignoreFiles: [/.*icons.*\.js/, /.*chunk.*\.js/],
|
|
199
|
+
filename: `var/px_plugins_${themeSlug}.json`,
|
|
200
|
+
}),
|
|
201
|
+
|
|
202
|
+
new SvgStorePlugin(),
|
|
203
|
+
|
|
204
|
+
new MiniCssExtractPlugin(miniCssChunksConfig),
|
|
153
205
|
],
|
|
154
|
-
}
|
|
155
|
-
output: outputConfig,
|
|
156
|
-
plugins: [
|
|
157
|
-
new Sw6PluginMapEmitterPlugin({
|
|
158
|
-
includes: ['js', 'css'],
|
|
159
|
-
ignoreFiles: [/.*icons.*\.js/, /.*chunk.*\.js/],
|
|
160
|
-
}),
|
|
161
|
-
|
|
162
|
-
new SvgStorePlugin(),
|
|
163
|
-
|
|
164
|
-
new MiniCssExtractPlugin(miniCssChunksConfig),
|
|
165
|
-
],
|
|
206
|
+
};
|
|
166
207
|
};
|