@oroinc/oro-webpack-config-builder 0.0.3 → 4.2.1-dev11
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/README.md +1 -1
- package/modules-config/layout-modules-config-loader.js +4 -4
- package/modules-config/modules-config-loader.js +9 -12
- package/oro-webpack-config.js +28 -10
- package/package.json +18 -17
- package/style/layout-style-loader.js +37 -12
- package/theme-config-factory.js +1 -1
- package/writer/scss-entry-point-file-writer.js +8 -2
package/README.md
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
|
|
3
3
|
An integration of OroPlatform based applications with the Webpack.
|
|
4
4
|
|
|
5
|
-
For more details see [the documentation](https://doc.oroinc.com/
|
|
5
|
+
For more details see [the documentation](https://doc.oroinc.com/bundles/platform/AssetBundle/).
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const merge = require('deepmerge');
|
|
3
|
-
const
|
|
3
|
+
const ModulesConfigLoader = require('./modules-config-loader');
|
|
4
4
|
|
|
5
|
-
class LayoutModulesConfigLoader extends
|
|
5
|
+
class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* @inheritdoc
|
|
8
8
|
*/
|
|
9
9
|
loadConfig(theme, filePath) {
|
|
10
10
|
let themeConfig = super.loadConfig(theme, path.join('/Resources/views/layouts/', theme, filePath));
|
|
11
11
|
// recursive process parent theme
|
|
12
|
-
const parentTheme = this.themes[theme];
|
|
12
|
+
const {parent: parentTheme} = this.themes[theme];
|
|
13
13
|
if (typeof parentTheme === 'string') {
|
|
14
14
|
const parentThemeConfig = this.loadConfig(parentTheme, filePath);
|
|
15
15
|
themeConfig = merge(parentThemeConfig, themeConfig);
|
|
@@ -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}
|
|
@@ -43,21 +46,15 @@ class ModulesConfigLoader {
|
|
|
43
46
|
if (!fs.existsSync(source)) return;
|
|
44
47
|
|
|
45
48
|
fs.readdirSync(source).forEach(name => {
|
|
46
|
-
const
|
|
47
|
-
if (!fs.lstatSync(
|
|
49
|
+
const themePath = path.resolve(source, name);
|
|
50
|
+
if (!fs.lstatSync(themePath).isDirectory()) {
|
|
48
51
|
return;
|
|
49
52
|
}
|
|
50
|
-
const themeFile = path.resolve(
|
|
53
|
+
const themeFile = path.resolve(themePath, themeInfoFileName);
|
|
51
54
|
if (!fs.existsSync(themeFile)) return;
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
const themeInfo = yaml.safeLoad(fs.readFileSync(themeFile, 'utf8'));
|
|
57
|
-
|
|
58
|
-
if ('parent' in themeInfo) {
|
|
59
|
-
themes[name] = themeInfo.parent;
|
|
60
|
-
}
|
|
56
|
+
const theme = yaml.load(fs.readFileSync(themeFile, 'utf8'));
|
|
57
|
+
themes[name] = merge(themes[name] || {}, theme, {arrayMerge});
|
|
61
58
|
});
|
|
62
59
|
});
|
|
63
60
|
|
|
@@ -75,7 +72,7 @@ class ModulesConfigLoader {
|
|
|
75
72
|
const absolutePath = bundle + filePath;
|
|
76
73
|
if (!fs.existsSync(absolutePath)) return;
|
|
77
74
|
|
|
78
|
-
const doc = yaml.
|
|
75
|
+
const doc = yaml.load(fs.readFileSync(absolutePath, 'utf8'));
|
|
79
76
|
configs = merge(configs, doc);
|
|
80
77
|
});
|
|
81
78
|
return configs;
|
package/oro-webpack-config.js
CHANGED
|
@@ -19,8 +19,9 @@ const ThemeConfigFactory = require('./theme-config-factory');
|
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const prepareModulesMap = require('./plugin/map/prepare-modules-map');
|
|
21
21
|
const resolve = require('enhanced-resolve');
|
|
22
|
-
const webpackMerge = require('webpack-merge');
|
|
22
|
+
const {merge: webpackMerge} = require('webpack-merge');
|
|
23
23
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
24
|
+
const WebpackRTLPlugin = require('webpack-rtl-plugin');
|
|
24
25
|
|
|
25
26
|
class ConfigBuilder {
|
|
26
27
|
constructor() {
|
|
@@ -145,7 +146,7 @@ class ConfigBuilder {
|
|
|
145
146
|
if (this._defaultLayoutThemes) {
|
|
146
147
|
themes = [...themes, ...this._defaultLayoutThemes];
|
|
147
148
|
} else {
|
|
148
|
-
themes = [...themes, ...
|
|
149
|
+
themes = [...themes, ...this._appConfig['themes']];
|
|
149
150
|
}
|
|
150
151
|
} else if (this._layoutThemes.indexOf(selectedTheme) !== -1) {
|
|
151
152
|
// build single layout theme
|
|
@@ -244,9 +245,12 @@ class ConfigBuilder {
|
|
|
244
245
|
}, {
|
|
245
246
|
loader: 'sass-loader',
|
|
246
247
|
options: {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
sassOptions: {
|
|
249
|
+
includePaths: [
|
|
250
|
+
path.join(resolvedPublicPath, '/bundles')
|
|
251
|
+
],
|
|
252
|
+
outputStyle: 'expanded'
|
|
253
|
+
},
|
|
250
254
|
sourceMap: true
|
|
251
255
|
}
|
|
252
256
|
}]
|
|
@@ -337,11 +341,11 @@ class ConfigBuilder {
|
|
|
337
341
|
|
|
338
342
|
plugins: [
|
|
339
343
|
new OptimizeCssAssetsPlugin({
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
344
|
+
cssProcessorPluginOptions: {
|
|
345
|
+
preset: ['default', {
|
|
346
|
+
// preserve comments for WebpackRTLPlugin, comments will be removed anyway later
|
|
347
|
+
discardComments: false,
|
|
348
|
+
}],
|
|
345
349
|
}
|
|
346
350
|
})
|
|
347
351
|
]
|
|
@@ -351,17 +355,21 @@ class ConfigBuilder {
|
|
|
351
355
|
const webpackConfigs = [];
|
|
352
356
|
|
|
353
357
|
themes.forEach(theme => {
|
|
358
|
+
let themeDefinition;
|
|
354
359
|
let themeConfig;
|
|
355
360
|
let buildPublicPath;
|
|
356
361
|
if (this._isAdminTheme(theme)) {
|
|
362
|
+
themeDefinition = this._modulesConfigLoader.themes[theme.split('.')[1]];
|
|
357
363
|
buildPublicPath = '/build/admin/';
|
|
358
364
|
themeConfig = this._themeConfigFactory
|
|
359
365
|
.create(theme, buildPublicPath, '/Resources/config/jsmodules.yml');
|
|
360
366
|
} else {
|
|
367
|
+
themeDefinition = this._layoutModulesConfigLoader.themes[theme];
|
|
361
368
|
buildPublicPath = `/build/${theme}/`;
|
|
362
369
|
themeConfig = this._layoutThemeConfigFactory
|
|
363
370
|
.create(theme, buildPublicPath, '/config/jsmodules.yml');
|
|
364
371
|
}
|
|
372
|
+
const {rtl_support: rtlSupport = false} = themeDefinition;
|
|
365
373
|
const resolvedBuildPath = path.join(resolvedPublicPath, buildPublicPath);
|
|
366
374
|
|
|
367
375
|
const resolverConfig = {
|
|
@@ -379,6 +387,15 @@ class ConfigBuilder {
|
|
|
379
387
|
return moduleName => resolver({}, '', moduleName, {});
|
|
380
388
|
})(resolve.create.sync({...resolverConfig}));
|
|
381
389
|
|
|
390
|
+
const plugins = [];
|
|
391
|
+
if (rtlSupport && !env.skipCSS && !env.skipRTL) {
|
|
392
|
+
plugins.push(new WebpackRTLPlugin({
|
|
393
|
+
filename: '[name].rtl.css',
|
|
394
|
+
// RTL all chunks, except those that already support RTL
|
|
395
|
+
test: '(?<!(-rtl-ready))\\.css'
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
|
|
382
399
|
const cssEntryPoints = !env.skipCSS ? this._getCssEntryPoints(theme, buildPublicPath) : {};
|
|
383
400
|
const jsEntryPoints = !env.skipJS ? themeConfig.entry : {};
|
|
384
401
|
|
|
@@ -400,6 +417,7 @@ class ConfigBuilder {
|
|
|
400
417
|
new MapModulesPlugin(prepareModulesMap(resolver, themeConfig.map))
|
|
401
418
|
]
|
|
402
419
|
},
|
|
420
|
+
plugins,
|
|
403
421
|
module: {
|
|
404
422
|
rules: [
|
|
405
423
|
{
|
package/package.json
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oroinc/oro-webpack-config-builder",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.2.1-dev11",
|
|
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": "9.
|
|
13
|
-
"babel-loader": "^8.
|
|
9
|
+
"@babel/core": "^7.16.0",
|
|
10
|
+
"@babel/plugin-transform-runtime": "^7.16.4",
|
|
11
|
+
"@babel/preset-env": "^7.16.4",
|
|
12
|
+
"autoprefixer": "^9.8.8",
|
|
13
|
+
"babel-loader": "^8.2.3",
|
|
14
14
|
"css-loader": "^3.6.0",
|
|
15
|
-
"deepmerge": "
|
|
15
|
+
"deepmerge": "4.2.2",
|
|
16
16
|
"exports-loader": "^0.7.0",
|
|
17
17
|
"expose-loader": "^0.7.5",
|
|
18
18
|
"extract-loader": "3.1.0",
|
|
19
19
|
"file-loader": "^4.3.0",
|
|
20
20
|
"font-awesome": "4.7.0",
|
|
21
21
|
"happypack": "^5.0.1",
|
|
22
|
-
"html-webpack-plugin": "^3.2.0",
|
|
23
22
|
"imports-loader": "^0.8.0",
|
|
24
23
|
"inject-loader": "^4.0.1",
|
|
25
|
-
"js-yaml": "
|
|
24
|
+
"js-yaml": "4.1.0",
|
|
26
25
|
"mini-css-extract-plugin": "0.7.0",
|
|
27
26
|
"minimist": "^1.2.3",
|
|
28
|
-
"node-sass": "^
|
|
27
|
+
"node-sass": "^6.0.1",
|
|
29
28
|
"optimize-css-assets-webpack-plugin": "5.0.3",
|
|
30
29
|
"path": "0.12.7",
|
|
31
30
|
"postcss-loader": "3.0.0",
|
|
32
|
-
"printf": "^0.6.
|
|
33
|
-
"sass-loader": "
|
|
31
|
+
"printf": "^0.6.1",
|
|
32
|
+
"sass-loader": "10.2.0",
|
|
34
33
|
"style-loader": "^0.23.1",
|
|
35
34
|
"terser": "4.1.2",
|
|
36
35
|
"text-loader": "0.0.1",
|
|
37
|
-
"underscore": "
|
|
36
|
+
"underscore": "1.13.*",
|
|
38
37
|
"url-loader": "2.0.1",
|
|
39
|
-
"webpack": "^4.
|
|
40
|
-
"webpack-bundle-analyzer": "^
|
|
38
|
+
"webpack": "^4.46.0",
|
|
39
|
+
"webpack-bundle-analyzer": "^4.5.0",
|
|
41
40
|
"webpack-cli": "^3.3.12",
|
|
42
|
-
"webpack-dev-server": "^
|
|
43
|
-
"webpack-merge": "
|
|
41
|
+
"webpack-dev-server": "^4.5.0",
|
|
42
|
+
"webpack-merge": "5.8.0",
|
|
43
|
+
"webpack-rtl-plugin": "^2.0.0",
|
|
44
|
+
"wildcard": "^2.0.0"
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const wildcard = require('wildcard');
|
|
3
|
+
const _ = require('underscore')
|
|
2
4
|
|
|
3
5
|
class LayoutStyleLoader {
|
|
4
6
|
/**
|
|
@@ -17,21 +19,25 @@ class LayoutStyleLoader {
|
|
|
17
19
|
*/
|
|
18
20
|
getThemeEntryPoints(theme, buildPath) {
|
|
19
21
|
const entryPoints = {};
|
|
20
|
-
|
|
22
|
+
const {rtl_support: rtlSupport = false} = this._configLoader.themes[theme];
|
|
21
23
|
const themeConfig = this._configLoader.loadConfig(theme, '/config/assets.yml');
|
|
24
|
+
const writingOptions = {};
|
|
22
25
|
|
|
23
|
-
for (const key
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const filePath = path.join(buildPath, config.output);
|
|
33
|
-
entryPoints[entryPointName] = this._entryPointFileWriter.write('./../../../', inputs, filePath);
|
|
26
|
+
for (const [key, config] of Object.entries(themeConfig)) {
|
|
27
|
+
let {inputs, output, auto_rtl_inputs: rtlMasks = []} = config;
|
|
28
|
+
if (config.output === undefined) {
|
|
29
|
+
throw new Error('"output" for "' + key + '" group in theme "' + theme + '" is not defined');
|
|
30
|
+
}
|
|
31
|
+
inputs = this._overrideInputs(inputs);
|
|
32
|
+
inputs = this._sortInputs(inputs);
|
|
33
|
+
if (rtlSupport) {
|
|
34
|
+
writingOptions.ignoreRTLInputs = _.difference(inputs, this._matchInputs(rtlMasks, inputs));
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
const entryPointName = output.replace(/\.[^/.]+$/, '');
|
|
38
|
+
const filePath = path.join(buildPath, output);
|
|
39
|
+
entryPoints[entryPointName] =
|
|
40
|
+
this._entryPointFileWriter.write('./../../../', inputs, filePath, writingOptions);
|
|
35
41
|
}
|
|
36
42
|
return entryPoints;
|
|
37
43
|
}
|
|
@@ -86,6 +92,25 @@ class LayoutStyleLoader {
|
|
|
86
92
|
});
|
|
87
93
|
return [...settingsInputs, ...variablesInputs, ...restInputs];
|
|
88
94
|
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Filter inputs that matches any mask from the list
|
|
98
|
+
*
|
|
99
|
+
* @param {[string]} masks list of wildcard masks
|
|
100
|
+
* @param {[string]} inputs
|
|
101
|
+
* @return {[string]} matched inputs
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
_matchInputs(masks, inputs) {
|
|
105
|
+
masks = masks.map(mask => wildcard(mask));
|
|
106
|
+
|
|
107
|
+
const whiteListedInputs = masks.reduce((include, mask) => {
|
|
108
|
+
include.push(...mask.match(inputs));
|
|
109
|
+
return include;
|
|
110
|
+
}, []);
|
|
111
|
+
|
|
112
|
+
return _.unique(whiteListedInputs);
|
|
113
|
+
}
|
|
89
114
|
}
|
|
90
115
|
|
|
91
116
|
module.exports = LayoutStyleLoader;
|
package/theme-config-factory.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class ThemeConfigFactory {
|
|
2
2
|
/**
|
|
3
|
-
* @param {
|
|
3
|
+
* @param {ModulesConfigLoader} configLoader
|
|
4
4
|
* @param {DynamicImportsFileWriter} dynamicImportsFileWriter
|
|
5
5
|
* @param {AppModulesFileWriter} appModulesFileWriter
|
|
6
6
|
* @param {ConfigsFileWriter} configsFileWriter
|
|
@@ -15,16 +15,22 @@ class SCSSEntryPointFileWriter {
|
|
|
15
15
|
* @param {string} baseInputPath base path for input files
|
|
16
16
|
* @param {Array} inputs List of inputs
|
|
17
17
|
* @param {string} output Output file path
|
|
18
|
+
* @param {Object} options writing options
|
|
18
19
|
* @returns {string} JS file path of an output file
|
|
19
20
|
*/
|
|
20
|
-
write(baseInputPath, inputs, output) {
|
|
21
|
+
write(baseInputPath, inputs, output, {ignoreRTLInputs = []}) {
|
|
21
22
|
let content = '';
|
|
22
23
|
inputs.forEach(input => {
|
|
24
|
+
const ignoreRTL = ignoreRTLInputs.indexOf(input) !== -1;
|
|
23
25
|
input = input.replace(/\.[^/.]+$/, '');
|
|
24
26
|
// don't add the base path to global node modules,
|
|
25
27
|
// e.g. '~bootstrap/scss/bootstrap'
|
|
26
28
|
const basePath = input.startsWith('~') ? '': baseInputPath;
|
|
27
|
-
|
|
29
|
+
let importModule = `@import "${basePath}${input}";\n`;
|
|
30
|
+
if (ignoreRTL) {
|
|
31
|
+
importModule = `/*rtl:begin:ignore*/\n${importModule}/*rtl:end:ignore*/\n`;
|
|
32
|
+
}
|
|
33
|
+
content += importModule;
|
|
28
34
|
});
|
|
29
35
|
const scssFilepath = path.resolve(this._publicPath + output + '.scss');
|
|
30
36
|
fs.mkdirSync(path.dirname(scssFilepath), {recursive: true});
|