@oroinc/oro-webpack-config-builder 5.1.0-alpha32 → 5.1.0-alpha35
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/error-handler.js +95 -0
- package/loader/inject-loader/index.js +1 -70
- package/modules-config/layout-modules-config-loader.js +7 -3
- package/modules-config/modules-config-loader.js +34 -9
- package/oro-webpack-config.js +83 -21
- package/package.json +10 -9
- package/plugin/logs/after-webpack-logs-plugin.js +25 -0
- package/style/admin-style-loader.js +2 -1
- package/style/style-loader.js +35 -10
- package/theme-config-factory.js +5 -9
- package/utils.js +30 -0
- package/validation/assets-validator.js +104 -0
- package/validation/errors/assets-input-file-error.js +24 -0
- package/validation/errors/assets-schema-error.js +40 -0
- package/validation/errors/base-error.js +37 -0
- package/validation/errors/jsmodules-extra-modules-error.js +22 -0
- package/validation/errors/jsmodules-schema-error.js +40 -0
- package/validation/errors/styles-error.js +24 -0
- package/validation/index.js +36 -0
- package/validation/jsmodules-validator.js +53 -0
- package/validation/schema-validator.js +62 -0
- package/validation/schemas/assets-schema-full.js +22 -0
- package/validation/schemas/assets-schema.js +32 -0
- package/validation/schemas/jsmodules-schema-full.js +11 -0
- package/validation/schemas/jsmodules-schema.js +76 -0
- package/writer/dynamic-imports-file-writer.js +2 -2
- package/writer/scss-entry-point-file-writer.js +1 -1
- package/messages.js +0 -29
package/error-handler.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const BaseError = require('./validation/errors/base-error');
|
|
2
|
+
const {isVerboseMode} = require('./utils');
|
|
3
|
+
const {red, yellow, green, bgRed} = require('colorette');
|
|
4
|
+
|
|
5
|
+
const emptyLine = length => new Array(length).fill(' ').join('');
|
|
6
|
+
const multiline = (color, msg) => {
|
|
7
|
+
msg = ` ${msg}`;
|
|
8
|
+
msg = msg + emptyLine(120 - msg.length);
|
|
9
|
+
|
|
10
|
+
return `\n${color(emptyLine(msg.length))}\n${color(msg)}\n${color(emptyLine(msg.length))}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
class ErrorHandler {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.failedThemes = [];
|
|
16
|
+
|
|
17
|
+
process.on('beforeExit', code => {
|
|
18
|
+
this.onProcess();
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Show a message about failed themes
|
|
24
|
+
*/
|
|
25
|
+
onProcess() {
|
|
26
|
+
if (this.failedThemes.length) {
|
|
27
|
+
let msg = '[ERROR] Assets build';
|
|
28
|
+
|
|
29
|
+
if (this.failedThemes.length === 1) {
|
|
30
|
+
msg = `${msg} for "${this.failedThemes[0]}" theme failed.`;
|
|
31
|
+
} else {
|
|
32
|
+
msg = `${msg} for "${this.failedThemes.join(', ')}" themes failed.`;
|
|
33
|
+
}
|
|
34
|
+
console.error(multiline(bgRed, msg));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Executes when the Webpack Compiler will complete a compilation
|
|
41
|
+
* In case of empty Webpack Config this method will not run
|
|
42
|
+
*
|
|
43
|
+
* @param {Object} stats
|
|
44
|
+
*/
|
|
45
|
+
onBuildComplete(stats) {
|
|
46
|
+
const failed = stats?.compilation?.errors.length !== 0;
|
|
47
|
+
|
|
48
|
+
if (failed) {
|
|
49
|
+
console.error(multiline(bgRed, '[ERROR] Assets build failed.'));
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Array|string} errors
|
|
56
|
+
* @param {string} [failedTheme]
|
|
57
|
+
*/
|
|
58
|
+
displayError(errors, failedTheme) {
|
|
59
|
+
if (typeof failedTheme === 'string') {
|
|
60
|
+
this.failedThemes.push(failedTheme);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (typeof errors === 'string') {
|
|
64
|
+
errors = [errors];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const errorMessage = errors.map(err => {
|
|
68
|
+
const highlightPrefix = str => {
|
|
69
|
+
const prefix = str.substring(0, str.search(':'));
|
|
70
|
+
return red(prefix) + str.substring(str.search(':'));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (err instanceof BaseError) {
|
|
74
|
+
err.message = `${err.message}\n${green(err.extra)}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let msg = err.message;
|
|
78
|
+
|
|
79
|
+
if (isVerboseMode()) {
|
|
80
|
+
msg = highlightPrefix(err.stack);
|
|
81
|
+
} else {
|
|
82
|
+
const command = yellow('php bin/console oro:assets:build --env=dev --verbose');
|
|
83
|
+
const info = `${green(`Run the command ${command} to see more information`)}`;
|
|
84
|
+
|
|
85
|
+
msg = highlightPrefix(`${err.name}: ${msg}\n${info}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return `${msg}\n`;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.error(errorMessage.join('\n'));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = ErrorHandler;
|
|
@@ -1,70 +1 @@
|
|
|
1
|
-
module.exports = function (e) {
|
|
2
|
-
var n = {};
|
|
3
|
-
|
|
4
|
-
function t(i) {
|
|
5
|
-
if (n[i]) return n[i].exports;
|
|
6
|
-
var r = n[i] = {i: i, l: !1, exports: {}};
|
|
7
|
-
return e[i].call(r.exports, r, r.exports, t), r.l = !0, r.exports
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return t.m = e, t.c = n, t.d = function (e, n, i) {
|
|
11
|
-
t.o(e, n) || Object.defineProperty(e, n, {configurable: !1, enumerable: !0, get: i})
|
|
12
|
-
}, t.r = function (e) {
|
|
13
|
-
Object.defineProperty(e, "__esModule", {value: !0})
|
|
14
|
-
}, t.n = function (e) {
|
|
15
|
-
var n = e && e.__esModule ? function () {
|
|
16
|
-
return e.default
|
|
17
|
-
} : function () {
|
|
18
|
-
return e
|
|
19
|
-
};
|
|
20
|
-
return t.d(n, "a", n), n
|
|
21
|
-
}, t.o = function (e, n) {
|
|
22
|
-
return Object.prototype.hasOwnProperty.call(e, n)
|
|
23
|
-
}, t.p = "", t.w = {}, t(t.s = 3)
|
|
24
|
-
}([function (e, n) {
|
|
25
|
-
e.exports = require("babel-core")
|
|
26
|
-
}, function (e, n, t) {
|
|
27
|
-
"use strict";
|
|
28
|
-
Object.defineProperty(n, "__esModule", {value: !0});
|
|
29
|
-
var i = t(0);
|
|
30
|
-
n.default = (0, i.template)("\n module.exports = function __injector(__injections) {\n __injections = __injections || {};\n\n (function __validateInjection() {\n var validDependencies = DEPENDENCIES;\n var injectedDependencies = Object.keys(__injections);\n var invalidInjectedDependencies = injectedDependencies.filter(function (dependency) {\n return validDependencies.indexOf(dependency) === -1;\n });\n\n if (invalidInjectedDependencies.length > 0) {\n var validDependenciesString = ' - ' + validDependencies.join('\\n - ');\n var injectedDependenciesString = ' - ' + injectedDependencies.join('\\n - ');\n var invalidDependenciesString = ' - ' + invalidInjectedDependencies.join('\\n - ');\n\n throw new Error('Injection Error in ' + SOURCE_PATH + '\\n\\n' +\n 'The following injections are invalid:\\n' + invalidDependenciesString + '\\n\\n' +\n 'The following injections were passed in:\\n' + injectedDependenciesString + '\\n\\n' +\n 'Valid injection targets for this module are:\\n' + validDependenciesString + '\\n'\n );\n }\n })();\n\n __injector.sourcePath = SOURCE_PATH;\n __injector.validDependencies = DEPENDENCIES;\n\n var module = { exports: {} };\n var exports = module.exports;\n\n (function () {\n SOURCE\n })();\n\n return module.exports;\n }\n"), e.exports = n.default
|
|
31
|
-
}, function (e, n, t) {
|
|
32
|
-
"use strict";
|
|
33
|
-
Object.defineProperty(n, "__esModule", {value: !0}), n.default = function (e, n, t) {
|
|
34
|
-
var i = (0, r.transform)(n, {babelrc: !1, code: !1, compact: !1, filename: e.resourcePath}).ast, o = [];
|
|
35
|
-
(0, r.traverse)(i, {
|
|
36
|
-
CallExpression: function (e) {
|
|
37
|
-
r.types.isIdentifier(e.node.callee, {name: "require"}) && (o.push(function (e) {
|
|
38
|
-
var n = e.node.arguments[0].value;
|
|
39
|
-
return e.replaceWith(r.types.expressionStatement(r.types.conditionalExpression(r.types.callExpression(r.types.memberExpression(r.types.identifier("__injections"), r.types.identifier("hasOwnProperty"), !1), [r.types.stringLiteral(n)]), r.types.memberExpression(r.types.identifier("__injections"), r.types.stringLiteral(n), !0), e.node))), n
|
|
40
|
-
}(e)), e.skip())
|
|
41
|
-
}
|
|
42
|
-
}), 0 === o.length && e.emitWarning("The module you are trying to inject into doesn't have any dependencies. Are you sure you want to do this?");
|
|
43
|
-
var a = r.types.file(r.types.program([(0, s.default)({
|
|
44
|
-
SOURCE: i,
|
|
45
|
-
SOURCE_PATH: r.types.stringLiteral(e.resourcePath),
|
|
46
|
-
DEPENDENCIES: r.types.arrayExpression(o.map(function (e) {
|
|
47
|
-
return r.types.stringLiteral(e)
|
|
48
|
-
}))
|
|
49
|
-
})]));
|
|
50
|
-
return (0, r.transformFromAst)(a, n, {
|
|
51
|
-
sourceMaps: e.sourceMap,
|
|
52
|
-
sourceFileName: e.resourcePath,
|
|
53
|
-
inputSourceMap: t,
|
|
54
|
-
babelrc: !1,
|
|
55
|
-
compact: !1,
|
|
56
|
-
filename: e.resourcePath
|
|
57
|
-
})
|
|
58
|
-
};
|
|
59
|
-
var i, r = t(0), o = t(1), s = (i = o) && i.__esModule ? i : {default: i};
|
|
60
|
-
e.exports = n.default
|
|
61
|
-
}, function (e, n, t) {
|
|
62
|
-
"use strict";
|
|
63
|
-
Object.defineProperty(n, "__esModule", {value: !0}), n.default = function (e, n) {
|
|
64
|
-
this.cacheable && this.cacheable();
|
|
65
|
-
var t = (0, o.default)(this, e, n), i = t.code, r = t.map;
|
|
66
|
-
this.callback(null, i, r)
|
|
67
|
-
};
|
|
68
|
-
var i, r = t(2), o = (i = r) && i.__esModule ? i : {default: i};
|
|
69
|
-
e.exports = n.default
|
|
70
|
-
}]);
|
|
1
|
+
module.exports=function(e){var n={};function t(i){if(n[i])return n[i].exports;var r=n[i]={i:i,l:!1,exports:{}};return e[i].call(r.exports,r,r.exports,t),r.l=!0,r.exports}return t.m=e,t.c=n,t.d=function(e,n,i){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:i})},t.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t.w={},t(t.s=3)}([function(e,n){e.exports=require("babel-core")},function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var i=t(0);n.default=(0,i.template)("\n module.exports = function __injector(__injections) {\n __injections = __injections || {};\n\n (function __validateInjection() {\n var validDependencies = DEPENDENCIES;\n var injectedDependencies = Object.keys(__injections);\n var invalidInjectedDependencies = injectedDependencies.filter(function (dependency) {\n return validDependencies.indexOf(dependency) === -1;\n });\n\n if (invalidInjectedDependencies.length > 0) {\n var validDependenciesString = ' - ' + validDependencies.join('\\n - ');\n var injectedDependenciesString = ' - ' + injectedDependencies.join('\\n - ');\n var invalidDependenciesString = ' - ' + invalidInjectedDependencies.join('\\n - ');\n\n throw new Error('Injection Error in ' + SOURCE_PATH + '\\n\\n' +\n 'The following injections are invalid:\\n' + invalidDependenciesString + '\\n\\n' +\n 'The following injections were passed in:\\n' + injectedDependenciesString + '\\n\\n' +\n 'Valid injection targets for this module are:\\n' + validDependenciesString + '\\n'\n );\n }\n })();\n\n __injector.sourcePath = SOURCE_PATH;\n __injector.validDependencies = DEPENDENCIES;\n\n var module = { exports: {} };\n var exports = module.exports;\n\n (function () {\n SOURCE\n })();\n\n return module.exports;\n }\n"),e.exports=n.default},function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(e,n,t){var i=(0,r.transform)(n,{babelrc:!1,code:!1,compact:!1,filename:e.resourcePath}).ast,o=[];(0,r.traverse)(i,{CallExpression:function(e){r.types.isIdentifier(e.node.callee,{name:"require"})&&(o.push(function(e){var n=e.node.arguments[0].value;return e.replaceWith(r.types.expressionStatement(r.types.conditionalExpression(r.types.callExpression(r.types.memberExpression(r.types.identifier("__injections"),r.types.identifier("hasOwnProperty"),!1),[r.types.stringLiteral(n)]),r.types.memberExpression(r.types.identifier("__injections"),r.types.stringLiteral(n),!0),e.node))),n}(e)),e.skip())}}),0===o.length&&e.emitWarning("The module you are trying to inject into doesn't have any dependencies. Are you sure you want to do this?");var a=r.types.file(r.types.program([(0,s.default)({SOURCE:i,SOURCE_PATH:r.types.stringLiteral(e.resourcePath),DEPENDENCIES:r.types.arrayExpression(o.map(function(e){return r.types.stringLiteral(e)}))})]));return(0,r.transformFromAst)(a,n,{sourceMaps:e.sourceMap,sourceFileName:e.resourcePath,inputSourceMap:t,babelrc:!1,compact:!1,filename:e.resourcePath})};var i,r=t(0),o=t(1),s=(i=o)&&i.__esModule?i:{default:i};e.exports=n.default},function(e,n,t){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.default=function(e,n){this.cacheable&&this.cacheable();var t=(0,o.default)(this,e,n),i=t.code,r=t.map;this.callback(null,i,r)};var i,r=t(2),o=(i=r)&&i.__esModule?i:{default:i};e.exports=n.default}]);
|
|
@@ -8,13 +8,17 @@ class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
|
8
8
|
*/
|
|
9
9
|
loadConfig(theme, filePath) {
|
|
10
10
|
let themeConfig = super.loadConfig(theme, path.join('Resources/views/layouts/', theme, filePath));
|
|
11
|
+
themeConfig = merge(themeConfig, super.loadConfig(theme, path.join('templates/layouts/', theme, filePath)));
|
|
11
12
|
// recursive process parent theme
|
|
12
13
|
const {parent: parentTheme} = this.themes[theme];
|
|
13
14
|
if (typeof parentTheme === 'string') {
|
|
15
|
+
const processedFiles = this.processedFiles;
|
|
14
16
|
const parentThemeConfig = this.loadConfig(parentTheme, filePath);
|
|
17
|
+
|
|
15
18
|
themeConfig = merge(parentThemeConfig, themeConfig);
|
|
19
|
+
// processedFiles from parent theme is added to processedFiles of current theme
|
|
20
|
+
this._processedFiles = [...processedFiles, ...this.processedFiles];
|
|
16
21
|
}
|
|
17
|
-
|
|
18
22
|
return themeConfig;
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -40,7 +44,7 @@ class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
|
40
44
|
* @return {string[]}
|
|
41
45
|
*/
|
|
42
46
|
extraJSBuildNames(theme) {
|
|
43
|
-
const {extra_js_builds:
|
|
47
|
+
const {extra_js_builds: extraJSBuilds = []} = this._themes[theme] || {};
|
|
44
48
|
return [...extraJSBuilds.map(suffix => `${theme}-${suffix}`)];
|
|
45
49
|
}
|
|
46
50
|
|
|
@@ -66,7 +70,7 @@ class LayoutModulesConfigLoader extends ModulesConfigLoader {
|
|
|
66
70
|
const result = [];
|
|
67
71
|
if (marches) {
|
|
68
72
|
const [, theme, suffix] = marches;
|
|
69
|
-
const {extra_js_builds:
|
|
73
|
+
const {extra_js_builds: extraJSBuilds = []} = this._themes[theme] || {};
|
|
70
74
|
if (extraJSBuilds.includes(suffix)) {
|
|
71
75
|
result.push(marches[1], marches[2]);
|
|
72
76
|
} else {
|
|
@@ -2,6 +2,7 @@ const path = require('path');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const merge = require('deepmerge');
|
|
4
4
|
const yaml = require('js-yaml');
|
|
5
|
+
const validation = require('../validation');
|
|
5
6
|
|
|
6
7
|
// merge only unique items
|
|
7
8
|
const arrayMerge = (target, source) => target.concat(source.filter(item => !target.includes(item)));
|
|
@@ -28,25 +29,43 @@ class ModulesConfigLoader {
|
|
|
28
29
|
return this.themeNames;
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @returns {Array}
|
|
34
|
+
*/
|
|
35
|
+
get processedFiles() {
|
|
36
|
+
return [...this._processedFiles];
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
/**
|
|
32
40
|
* @param {Array} bundles Array of ordered symfony bundle paths
|
|
33
|
-
* @param {string} themesLocation Path inside the bundle, where to find the theme
|
|
41
|
+
* @param {string|Array} themesLocation Path inside the bundle, where to find the theme
|
|
34
42
|
* @param {string} themeInfoFileName Yaml File name with theme info
|
|
35
43
|
*/
|
|
36
44
|
constructor(bundles, themesLocation, themeInfoFileName) {
|
|
37
45
|
this._bundles = bundles;
|
|
38
|
-
|
|
46
|
+
if (!Array.isArray(themesLocation)) {
|
|
47
|
+
themesLocation = [themesLocation];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const themes = {};
|
|
51
|
+
const self = this;
|
|
52
|
+
themesLocation.forEach(themesLocation => {
|
|
53
|
+
self._collectThemes(themes, themesLocation, themeInfoFileName);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this._themes = themes;
|
|
57
|
+
this._processedFiles = [];
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
/**
|
|
42
|
-
*
|
|
61
|
+
* Collects list of themes with their parents into given storage(themes param)
|
|
62
|
+
*
|
|
63
|
+
* @param {Object} themes
|
|
43
64
|
* @param {string} themesLocation
|
|
44
65
|
* @param {string} themeInfoFileName
|
|
45
|
-
* @returns {Object.<string|null>}
|
|
46
66
|
* @private
|
|
47
67
|
*/
|
|
48
|
-
|
|
49
|
-
const themes = {};
|
|
68
|
+
_collectThemes(themes, themesLocation, themeInfoFileName) {
|
|
50
69
|
this._bundles.forEach(bundle => {
|
|
51
70
|
const source = bundle + themesLocation;
|
|
52
71
|
|
|
@@ -64,8 +83,6 @@ class ModulesConfigLoader {
|
|
|
64
83
|
themes[name] = merge(themes[name] || {}, theme, {arrayMerge});
|
|
65
84
|
});
|
|
66
85
|
});
|
|
67
|
-
|
|
68
|
-
return themes;
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
/**
|
|
@@ -76,6 +93,8 @@ class ModulesConfigLoader {
|
|
|
76
93
|
loadConfig(theme, filePath) {
|
|
77
94
|
let configs = {};
|
|
78
95
|
const filePaths = [].concat(filePath);
|
|
96
|
+
|
|
97
|
+
this._processedFiles = [];
|
|
79
98
|
this._bundles.forEach(bundle => {
|
|
80
99
|
let absolutePath;
|
|
81
100
|
|
|
@@ -88,10 +107,16 @@ class ModulesConfigLoader {
|
|
|
88
107
|
}
|
|
89
108
|
|
|
90
109
|
if (absolutePath) {
|
|
91
|
-
const
|
|
110
|
+
const rawDoc = fs.readFileSync(absolutePath, 'utf8');
|
|
111
|
+
const doc = yaml.load(rawDoc);
|
|
112
|
+
|
|
113
|
+
this._processedFiles.push(absolutePath);
|
|
114
|
+
|
|
115
|
+
validation.checkSchema(absolutePath, doc, theme);
|
|
92
116
|
configs = merge(configs, doc);
|
|
93
117
|
}
|
|
94
118
|
});
|
|
119
|
+
|
|
95
120
|
return configs;
|
|
96
121
|
}
|
|
97
122
|
}
|
package/oro-webpack-config.js
CHANGED
|
@@ -3,6 +3,7 @@ const printf = require('printf');
|
|
|
3
3
|
const AppConfigLoader = require('./app-config-loader');
|
|
4
4
|
const AppModulesFileWriter = require('./writer/app-modules-file-writer');
|
|
5
5
|
const CleanupStatsPlugin = require('./plugin/stats/cleanup-stats-plugin');
|
|
6
|
+
const AfterWebpackLogsPlugin = require('./plugin/logs/after-webpack-logs-plugin');
|
|
6
7
|
const ConfigsFileWriter = require('./writer/configs-file-writer');
|
|
7
8
|
const EntryPointFileWriter = require('./writer/scss-entry-point-file-writer');
|
|
8
9
|
const LayoutModulesConfigLoader = require('./modules-config/layout-modules-config-loader');
|
|
@@ -23,33 +24,45 @@ const resolve = require('enhanced-resolve');
|
|
|
23
24
|
const {merge: webpackMerge} = require('webpack-merge');
|
|
24
25
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
25
26
|
const RtlCssWebpackPlugin = require('rtlcss-webpack-plugin');
|
|
26
|
-
const
|
|
27
|
+
const validation = require('./validation');
|
|
28
|
+
const EventEmitter = require('events');
|
|
29
|
+
const ErrorHandler = require('./error-handler');
|
|
30
|
+
|
|
27
31
|
require('resolve-url-loader');
|
|
28
32
|
|
|
29
33
|
class ConfigBuilder {
|
|
30
34
|
constructor() {
|
|
31
|
-
this.
|
|
32
|
-
this._adminTheme = 'admin.oro';
|
|
35
|
+
this._projectPath = '';
|
|
33
36
|
this._enableLayoutThemes = false;
|
|
34
37
|
this._defaultLayoutThemes = null;
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
38
|
+
this.emitter = new EventEmitter();
|
|
39
|
+
this.errorHandler = new ErrorHandler();
|
|
40
|
+
this.addListeners();
|
|
41
|
+
this.setPublicPath('public/');
|
|
42
|
+
this.setAdminTheme('admin.oro');
|
|
43
|
+
this.setVersionFormat('%s?v=%s');
|
|
44
|
+
this.setBabelConfig({
|
|
37
45
|
sourceType: 'unambiguous',
|
|
38
46
|
presets: [
|
|
39
47
|
[
|
|
40
48
|
'@babel/preset-env', {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
useBuiltIns: 'usage',
|
|
50
|
+
corejs: {
|
|
51
|
+
version: 3,
|
|
52
|
+
proposals: true
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
|
-
}
|
|
47
55
|
]
|
|
48
56
|
],
|
|
49
57
|
plugins: [
|
|
50
58
|
'@babel/plugin-transform-runtime'
|
|
51
59
|
]
|
|
52
|
-
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
addListeners() {
|
|
64
|
+
this.emitter.on('publicPath:updated', path => validation.setPublicPath(path));
|
|
65
|
+
this.emitter.on('build:complete', stats => this.errorHandler.onBuildComplete(stats));
|
|
53
66
|
}
|
|
54
67
|
|
|
55
68
|
/**
|
|
@@ -59,6 +72,7 @@ class ConfigBuilder {
|
|
|
59
72
|
*/
|
|
60
73
|
setPublicPath(publicPath) {
|
|
61
74
|
this._publicPath = publicPath;
|
|
75
|
+
this.emitter.emit('publicPath:updated', publicPath);
|
|
62
76
|
return this;
|
|
63
77
|
}
|
|
64
78
|
|
|
@@ -80,6 +94,7 @@ class ConfigBuilder {
|
|
|
80
94
|
*/
|
|
81
95
|
setVersionFormat(versionFormat) {
|
|
82
96
|
this._versionFormat = versionFormat;
|
|
97
|
+
this.emitter.emit('versionFormat:updated', versionFormat);
|
|
83
98
|
return this;
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -96,6 +111,7 @@ class ConfigBuilder {
|
|
|
96
111
|
}
|
|
97
112
|
|
|
98
113
|
this._adminTheme = adminTheme;
|
|
114
|
+
this.emitter.emit('adminTheme:updated', adminTheme);
|
|
99
115
|
return this;
|
|
100
116
|
}
|
|
101
117
|
|
|
@@ -105,8 +121,10 @@ class ConfigBuilder {
|
|
|
105
121
|
enableLayoutThemes(themes) {
|
|
106
122
|
if (themes) {
|
|
107
123
|
this._defaultLayoutThemes = themes;
|
|
124
|
+
this.emitter.emit('defaultLayoutThemes:updated', themes);
|
|
108
125
|
}
|
|
109
126
|
this._enableLayoutThemes = true;
|
|
127
|
+
this.emitter.emit('enableLayoutThemes:updated', true);
|
|
110
128
|
return this;
|
|
111
129
|
}
|
|
112
130
|
|
|
@@ -117,6 +135,7 @@ class ConfigBuilder {
|
|
|
117
135
|
*/
|
|
118
136
|
setBabelConfig(babelConfig) {
|
|
119
137
|
this._babelConfig = babelConfig;
|
|
138
|
+
this.emitter.emit('babelConfig:updated', babelConfig);
|
|
120
139
|
return this;
|
|
121
140
|
}
|
|
122
141
|
|
|
@@ -132,19 +151,30 @@ class ConfigBuilder {
|
|
|
132
151
|
try {
|
|
133
152
|
commonConfig = this._getCommonWebpackConfig(args, env);
|
|
134
153
|
} catch (e) {
|
|
135
|
-
|
|
154
|
+
this.errorHandler.displayError(e);
|
|
136
155
|
process.exit(1);
|
|
137
156
|
}
|
|
138
157
|
|
|
139
158
|
const webpackConfigs = [];
|
|
140
159
|
const requestedBuildNames = env.theme ? env.theme.split(',') : [];
|
|
141
160
|
const buildNames = this._getBuildNames(requestedBuildNames);
|
|
161
|
+
|
|
162
|
+
const buildErrors = [];
|
|
163
|
+
validation.jsmodulesValidator.emitter.on('error', error => buildErrors.push(error));
|
|
164
|
+
validation.assetsValidation.emitter.on('error', error => buildErrors.push(error));
|
|
142
165
|
buildNames.forEach(buildName => {
|
|
143
166
|
let buildConfig;
|
|
167
|
+
// flush all collected errors from previews builds
|
|
168
|
+
buildErrors.splice(0, buildErrors.length);
|
|
169
|
+
|
|
144
170
|
try {
|
|
145
171
|
buildConfig = this._getThemeWebpackConfig(buildName, args, env);
|
|
146
|
-
} catch (
|
|
147
|
-
|
|
172
|
+
} catch (error) {
|
|
173
|
+
buildErrors.push(error);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (buildErrors.length) {
|
|
177
|
+
this.errorHandler.displayError(buildErrors, buildName);
|
|
148
178
|
return;
|
|
149
179
|
}
|
|
150
180
|
|
|
@@ -157,6 +187,13 @@ class ConfigBuilder {
|
|
|
157
187
|
};
|
|
158
188
|
}
|
|
159
189
|
|
|
190
|
+
get resolvedProjectPath() {
|
|
191
|
+
if (this._resolvedProjectPath == undefined) {
|
|
192
|
+
this._resolvedProjectPath = path.resolve(this._projectPath);
|
|
193
|
+
}
|
|
194
|
+
return this._resolvedProjectPath;
|
|
195
|
+
}
|
|
196
|
+
|
|
160
197
|
get resolvedPublicPath() {
|
|
161
198
|
if (this._resolvedPublicPath === undefined) {
|
|
162
199
|
this._resolvedPublicPath = path.resolve(this._publicPath);
|
|
@@ -331,7 +368,10 @@ class ConfigBuilder {
|
|
|
331
368
|
}),
|
|
332
369
|
new webpack.optimize.MinChunkSizePlugin({
|
|
333
370
|
minChunkSize: 30000 // Minimum number of characters
|
|
334
|
-
})
|
|
371
|
+
}),
|
|
372
|
+
new AfterWebpackLogsPlugin(
|
|
373
|
+
stats => this.emitter.emit('build:complete', stats)
|
|
374
|
+
)
|
|
335
375
|
]
|
|
336
376
|
};
|
|
337
377
|
|
|
@@ -401,8 +441,18 @@ class ConfigBuilder {
|
|
|
401
441
|
if (this._isAdminTheme(buildName)) {
|
|
402
442
|
themeDefinition = this._modulesConfigLoader.themes[buildName.split('.')[1]];
|
|
403
443
|
buildPublicPath = '/build/admin/';
|
|
404
|
-
const jsModulesConfig = this._themeConfigFactory.loadConfig(
|
|
405
|
-
|
|
444
|
+
const jsModulesConfig = this._themeConfigFactory.loadConfig(
|
|
445
|
+
buildName,
|
|
446
|
+
[
|
|
447
|
+
'Resources/config/oro/jsmodules.yml',
|
|
448
|
+
'Resources/config/jsmodules.yml',
|
|
449
|
+
'config/oro/jsmodules.yml'
|
|
450
|
+
]
|
|
451
|
+
); validation.jsmodulesValidator.checkFullSchema(
|
|
452
|
+
jsModulesConfig,
|
|
453
|
+
this._themeConfigFactory?._configLoader.processedFiles,
|
|
454
|
+
buildName
|
|
455
|
+
);
|
|
406
456
|
jsBuildConfig = this._themeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
407
457
|
} else if (this._layoutModulesConfigLoader.isExtraJSBuild(buildName)) {
|
|
408
458
|
const [theme, suffix] = this._layoutModulesConfigLoader.splitBuildName(buildName);
|
|
@@ -412,11 +462,21 @@ class ConfigBuilder {
|
|
|
412
462
|
const baseConfig = this._layoutThemeConfigFactory.loadConfig(theme, 'config/jsmodules.yml');
|
|
413
463
|
const extraConfig = this._layoutThemeConfigFactory.loadConfig(theme, `config/jsmodules-${suffix}.yml`);
|
|
414
464
|
const jsModulesConfig = this._layoutThemeConfigFactory.extendConfig(baseConfig, extraConfig);
|
|
465
|
+
validation.jsmodulesValidator.checkFullSchema(
|
|
466
|
+
jsModulesConfig,
|
|
467
|
+
this._layoutThemeConfigFactory?._configLoader.processedFiles,
|
|
468
|
+
buildName
|
|
469
|
+
);
|
|
415
470
|
jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
416
471
|
} else {
|
|
417
472
|
themeDefinition = this._layoutModulesConfigLoader.themes[buildName];
|
|
418
473
|
buildPublicPath = `/build/${buildName}/`;
|
|
419
474
|
const jsModulesConfig = this._layoutThemeConfigFactory.loadConfig(buildName, 'config/jsmodules.yml');
|
|
475
|
+
validation.jsmodulesValidator.checkFullSchema(
|
|
476
|
+
jsModulesConfig,
|
|
477
|
+
this._layoutThemeConfigFactory?._configLoader.processedFiles,
|
|
478
|
+
buildName
|
|
479
|
+
);
|
|
420
480
|
jsBuildConfig = this._layoutThemeConfigFactory.create(buildPublicPath, jsModulesConfig);
|
|
421
481
|
}
|
|
422
482
|
const {rtl_support: rtlSupport = false} = themeDefinition;
|
|
@@ -426,6 +486,7 @@ class ConfigBuilder {
|
|
|
426
486
|
modules: [
|
|
427
487
|
resolvedBuildPath,
|
|
428
488
|
this.resolvedPublicPath,
|
|
489
|
+
path.join(this.resolvedProjectPath, '/assets'),
|
|
429
490
|
path.join(this.resolvedPublicPath, '/bundles'),
|
|
430
491
|
path.join(this.resolvedPublicPath, '/js'),
|
|
431
492
|
this.resolvedNodeModulesPath
|
|
@@ -481,7 +542,7 @@ class ConfigBuilder {
|
|
|
481
542
|
...prepareModulesShim(resolver, jsBuildConfig.shim)
|
|
482
543
|
]
|
|
483
544
|
}
|
|
484
|
-
}
|
|
545
|
+
};
|
|
485
546
|
}
|
|
486
547
|
|
|
487
548
|
_initialize(args, env) {
|
|
@@ -490,10 +551,11 @@ class ConfigBuilder {
|
|
|
490
551
|
this._isProduction = args.mode === 'production';
|
|
491
552
|
this._symfonyEnv = env.symfony;
|
|
492
553
|
this._appConfig = AppConfigLoader.getConfig(this._cachePath, this._symfonyEnv);
|
|
554
|
+
this._appConfig.paths.push(this.resolvedProjectPath);
|
|
493
555
|
|
|
494
556
|
this._modulesConfigLoader = new ModulesConfigLoader(
|
|
495
557
|
this._appConfig.paths,
|
|
496
|
-
'/Resources/public/themes/',
|
|
558
|
+
['/Resources/public/themes/', '/public/themes/admin/'],
|
|
497
559
|
'settings.yml'
|
|
498
560
|
);
|
|
499
561
|
this._adminThemes = this._modulesConfigLoader.themeNames.map(themeName => 'admin.' + themeName);
|
|
@@ -507,7 +569,7 @@ class ConfigBuilder {
|
|
|
507
569
|
|
|
508
570
|
this._layoutModulesConfigLoader = new LayoutModulesConfigLoader(
|
|
509
571
|
this._appConfig.paths,
|
|
510
|
-
'/Resources/views/layouts/',
|
|
572
|
+
['/Resources/views/layouts/', '/templates/layouts/'],
|
|
511
573
|
'theme.yml'
|
|
512
574
|
);
|
|
513
575
|
this._layoutStyleLoader = new LayoutStyleLoader(this._layoutModulesConfigLoader, entryPointFileWriter);
|
|
@@ -520,7 +582,7 @@ class ConfigBuilder {
|
|
|
520
582
|
}
|
|
521
583
|
|
|
522
584
|
_getVersionedPath(name, assetVersion) {
|
|
523
|
-
if(!assetVersion) {
|
|
585
|
+
if (!assetVersion) {
|
|
524
586
|
return name;
|
|
525
587
|
}
|
|
526
588
|
return printf(this._versionFormat, name, assetVersion);
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oroinc/oro-webpack-config-builder",
|
|
3
|
-
"version": "5.1.0-
|
|
3
|
+
"version": "5.1.0-alpha35",
|
|
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.
|
|
9
|
+
"@babel/core": "~7.17.9",
|
|
10
|
+
"@babel/plugin-transform-runtime": "~7.17.0",
|
|
11
11
|
"@babel/preset-env": "~7.16.11",
|
|
12
12
|
"autoprefixer": "~10.4.0",
|
|
13
13
|
"babel-loader": "~8.2.3",
|
|
14
14
|
"bindings": "~1.5.0",
|
|
15
|
-
"css-loader": "~6.
|
|
15
|
+
"css-loader": "~6.7.1",
|
|
16
16
|
"css-minimizer-webpack-plugin": "~3.4.1",
|
|
17
17
|
"deepmerge": "~4.2.2",
|
|
18
18
|
"exports-loader": "~3.1.0",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"html-webpack-plugin": "~5.5.0",
|
|
24
24
|
"imports-loader": "~3.1.1",
|
|
25
25
|
"js-yaml": "~4.1.0",
|
|
26
|
-
"mini-css-extract-plugin": "~2.
|
|
26
|
+
"mini-css-extract-plugin": "~2.6.0",
|
|
27
27
|
"minimist": "~1.2.3",
|
|
28
28
|
"nan": "~2.15.0",
|
|
29
29
|
"path": "0.12.7",
|
|
@@ -32,14 +32,15 @@
|
|
|
32
32
|
"printf": "~0.6.0",
|
|
33
33
|
"resolve-url-loader": "^5.0.0",
|
|
34
34
|
"rtlcss-webpack-plugin": "~4.0.6",
|
|
35
|
-
"sass": "~1.
|
|
36
|
-
"sass-loader": "~12.
|
|
35
|
+
"sass": "~1.50.0",
|
|
36
|
+
"sass-loader": "~12.6.0",
|
|
37
|
+
"schema-utils": "^4.0.0",
|
|
37
38
|
"style-loader": "~3.3.1",
|
|
38
|
-
"terser": "~5.
|
|
39
|
+
"terser": "~5.12.1",
|
|
39
40
|
"text-loader": "0.0.1",
|
|
40
41
|
"underscore": "~1.13.1",
|
|
41
42
|
"url-loader": "~4.1.1",
|
|
42
|
-
"webpack": "~5.
|
|
43
|
+
"webpack": "~5.72.0",
|
|
43
44
|
"webpack-bundle-analyzer": "~4.5.0",
|
|
44
45
|
"webpack-cli": "~4.9.1",
|
|
45
46
|
"webpack-dev-server": "^4.7.3",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const {once} = require('underscore');
|
|
2
|
+
|
|
3
|
+
class AfterWebpackLogsPlugin {
|
|
4
|
+
/**
|
|
5
|
+
* @param {function} afterLogsCb
|
|
6
|
+
*/
|
|
7
|
+
constructor(afterLogsCb) {
|
|
8
|
+
if (typeof afterLogsCb !== 'function') {
|
|
9
|
+
throw new Error('The "afterLogsCb" arg should be a function');
|
|
10
|
+
}
|
|
11
|
+
this._afterLogsCb = once(afterLogsCb);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
apply(compiler) {
|
|
15
|
+
compiler.hooks.done.tap('AfterWebpackLogsPlugin', stats => {
|
|
16
|
+
const compilerStats = stats;
|
|
17
|
+
stats.compilation.hooks.statsPrinter.tap('AfterWebpackLogsPlugin', stats => {
|
|
18
|
+
// Making logs to be after all webpack logs in the console
|
|
19
|
+
setImmediate(() => this._afterLogsCb(compilerStats));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = AfterWebpackLogsPlugin;
|
|
@@ -9,8 +9,9 @@ class AdminStyleLoader extends StyleLoader {
|
|
|
9
9
|
const {rtl_support: rtlSupport = false, styles: extraThemeConfig} =
|
|
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
|
+
const appRootExtraConfig = this._configLoader.loadConfig(themeName, 'config/oro/assets.yml');
|
|
12
13
|
/** @type {Object.<string, ThemeGroupConfig>} */
|
|
13
|
-
const themeConfig = merge(baseThemeConfig, extraThemeConfig);
|
|
14
|
+
const themeConfig = merge(baseThemeConfig, appRootExtraConfig, extraThemeConfig);
|
|
14
15
|
|
|
15
16
|
return {
|
|
16
17
|
themeConfig,
|