@oroinc/oro-webpack-config-builder 5.1.0-alpha5 → 5.1.0-alpha50

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/error-handler.js +95 -0
  3. package/loader/config-loader.js +1 -2
  4. package/loader/inject-loader/LICENSE.md +21 -0
  5. package/loader/inject-loader/README.md +54 -0
  6. package/loader/inject-loader/index.js +10 -0
  7. package/loader/inject-loader/injectify.js +66 -0
  8. package/loader/inject-loader/package.json +55 -0
  9. package/loader/inject-loader/wrapper_template.js +32 -0
  10. package/modules-config/layout-modules-config-loader.js +67 -3
  11. package/modules-config/modules-config-loader.js +49 -14
  12. package/oro-webpack-config.js +406 -296
  13. package/package.json +37 -36
  14. package/plugin/logs/after-webpack-logs-plugin.js +25 -0
  15. package/prepare-modules-shim.js +13 -1
  16. package/style/admin-style-loader.js +22 -0
  17. package/style/layout-style-loader.js +12 -109
  18. package/style/style-loader.js +134 -46
  19. package/theme-config-factory.js +45 -6
  20. package/utils.js +30 -0
  21. package/validation/assets-validator.js +103 -0
  22. package/validation/errors/assets-input-file-error.js +24 -0
  23. package/validation/errors/assets-schema-error.js +40 -0
  24. package/validation/errors/base-error.js +37 -0
  25. package/validation/errors/jsmodules-extra-modules-error.js +22 -0
  26. package/validation/errors/jsmodules-schema-error.js +40 -0
  27. package/validation/errors/styles-error.js +24 -0
  28. package/validation/index.js +36 -0
  29. package/validation/jsmodules-validator.js +53 -0
  30. package/validation/schema-validator.js +62 -0
  31. package/validation/schemas/assets-schema-full.js +22 -0
  32. package/validation/schemas/assets-schema.js +32 -0
  33. package/validation/schemas/jsmodules-schema-full.js +11 -0
  34. package/validation/schemas/jsmodules-schema.js +76 -0
  35. package/writer/configs-file-writer.js +1 -1
  36. package/writer/dynamic-imports-file-writer.js +3 -3
  37. package/writer/scss-entry-point-file-writer.js +1 -1
package/package.json CHANGED
@@ -1,48 +1,49 @@
1
1
  {
2
2
  "name": "@oroinc/oro-webpack-config-builder",
3
- "version": "5.1.0-alpha5",
3
+ "version": "5.1.0-alpha50",
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.4",
10
- "@babel/plugin-transform-runtime": "^7.10.4",
11
- "@babel/preset-env": "^7.10.4",
12
- "autoprefixer": "^9.8.6",
13
- "babel-loader": "^8.1.0",
14
- "bindings": "^1.5.0",
15
- "css-loader": "^5.0.2",
16
- "css-minimizer-webpack-plugin": "^1.2.0",
17
- "deepmerge": "^4.2.2",
18
- "exports-loader": "^2.0.0",
19
- "expose-loader": "^2.0.0",
20
- "extract-loader": "^5.1.0",
21
- "file-loader": "^6.2.0",
22
- "happypack": "^5.0.1",
23
- "html-webpack-plugin": "^5.2.0",
24
- "imports-loader": "^2.0.0",
25
- "js-yaml": "^4.0.0",
26
- "mini-css-extract-plugin": "^1.3.8",
27
- "minimist": "^1.2.3",
28
- "nan": "^2.14.2",
9
+ "@babel/core": "^7.20.12",
10
+ "@babel/plugin-transform-runtime": "^7.19.6",
11
+ "@babel/preset-env": "~7.20.2",
12
+ "autoprefixer": "^10.4.13",
13
+ "babel-loader": "~8.2.3",
14
+ "bindings": "~1.5.0",
15
+ "css-loader": "^6.7.3",
16
+ "css-minimizer-webpack-plugin": "~4.2.2",
17
+ "deepmerge": "~4.2.2",
18
+ "exports-loader": "~4.0.0",
19
+ "expose-loader": "~4.0.0",
20
+ "file-loader": "~6.2.0",
21
+ "happypack": "~5.0.1",
22
+ "html-webpack-plugin": "~5.5.0",
23
+ "imports-loader": "~4.0.0",
24
+ "js-yaml": "~4.1.0",
25
+ "mini-css-extract-plugin": "^2.7.1",
26
+ "minimist": "^1.2.7",
27
+ "nan": "^2.17.0",
29
28
  "path": "0.12.7",
30
- "postcss": "^8.2.9",
31
- "postcss-loader": "^5.0.0",
32
- "printf": "^0.6.0",
33
- "rtlcss-webpack-plugin": "^4.0.6",
34
- "sass": "^1.32.8",
35
- "sass-loader": "^11.0.1",
36
- "style-loader": "^2.0.0",
37
- "terser": "^5.6.0",
29
+ "postcss": "~8.4.19",
30
+ "postcss-loader": "^7.0.2",
31
+ "printf": "~0.6.0",
32
+ "resolve-url-loader": "^5.0.0",
33
+ "rtlcss-webpack-plugin": "~4.0.6",
34
+ "sass": "^1.57.1",
35
+ "sass-loader": "~13.2.0",
36
+ "schema-utils": "^4.0.0",
37
+ "style-loader": "~3.3.1",
38
+ "terser": "^5.16.1",
38
39
  "text-loader": "0.0.1",
39
- "underscore": "^1.10.2",
40
+ "underscore": "^1.13.6",
40
41
  "url-loader": "^4.1.1",
41
- "webpack": "^5.23.0",
42
- "webpack-bundle-analyzer": "^4.4.0",
43
- "webpack-cli": "^4.5.0",
44
- "webpack-dev-server": "^3.11.0",
45
- "webpack-merge": "^5.7.3",
46
- "wildcard": "^2.0.0"
42
+ "webpack": "^5.76.0",
43
+ "webpack-bundle-analyzer": "^4.7.0",
44
+ "webpack-cli": "~4.9.1",
45
+ "webpack-dev-server": "^4.11.1",
46
+ "webpack-merge": "~5.8.0",
47
+ "wildcard": "~2.0.0"
47
48
  }
48
49
  }
@@ -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;
@@ -12,7 +12,19 @@ module.exports = (resolver, config) => {
12
12
 
13
13
  // convert to imports-loader? syntax
14
14
  if (imports && imports.length) {
15
- uses.push(`imports-loader?type=commonjs&imports=${imports.join(',')}`);
15
+ let importParams = Object.assign(
16
+ {
17
+ type: 'commonjs',
18
+ imports: imports.filter(item => typeof item === 'string').join(',')
19
+ },
20
+ ...imports.filter(item => typeof item === 'object')
21
+ );
22
+
23
+ importParams = Object.entries(importParams)
24
+ .filter(([, value]) => Boolean(value))
25
+ .map(([key, value]) => `${key}=${value.replace(/ /g, '%20')}`);
26
+
27
+ uses.push(`imports-loader?${importParams.join('&')}`);
16
28
  }
17
29
 
18
30
  // convert to exports-loader? syntax
@@ -0,0 +1,22 @@
1
+ const merge = require('deepmerge');
2
+ const StyleLoader = require('./style-loader');
3
+
4
+ class AdminStyleLoader extends StyleLoader {
5
+ /**
6
+ * @inheritdoc
7
+ */
8
+ _fetchThemeConfig(themeName) {
9
+ const {rtl_support: rtlSupport = false, styles: extraThemeConfig} =
10
+ this._configLoader.loadConfig(themeName, 'Resources/public/themes/' + themeName + '/settings.yml');
11
+ const baseThemeConfig = this._configLoader.loadConfig(themeName, 'Resources/config/oro/assets.yml');
12
+ /** @type {Object.<string, ThemeGroupConfig>} */
13
+ const themeConfig = merge(baseThemeConfig, extraThemeConfig);
14
+
15
+ return {
16
+ themeConfig,
17
+ settings: {rtlSupport}
18
+ };
19
+ }
20
+ }
21
+
22
+ module.exports = AdminStyleLoader;
@@ -1,115 +1,18 @@
1
- const path = require('path');
2
- const wildcard = require('wildcard');
3
- const _ = require('underscore')
1
+ const StyleLoader = require('./style-loader');
4
2
 
5
- class LayoutStyleLoader {
3
+ class LayoutStyleLoader extends StyleLoader {
6
4
  /**
7
- * @param {YamlConfigLoader} configLoader
8
- * @param {SCSSEntryPointFileWriter} entryPointFileWriter
5
+ * @inheritdoc
9
6
  */
10
- constructor(configLoader, entryPointFileWriter) {
11
- this._configLoader = configLoader;
12
- this._entryPointFileWriter = entryPointFileWriter;
13
- }
14
-
15
- /**
16
- * @param {string} theme Theme name
17
- * @param {string} buildPath Build path
18
- * @return {Object} List of Webpack entry-points
19
- */
20
- getThemeEntryPoints(theme, buildPath) {
21
- const entryPoints = {};
22
- const {rtl_support: rtlSupport = false} = this._configLoader.themes[theme];
23
- const themeConfig = this._configLoader.loadConfig(theme, '/config/assets.yml');
24
- const writingOptions = {};
25
-
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));
35
- }
36
-
37
- const entryPointName = output.replace(/\.[^/.]+$/, '');
38
- const filePath = path.join(buildPath, output);
39
- entryPoints[entryPointName] =
40
- this._entryPointFileWriter.write('./../../../', inputs, filePath, writingOptions);
41
- }
42
- return entryPoints;
43
- }
44
-
45
- /**
46
- * @param {Object} inputs
47
- * @returns {string[]} List of inputs
48
- * @private
49
- */
50
- _overrideInputs(inputs) {
51
- const newInputs = [];
52
-
53
- inputs.forEach((input, index) => {
54
- if (typeof input !== 'string') {
55
- const oldInput = Object.keys(input)[0];
56
- const newInput = input[oldInput];
57
- const oldInputIndex = newInputs.findIndex(element => element === oldInput);
58
-
59
- if (newInput) { // replace input
60
- newInputs[oldInputIndex] = newInput;
61
- } else { // delete input
62
- newInputs.splice(oldInputIndex, 1);
63
- }
64
- newInputs.splice(index);
65
- } else {
66
- newInputs[index] = input;
67
- }
68
- });
69
-
70
- return newInputs;
71
- }
72
-
73
- /**
74
- * Sort inputs, so first will be settings, then variables, then other files
75
- * @param {Object} inputs
76
- * @returns {string[]} List of ordered inputs
77
- * @private
78
- */
79
- _sortInputs(inputs) {
80
- const settingsInputs = [];
81
- const variablesInputs = [];
82
- const restInputs = [];
83
-
84
- inputs.forEach(input => {
85
- if (input.indexOf('/settings/') > 0) {
86
- settingsInputs.push(input);
87
- } else if (input.indexOf('/variables/') > 0) {
88
- variablesInputs.push(input);
89
- } else {
90
- restInputs.push(input);
91
- }
92
- });
93
- return [...settingsInputs, ...variablesInputs, ...restInputs];
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);
7
+ _fetchThemeConfig(themeName) {
8
+ const {rtl_support: rtlSupport = false} = this._configLoader.themes[themeName];
9
+ /** @type {Object.<string, ThemeGroupConfig>} */
10
+ const themeConfig = this._configLoader.loadConfig(themeName, 'config/assets.yml');
11
+
12
+ return {
13
+ themeConfig,
14
+ settings: {rtlSupport}
15
+ };
113
16
  }
114
17
  }
115
18
 
@@ -1,78 +1,166 @@
1
- const merge = require('deepmerge');
1
+ const path = require('path');
2
+ const wildcard = require('wildcard');
3
+ const _ = require('underscore');
4
+ const {isProdMode} = require('../utils');
5
+ const {assetsValidation} = require('../validation');
6
+ const StylesError = require('../validation/errors/styles-error');
7
+
8
+ /**
9
+ * @typedef ThemeGroupConfig
10
+ * @type {Object}
11
+ * @property {Array.<string|Object>} inputs - list of input resources for import into root SCSS file
12
+ * @property {Array.<string>} entries - list of direct entry resources
13
+ * @property {string} output - name or out put resource
14
+ * @property {[boolean]} auto_rtl_inputs - whether theme support RTL
15
+ */
2
16
 
3
17
  class StyleLoader {
4
18
  /**
5
19
  * @param {YamlConfigLoader} configLoader
20
+ * @param {SCSSEntryPointFileWriter} entryPointFileWriter
6
21
  */
7
- constructor(configLoader) {
22
+ constructor(configLoader, entryPointFileWriter) {
8
23
  this._configLoader = configLoader;
24
+ this._entryPointFileWriter = entryPointFileWriter;
9
25
  }
10
26
 
11
27
  /**
12
28
  * @param {string} theme Theme name
29
+ * @param {string} buildPath Build path
13
30
  * @return {Object} List of Webpack entry-points
14
31
  */
15
- getThemeEntryPoints(theme) {
32
+ getThemeEntryPoints(theme, buildPath) {
33
+ const {themeConfig, settings = {}} = this._fetchThemeConfig(theme);
34
+
35
+ assetsValidation.checkFullSchema(themeConfig, this._configLoader.processedFiles, theme);
36
+
16
37
  const entryPoints = {};
17
- const commonConfig = this._configLoader.loadConfig(theme, '/Resources/config/oro/assets.yml');
18
- let themeConfig = this._configLoader.loadConfig(theme, '/Resources/public/themes/' + theme + '/settings.yml');
19
-
20
- themeConfig = themeConfig.styles;
21
- for (const key in themeConfig) {
22
- if (themeConfig.hasOwnProperty(key)) {
23
- const config = themeConfig[key];
24
- if (commonConfig[key]) {
25
- commonConfig[key] = merge(commonConfig[key], config);
26
- }
38
+ const writingOptions = {};
39
+ for (const [group, config] of Object.entries(themeConfig)) {
40
+ let {inputs, entries = [], output, auto_rtl_inputs: rtlMasks = []} = config;
41
+
42
+ if (isProdMode() && output === void 0) {
43
+ throw new StylesError('output', group, theme);
27
44
  }
28
- }
29
45
 
30
- for (const key in commonConfig) {
31
- if (commonConfig.hasOwnProperty(key)) {
32
- const config = commonConfig[key];
33
- const inputs = this._overrideInputs(config.inputs);
34
- if (config.output === undefined) {
35
- throw new Error('"output" for "' + key + '" group in theme "' + theme + '" is not defined');
36
- }
37
- entryPoints[config.output.replace(/\.[^/.]+$/, '')] = inputs;
46
+ if (isProdMode() && inputs === void 0) {
47
+ throw new StylesError('inputs', group, theme);
48
+ }
49
+
50
+ inputs = this._overrideInputs(inputs);
51
+ inputs = this._sortInputs(inputs);
52
+
53
+ if (settings.rtlSupport) {
54
+ writingOptions.ignoreRTLInputs = _.difference(inputs, this._matchInputs(rtlMasks, inputs));
38
55
  }
56
+
57
+ const entryPointName = output.replace(/\.[^/.]+$/, '');
58
+ const filePath = path.join(buildPath, output);
59
+ entryPoints[entryPointName] = [
60
+ ...entries,
61
+ this._entryPointFileWriter.write('./../../../', inputs, filePath, writingOptions)
62
+ ];
39
63
  }
40
64
  return entryPoints;
41
65
  }
42
66
 
43
67
  /**
44
- * @param {Object} inputs
68
+ * Extracts theme configuration with its settings
69
+ *
70
+ * @param {string} themeName
71
+ * @return {{themeConfig: Object.<string, ThemeGroupConfig>, settings: {rtlSupport: boolean}}}
72
+ * @abstract
73
+ * @protected
74
+ */
75
+ _fetchThemeConfig(themeName) {
76
+ throw new Error('Method `_fetchThemeConfig` has to be implemented in extends');
77
+ }
78
+
79
+ /**
80
+ * Override inputs
81
+ *
82
+ * @param {(string|Object)[]} inputs
45
83
  * @returns {string[]} List of inputs
46
- * @private
84
+ * @protected
47
85
  */
48
86
  _overrideInputs(inputs) {
49
- const newInputs = [];
50
-
51
- inputs.forEach((input, index) => {
52
- if (typeof input !== 'string') {
53
- const oldInput = Object.keys(input)[0];
54
- const newInput = input[oldInput];
55
- const oldInputIndex = newInputs.findIndex(element => element === oldInput);
56
-
57
- if (newInput) { // replace input
58
- newInputs[oldInputIndex] = newInput;
59
- } else { // delete input
60
- newInputs.splice(oldInputIndex, 1);
61
- }
62
- newInputs.splice(index);
87
+ const mappedInputs = [];
88
+ inputs.forEach(input => {
89
+ if (typeof input === 'string') {
90
+ mappedInputs.push(input);
63
91
  } else {
64
- // cut off ~ prefix from the path,
65
- // if someone acidentaly used it for the admin theme assets.yml or settings.yml file,
66
- // because the syntax is valid only in the @import statement, that is
67
- // not used for the admin theme yaml files configuration
68
- if (input.startsWith('~')) {
69
- input = input.substr(1);
92
+ const [oldInput, newInput] = Object.entries(input)[0];
93
+ const oldInputIndex = mappedInputs.findIndex(item => item === oldInput);
94
+
95
+ if (oldInputIndex === -1) {
96
+ // old input does not exist anymore
97
+ mappedInputs.push(newInput);
98
+ } else if (newInput) {
99
+ // replace input
100
+ mappedInputs[oldInputIndex] = newInput;
101
+ } else {
102
+ // delete input
103
+ mappedInputs.splice(oldInputIndex, 1);
70
104
  }
71
- newInputs.push(input);
72
105
  }
73
106
  });
107
+ return mappedInputs;
108
+ }
109
+
110
+ /**
111
+ * Sort inputs, so first will be settings, then variables, then other files
112
+ *
113
+ * @param {string[]} inputs
114
+ * @returns {string[]} List of ordered inputs
115
+ * @protected
116
+ */
117
+ _sortInputs(inputs) {
118
+ const primarySettingsInputs = [];
119
+ const settingsInputs = [];
120
+ const primaryVariablesInputs = [];
121
+ const variablesInputs = [];
122
+ const restInputs = [];
123
+
124
+ inputs.forEach(input => {
125
+ if (input.indexOf('/settings/primary-settings') > 0) {
126
+ primarySettingsInputs.push(input);
127
+ } else if (input.indexOf('/settings/') > 0) {
128
+ settingsInputs.push(input);
129
+ } else if (input.indexOf('/variables/primary-variables') > 0) {
130
+ primaryVariablesInputs.push(input);
131
+ } else if (input.indexOf('/variables/') > 0) {
132
+ variablesInputs.push(input);
133
+ } else {
134
+ restInputs.push(input);
135
+ }
136
+ });
137
+
138
+ return [
139
+ ...primarySettingsInputs,
140
+ ...settingsInputs,
141
+ ...primaryVariablesInputs,
142
+ ...variablesInputs,
143
+ ...restInputs
144
+ ];
145
+ }
146
+
147
+ /**
148
+ * Filter inputs that matches any mask from the list
149
+ *
150
+ * @param {string[]} masks list of wildcard masks
151
+ * @param {string[]} inputs
152
+ * @return {string[]} matched inputs
153
+ * @protected
154
+ */
155
+ _matchInputs(masks, inputs) {
156
+ masks = masks.map(mask => wildcard(mask));
157
+
158
+ const whiteListedInputs = masks.reduce((include, mask) => {
159
+ include.push(...mask.match(inputs));
160
+ return include;
161
+ }, []);
74
162
 
75
- return newInputs;
163
+ return _.unique(whiteListedInputs);
76
164
  }
77
165
  }
78
166
 
@@ -1,3 +1,5 @@
1
+ const JSModulesExtraModulesError = require('./validation/errors/jsmodules-extra-modules-error');
2
+
1
3
  class ThemeConfigFactory {
2
4
  /**
3
5
  * @param {ModulesConfigLoader} configLoader
@@ -11,22 +13,59 @@ class ThemeConfigFactory {
11
13
  this._appModulesFileWriter = appModulesFileWriter;
12
14
  this._configsFileWriter = configsFileWriter;
13
15
  }
14
-
15
16
  /**
16
17
  * @param {string} theme Theme name
18
+ * @param {string|string[]} configFilepath Path (or paths with fallback) to yaml config file in a bundle
19
+ * @return {Object} Merged Configs loaded from all the bundles Yaml files matched by filePath
20
+ */
21
+ loadConfig(theme, configFilepath) {
22
+ return this._configLoader.loadConfig(theme, configFilepath);
23
+ }
24
+
25
+ extendConfig(baseConfig, extraConfig) {
26
+ const {
27
+ aliases = {},
28
+ configs,
29
+ map = {},
30
+ shim = {}
31
+ } = baseConfig;
32
+
33
+ const {
34
+ ['app-modules']: appModules,
35
+ ['dynamic-imports']: dynamicImports,
36
+ entry,
37
+ ...rest
38
+ } = extraConfig;
39
+
40
+ const beyondKeys = Object.keys(rest);
41
+ if (beyondKeys.length) {
42
+ throw new JSModulesExtraModulesError(beyondKeys);
43
+ }
44
+
45
+ return {
46
+ aliases,
47
+ 'app-modules': appModules,
48
+ configs,
49
+ 'dynamic-imports': dynamicImports,
50
+ entry,
51
+ map,
52
+ shim
53
+ };
54
+ }
55
+
56
+ /**
17
57
  * @param {string} buildPath Path to theme build folder
18
- * @param {string} configFilepath Path to yaml config file in a bundle
19
- * @return {Object} List of Webpack entry-points
58
+ * @param {Object} jsModulesConfig configuration loaded from jsmodules files and merged together
59
+ * @return {Object} webpack configuration fragment
20
60
  */
21
- create(theme, buildPath, configFilepath) {
22
- const jsModulesConfig = this._configLoader.loadConfig(theme, configFilepath);
61
+ create(buildPath, jsModulesConfig) {
23
62
  const {
24
63
  entry,
25
64
  map = {},
26
65
  shim = {},
27
66
  configs,
28
67
  aliases = {},
29
- ['app-modules']: appModules,
68
+ ['app-modules']: appModules = [],
30
69
  ['dynamic-imports']: dynamicImports
31
70
  } = jsModulesConfig;
32
71
 
package/utils.js ADDED
@@ -0,0 +1,30 @@
1
+ let prodMode;
2
+ let verboseMode;
3
+
4
+ module.exports = {
5
+ isVerboseMode() {
6
+ if (verboseMode === void 0) {
7
+ verboseMode = process.argv.filter(arg => {
8
+ // Depending on how the command was run (-v, -vv, -vvv, --verbose) -
9
+ // arguments can be present in different formats: stats=normal, stats=detailed, stats=verbose, verbose
10
+ return arg.search(/^verbose|(^stats=(normal|detailed|verbose))/) !== -1;
11
+ }).length > 0;
12
+ }
13
+
14
+ return verboseMode;
15
+ },
16
+ isProdMode() {
17
+ if (prodMode !== void 0) {
18
+ return prodMode;
19
+ }
20
+
21
+ process.argv.forEach(arg => {
22
+ if (prodMode) {
23
+ return;
24
+ }
25
+ prodMode = ['--mode=production', '--env=prod'].some(item => item === arg);
26
+ });
27
+
28
+ return prodMode;
29
+ }
30
+ };