@oroinc/oro-webpack-config-builder 5.1.0-alpha25 → 5.1.0-alpha29
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/modules-config/layout-modules-config-loader.js +60 -0
- package/modules-config/modules-config-loader.js +17 -9
- package/oro-webpack-config.js +326 -279
- package/package.json +24 -24
- package/style/admin-style-loader.js +1 -1
- package/style/style-loader.js +16 -3
- package/theme-config-factory.js +42 -5
|
@@ -17,6 +17,66 @@ class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
|
17
17
|
|
|
18
18
|
return themeConfig;
|
|
19
19
|
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* All build names:
|
|
23
|
+
* - based on theme names
|
|
24
|
+
* - and theme's extra js builds
|
|
25
|
+
*
|
|
26
|
+
* @return {string[]}
|
|
27
|
+
*/
|
|
28
|
+
get buildNames() {
|
|
29
|
+
const buildNames = super.buildNames;
|
|
30
|
+
this.themeNames.forEach(theme => {
|
|
31
|
+
buildNames.push(...this.extraJSBuildNames(theme));
|
|
32
|
+
});
|
|
33
|
+
return buildNames;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Collect extra js-build names for a theme
|
|
38
|
+
*
|
|
39
|
+
* @param {string} theme name on the theme
|
|
40
|
+
* @return {string[]}
|
|
41
|
+
*/
|
|
42
|
+
extraJSBuildNames(theme) {
|
|
43
|
+
const {extra_js_builds: extraJSBuilds = []} = this._themes[theme] || {}
|
|
44
|
+
return [...extraJSBuilds.map(suffix => `${theme}-${suffix}`)];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if buildName is an extra js build of layout theme
|
|
49
|
+
*
|
|
50
|
+
* @param {string} buildName name of the build
|
|
51
|
+
* @return {boolean}
|
|
52
|
+
*/
|
|
53
|
+
isExtraJSBuild(buildName) {
|
|
54
|
+
const [, suffix] = this.splitBuildName(buildName);
|
|
55
|
+
return suffix !== void 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Splits build name on parts theme name and suffix (name of extra js build)
|
|
60
|
+
* @param {string} buildName
|
|
61
|
+
* @return {[string]|[string, string]}
|
|
62
|
+
*/
|
|
63
|
+
splitBuildName(buildName) {
|
|
64
|
+
// suffix can not contain '-'
|
|
65
|
+
const marches = buildName.match(/(.+)-([^\-]+)?/);
|
|
66
|
+
const result = [];
|
|
67
|
+
if (marches) {
|
|
68
|
+
const [, theme, suffix] = marches;
|
|
69
|
+
const {extra_js_builds: extraJSBuilds = []} = this._themes[theme] || {}
|
|
70
|
+
if (extraJSBuilds.includes(suffix)) {
|
|
71
|
+
result.push(marches[1], marches[2]);
|
|
72
|
+
} else {
|
|
73
|
+
result.push(buildName);
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
result.push(buildName);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
20
80
|
}
|
|
21
81
|
|
|
22
82
|
module.exports = LayoutModulesConfigLoader;
|
|
@@ -3,6 +3,9 @@ const fs = require('fs');
|
|
|
3
3
|
const merge = require('deepmerge');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
5
|
|
|
6
|
+
// merge only unique items
|
|
7
|
+
const arrayMerge = (target, source) => target.concat(source.filter(item => !target.includes(item)));
|
|
8
|
+
|
|
6
9
|
class ModulesConfigLoader {
|
|
7
10
|
/**
|
|
8
11
|
* @returns {Array}
|
|
@@ -18,10 +21,17 @@ class ModulesConfigLoader {
|
|
|
18
21
|
return Object.keys(this._themes);
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @returns {Array}
|
|
26
|
+
*/
|
|
27
|
+
get buildNames() {
|
|
28
|
+
return this.themeNames;
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
/**
|
|
22
32
|
* @param {Array} bundles Array of ordered symfony bundle paths
|
|
23
33
|
* @param {string} themesLocation Path inside the bundle, where to find the theme
|
|
24
|
-
* @param {string} themeInfoFileName
|
|
34
|
+
* @param {string} themeInfoFileName Yaml File name with theme info
|
|
25
35
|
*/
|
|
26
36
|
constructor(bundles, themesLocation, themeInfoFileName) {
|
|
27
37
|
this._bundles = bundles;
|
|
@@ -43,17 +53,15 @@ class ModulesConfigLoader {
|
|
|
43
53
|
if (!fs.existsSync(source)) return;
|
|
44
54
|
|
|
45
55
|
fs.readdirSync(source).forEach(name => {
|
|
46
|
-
const
|
|
47
|
-
if (!fs.lstatSync(
|
|
56
|
+
const themePath = path.resolve(source, name);
|
|
57
|
+
if (!fs.lstatSync(themePath).isDirectory()) {
|
|
48
58
|
return;
|
|
49
59
|
}
|
|
50
|
-
const themeFile = path.resolve(
|
|
60
|
+
const themeFile = path.resolve(themePath, themeInfoFileName);
|
|
51
61
|
if (!fs.existsSync(themeFile)) return;
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
themes[name] = yaml.load(fs.readFileSync(themeFile, 'utf8'));
|
|
63
|
+
const theme = yaml.load(fs.readFileSync(themeFile, 'utf8'));
|
|
64
|
+
themes[name] = merge(themes[name] || {}, theme, {arrayMerge});
|
|
57
65
|
});
|
|
58
66
|
});
|
|
59
67
|
|
|
@@ -63,7 +71,7 @@ class ModulesConfigLoader {
|
|
|
63
71
|
/**
|
|
64
72
|
* @param {string} theme Theme name
|
|
65
73
|
* @param {string|string[]} filePath Path (or paths with fallback) to the file inside bundle directory where to find the configs
|
|
66
|
-
* @return {Object} Merged Configs loaded from all the bundles
|
|
74
|
+
* @return {Object} Merged Configs loaded from all the bundles Yaml files matched by filePath
|
|
67
75
|
*/
|
|
68
76
|
loadConfig(theme, filePath) {
|
|
69
77
|
let configs = {};
|
package/oro-webpack-config.js
CHANGED
|
@@ -127,298 +127,346 @@ class ConfigBuilder {
|
|
|
127
127
|
return (env = {}, args = {}) => {
|
|
128
128
|
this._initialize(args, env);
|
|
129
129
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
themes.push(selectedTheme);
|
|
141
|
-
}
|
|
130
|
+
const commonConfig = this._getCommonWebpackConfig(args, env);
|
|
131
|
+
const webpackConfigs = [];
|
|
132
|
+
const requestedBuildNames = env.theme ? env.theme.split(',') : [];
|
|
133
|
+
const buildNames = this._getBuildNames(requestedBuildNames);
|
|
134
|
+
buildNames.forEach(buildName => {
|
|
135
|
+
const buildConfig = this._getThemeWebpackConfig(buildName, args, env);
|
|
136
|
+
if (buildConfig) {
|
|
137
|
+
webpackConfigs.push(webpackMerge(buildConfig, commonConfig));
|
|
138
|
+
}
|
|
139
|
+
});
|
|
142
140
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
141
|
+
return webpackConfigs;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
get resolvedPublicPath() {
|
|
146
|
+
if (this._resolvedPublicPath === undefined) {
|
|
147
|
+
this._resolvedPublicPath = path.resolve(this._publicPath);
|
|
148
|
+
}
|
|
149
|
+
return this._resolvedPublicPath;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
get resolvedNodeModulesPath() {
|
|
153
|
+
if (this._resolvedNodeModulesPath === undefined) {
|
|
154
|
+
this._resolvedNodeModulesPath = path.resolve('node_modules');
|
|
155
|
+
}
|
|
156
|
+
return this._resolvedNodeModulesPath;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
get assetVersion() {
|
|
160
|
+
if (this._assetVersion === undefined) {
|
|
161
|
+
const filePath = path.join(this.resolvedPublicPath, '/build/build_version.txt');
|
|
162
|
+
this._assetVersion = fs.existsSync(filePath) ? String(fs.readFileSync(filePath)) : null;
|
|
163
|
+
}
|
|
164
|
+
return this._assetVersion;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
_getBuildNames(requestedBuildNames = []) {
|
|
168
|
+
const buildNames = [];
|
|
169
|
+
requestedBuildNames.forEach(buildName => this._validateBuildName(buildName));
|
|
170
|
+
|
|
171
|
+
// Admin themes
|
|
172
|
+
if (!requestedBuildNames.length) {
|
|
173
|
+
buildNames.push(this._adminTheme);
|
|
174
|
+
} else {
|
|
175
|
+
requestedBuildNames.forEach(buildName => {
|
|
176
|
+
if (this._isAdminTheme(buildName)) {
|
|
177
|
+
buildNames.push(buildName);
|
|
155
178
|
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Layout Themes
|
|
183
|
+
if (this._enableLayoutThemes) {
|
|
184
|
+
if (!requestedBuildNames.length) {
|
|
185
|
+
// build all layout themes
|
|
186
|
+
const themes = this._defaultLayoutThemes || this._appConfig.themes;
|
|
187
|
+
buildNames.push(...themes);
|
|
188
|
+
themes.forEach(theme => {
|
|
189
|
+
buildNames.push(...this._layoutModulesConfigLoader.extraJSBuildNames(theme));
|
|
190
|
+
});
|
|
191
|
+
} else {
|
|
192
|
+
// build single layout theme
|
|
193
|
+
requestedBuildNames.forEach(buildName => {
|
|
194
|
+
if (this._layoutModulesConfigLoader.buildNames.includes(buildName)) {
|
|
195
|
+
buildNames.push(buildName);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
156
198
|
}
|
|
199
|
+
}
|
|
157
200
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
201
|
+
return buildNames;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
_getCommonWebpackConfig(args, env) {
|
|
205
|
+
const stats = env.stats || {
|
|
206
|
+
hash: false,
|
|
207
|
+
version: false,
|
|
208
|
+
// Do not write the information about files emitted from node_modules or public bundles,
|
|
209
|
+
// and hide css/*/*.js files from the output.
|
|
210
|
+
excludeAssets: [/^bundles\//, /^\.\.\/_static\//, /^css\/.+\.js/],
|
|
211
|
+
children: false,
|
|
212
|
+
entrypoints: false,
|
|
213
|
+
performance: this._isProduction,
|
|
214
|
+
chunks: false,
|
|
215
|
+
modules: false,
|
|
216
|
+
source: false,
|
|
217
|
+
publicPath: true,
|
|
218
|
+
builtAt: false,
|
|
219
|
+
warnings: false
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const webpackConfig = {
|
|
223
|
+
watchOptions: {
|
|
224
|
+
aggregateTimeout: 200,
|
|
225
|
+
ignored: /[\/\\]node_modules[\/\\].*\.js$/
|
|
226
|
+
},
|
|
227
|
+
stats,
|
|
228
|
+
output: {
|
|
229
|
+
filename: '[name].js',
|
|
230
|
+
// Because we use third party libraries 'chunkFilename' should include only [name]
|
|
231
|
+
chunkFilename: this._getVersionedPath('chunk/[name].js', this.assetVersion)
|
|
232
|
+
},
|
|
233
|
+
devtool: !env.skipSourcemap && 'inline-cheap-module-source-map',
|
|
234
|
+
mode: 'development',
|
|
235
|
+
optimization: {
|
|
236
|
+
moduleIds: 'named',
|
|
237
|
+
splitChunks: {
|
|
238
|
+
cacheGroups: {
|
|
239
|
+
defaultVendors: false
|
|
198
240
|
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
]
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
loader: 'sass-loader',
|
|
237
|
-
options: {
|
|
238
|
-
sassOptions: {
|
|
239
|
-
includePaths: [
|
|
240
|
-
resolvedPublicPath + '/bundles'
|
|
241
|
-
],
|
|
242
|
-
outputStyle: 'expanded'
|
|
243
|
-
},
|
|
244
|
-
sourceMap: true
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
resolveLoader: {
|
|
244
|
+
modules: [
|
|
245
|
+
this.resolvedPublicPath,
|
|
246
|
+
path.join(__dirname, './loader'),
|
|
247
|
+
path.join(this.resolvedPublicPath, '/bundles'),
|
|
248
|
+
this.resolvedNodeModulesPath
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
module: {
|
|
252
|
+
noParse: [
|
|
253
|
+
/[\/\\]bundles[\/\\]\.*[\/\\]lib[\/\\](?!chaplin|bootstrap|jquery\.dialog).*\.js$/
|
|
254
|
+
],
|
|
255
|
+
rules: [
|
|
256
|
+
{
|
|
257
|
+
test: /\.s?css$/,
|
|
258
|
+
use: [{
|
|
259
|
+
loader: args.hot ? 'style-loader' : MiniCssExtractPlugin.loader
|
|
260
|
+
}, {
|
|
261
|
+
loader: 'css-loader',
|
|
262
|
+
options: {
|
|
263
|
+
importLoaders: 1,
|
|
264
|
+
sourceMap: true,
|
|
265
|
+
// can't use esModule since resolve-url-loader needs file path to start with '~'
|
|
266
|
+
esModule: false
|
|
267
|
+
}
|
|
268
|
+
}, {
|
|
269
|
+
loader: 'resolve-url-loader'
|
|
270
|
+
}, {
|
|
271
|
+
loader: 'postcss-loader',
|
|
272
|
+
options: {
|
|
273
|
+
sourceMap: true,
|
|
274
|
+
postcssOptions: {
|
|
275
|
+
plugins: [
|
|
276
|
+
require('autoprefixer')
|
|
277
|
+
]
|
|
245
278
|
}
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
test: /\.(eot|ttf|woff|woff2|cur|ico|svg|png|jpg|gif)$/,
|
|
250
|
-
loader: 'url-loader',
|
|
279
|
+
}
|
|
280
|
+
}, {
|
|
281
|
+
loader: 'sass-loader',
|
|
251
282
|
options: {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
283
|
+
sassOptions: {
|
|
284
|
+
includePaths: [
|
|
285
|
+
path.join(this.resolvedPublicPath, '/bundles')
|
|
286
|
+
],
|
|
287
|
+
outputStyle: 'expanded'
|
|
288
|
+
},
|
|
289
|
+
sourceMap: true
|
|
257
290
|
}
|
|
291
|
+
}]
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
test: /\.(eot|ttf|woff|woff2|cur|ico|svg|png|jpg|gif)$/,
|
|
295
|
+
loader: 'url-loader',
|
|
296
|
+
options: {
|
|
297
|
+
limit: 1,
|
|
298
|
+
emitFile: true,
|
|
299
|
+
outputPath: '../_static/',
|
|
300
|
+
publicPath: '../../_static/',
|
|
301
|
+
name: this._getVersionedPath('[path][name].[ext]', this.assetVersion)
|
|
258
302
|
}
|
|
259
|
-
|
|
260
|
-
},
|
|
261
|
-
performance: {hints: false},
|
|
262
|
-
plugins: [
|
|
263
|
-
new MiniCssExtractPlugin({
|
|
264
|
-
filename: '[name].css'
|
|
265
|
-
}),
|
|
266
|
-
new CleanupStatsPlugin(),
|
|
267
|
-
// Ignore all locale files of moment.js
|
|
268
|
-
new webpack.IgnorePlugin({
|
|
269
|
-
resourceRegExp: /^\.[\/\\]locale$/,
|
|
270
|
-
contextRegExp: /moment$/
|
|
271
|
-
}),
|
|
272
|
-
new webpack.optimize.MinChunkSizePlugin({
|
|
273
|
-
minChunkSize: 30000 // Minimum number of characters
|
|
274
|
-
})
|
|
303
|
+
}
|
|
275
304
|
]
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
305
|
+
},
|
|
306
|
+
performance: {hints: false},
|
|
307
|
+
plugins: [
|
|
308
|
+
new MiniCssExtractPlugin({
|
|
309
|
+
filename: '[name].css'
|
|
310
|
+
}),
|
|
311
|
+
new CleanupStatsPlugin(),
|
|
312
|
+
// Ignore all locale files of moment.js
|
|
313
|
+
new webpack.IgnorePlugin({
|
|
314
|
+
resourceRegExp: /^\.[\/\\]locale$/,
|
|
315
|
+
contextRegExp: /moment$/
|
|
316
|
+
}),
|
|
317
|
+
new webpack.optimize.MinChunkSizePlugin({
|
|
318
|
+
minChunkSize: 30000 // Minimum number of characters
|
|
319
|
+
})
|
|
320
|
+
]
|
|
321
|
+
};
|
|
281
322
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
loaders: [
|
|
286
|
-
{
|
|
287
|
-
loader: 'babel-loader',
|
|
288
|
-
options: this._babelConfig
|
|
289
|
-
}
|
|
290
|
-
]
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
webpackConfig.plugins.push(new HappyPack(happyPackOptions));
|
|
294
|
-
|
|
295
|
-
webpackConfig.module.rules.push({
|
|
296
|
-
test: /\.js$/,
|
|
297
|
-
exclude: [
|
|
298
|
-
/[\/\\]platform[\/\\]build[\/\\]/,
|
|
299
|
-
/[\/\\]node_modules[\/\\]/,
|
|
300
|
-
/[\/\\]bundles[\/\\].+[\/\\]lib[\/\\]?/
|
|
301
|
-
],
|
|
302
|
-
use: 'happypack/loader?id=babel'
|
|
303
|
-
});
|
|
304
|
-
}
|
|
323
|
+
if (env.analyze) {
|
|
324
|
+
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
|
|
325
|
+
}
|
|
305
326
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
host: devServerHost,
|
|
314
|
-
port: devServerPort,
|
|
315
|
-
https: https,
|
|
316
|
-
compress: true,
|
|
317
|
-
stats: stats,
|
|
318
|
-
disableHostCheck: true,
|
|
319
|
-
clientLogLevel: 'error',
|
|
320
|
-
headers: {
|
|
321
|
-
'Access-Control-Allow-Origin': '*'
|
|
327
|
+
if (!env.skipJS && !env.skipBabel) {
|
|
328
|
+
const happyPackOptions = {
|
|
329
|
+
id: 'babel',
|
|
330
|
+
loaders: [
|
|
331
|
+
{
|
|
332
|
+
loader: 'babel-loader',
|
|
333
|
+
options: this._babelConfig
|
|
322
334
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Additional setting for production mode
|
|
328
|
-
if (this._isProduction) {
|
|
329
|
-
webpackConfig = webpackMerge(webpackConfig, {
|
|
330
|
-
devtool: false,
|
|
335
|
+
]
|
|
336
|
+
};
|
|
331
337
|
|
|
332
|
-
|
|
333
|
-
new CssMinimizerPlugin()
|
|
334
|
-
]
|
|
335
|
-
});
|
|
336
|
-
}
|
|
338
|
+
webpackConfig.plugins.push(new HappyPack(happyPackOptions));
|
|
337
339
|
|
|
338
|
-
|
|
340
|
+
webpackConfig.module.rules.push({
|
|
341
|
+
test: /\.js$/,
|
|
342
|
+
exclude: [
|
|
343
|
+
/[\/\\]platform[\/\\]build[\/\\]/,
|
|
344
|
+
/[\/\\]node_modules[\/\\]/,
|
|
345
|
+
/[\/\\]bundles[\/\\].+[\/\\]lib[\/\\]?/
|
|
346
|
+
],
|
|
347
|
+
use: 'happypack/loader?id=babel'
|
|
348
|
+
});
|
|
349
|
+
}
|
|
339
350
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const {rtl_support: rtlSupport = false} = themeDefinition;
|
|
357
|
-
const resolvedBuildPath = path.join(resolvedPublicPath, buildPublicPath);
|
|
358
|
-
|
|
359
|
-
const resolverConfig = {
|
|
360
|
-
modules: [
|
|
361
|
-
resolvedBuildPath,
|
|
362
|
-
resolvedPublicPath,
|
|
363
|
-
resolvedPublicPath + '/bundles',
|
|
364
|
-
resolvedPublicPath + '/js',
|
|
365
|
-
resolvedNodeModulesPath
|
|
366
|
-
],
|
|
367
|
-
alias: themeConfig.aliases,
|
|
368
|
-
cacheWithContext: true,
|
|
369
|
-
symlinks: false
|
|
370
|
-
};
|
|
371
|
-
const resolver = (resolver => {
|
|
372
|
-
return moduleName => resolver({}, '', moduleName, {});
|
|
373
|
-
})(resolve.create.sync({...resolverConfig}));
|
|
374
|
-
|
|
375
|
-
const plugins = [];
|
|
376
|
-
if (rtlSupport && !env.skipCSS && !env.skipRTL) {
|
|
377
|
-
plugins.push(new RtlCssWebpackPlugin({
|
|
378
|
-
filename: '[name].rtl.css'
|
|
379
|
-
}));
|
|
351
|
+
if (args.hot) {
|
|
352
|
+
const https = this._appConfig.devServerOptions.https;
|
|
353
|
+
const schema = https ? 'https' : 'http';
|
|
354
|
+
const devServerHost = this._appConfig.devServerOptions.host;
|
|
355
|
+
const devServerPort = this._appConfig.devServerOptions.port;
|
|
356
|
+
webpackConfig.devServer = {
|
|
357
|
+
contentBase: this.resolvedPublicPath,
|
|
358
|
+
host: devServerHost,
|
|
359
|
+
port: devServerPort,
|
|
360
|
+
https: https,
|
|
361
|
+
compress: true,
|
|
362
|
+
stats: webpackConfig.stats,
|
|
363
|
+
disableHostCheck: true,
|
|
364
|
+
clientLogLevel: 'error',
|
|
365
|
+
headers: {
|
|
366
|
+
'Access-Control-Allow-Origin': '*'
|
|
380
367
|
}
|
|
368
|
+
};
|
|
369
|
+
webpackConfig.output.publicPath = `${schema}://${devServerHost}:${devServerPort}/`;
|
|
370
|
+
}
|
|
381
371
|
|
|
382
|
-
|
|
383
|
-
|
|
372
|
+
// Additional setting for production mode
|
|
373
|
+
if (this._isProduction) {
|
|
374
|
+
webpackConfig.devtool = false;
|
|
375
|
+
webpackConfig.plugins.push(new CssMinimizerPlugin());
|
|
376
|
+
}
|
|
384
377
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
webpackConfigs.push(webpackMerge({
|
|
390
|
-
entry: entryPoints,
|
|
391
|
-
name: theme + ' theme',
|
|
392
|
-
output: {
|
|
393
|
-
publicPath: buildPublicPath,
|
|
394
|
-
path: resolvedBuildPath
|
|
395
|
-
},
|
|
396
|
-
context: resolvedPublicPath,
|
|
397
|
-
resolve: {
|
|
398
|
-
...resolverConfig,
|
|
399
|
-
plugins: [
|
|
400
|
-
new MapModulesPlugin(prepareModulesMap(resolver, themeConfig.map))
|
|
401
|
-
]
|
|
402
|
-
},
|
|
403
|
-
plugins,
|
|
404
|
-
module: {
|
|
405
|
-
rules: [
|
|
406
|
-
{
|
|
407
|
-
test: /[\/\\]configs\.json$/,
|
|
408
|
-
loader: 'config-loader',
|
|
409
|
-
options: {
|
|
410
|
-
resolver,
|
|
411
|
-
relativeTo: resolvedPublicPath
|
|
412
|
-
}
|
|
413
|
-
},
|
|
414
|
-
...prepareModulesShim(resolver, themeConfig.shim)
|
|
415
|
-
]
|
|
416
|
-
}
|
|
417
|
-
}, webpackConfig));
|
|
418
|
-
});
|
|
378
|
+
return webpackConfig;
|
|
379
|
+
}
|
|
419
380
|
|
|
420
|
-
|
|
381
|
+
_getThemeWebpackConfig(buildName, args, env) {
|
|
382
|
+
let {skipCSS, skipJS, skipRTL} = env;
|
|
383
|
+
let themeDefinition;
|
|
384
|
+
let jsBuildConfig;
|
|
385
|
+
let buildPublicPath;
|
|
386
|
+
if (this._isAdminTheme(buildName)) {
|
|
387
|
+
themeDefinition = this._modulesConfigLoader.themes[buildName.split('.')[1]];
|
|
388
|
+
buildPublicPath = '/build/admin/';
|
|
389
|
+
const jsModulesConfig = this._themeConfigFactory.loadConfig(buildName,
|
|
390
|
+
['Resources/config/oro/jsmodules.yml', 'Resources/config/jsmodules.yml']);
|
|
391
|
+
jsBuildConfig = this._themeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
392
|
+
} else if (this._layoutModulesConfigLoader.isExtraJSBuild(buildName)) {
|
|
393
|
+
const [theme, suffix] = this._layoutModulesConfigLoader.splitBuildName(buildName);
|
|
394
|
+
skipCSS = true;
|
|
395
|
+
themeDefinition = this._layoutModulesConfigLoader.themes[theme];
|
|
396
|
+
buildPublicPath = `/build/${buildName}/`;
|
|
397
|
+
const baseConfig = this._layoutThemeConfigFactory.loadConfig(theme, 'config/jsmodules.yml');
|
|
398
|
+
const extraConfig = this._layoutThemeConfigFactory.loadConfig(theme, `config/jsmodules-${suffix}.yml`);
|
|
399
|
+
const jsModulesConfig = this._layoutThemeConfigFactory.extendConfig(baseConfig, extraConfig);
|
|
400
|
+
jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
401
|
+
} else {
|
|
402
|
+
themeDefinition = this._layoutModulesConfigLoader.themes[buildName];
|
|
403
|
+
buildPublicPath = `/build/${buildName}/`;
|
|
404
|
+
const jsModulesConfig = this._layoutThemeConfigFactory.loadConfig(buildName, 'config/jsmodules.yml');
|
|
405
|
+
jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
406
|
+
}
|
|
407
|
+
const {rtl_support: rtlSupport = false} = themeDefinition;
|
|
408
|
+
const resolvedBuildPath = path.join(this.resolvedPublicPath, buildPublicPath);
|
|
409
|
+
|
|
410
|
+
const resolverConfig = {
|
|
411
|
+
modules: [
|
|
412
|
+
resolvedBuildPath,
|
|
413
|
+
this.resolvedPublicPath,
|
|
414
|
+
path.join(this.resolvedPublicPath, '/bundles'),
|
|
415
|
+
path.join(this.resolvedPublicPath, '/js'),
|
|
416
|
+
this.resolvedNodeModulesPath
|
|
417
|
+
],
|
|
418
|
+
alias: jsBuildConfig.aliases,
|
|
419
|
+
cacheWithContext: true,
|
|
420
|
+
symlinks: false
|
|
421
421
|
};
|
|
422
|
+
const resolver = (resolver => {
|
|
423
|
+
return moduleName => resolver({}, '', moduleName, {});
|
|
424
|
+
})(resolve.create.sync({...resolverConfig}));
|
|
425
|
+
|
|
426
|
+
const plugins = [];
|
|
427
|
+
if (rtlSupport && !skipCSS && !skipRTL) {
|
|
428
|
+
plugins.push(new RtlCssWebpackPlugin({
|
|
429
|
+
filename: '[name].rtl.css'
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const cssEntryPoints = !skipCSS ? this._getCssEntryPoints(buildName, buildPublicPath) : {};
|
|
434
|
+
const jsEntryPoints = !skipJS ? jsBuildConfig.entry : {};
|
|
435
|
+
|
|
436
|
+
const entryPoints = {...cssEntryPoints, ...jsEntryPoints};
|
|
437
|
+
if (Object.keys(entryPoints).length === 0) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return {
|
|
442
|
+
entry: entryPoints,
|
|
443
|
+
name: buildName + ' theme',
|
|
444
|
+
output: {
|
|
445
|
+
publicPath: buildPublicPath,
|
|
446
|
+
path: resolvedBuildPath
|
|
447
|
+
},
|
|
448
|
+
context: this.resolvedPublicPath,
|
|
449
|
+
resolve: {
|
|
450
|
+
...resolverConfig,
|
|
451
|
+
plugins: [
|
|
452
|
+
new MapModulesPlugin(prepareModulesMap(resolver, jsBuildConfig.map))
|
|
453
|
+
]
|
|
454
|
+
},
|
|
455
|
+
plugins,
|
|
456
|
+
module: {
|
|
457
|
+
rules: [
|
|
458
|
+
{
|
|
459
|
+
test: /[\/\\]configs\.json$/,
|
|
460
|
+
loader: 'config-loader',
|
|
461
|
+
options: {
|
|
462
|
+
resolver,
|
|
463
|
+
relativeTo: this.resolvedPublicPath
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
...prepareModulesShim(resolver, jsBuildConfig.shim)
|
|
467
|
+
]
|
|
468
|
+
}
|
|
469
|
+
}
|
|
422
470
|
}
|
|
423
471
|
|
|
424
472
|
_initialize(args, env) {
|
|
@@ -447,7 +495,6 @@ class ConfigBuilder {
|
|
|
447
495
|
'/Resources/views/layouts/',
|
|
448
496
|
'theme.yml'
|
|
449
497
|
);
|
|
450
|
-
this._layoutThemes = this._layoutModulesConfigLoader.themeNames;
|
|
451
498
|
this._layoutStyleLoader = new LayoutStyleLoader(this._layoutModulesConfigLoader, entryPointFileWriter);
|
|
452
499
|
this._layoutThemeConfigFactory = new ThemeConfigFactory(
|
|
453
500
|
this._layoutModulesConfigLoader,
|
|
@@ -472,25 +519,25 @@ class ConfigBuilder {
|
|
|
472
519
|
return this._layoutStyleLoader.getThemeEntryPoints(theme, buildPath);
|
|
473
520
|
}
|
|
474
521
|
|
|
475
|
-
|
|
476
|
-
|
|
522
|
+
_validateBuildName(buildName) {
|
|
523
|
+
const buildNames = [...this._adminThemes];
|
|
477
524
|
if (this._enableLayoutThemes) {
|
|
478
|
-
|
|
525
|
+
buildNames.push(...this._layoutModulesConfigLoader.buildNames);
|
|
479
526
|
}
|
|
480
|
-
if (
|
|
527
|
+
if (buildName === 'admin') {
|
|
481
528
|
throw new Error(
|
|
482
529
|
'The "admin" is a reserved word and cannot be used as a theme name.'
|
|
483
530
|
);
|
|
484
531
|
}
|
|
485
|
-
if (
|
|
532
|
+
if (buildName !== undefined && !buildNames.includes(buildName)) {
|
|
486
533
|
throw new Error(
|
|
487
|
-
'Theme "' +
|
|
534
|
+
'Theme "' + buildName + '" doesn\'t exists. Existing themes:' + buildNames.join(', ')
|
|
488
535
|
);
|
|
489
536
|
}
|
|
490
537
|
}
|
|
491
538
|
|
|
492
539
|
_isAdminTheme(theme) {
|
|
493
|
-
return this._adminThemes.
|
|
540
|
+
return this._adminThemes.includes(theme);
|
|
494
541
|
}
|
|
495
542
|
}
|
|
496
543
|
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oroinc/oro-webpack-config-builder",
|
|
3
|
-
"version": "5.1.0-
|
|
3
|
+
"version": "5.1.0-alpha29",
|
|
4
4
|
"author": "Oro, Inc (https://www.oroinc.com)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "An integration of OroPlatform based applications with the Webpack.",
|
|
7
7
|
"main": "oro-webpack-config.js",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@babel/core": "^7.
|
|
10
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
11
|
-
"@babel/preset-env": "^7.
|
|
12
|
-
"autoprefixer": "^10.
|
|
13
|
-
"babel-loader": "^8.
|
|
9
|
+
"@babel/core": "^7.16.0",
|
|
10
|
+
"@babel/plugin-transform-runtime": "^7.16.0",
|
|
11
|
+
"@babel/preset-env": "^7.16.0",
|
|
12
|
+
"autoprefixer": "^10.4.0",
|
|
13
|
+
"babel-loader": "^8.2.3",
|
|
14
14
|
"bindings": "^1.5.0",
|
|
15
|
-
"css-loader": "^5.
|
|
16
|
-
"css-minimizer-webpack-plugin": "^3.
|
|
15
|
+
"css-loader": "^6.5.1",
|
|
16
|
+
"css-minimizer-webpack-plugin": "^3.1.3",
|
|
17
17
|
"deepmerge": "^4.2.2",
|
|
18
|
-
"exports-loader": "^3.
|
|
19
|
-
"expose-loader": "^3.
|
|
18
|
+
"exports-loader": "^3.1.0",
|
|
19
|
+
"expose-loader": "^3.1.0",
|
|
20
20
|
"extract-loader": "^5.1.0",
|
|
21
21
|
"file-loader": "^6.2.0",
|
|
22
22
|
"happypack": "^5.0.1",
|
|
23
|
-
"html-webpack-plugin": "^5.
|
|
24
|
-
"imports-loader": "^3.
|
|
23
|
+
"html-webpack-plugin": "^5.5.0",
|
|
24
|
+
"imports-loader": "^3.1.1",
|
|
25
25
|
"js-yaml": "^4.1.0",
|
|
26
|
-
"mini-css-extract-plugin": "^
|
|
26
|
+
"mini-css-extract-plugin": "^2.4.4",
|
|
27
27
|
"minimist": "^1.2.3",
|
|
28
|
-
"nan": "^2.
|
|
28
|
+
"nan": "^2.15.0",
|
|
29
29
|
"path": "0.12.7",
|
|
30
|
-
"postcss": "^8.3.
|
|
31
|
-
"postcss-loader": "^
|
|
30
|
+
"postcss": "^8.3.11",
|
|
31
|
+
"postcss-loader": "^6.2.0",
|
|
32
32
|
"printf": "^0.6.0",
|
|
33
33
|
"resolve-url-loader": "^4.0.0",
|
|
34
34
|
"rtlcss-webpack-plugin": "^4.0.6",
|
|
35
|
-
"sass": "^1.
|
|
36
|
-
"sass-loader": "^
|
|
37
|
-
"style-loader": "^
|
|
38
|
-
"terser": "^5.
|
|
35
|
+
"sass": "^1.43.4",
|
|
36
|
+
"sass-loader": "^12.3.0",
|
|
37
|
+
"style-loader": "^3.3.1",
|
|
38
|
+
"terser": "^5.9.0",
|
|
39
39
|
"text-loader": "0.0.1",
|
|
40
40
|
"underscore": "^1.13.1",
|
|
41
41
|
"url-loader": "^4.1.1",
|
|
42
|
-
"webpack": "^5.
|
|
43
|
-
"webpack-bundle-analyzer": "^4.
|
|
44
|
-
"webpack-cli": "^4.
|
|
45
|
-
"webpack-dev-server": "^
|
|
42
|
+
"webpack": "^5.63.0",
|
|
43
|
+
"webpack-bundle-analyzer": "^4.5.0",
|
|
44
|
+
"webpack-cli": "^4.9.1",
|
|
45
|
+
"webpack-dev-server": "^4.4.0",
|
|
46
46
|
"webpack-merge": "^5.8.0",
|
|
47
47
|
"wildcard": "^2.0.0"
|
|
48
48
|
}
|
|
@@ -10,7 +10,7 @@ class AdminStyleLoader extends StyleLoader {
|
|
|
10
10
|
this._configLoader.loadConfig(themeName, 'Resources/public/themes/' + themeName + '/settings.yml');
|
|
11
11
|
const baseThemeConfig = this._configLoader.loadConfig(themeName, 'Resources/config/oro/assets.yml');
|
|
12
12
|
/** @type {Object.<string, ThemeGroupConfig>} */
|
|
13
|
-
const themeConfig = merge(
|
|
13
|
+
const themeConfig = merge(baseThemeConfig, extraThemeConfig);
|
|
14
14
|
|
|
15
15
|
return {
|
|
16
16
|
themeConfig,
|
package/style/style-loader.js
CHANGED
|
@@ -105,20 +105,33 @@ class StyleLoader {
|
|
|
105
105
|
* @protected
|
|
106
106
|
*/
|
|
107
107
|
_sortInputs(inputs) {
|
|
108
|
+
const primarySettingsInputs = [];
|
|
108
109
|
const settingsInputs = [];
|
|
110
|
+
const primaryVariablesInputs = [];
|
|
109
111
|
const variablesInputs = [];
|
|
110
112
|
const restInputs = [];
|
|
111
113
|
|
|
112
114
|
inputs.forEach(input => {
|
|
113
|
-
if (input.indexOf('/settings/') > 0) {
|
|
115
|
+
if (input.indexOf('/settings/primary-settings') > 0) {
|
|
116
|
+
primarySettingsInputs.push(input);
|
|
117
|
+
} else if (input.indexOf('/settings/') > 0) {
|
|
114
118
|
settingsInputs.push(input);
|
|
115
|
-
} else
|
|
119
|
+
} else if (input.indexOf('/variables/primary-variables') > 0) {
|
|
120
|
+
primaryVariablesInputs.push(input);
|
|
121
|
+
} else if (input.indexOf('/variables/') > 0) {
|
|
116
122
|
variablesInputs.push(input);
|
|
117
123
|
} else {
|
|
118
124
|
restInputs.push(input);
|
|
119
125
|
}
|
|
120
126
|
});
|
|
121
|
-
|
|
127
|
+
|
|
128
|
+
return [
|
|
129
|
+
...primarySettingsInputs,
|
|
130
|
+
...settingsInputs,
|
|
131
|
+
...primaryVariablesInputs,
|
|
132
|
+
...variablesInputs,
|
|
133
|
+
...restInputs
|
|
134
|
+
];
|
|
122
135
|
}
|
|
123
136
|
|
|
124
137
|
/**
|
package/theme-config-factory.js
CHANGED
|
@@ -11,15 +11,52 @@ class ThemeConfigFactory {
|
|
|
11
11
|
this._appModulesFileWriter = appModulesFileWriter;
|
|
12
12
|
this._configsFileWriter = configsFileWriter;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
14
|
/**
|
|
16
15
|
* @param {string} theme Theme name
|
|
17
|
-
* @param {string} buildPath Path to theme build folder
|
|
18
16
|
* @param {string|string[]} configFilepath Path (or paths with fallback) to yaml config file in a bundle
|
|
19
|
-
* @return {Object}
|
|
17
|
+
* @return {Object} Merged Configs loaded from all the bundles Yaml files matched by filePath
|
|
18
|
+
*/
|
|
19
|
+
loadConfig(theme, configFilepath) {
|
|
20
|
+
return this._configLoader.loadConfig(theme, configFilepath);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
extendConfig(baseConfig, extraConfig) {
|
|
24
|
+
const {
|
|
25
|
+
aliases = {},
|
|
26
|
+
configs,
|
|
27
|
+
map = {},
|
|
28
|
+
shim = {},
|
|
29
|
+
} = baseConfig;
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
['app-modules']: appModules,
|
|
33
|
+
['dynamic-imports']: dynamicImports,
|
|
34
|
+
entry,
|
|
35
|
+
...rest
|
|
36
|
+
} = extraConfig;
|
|
37
|
+
|
|
38
|
+
const beyondKeys = Object.keys(rest);
|
|
39
|
+
if (beyondKeys.length) {
|
|
40
|
+
throw new Error(`Sections ["${beyondKeys.join('", "')}"] are not allowed in extra js build definition`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
aliases,
|
|
45
|
+
'app-modules': appModules,
|
|
46
|
+
configs,
|
|
47
|
+
'dynamic-imports': dynamicImports,
|
|
48
|
+
entry,
|
|
49
|
+
map,
|
|
50
|
+
shim
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} buildPath Path to theme build folder
|
|
56
|
+
* @param {Object} jsModulesConfig configuration loaded from jsmodules files and merged together
|
|
57
|
+
* @return {Object} webpack configuration fragment
|
|
20
58
|
*/
|
|
21
|
-
create(
|
|
22
|
-
const jsModulesConfig = this._configLoader.loadConfig(theme, configFilepath);
|
|
59
|
+
create(buildPath, jsModulesConfig) {
|
|
23
60
|
const {
|
|
24
61
|
entry,
|
|
25
62
|
map = {},
|