@nitro/webpack 11.0.0-beta.3 → 11.0.1
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/lib/utils.js +12 -12
- package/lib/webpack-rules.js +124 -124
- package/package.json +2 -2
- package/readme.md +1 -1
- package/webpack-config/webpack.config.prod.js +312 -311
package/lib/utils.js
CHANGED
|
@@ -16,18 +16,18 @@ function getEnrichedConfig(rule, config) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// load optional package
|
|
19
|
-
function getOptionalPackage(x) {
|
|
20
|
-
let mod;
|
|
21
|
-
try {
|
|
22
|
-
mod = require(x);
|
|
23
|
-
} catch (error) {
|
|
24
|
-
mod = null;
|
|
25
|
-
}
|
|
26
|
-
if (!mod) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
return mod.default ? mod.default : mod;
|
|
30
|
-
}
|
|
19
|
+
function getOptionalPackage(x) {
|
|
20
|
+
let mod;
|
|
21
|
+
try {
|
|
22
|
+
mod = require(x);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
mod = null;
|
|
25
|
+
}
|
|
26
|
+
if (!mod) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return mod.default ? mod.default : mod;
|
|
30
|
+
}
|
|
31
31
|
|
|
32
32
|
module.exports = {
|
|
33
33
|
getEnrichedConfig,
|
package/lib/webpack-rules.js
CHANGED
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const typescript = require('typescript');
|
|
6
|
-
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
|
7
|
-
const utils = require('./utils');
|
|
8
|
-
|
|
9
|
-
function resolveBabelConfigFile(context, ruleOptions) {
|
|
10
|
-
if (ruleOptions && ruleOptions.babelConfigFile) {
|
|
11
|
-
return path.resolve(context, ruleOptions.babelConfigFile);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const candidates = ['babel.config.js', '.babelrc', '.babelrc.js', '.babelrc.json'];
|
|
15
|
-
for (const candidate of candidates) {
|
|
16
|
-
const candidatePath = path.resolve(context, candidate);
|
|
17
|
-
if (fs.existsSync(candidatePath)) {
|
|
18
|
-
return candidatePath;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function resolveTsConfigFile(context, ruleOptions) {
|
|
26
|
-
if (ruleOptions && ruleOptions.tsConfigFile) {
|
|
27
|
-
return path.resolve(context, ruleOptions.tsConfigFile);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return typescript.findConfigFile(context, fs.existsSync);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getRuleOptions(ruleOptions) {
|
|
34
|
-
return ruleOptions && typeof ruleOptions === 'object' ? ruleOptions : null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function ensureResolveExtensions(webpackConfig, extensions, { prepend }) {
|
|
38
|
-
if (!webpackConfig.resolve) {
|
|
39
|
-
webpackConfig.resolve = {};
|
|
40
|
-
}
|
|
41
|
-
if (!Array.isArray(webpackConfig.resolve.extensions)) {
|
|
42
|
-
webpackConfig.resolve.extensions = ['.js', '.json'];
|
|
43
|
-
}
|
|
44
|
-
const target = webpackConfig.resolve.extensions;
|
|
45
|
-
const missing = extensions.filter((ext) => !target.includes(ext));
|
|
46
|
-
if (missing.length === 0) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (prepend) {
|
|
50
|
-
target.unshift(...missing);
|
|
51
|
-
} else {
|
|
52
|
-
target.push(...missing);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getBabelLoaderOptions(context, ruleOptions) {
|
|
57
|
-
const babelConfigFile = resolveBabelConfigFile(context, ruleOptions);
|
|
58
|
-
const babelLoaderOptions = {
|
|
59
|
-
cacheDirectory: true,
|
|
60
|
-
compact: true,
|
|
61
|
-
};
|
|
62
|
-
if (babelConfigFile) {
|
|
63
|
-
babelLoaderOptions.configFile = babelConfigFile;
|
|
64
|
-
}
|
|
65
|
-
return babelLoaderOptions;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function addJSConfig(webpackConfig, context, ruleOptions) {
|
|
69
|
-
const babelLoaderOptions = getBabelLoaderOptions(context, ruleOptions);
|
|
70
|
-
const scriptRuleJs = {
|
|
71
|
-
test: /\.[cm]?jsx?$/,
|
|
72
|
-
exclude: [/[/\\\\]node_modules[/\\\\]/],
|
|
73
|
-
use: [
|
|
74
|
-
{
|
|
75
|
-
loader: require.resolve('babel-loader'),
|
|
76
|
-
options: babelLoaderOptions,
|
|
77
|
-
},
|
|
78
|
-
],
|
|
79
|
-
};
|
|
80
|
-
webpackConfig.module.rules.push(utils.getEnrichedConfig(scriptRuleJs, getRuleOptions(ruleOptions)));
|
|
81
|
-
ensureResolveExtensions(webpackConfig, ['.js', '.jsx', '.mjs', '.cjs'], { prepend: true });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function addTsConfig(webpackConfig, context, ruleOptions, { isProduction }) {
|
|
85
|
-
const babelLoaderOptions = getBabelLoaderOptions(context, ruleOptions);
|
|
86
|
-
const scriptRuleTs = {
|
|
87
|
-
test: /\.[cm]?tsx?$/,
|
|
88
|
-
exclude: [/[/\\\\]node_modules[/\\\\]/],
|
|
89
|
-
use: [
|
|
90
|
-
{
|
|
91
|
-
loader: require.resolve('babel-loader'),
|
|
92
|
-
options: babelLoaderOptions,
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
loader: require.resolve('ts-loader'),
|
|
96
|
-
options: {
|
|
97
|
-
transpileOnly: true,
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
],
|
|
101
|
-
};
|
|
102
|
-
webpackConfig.module.rules.push(utils.getEnrichedConfig(scriptRuleTs, getRuleOptions(ruleOptions)));
|
|
103
|
-
ensureResolveExtensions(webpackConfig, ['.ts', '.tsx', '.mts', '.cts'], { prepend: true });
|
|
104
|
-
|
|
105
|
-
const tsConfigFile = resolveTsConfigFile(context, ruleOptions);
|
|
106
|
-
if (tsConfigFile) {
|
|
107
|
-
const forkCheckerOptions = {
|
|
108
|
-
async: !isProduction,
|
|
109
|
-
typescript: {
|
|
110
|
-
diagnosticOptions: {
|
|
111
|
-
semantic: true,
|
|
112
|
-
syntactic: true,
|
|
113
|
-
},
|
|
114
|
-
configFile: tsConfigFile,
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
webpackConfig.plugins.push(new ForkTsCheckerWebpackPlugin(forkCheckerOptions));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
module.exports = {
|
|
122
|
-
addJSConfig,
|
|
123
|
-
addTsConfig,
|
|
124
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const typescript = require('typescript');
|
|
6
|
+
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
|
7
|
+
const utils = require('./utils');
|
|
8
|
+
|
|
9
|
+
function resolveBabelConfigFile(context, ruleOptions) {
|
|
10
|
+
if (ruleOptions && ruleOptions.babelConfigFile) {
|
|
11
|
+
return path.resolve(context, ruleOptions.babelConfigFile);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const candidates = ['babel.config.js', '.babelrc', '.babelrc.js', '.babelrc.json'];
|
|
15
|
+
for (const candidate of candidates) {
|
|
16
|
+
const candidatePath = path.resolve(context, candidate);
|
|
17
|
+
if (fs.existsSync(candidatePath)) {
|
|
18
|
+
return candidatePath;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function resolveTsConfigFile(context, ruleOptions) {
|
|
26
|
+
if (ruleOptions && ruleOptions.tsConfigFile) {
|
|
27
|
+
return path.resolve(context, ruleOptions.tsConfigFile);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return typescript.findConfigFile(context, fs.existsSync);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getRuleOptions(ruleOptions) {
|
|
34
|
+
return ruleOptions && typeof ruleOptions === 'object' ? ruleOptions : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ensureResolveExtensions(webpackConfig, extensions, { prepend }) {
|
|
38
|
+
if (!webpackConfig.resolve) {
|
|
39
|
+
webpackConfig.resolve = {};
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(webpackConfig.resolve.extensions)) {
|
|
42
|
+
webpackConfig.resolve.extensions = ['.js', '.json'];
|
|
43
|
+
}
|
|
44
|
+
const target = webpackConfig.resolve.extensions;
|
|
45
|
+
const missing = extensions.filter((ext) => !target.includes(ext));
|
|
46
|
+
if (missing.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (prepend) {
|
|
50
|
+
target.unshift(...missing);
|
|
51
|
+
} else {
|
|
52
|
+
target.push(...missing);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getBabelLoaderOptions(context, ruleOptions) {
|
|
57
|
+
const babelConfigFile = resolveBabelConfigFile(context, ruleOptions);
|
|
58
|
+
const babelLoaderOptions = {
|
|
59
|
+
cacheDirectory: true,
|
|
60
|
+
compact: true,
|
|
61
|
+
};
|
|
62
|
+
if (babelConfigFile) {
|
|
63
|
+
babelLoaderOptions.configFile = babelConfigFile;
|
|
64
|
+
}
|
|
65
|
+
return babelLoaderOptions;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function addJSConfig(webpackConfig, context, ruleOptions) {
|
|
69
|
+
const babelLoaderOptions = getBabelLoaderOptions(context, ruleOptions);
|
|
70
|
+
const scriptRuleJs = {
|
|
71
|
+
test: /\.[cm]?jsx?$/,
|
|
72
|
+
exclude: [/[/\\\\]node_modules[/\\\\]/],
|
|
73
|
+
use: [
|
|
74
|
+
{
|
|
75
|
+
loader: require.resolve('babel-loader'),
|
|
76
|
+
options: babelLoaderOptions,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(scriptRuleJs, getRuleOptions(ruleOptions)));
|
|
81
|
+
ensureResolveExtensions(webpackConfig, ['.js', '.jsx', '.mjs', '.cjs'], { prepend: true });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function addTsConfig(webpackConfig, context, ruleOptions, { isProduction }) {
|
|
85
|
+
const babelLoaderOptions = getBabelLoaderOptions(context, ruleOptions);
|
|
86
|
+
const scriptRuleTs = {
|
|
87
|
+
test: /\.[cm]?tsx?$/,
|
|
88
|
+
exclude: [/[/\\\\]node_modules[/\\\\]/],
|
|
89
|
+
use: [
|
|
90
|
+
{
|
|
91
|
+
loader: require.resolve('babel-loader'),
|
|
92
|
+
options: babelLoaderOptions,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
loader: require.resolve('ts-loader'),
|
|
96
|
+
options: {
|
|
97
|
+
transpileOnly: true,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(scriptRuleTs, getRuleOptions(ruleOptions)));
|
|
103
|
+
ensureResolveExtensions(webpackConfig, ['.ts', '.tsx', '.mts', '.cts'], { prepend: true });
|
|
104
|
+
|
|
105
|
+
const tsConfigFile = resolveTsConfigFile(context, ruleOptions);
|
|
106
|
+
if (tsConfigFile) {
|
|
107
|
+
const forkCheckerOptions = {
|
|
108
|
+
async: !isProduction,
|
|
109
|
+
typescript: {
|
|
110
|
+
diagnosticOptions: {
|
|
111
|
+
semantic: true,
|
|
112
|
+
syntactic: true,
|
|
113
|
+
},
|
|
114
|
+
configFile: tsConfigFile,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
webpackConfig.plugins.push(new ForkTsCheckerWebpackPlugin(forkCheckerOptions));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
addJSConfig,
|
|
123
|
+
addTsConfig,
|
|
124
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitro/webpack",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.1",
|
|
4
4
|
"description": "nitro webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "The Nitro Team",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"nitro"
|
|
23
23
|
],
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@nitro/app": ">=11.0.
|
|
25
|
+
"@nitro/app": ">=11.0.1",
|
|
26
26
|
"webpack": "^5"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
package/readme.md
CHANGED
|
@@ -157,7 +157,7 @@ It makes sense to use a dynamic value e.g. an environment variable, as shown in
|
|
|
157
157
|
|
|
158
158
|
By default, all js imports from 'node_modules' are extracted to a 'vendors.js' to use in your view files.
|
|
159
159
|
|
|
160
|
-
Dynamically imported js files will be extracted to `public/js/
|
|
160
|
+
Dynamically imported js files will be extracted to `public/js/chunk/`.
|
|
161
161
|
You may use them in a promise chain.
|
|
162
162
|
|
|
163
163
|
```js
|
|
@@ -1,311 +1,312 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const webpack = require('webpack');
|
|
4
|
-
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
5
|
-
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
|
6
|
-
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
7
|
-
const TerserPlugin = require('terser-webpack-plugin');
|
|
8
|
-
const WebpackBar = require('webpackbar');
|
|
9
|
-
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
|
|
10
|
-
const utils = require('../lib/utils');
|
|
11
|
-
const webpackRules = require('../lib/webpack-rules');
|
|
12
|
-
|
|
13
|
-
const appDirectory = fs.realpathSync(process.cwd());
|
|
14
|
-
|
|
15
|
-
const bannerData = {
|
|
16
|
-
date: new Date().toISOString().slice(0, 19),
|
|
17
|
-
pkg: require(`${appDirectory}/package.json`),
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const banner = `${bannerData.pkg.name}
|
|
21
|
-
@version v${bannerData.pkg.version}
|
|
22
|
-
@date ${bannerData.date}`;
|
|
23
|
-
|
|
24
|
-
module.exports = (options = { rules: {}, features: {} }) => {
|
|
25
|
-
const imageMinimizerPlugins = [];
|
|
26
|
-
const imageminMozjpeg = utils.getOptionalPackage('imagemin-mozjpeg');
|
|
27
|
-
const imageminOptipng = utils.getOptionalPackage('imagemin-optipng');
|
|
28
|
-
const imageminPngquant = utils.getOptionalPackage('imagemin-pngquant');
|
|
29
|
-
const imageminSvgo = utils.getOptionalPackage('imagemin-svgo');
|
|
30
|
-
|
|
31
|
-
if (imageminMozjpeg) {
|
|
32
|
-
imageMinimizerPlugins.push(
|
|
33
|
-
[
|
|
34
|
-
'mozjpeg',
|
|
35
|
-
{
|
|
36
|
-
quality: 75,
|
|
37
|
-
progressive: true,
|
|
38
|
-
},
|
|
39
|
-
]
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (imageminOptipng) {
|
|
43
|
-
imageMinimizerPlugins.push(
|
|
44
|
-
[
|
|
45
|
-
'optipng',
|
|
46
|
-
{
|
|
47
|
-
optimizationLevel: 7,
|
|
48
|
-
},
|
|
49
|
-
]
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
if (imageminPngquant) {
|
|
53
|
-
imageMinimizerPlugins.push('pngquant');
|
|
54
|
-
}
|
|
55
|
-
if (imageminSvgo) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
webpackConfig.
|
|
157
|
-
webpackConfig.output.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
flexbox: 'no-2009'
|
|
203
|
-
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const webpack = require('webpack');
|
|
4
|
+
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
|
5
|
+
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
|
6
|
+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|
7
|
+
const TerserPlugin = require('terser-webpack-plugin');
|
|
8
|
+
const WebpackBar = require('webpackbar');
|
|
9
|
+
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
|
|
10
|
+
const utils = require('../lib/utils');
|
|
11
|
+
const webpackRules = require('../lib/webpack-rules');
|
|
12
|
+
|
|
13
|
+
const appDirectory = fs.realpathSync(process.cwd());
|
|
14
|
+
|
|
15
|
+
const bannerData = {
|
|
16
|
+
date: new Date().toISOString().slice(0, 19),
|
|
17
|
+
pkg: require(`${appDirectory}/package.json`),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const banner = `${bannerData.pkg.name}
|
|
21
|
+
@version v${bannerData.pkg.version}
|
|
22
|
+
@date ${bannerData.date}`;
|
|
23
|
+
|
|
24
|
+
module.exports = (options = { rules: {}, features: {} }) => {
|
|
25
|
+
const imageMinimizerPlugins = [];
|
|
26
|
+
const imageminMozjpeg = utils.getOptionalPackage('imagemin-mozjpeg');
|
|
27
|
+
const imageminOptipng = utils.getOptionalPackage('imagemin-optipng');
|
|
28
|
+
const imageminPngquant = utils.getOptionalPackage('imagemin-pngquant');
|
|
29
|
+
const imageminSvgo = utils.getOptionalPackage('imagemin-svgo');
|
|
30
|
+
|
|
31
|
+
if (imageminMozjpeg) {
|
|
32
|
+
imageMinimizerPlugins.push(
|
|
33
|
+
[
|
|
34
|
+
'mozjpeg',
|
|
35
|
+
{
|
|
36
|
+
quality: 75,
|
|
37
|
+
progressive: true,
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (imageminOptipng) {
|
|
43
|
+
imageMinimizerPlugins.push(
|
|
44
|
+
[
|
|
45
|
+
'optipng',
|
|
46
|
+
{
|
|
47
|
+
optimizationLevel: 7,
|
|
48
|
+
},
|
|
49
|
+
]
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (imageminPngquant) {
|
|
53
|
+
imageMinimizerPlugins.push('pngquant');
|
|
54
|
+
}
|
|
55
|
+
if (imageminSvgo) {
|
|
56
|
+
// svgo configuration: https://github.com/svg/svgo#configuration
|
|
57
|
+
imageMinimizerPlugins.push(
|
|
58
|
+
[
|
|
59
|
+
'svgo',
|
|
60
|
+
{
|
|
61
|
+
plugins: [
|
|
62
|
+
{
|
|
63
|
+
name: 'preset-default',
|
|
64
|
+
params: {
|
|
65
|
+
overrides: {
|
|
66
|
+
removeViewBox: false,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
]
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const minimizerPlugins = [new TerserPlugin({ extractComments: false })];
|
|
77
|
+
if (!(options.features.imageMinimizer === false || imageMinimizerPlugins.length === 0)) {
|
|
78
|
+
minimizerPlugins.push(
|
|
79
|
+
new ImageMinimizerPlugin({
|
|
80
|
+
minimizer: {
|
|
81
|
+
implementation: ImageMinimizerPlugin.imageminMinify,
|
|
82
|
+
options: {
|
|
83
|
+
plugins: imageMinimizerPlugins,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const webpackConfig = {
|
|
91
|
+
mode: 'production',
|
|
92
|
+
devtool: 'hidden-source-map',
|
|
93
|
+
context: appDirectory,
|
|
94
|
+
entry: {
|
|
95
|
+
ui: './src/ui',
|
|
96
|
+
proto: './src/proto',
|
|
97
|
+
},
|
|
98
|
+
output: {
|
|
99
|
+
path: path.resolve(appDirectory, 'public', 'assets'),
|
|
100
|
+
filename: 'js/[name].min.js',
|
|
101
|
+
chunkFilename: 'js/chunks/[name]-[contenthash:7].min.js',
|
|
102
|
+
publicPath: '/assets/',
|
|
103
|
+
},
|
|
104
|
+
resolve: {
|
|
105
|
+
symlinks: false,
|
|
106
|
+
},
|
|
107
|
+
module: {
|
|
108
|
+
rules: [],
|
|
109
|
+
},
|
|
110
|
+
plugins: [new CaseSensitivePathsPlugin({ debug: false }), new WebpackBar()],
|
|
111
|
+
optimization: {
|
|
112
|
+
moduleIds: 'deterministic',
|
|
113
|
+
chunkIds: 'deterministic',
|
|
114
|
+
runtimeChunk: false,
|
|
115
|
+
splitChunks: {
|
|
116
|
+
chunks: 'all',
|
|
117
|
+
minSize: 3000,
|
|
118
|
+
cacheGroups: {
|
|
119
|
+
default: false,
|
|
120
|
+
defaultVendors: false,
|
|
121
|
+
vendors: {
|
|
122
|
+
test: /[\\/]node_modules[\\/].*\.(js|jsx|mjs|ts|tsx)$/,
|
|
123
|
+
chunks: (chunk) => chunk.canBeInitial() && chunk.name && chunk.name !== 'proto',
|
|
124
|
+
name: 'vendors',
|
|
125
|
+
enforce: true,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
minimizer: minimizerPlugins,
|
|
130
|
+
},
|
|
131
|
+
stats: {
|
|
132
|
+
preset: 'errors-warnings',
|
|
133
|
+
assets: true,
|
|
134
|
+
assetsSort: 'size',
|
|
135
|
+
children: false,
|
|
136
|
+
chunks: false,
|
|
137
|
+
modules: false,
|
|
138
|
+
colors: true,
|
|
139
|
+
entrypoints: true,
|
|
140
|
+
errors: true,
|
|
141
|
+
errorDetails: true,
|
|
142
|
+
hash: false,
|
|
143
|
+
builtAt: false,
|
|
144
|
+
timings: true,
|
|
145
|
+
performance: true,
|
|
146
|
+
warnings: true,
|
|
147
|
+
},
|
|
148
|
+
performance: {
|
|
149
|
+
hints: 'warning',
|
|
150
|
+
maxEntrypointSize: 760 * 1024,
|
|
151
|
+
maxAssetSize: 380 * 1024,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
const theme = options.features.theme ? options.features.theme : false;
|
|
155
|
+
if (theme) {
|
|
156
|
+
webpackConfig.entry.ui = `./src/ui.${theme}`;
|
|
157
|
+
webpackConfig.output.path = path.resolve(webpackConfig.output.path, theme);
|
|
158
|
+
webpackConfig.output.publicPath = `${webpackConfig.output.publicPath}${theme}/`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// scripts (js/ts via babel)
|
|
162
|
+
if (options.rules.script) {
|
|
163
|
+
const scriptOptions = typeof options.rules.script === 'object' ? options.rules.script : null;
|
|
164
|
+
webpackRules.addJSConfig(webpackConfig, appDirectory, scriptOptions);
|
|
165
|
+
if (scriptOptions && scriptOptions.typescript) {
|
|
166
|
+
webpackRules.addTsConfig(webpackConfig, appDirectory, scriptOptions, { isProduction: true });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// css & scss
|
|
171
|
+
if (options.rules.style) {
|
|
172
|
+
const scssMiniCSSExtractOptions = {
|
|
173
|
+
...(options.rules.style.publicPath && { publicPath: options.rules.style.publicPath })
|
|
174
|
+
};
|
|
175
|
+
const scssLoaderOptions = {
|
|
176
|
+
sourceMap: true,
|
|
177
|
+
...(options.rules.style.sassOptions && { sassOptions: options.rules.style.sassOptions }),
|
|
178
|
+
};
|
|
179
|
+
webpackConfig.module.rules.push({
|
|
180
|
+
test: /\.s?css$/,
|
|
181
|
+
use: [
|
|
182
|
+
{
|
|
183
|
+
loader: MiniCssExtractPlugin.loader,
|
|
184
|
+
options: scssMiniCSSExtractOptions,
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
loader: require.resolve('css-loader'),
|
|
188
|
+
options: {
|
|
189
|
+
importLoaders: 2,
|
|
190
|
+
sourceMap: true,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
loader: require.resolve('postcss-loader'),
|
|
195
|
+
options: {
|
|
196
|
+
sourceMap: true,
|
|
197
|
+
postcssOptions: () => {
|
|
198
|
+
return {
|
|
199
|
+
plugins: [
|
|
200
|
+
require('autoprefixer')({
|
|
201
|
+
// @see autoprefixer options: https://github.com/postcss/autoprefixer#options
|
|
202
|
+
// flexbox: 'no-2009' will add prefixes only for final and IE versions of specification.
|
|
203
|
+
flexbox: 'no-2009',
|
|
204
|
+
// grid: 'autoplace': enable autoprefixer grid translations and include autoplacement support.
|
|
205
|
+
// not enabled - use `/* autoprefixer grid: autoplace */` in your css file
|
|
206
|
+
}),
|
|
207
|
+
require('cssnano'),
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
loader: require.resolve('resolve-url-loader'),
|
|
215
|
+
options: {
|
|
216
|
+
sourceMap: true,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
loader: require.resolve('sass-loader'),
|
|
221
|
+
options: scssLoaderOptions,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
webpackConfig.plugins.push(
|
|
227
|
+
new MiniCssExtractPlugin({
|
|
228
|
+
filename: 'css/[name].min.css',
|
|
229
|
+
chunkFilename: 'css/chunks/[name]-[contenthash:7].min.css',
|
|
230
|
+
}),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// handlebars precompiled templates
|
|
235
|
+
if (options.rules.hbs) {
|
|
236
|
+
const hbsRule = {
|
|
237
|
+
test: /\.hbs$/,
|
|
238
|
+
use: {
|
|
239
|
+
loader: require.resolve('handlebars-loader'),
|
|
240
|
+
// options: {
|
|
241
|
+
// helperDirs: [
|
|
242
|
+
// path.resolve(__dirname, '../../app/templating/hbs/helpers'),
|
|
243
|
+
// ],
|
|
244
|
+
// knownHelpers: [],
|
|
245
|
+
// runtime: '',
|
|
246
|
+
// partialDirs: ''
|
|
247
|
+
// },
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(hbsRule, options.rules.hbs));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// woff fonts (for example, in CSS files)
|
|
254
|
+
if (options.rules.woff) {
|
|
255
|
+
const woffRule = {
|
|
256
|
+
test: /.(woff(2)?)(\?[a-z0-9]+)?$/,
|
|
257
|
+
type: 'asset/resource',
|
|
258
|
+
generator: {
|
|
259
|
+
filename: 'media/fonts/[name]-[contenthash:7].[ext]',
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(woffRule, options.rules.woff));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// different font types (legacy - eg. used in older library css)
|
|
266
|
+
if (options.rules.font) {
|
|
267
|
+
const fontRule = {
|
|
268
|
+
test: /\.(eot|svg|ttf|woff|woff2)([?#]+[A-Za-z0-9-_]*)*$/,
|
|
269
|
+
type: 'asset',
|
|
270
|
+
parser: {
|
|
271
|
+
dataUrlCondition: {
|
|
272
|
+
maxSize: 2 * 1028,
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
generator: {
|
|
276
|
+
filename: 'media/font/[name]-[contenthash:7].[ext]',
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(fontRule, options.rules.font));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// images
|
|
283
|
+
if (options.rules.image) {
|
|
284
|
+
const imageRule = {
|
|
285
|
+
test: /\.(png|jpg|gif|svg)$/,
|
|
286
|
+
type: 'asset',
|
|
287
|
+
parser: {
|
|
288
|
+
dataUrlCondition: {
|
|
289
|
+
maxSize: 1028,
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
generator: {
|
|
293
|
+
filename: 'media/[ext]/[name]-[contenthash:7].[ext]',
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
webpackConfig.module.rules.push(utils.getEnrichedConfig(imageRule, options.rules.image));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// feature banner (enabled by default)
|
|
301
|
+
if (!options.features.banner === false) {
|
|
302
|
+
webpackConfig.plugins.push(new webpack.BannerPlugin({ banner, entryOnly: true }));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// feature bundle analyzer
|
|
306
|
+
if (options.features.bundleAnalyzer) {
|
|
307
|
+
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return webpackConfig;
|
|
311
|
+
};
|
|
312
|
+
module.exports.appDirectory = appDirectory;
|