@oroinc/oro-webpack-config-builder 5.1.0-alpha3 → 5.1.0-alpha30

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.
@@ -14,14 +14,17 @@ const ModulesConfigLoader = require('./modules-config/modules-config-loader');
14
14
  const DynamicImportsFileWriter = require('./writer/dynamic-imports-file-writer');
15
15
  const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
16
16
  const prepareModulesShim = require('./prepare-modules-shim');
17
- const StyleLoader = require('./style/style-loader');
17
+ const AdminStyleLoader = require('./style/admin-style-loader');
18
18
  const ThemeConfigFactory = require('./theme-config-factory');
19
19
  const path = require('path');
20
+ const fs = require('fs');
20
21
  const prepareModulesMap = require('./plugin/map/prepare-modules-map');
21
22
  const resolve = require('enhanced-resolve');
22
23
  const {merge: webpackMerge} = require('webpack-merge');
23
24
  const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
24
25
  const RtlCssWebpackPlugin = require('rtlcss-webpack-plugin');
26
+ const {red: colorRed} = require('colorette');
27
+ require('resolve-url-loader');
25
28
 
26
29
  class ConfigBuilder {
27
30
  constructor() {
@@ -29,18 +32,18 @@ class ConfigBuilder {
29
32
  this._adminTheme = 'admin.oro';
30
33
  this._enableLayoutThemes = false;
31
34
  this._defaultLayoutThemes = null;
32
- this._versionFormat = '%s?version=%s';
35
+ this._versionFormat = '%s?v=%s';
33
36
  this._babelConfig = {
34
37
  sourceType: 'unambiguous',
35
38
  presets: [
36
39
  [
37
40
  '@babel/preset-env', {
38
- useBuiltIns: 'usage',
39
- corejs: {
40
- version: 3,
41
- proposals: true
42
- }
41
+ useBuiltIns: 'usage',
42
+ corejs: {
43
+ version: 3,
44
+ proposals: true
43
45
  }
46
+ }
44
47
  ]
45
48
  ],
46
49
  plugins: [
@@ -71,7 +74,7 @@ class ConfigBuilder {
71
74
 
72
75
  /**
73
76
  * Specifies a sprintf pattern that will be used with the version option to construct an asset’s path.
74
- * By default ts `%s?version=%s`
77
+ * By default ts `%s?v=%s`
75
78
  * @param {string} versionFormat
76
79
  * @returns {ConfigBuilder}
77
80
  */
@@ -125,310 +128,365 @@ class ConfigBuilder {
125
128
  return (env = {}, args = {}) => {
126
129
  this._initialize(args, env);
127
130
 
128
- const {assetVersion} = this._appConfig;
129
- const {theme: selectedTheme} = env;
130
- this._validateThemeName(selectedTheme);
131
-
132
- let themes = [];
133
- // Admin themes
134
- if (selectedTheme === undefined) {
135
- // themes.push(this._adminTheme.split(".")[1]);
136
- themes.push(this._adminTheme);
137
- } else if (this._adminThemes.indexOf(selectedTheme) !== -1) {
138
- // themes.push(selectedTheme.split(".")[1]);
139
- themes.push(selectedTheme);
131
+ let commonConfig = {};
132
+ try {
133
+ commonConfig = this._getCommonWebpackConfig(args, env);
134
+ } catch (e) {
135
+ console.error(colorRed(`Error: ${e.message}`));
136
+ process.exit(1);
140
137
  }
141
138
 
142
- // Layout Themes
143
- if (this._enableLayoutThemes) {
144
- if (selectedTheme === undefined) {
145
- // build all layout themes
146
- if (this._defaultLayoutThemes) {
147
- themes = [...themes, ...this._defaultLayoutThemes];
148
- } else {
149
- themes = [...themes, ...Object.keys(this._layoutModulesConfigLoader.themes)];
150
- }
151
- } else if (this._layoutThemes.indexOf(selectedTheme) !== -1) {
152
- // build single layout theme
153
- themes.push(selectedTheme);
139
+ const webpackConfigs = [];
140
+ const requestedBuildNames = env.theme ? env.theme.split(',') : [];
141
+ const buildNames = this._getBuildNames(requestedBuildNames);
142
+ buildNames.forEach(buildName => {
143
+ let buildConfig;
144
+ try {
145
+ buildConfig = this._getThemeWebpackConfig(buildName, args, env);
146
+ } catch (e) {
147
+ console.error(colorRed(`Error: ${e.message}`));
148
+ return;
149
+ }
150
+
151
+ if (buildConfig) {
152
+ webpackConfigs.push(webpackMerge(buildConfig, commonConfig));
153
+ }
154
+ });
155
+
156
+ return webpackConfigs;
157
+ };
158
+ }
159
+
160
+ get resolvedPublicPath() {
161
+ if (this._resolvedPublicPath === undefined) {
162
+ this._resolvedPublicPath = path.resolve(this._publicPath);
163
+ }
164
+ return this._resolvedPublicPath;
165
+ }
166
+
167
+ get resolvedNodeModulesPath() {
168
+ if (this._resolvedNodeModulesPath === undefined) {
169
+ this._resolvedNodeModulesPath = path.resolve('node_modules');
170
+ }
171
+ return this._resolvedNodeModulesPath;
172
+ }
173
+
174
+ get assetVersion() {
175
+ if (this._assetVersion === undefined) {
176
+ const filePath = path.join(this.resolvedPublicPath, '/build/build_version.txt');
177
+ this._assetVersion = fs.existsSync(filePath) ? String(fs.readFileSync(filePath)) : null;
178
+ }
179
+ return this._assetVersion;
180
+ }
181
+
182
+ _getBuildNames(requestedBuildNames = []) {
183
+ const buildNames = [];
184
+ requestedBuildNames.forEach(buildName => this._validateBuildName(buildName));
185
+
186
+ // Admin themes
187
+ if (!requestedBuildNames.length) {
188
+ buildNames.push(this._adminTheme);
189
+ } else {
190
+ requestedBuildNames.forEach(buildName => {
191
+ if (this._isAdminTheme(buildName)) {
192
+ buildNames.push(buildName);
154
193
  }
194
+ });
195
+ }
196
+
197
+ // Layout Themes
198
+ if (this._enableLayoutThemes) {
199
+ if (!requestedBuildNames.length) {
200
+ // build all layout themes
201
+ const themes = this._defaultLayoutThemes || this._appConfig.themes;
202
+ buildNames.push(...themes);
203
+ themes.forEach(theme => {
204
+ buildNames.push(...this._layoutModulesConfigLoader.extraJSBuildNames(theme));
205
+ });
206
+ } else {
207
+ // build single layout theme
208
+ requestedBuildNames.forEach(buildName => {
209
+ if (this._layoutModulesConfigLoader.buildNames.includes(buildName)) {
210
+ buildNames.push(buildName);
211
+ }
212
+ });
155
213
  }
214
+ }
156
215
 
157
- const resolvedPublicPath = path.resolve(this._publicPath);
158
- const resolvedNodeModulesPath = path.resolve('node_modules');
159
- const stats = env.stats || {
160
- hash: false,
161
- version: false,
162
- // Do not write the information about files emitted from node_modules or public bundles,
163
- // and hide css/*/*.js files from the output.
164
- excludeAssets: [/^bundles\//, /^\.\.\/_static\//, /^css\/.+\.js/],
165
- children: false,
166
- entrypoints: false,
167
- performance: this._isProduction,
168
- chunks: false,
169
- modules: false,
170
- source: false,
171
- publicPath: true,
172
- builtAt: false,
173
- warnings: false
174
- };
175
- let webpackConfig = {
176
- watchOptions: {
177
- aggregateTimeout: 200,
178
- ignored: /[\/\\]node_modules[\/\\].*\.js$/
179
- },
180
- stats: stats,
181
- output: {
182
- filename: '[name].js',
183
- // Because we use third party libraries 'chunkFilename' should include only [name]
184
- chunkFilename: printf(this._versionFormat, 'chunk/[name].js', assetVersion)
185
- },
186
- devtool: !env.skipSourcemap && 'inline-cheap-module-source-map',
187
- mode: 'development',
188
- optimization: {
189
- moduleIds: 'named',
190
- splitChunks: {
191
- cacheGroups: {
192
- commons: {
193
- minSize: 30,
194
- minChunks: 2,
195
- priority: 10,
196
- reuseExistingChunk: true
197
- },
198
- tinymce: {
199
- test: /tinymce/,
200
- name: 'tinymce.min',
201
- minChunks: 1
202
- },
203
- fusioncharts: {
204
- test: /fusioncharts/,
205
- name: 'fusioncharts',
206
- minChunks: 1
207
- }
208
- }
216
+ return buildNames;
217
+ }
218
+
219
+ _getCommonWebpackConfig(args, env) {
220
+ const stats = env.stats || {
221
+ hash: false,
222
+ version: false,
223
+ // Do not write the information about files emitted from node_modules or public bundles,
224
+ // and hide css/*/*.js files from the output.
225
+ excludeAssets: [/^bundles\//, /^\.\.\/_static\//, /^css\/.+\.js/],
226
+ children: false,
227
+ entrypoints: false,
228
+ performance: this._isProduction,
229
+ chunks: false,
230
+ modules: false,
231
+ source: false,
232
+ publicPath: true,
233
+ builtAt: false,
234
+ warnings: false
235
+ };
236
+
237
+ const webpackConfig = {
238
+ watchOptions: {
239
+ aggregateTimeout: 200,
240
+ ignored: /[\/\\]node_modules[\/\\].*\.js$/
241
+ },
242
+ stats,
243
+ output: {
244
+ filename: '[name].js',
245
+ // Because we use third party libraries 'chunkFilename' should include only [name]
246
+ chunkFilename: this._getVersionedPath('chunk/[name].js', this.assetVersion)
247
+ },
248
+ devtool: !env.skipSourcemap && 'inline-cheap-module-source-map',
249
+ mode: 'development',
250
+ optimization: {
251
+ moduleIds: 'named',
252
+ splitChunks: {
253
+ cacheGroups: {
254
+ defaultVendors: false
209
255
  }
210
- },
211
- resolveLoader: {
212
- modules: [
213
- resolvedPublicPath,
214
- path.join(__dirname, './loader'),
215
- resolvedPublicPath + '/bundles',
216
- resolvedNodeModulesPath
217
- ]
218
- },
219
- module: {
220
- noParse: [
221
- /[\/\\]bundles[\/\\]\.*[\/\\]lib[\/\\](?!chaplin|bootstrap|jquery\.dialog).*\.js$/
222
- ],
223
- rules: [
224
- {
225
- test: /\.s?css$/,
226
- use: [{
227
- loader: args.hot ? 'style-loader' : MiniCssExtractPlugin.loader
228
- }, {
229
- loader: 'css-loader',
230
- options: {
231
- importLoaders: 1,
232
- sourceMap: true
233
- }
234
- }, {
235
- loader: 'postcss-loader',
236
- options: {
237
- sourceMap: true,
238
- postcssOptions: {
239
- plugins: [
240
- require('autoprefixer')
241
- ]
242
- }
243
- }
244
- }, {
245
- loader: 'sass-loader',
246
- options: {
247
- sassOptions: {
248
- includePaths: [
249
- resolvedPublicPath + '/bundles'
250
- ],
251
- outputStyle: 'expanded'
252
- },
253
- sourceMap: true
256
+ }
257
+ },
258
+ resolveLoader: {
259
+ modules: [
260
+ this.resolvedPublicPath,
261
+ path.join(__dirname, './loader'),
262
+ path.join(this.resolvedPublicPath, '/bundles'),
263
+ this.resolvedNodeModulesPath
264
+ ]
265
+ },
266
+ module: {
267
+ noParse: [
268
+ /[\/\\]bundles[\/\\]\.*[\/\\]lib[\/\\](?!chaplin|bootstrap|jquery\.dialog).*\.js$/
269
+ ],
270
+ rules: [
271
+ {
272
+ test: /\.s?css$/,
273
+ use: [{
274
+ loader: args.hot ? 'style-loader' : MiniCssExtractPlugin.loader
275
+ }, {
276
+ loader: 'css-loader',
277
+ options: {
278
+ importLoaders: 1,
279
+ sourceMap: true,
280
+ // can't use esModule since resolve-url-loader needs file path to start with '~'
281
+ esModule: false
282
+ }
283
+ }, {
284
+ loader: 'resolve-url-loader'
285
+ }, {
286
+ loader: 'postcss-loader',
287
+ options: {
288
+ sourceMap: true,
289
+ postcssOptions: {
290
+ plugins: [
291
+ require('autoprefixer')
292
+ ]
254
293
  }
255
- }]
256
- },
257
- {
258
- test: /\.(eot|ttf|woff|woff2|cur|ico|svg|png|jpg|gif)$/,
259
- loader: 'url-loader',
294
+ }
295
+ }, {
296
+ loader: 'sass-loader',
260
297
  options: {
261
- limit: 1,
262
- emitFile: true,
263
- outputPath: '../_static/',
264
- publicPath: '../../_static/',
265
- name: printf(this._versionFormat, '[path][name].[ext]', assetVersion)
298
+ sassOptions: {
299
+ includePaths: [
300
+ path.join(this.resolvedPublicPath, '/bundles')
301
+ ],
302
+ outputStyle: 'expanded'
303
+ },
304
+ sourceMap: true
266
305
  }
306
+ }]
307
+ },
308
+ {
309
+ test: /\.(eot|ttf|woff|woff2|cur|ico|svg|png|jpg|gif)$/,
310
+ loader: 'url-loader',
311
+ options: {
312
+ limit: 1,
313
+ emitFile: true,
314
+ outputPath: '../_static/',
315
+ publicPath: '../../_static/',
316
+ name: this._getVersionedPath('[path][name].[ext]', this.assetVersion)
267
317
  }
268
- ]
269
- },
270
- performance: {hints: false},
271
- plugins: [
272
- new MiniCssExtractPlugin({
273
- filename: '[name].css'
274
- }),
275
- new CleanupStatsPlugin(),
276
- // Ignore all locale files of moment.js
277
- new webpack.IgnorePlugin({
278
- resourceRegExp: /^\.[\/\\]locale$/,
279
- contextRegExp: /moment$/
280
- }),
281
- new webpack.optimize.MinChunkSizePlugin({
282
- minChunkSize: 30000 // Minimum number of characters
283
- })
318
+ }
284
319
  ]
285
- };
286
-
287
- if (env.analyze) {
288
- webpackConfig.plugins.push(new BundleAnalyzerPlugin());
289
- }
320
+ },
321
+ performance: {hints: false},
322
+ plugins: [
323
+ new MiniCssExtractPlugin({
324
+ filename: '[name].css'
325
+ }),
326
+ new CleanupStatsPlugin(),
327
+ // Ignore all locale files of moment.js
328
+ new webpack.IgnorePlugin({
329
+ resourceRegExp: /^\.[\/\\]locale$/,
330
+ contextRegExp: /moment$/
331
+ }),
332
+ new webpack.optimize.MinChunkSizePlugin({
333
+ minChunkSize: 30000 // Minimum number of characters
334
+ })
335
+ ]
336
+ };
290
337
 
291
- if (!env.skipJS && !env.skipBabel) {
292
- const happyPackOptions = {
293
- id: 'babel',
294
- loaders: [
295
- {
296
- loader: 'babel-loader',
297
- options: this._babelConfig
298
- }
299
- ]
300
- };
301
-
302
- webpackConfig.plugins.push(new HappyPack(happyPackOptions));
303
-
304
- webpackConfig.module.rules.push({
305
- test: /\.js$/,
306
- exclude: [
307
- /[\/\\]platform[\/\\]build[\/\\]/,
308
- /[\/\\]node_modules[\/\\]/,
309
- /[\/\\]bundles[\/\\].+[\/\\]lib[\/\\]?/
310
- ],
311
- use: 'happypack/loader?id=babel'
312
- });
313
- }
338
+ if (env.analyze) {
339
+ webpackConfig.plugins.push(new BundleAnalyzerPlugin());
340
+ }
314
341
 
315
- if (args.hot) {
316
- const https = this._appConfig.devServerOptions.https;
317
- const schema = https ? 'https' : 'http';
318
- const devServerHost = this._appConfig.devServerOptions.host;
319
- const devServerPort = this._appConfig.devServerOptions.port;
320
- webpackConfig.devServer = {
321
- contentBase: resolvedPublicPath,
322
- host: devServerHost,
323
- port: devServerPort,
324
- https: https,
325
- compress: true,
326
- stats: stats,
327
- disableHostCheck: true,
328
- clientLogLevel: 'error',
329
- headers: {
330
- 'Access-Control-Allow-Origin': '*'
342
+ if (!env.skipJS && !env.skipBabel) {
343
+ const happyPackOptions = {
344
+ id: 'babel',
345
+ loaders: [
346
+ {
347
+ loader: 'babel-loader',
348
+ options: this._babelConfig
331
349
  }
332
- };
333
- webpackConfig.output.publicPath = `${schema}://${devServerHost}:${devServerPort}/`;
334
- }
350
+ ]
351
+ };
335
352
 
336
- // Additional setting for production mode
337
- if (this._isProduction) {
338
- webpackConfig = webpackMerge(webpackConfig, {
339
- devtool: false,
353
+ webpackConfig.plugins.push(new HappyPack(happyPackOptions));
340
354
 
341
- plugins: [
342
- new CssMinimizerPlugin()
343
- ]
344
- });
345
- }
346
-
347
- const webpackConfigs = [];
355
+ webpackConfig.module.rules.push({
356
+ test: /\.js$/,
357
+ exclude: [
358
+ /[\/\\]platform[\/\\]build[\/\\]/,
359
+ /[\/\\]node_modules[\/\\]/,
360
+ /[\/\\]bundles[\/\\].+[\/\\]lib[\/\\]?/
361
+ ],
362
+ use: 'happypack/loader?id=babel'
363
+ });
364
+ }
348
365
 
349
- themes.forEach(theme => {
350
- let themeDefinition;
351
- let themeConfig;
352
- let buildPublicPath;
353
- if (this._isAdminTheme(theme)) {
354
- themeDefinition = this._modulesConfigLoader.themes[theme.split('.')[1]];
355
- buildPublicPath = '/build/admin/';
356
- themeConfig = this._themeConfigFactory
357
- .create(theme, buildPublicPath, '/Resources/config/jsmodules.yml');
358
- } else {
359
- themeDefinition = this._layoutModulesConfigLoader.themes[theme];
360
- buildPublicPath = `/build/${theme}/`;
361
- themeConfig = this._layoutThemeConfigFactory
362
- .create(theme, buildPublicPath, '/config/jsmodules.yml');
363
- }
364
- const {rtl_support: rtlSupport = false} = themeDefinition;
365
- const resolvedBuildPath = path.join(resolvedPublicPath, buildPublicPath);
366
-
367
- const resolverConfig = {
368
- modules: [
369
- resolvedBuildPath,
370
- resolvedPublicPath,
371
- resolvedPublicPath + '/bundles',
372
- resolvedPublicPath + '/js',
373
- resolvedNodeModulesPath
374
- ],
375
- alias: themeConfig.aliases,
376
- symlinks: false
377
- };
378
- const resolver = (resolver => {
379
- return moduleName => resolver({}, '', moduleName, {});
380
- })(resolve.create.sync({...resolverConfig}));
381
-
382
- const plugins = [];
383
- if (rtlSupport && !env.skipCSS && !env.skipRTL) {
384
- plugins.push(new RtlCssWebpackPlugin({
385
- filename: '[name].rtl.css'
386
- }));
366
+ if (args.hot) {
367
+ const https = this._appConfig.devServerOptions.https;
368
+ const schema = https ? 'https' : 'http';
369
+ const devServerHost = this._appConfig.devServerOptions.host;
370
+ const devServerPort = this._appConfig.devServerOptions.port;
371
+ webpackConfig.devServer = {
372
+ contentBase: this.resolvedPublicPath,
373
+ host: devServerHost,
374
+ port: devServerPort,
375
+ https: https,
376
+ compress: true,
377
+ stats: webpackConfig.stats,
378
+ disableHostCheck: true,
379
+ clientLogLevel: 'error',
380
+ headers: {
381
+ 'Access-Control-Allow-Origin': '*'
387
382
  }
383
+ };
384
+ webpackConfig.output.publicPath = `${schema}://${devServerHost}:${devServerPort}/`;
385
+ }
388
386
 
389
- const cssEntryPoints = !env.skipCSS ? this._getCssEntryPoints(theme, buildPublicPath) : {};
390
- const jsEntryPoints = !env.skipJS ? themeConfig.entry : {};
387
+ // Additional setting for production mode
388
+ if (this._isProduction) {
389
+ webpackConfig.devtool = false;
390
+ webpackConfig.plugins.push(new CssMinimizerPlugin());
391
+ }
391
392
 
392
- const entryPoints = {...cssEntryPoints, ...jsEntryPoints};
393
- if (Object.keys(entryPoints).length === 0) {
394
- return;
395
- }
396
- webpackConfigs.push(webpackMerge({
397
- entry: entryPoints,
398
- name: theme + ' theme',
399
- output: {
400
- publicPath: buildPublicPath,
401
- path: resolvedBuildPath
402
- },
403
- context: resolvedPublicPath,
404
- resolve: {
405
- ...resolverConfig,
406
- plugins: [
407
- new MapModulesPlugin(prepareModulesMap(resolver, themeConfig.map))
408
- ]
409
- },
410
- plugins,
411
- module: {
412
- rules: [
413
- {
414
- test: /[\/\\]configs\.json$/,
415
- loader: 'config-loader',
416
- options: {
417
- resolver,
418
- relativeTo: resolvedPublicPath
419
- }
420
- },
421
- ...prepareModulesShim(resolver, themeConfig.shim)
422
- ]
423
- }
424
- }, webpackConfig));
425
- });
393
+ return webpackConfig;
394
+ }
426
395
 
427
- return webpackConfigs;
396
+ _getThemeWebpackConfig(buildName, args, env) {
397
+ let {skipCSS, skipJS, skipRTL} = env;
398
+ let themeDefinition;
399
+ let jsBuildConfig;
400
+ let buildPublicPath;
401
+ if (this._isAdminTheme(buildName)) {
402
+ themeDefinition = this._modulesConfigLoader.themes[buildName.split('.')[1]];
403
+ buildPublicPath = '/build/admin/';
404
+ const jsModulesConfig = this._themeConfigFactory.loadConfig(buildName,
405
+ ['Resources/config/oro/jsmodules.yml', 'Resources/config/jsmodules.yml']);
406
+ jsBuildConfig = this._themeConfigFactory.create(buildPublicPath, jsModulesConfig);
407
+ } else if (this._layoutModulesConfigLoader.isExtraJSBuild(buildName)) {
408
+ const [theme, suffix] = this._layoutModulesConfigLoader.splitBuildName(buildName);
409
+ skipCSS = true;
410
+ themeDefinition = this._layoutModulesConfigLoader.themes[theme];
411
+ buildPublicPath = `/build/${buildName}/`;
412
+ const baseConfig = this._layoutThemeConfigFactory.loadConfig(theme, 'config/jsmodules.yml');
413
+ const extraConfig = this._layoutThemeConfigFactory.loadConfig(theme, `config/jsmodules-${suffix}.yml`);
414
+ const jsModulesConfig = this._layoutThemeConfigFactory.extendConfig(baseConfig, extraConfig);
415
+ jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
416
+ } else {
417
+ themeDefinition = this._layoutModulesConfigLoader.themes[buildName];
418
+ buildPublicPath = `/build/${buildName}/`;
419
+ const jsModulesConfig = this._layoutThemeConfigFactory.loadConfig(buildName, 'config/jsmodules.yml');
420
+ jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
421
+ }
422
+ const {rtl_support: rtlSupport = false} = themeDefinition;
423
+ const resolvedBuildPath = path.join(this.resolvedPublicPath, buildPublicPath);
424
+
425
+ const resolverConfig = {
426
+ modules: [
427
+ resolvedBuildPath,
428
+ this.resolvedPublicPath,
429
+ path.join(this.resolvedPublicPath, '/bundles'),
430
+ path.join(this.resolvedPublicPath, '/js'),
431
+ this.resolvedNodeModulesPath
432
+ ],
433
+ alias: jsBuildConfig.aliases,
434
+ cacheWithContext: true,
435
+ symlinks: false
428
436
  };
437
+ const resolver = (resolver => {
438
+ return moduleName => resolver({}, '', moduleName, {});
439
+ })(resolve.create.sync({...resolverConfig}));
440
+
441
+ const plugins = [];
442
+ if (rtlSupport && !skipCSS && !skipRTL) {
443
+ plugins.push(new RtlCssWebpackPlugin({
444
+ filename: '[name].rtl.css'
445
+ }));
446
+ }
447
+
448
+ const cssEntryPoints = !skipCSS ? this._getCssEntryPoints(buildName, buildPublicPath) : {};
449
+ const jsEntryPoints = !skipJS ? jsBuildConfig.entry : {};
450
+
451
+ const entryPoints = {...cssEntryPoints, ...jsEntryPoints};
452
+ if (Object.keys(entryPoints).length === 0) {
453
+ return;
454
+ }
455
+
456
+ return {
457
+ entry: entryPoints,
458
+ name: buildName + ' theme',
459
+ output: {
460
+ publicPath: buildPublicPath,
461
+ path: resolvedBuildPath
462
+ },
463
+ context: this.resolvedPublicPath,
464
+ resolve: {
465
+ ...resolverConfig,
466
+ plugins: [
467
+ new MapModulesPlugin(prepareModulesMap(resolver, jsBuildConfig.map))
468
+ ]
469
+ },
470
+ plugins,
471
+ module: {
472
+ rules: [
473
+ {
474
+ test: /[\/\\]configs\.json$/,
475
+ loader: 'config-loader',
476
+ options: {
477
+ resolver,
478
+ relativeTo: this.resolvedPublicPath
479
+ }
480
+ },
481
+ ...prepareModulesShim(resolver, jsBuildConfig.shim)
482
+ ]
483
+ }
484
+ }
429
485
  }
430
486
 
431
487
  _initialize(args, env) {
488
+ const entryPointFileWriter = new EntryPointFileWriter(this._publicPath);
489
+
432
490
  this._isProduction = args.mode === 'production';
433
491
  this._symfonyEnv = env.symfony;
434
492
  this._appConfig = AppConfigLoader.getConfig(this._cachePath, this._symfonyEnv);
@@ -439,7 +497,7 @@ class ConfigBuilder {
439
497
  'settings.yml'
440
498
  );
441
499
  this._adminThemes = this._modulesConfigLoader.themeNames.map(themeName => 'admin.' + themeName);
442
- this._styleLoader = new StyleLoader(this._modulesConfigLoader);
500
+ this._adminStyleLoader = new AdminStyleLoader(this._modulesConfigLoader, entryPointFileWriter);
443
501
  this._themeConfigFactory = new ThemeConfigFactory(
444
502
  this._modulesConfigLoader,
445
503
  new DynamicImportsFileWriter(this._publicPath),
@@ -452,8 +510,6 @@ class ConfigBuilder {
452
510
  '/Resources/views/layouts/',
453
511
  'theme.yml'
454
512
  );
455
- this._layoutThemes = this._layoutModulesConfigLoader.themeNames;
456
- const entryPointFileWriter = new EntryPointFileWriter(this._publicPath);
457
513
  this._layoutStyleLoader = new LayoutStyleLoader(this._layoutModulesConfigLoader, entryPointFileWriter);
458
514
  this._layoutThemeConfigFactory = new ThemeConfigFactory(
459
515
  this._layoutModulesConfigLoader,
@@ -463,33 +519,40 @@ class ConfigBuilder {
463
519
  );
464
520
  }
465
521
 
522
+ _getVersionedPath(name, assetVersion) {
523
+ if(!assetVersion) {
524
+ return name;
525
+ }
526
+ return printf(this._versionFormat, name, assetVersion);
527
+ }
528
+
466
529
  _getCssEntryPoints(theme, buildPath) {
467
530
  if (this._isAdminTheme(theme)) {
468
- return this._styleLoader.getThemeEntryPoints(theme.split('.')[1]);
531
+ return this._adminStyleLoader.getThemeEntryPoints(theme.split('.')[1], buildPath);
469
532
  }
470
533
 
471
534
  return this._layoutStyleLoader.getThemeEntryPoints(theme, buildPath);
472
535
  }
473
536
 
474
- _validateThemeName(theme) {
475
- let existingThemes = this._adminThemes;
537
+ _validateBuildName(buildName) {
538
+ const buildNames = [...this._adminThemes];
476
539
  if (this._enableLayoutThemes) {
477
- existingThemes = existingThemes.concat(this._layoutThemes);
540
+ buildNames.push(...this._layoutModulesConfigLoader.buildNames);
478
541
  }
479
- if (theme === 'admin') {
542
+ if (buildName === 'admin') {
480
543
  throw new Error(
481
544
  'The "admin" is a reserved word and cannot be used as a theme name.'
482
545
  );
483
546
  }
484
- if (theme !== undefined && !existingThemes.includes(theme)) {
547
+ if (buildName !== undefined && !buildNames.includes(buildName)) {
485
548
  throw new Error(
486
- 'Theme "' + theme + '" doesn\'t exists. Existing themes:' + existingThemes.join(', ')
549
+ 'Theme "' + buildName + '" doesn\'t exists. Existing themes:' + buildNames.join(', ')
487
550
  );
488
551
  }
489
552
  }
490
553
 
491
554
  _isAdminTheme(theme) {
492
- return this._adminThemes.indexOf(theme) !== -1;
555
+ return this._adminThemes.includes(theme);
493
556
  }
494
557
  }
495
558