@apollion-dsi/scripts 0.7.7
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/.prettierignore +6 -0
- package/.prettierrc.js +1 -0
- package/CHANGELOG.md +8 -0
- package/README.MD +91 -0
- package/audit-ci.json +5 -0
- package/eslint.config.js +33 -0
- package/lib/bin.d.ts +2 -0
- package/lib/bin.js +34 -0
- package/lib/bin.js.map +1 -0
- package/lib/command/build.d.ts +3 -0
- package/lib/command/build.js +145 -0
- package/lib/command/build.js.map +1 -0
- package/lib/command/create/helper.d.ts +7 -0
- package/lib/command/create/helper.js +98 -0
- package/lib/command/create/helper.js.map +1 -0
- package/lib/command/create/index.d.ts +1 -0
- package/lib/command/create/index.js +149 -0
- package/lib/command/create/index.js.map +1 -0
- package/lib/command/dev.d.ts +3 -0
- package/lib/command/dev.js +85 -0
- package/lib/command/dev.js.map +1 -0
- package/lib/command/test.d.ts +1 -0
- package/lib/command/test.js +32 -0
- package/lib/command/test.js.map +1 -0
- package/lib/config/env.d.ts +15 -0
- package/lib/config/env.js +78 -0
- package/lib/config/env.js.map +1 -0
- package/lib/config/modules.d.ts +15 -0
- package/lib/config/modules.js +92 -0
- package/lib/config/modules.js.map +1 -0
- package/lib/config/paths.d.ts +22 -0
- package/lib/config/paths.js +61 -0
- package/lib/config/paths.js.map +1 -0
- package/lib/config/shared.d.ts +24 -0
- package/lib/config/shared.js +14 -0
- package/lib/config/shared.js.map +1 -0
- package/lib/config/webpack.config.d.ts +187 -0
- package/lib/config/webpack.config.js +300 -0
- package/lib/config/webpack.config.js.map +1 -0
- package/lib/config/webpackDevServer.config.d.ts +34 -0
- package/lib/config/webpackDevServer.config.js +67 -0
- package/lib/config/webpackDevServer.config.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/FileSizeReporter.d.ts +12 -0
- package/lib/utils/FileSizeReporter.js +151 -0
- package/lib/utils/FileSizeReporter.js.map +1 -0
- package/lib/utils/InlineChunkHtmlPlugin.d.ts +8 -0
- package/lib/utils/InlineChunkHtmlPlugin.js +54 -0
- package/lib/utils/InlineChunkHtmlPlugin.js.map +1 -0
- package/lib/utils/InterpolateHtmlPlugin.d.ts +7 -0
- package/lib/utils/InterpolateHtmlPlugin.js +21 -0
- package/lib/utils/InterpolateHtmlPlugin.js.map +1 -0
- package/lib/utils/ModuleNotFoundPlugin.d.ts +5 -0
- package/lib/utils/ModuleNotFoundPlugin.js +11 -0
- package/lib/utils/ModuleNotFoundPlugin.js.map +1 -0
- package/lib/utils/ModuleScopePlugin.d.ts +5 -0
- package/lib/utils/ModuleScopePlugin.js +11 -0
- package/lib/utils/ModuleScopePlugin.js.map +1 -0
- package/lib/utils/WebpackDevServerUtils.d.ts +22 -0
- package/lib/utils/WebpackDevServerUtils.js +154 -0
- package/lib/utils/WebpackDevServerUtils.js.map +1 -0
- package/lib/utils/checkRequiredFiles.d.ts +1 -0
- package/lib/utils/checkRequiredFiles.js +28 -0
- package/lib/utils/checkRequiredFiles.js.map +1 -0
- package/lib/utils/devServerMiddleware.d.ts +8 -0
- package/lib/utils/devServerMiddleware.js +19 -0
- package/lib/utils/devServerMiddleware.js.map +1 -0
- package/lib/utils/formatWebpackMessages.d.ts +5 -0
- package/lib/utils/formatWebpackMessages.js +32 -0
- package/lib/utils/formatWebpackMessages.js.map +1 -0
- package/lib/utils/getPublicUrlOrPath.d.ts +1 -0
- package/lib/utils/getPublicUrlOrPath.js +39 -0
- package/lib/utils/getPublicUrlOrPath.js.map +1 -0
- package/lib/utils/printBuildError.d.ts +1 -0
- package/lib/utils/printBuildError.js +14 -0
- package/lib/utils/printBuildError.js.map +1 -0
- package/lib/utils/printHostingInstructions.d.ts +1 -0
- package/lib/utils/printHostingInstructions.js +12 -0
- package/lib/utils/printHostingInstructions.js.map +1 -0
- package/package.json +81 -0
- package/scripts/validate.sh +16 -0
- package/src/bin.ts +41 -0
- package/src/command/build.ts +188 -0
- package/src/command/create/helper.ts +97 -0
- package/src/command/create/index.ts +200 -0
- package/src/command/dev.ts +95 -0
- package/src/command/test.ts +33 -0
- package/src/config/env.ts +82 -0
- package/src/config/modules.ts +115 -0
- package/src/config/paths.ts +88 -0
- package/src/config/shared.ts +27 -0
- package/src/config/webpack.config.js +308 -0
- package/src/config/webpackDevServer.config.ts +78 -0
- package/src/index.ts +3 -0
- package/src/utils/FileSizeReporter.ts +168 -0
- package/src/utils/InlineChunkHtmlPlugin.js +67 -0
- package/src/utils/InterpolateHtmlPlugin.js +27 -0
- package/src/utils/ModuleNotFoundPlugin.js +13 -0
- package/src/utils/ModuleScopePlugin.js +13 -0
- package/src/utils/WebpackDevServerUtils.ts +179 -0
- package/src/utils/checkRequiredFiles.ts +22 -0
- package/src/utils/devServerMiddleware.ts +20 -0
- package/src/utils/formatWebpackMessages.ts +30 -0
- package/src/utils/getPublicUrlOrPath.ts +39 -0
- package/src/utils/printBuildError.ts +8 -0
- package/src/utils/printHostingInstructions.ts +12 -0
- package/template/.editorconfig +43 -0
- package/template/.prettierignore +6 -0
- package/template/.prettierrc.js +1 -0
- package/template/audit-ci.json +5 -0
- package/template/commitlint.config.js +1 -0
- package/template/eslint.config.js +3 -0
- package/template/jest.config.js +4 -0
- package/template/public/index.html +20 -0
- package/template/src/App.test.tsx +10 -0
- package/template/src/App.tsx +35 -0
- package/template/src/index.tsx +10 -0
- package/template/tsconfig.json +25 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
|
4
|
+
import InlineChunkHtmlPlugin from '../utils/InlineChunkHtmlPlugin';
|
|
5
|
+
import InterpolateHtmlPlugin from '../utils/InterpolateHtmlPlugin';
|
|
6
|
+
import ModuleNotFoundPlugin from '../utils/ModuleNotFoundPlugin';
|
|
7
|
+
import ModuleScopePlugin from '../utils/ModuleScopePlugin';
|
|
8
|
+
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
|
|
9
|
+
import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
|
|
10
|
+
import GitRevision from 'git-revision-webpack-plugin';
|
|
11
|
+
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
12
|
+
import resolve from 'resolve';
|
|
13
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
|
14
|
+
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
|
15
|
+
import webpack from 'webpack';
|
|
16
|
+
import { WebpackManifestPlugin } from 'webpack-manifest-plugin';
|
|
17
|
+
|
|
18
|
+
import getClientEnvironment from './env';
|
|
19
|
+
import modules from './modules';
|
|
20
|
+
|
|
21
|
+
export default (webpackEnv, paths, options = {}) => {
|
|
22
|
+
const appPackageJson = require(paths.appPackageJson);
|
|
23
|
+
|
|
24
|
+
const GitRevisionPlugin = new GitRevision({ branch: true });
|
|
25
|
+
|
|
26
|
+
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
|
|
27
|
+
|
|
28
|
+
const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000');
|
|
29
|
+
|
|
30
|
+
const useTypeScript = true;
|
|
31
|
+
|
|
32
|
+
const hasJsxRuntime = (() => {
|
|
33
|
+
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
require.resolve('react/jsx-runtime');
|
|
38
|
+
return true;
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
})();
|
|
43
|
+
|
|
44
|
+
const isEnvDevelopment = webpackEnv === 'development';
|
|
45
|
+
const isEnvProduction = webpackEnv === 'production';
|
|
46
|
+
const shouldUseSourceMap = isEnvDevelopment;
|
|
47
|
+
|
|
48
|
+
const isEnvProductionProfile = isEnvProduction && process.argv.includes('--profile');
|
|
49
|
+
|
|
50
|
+
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1), options);
|
|
51
|
+
|
|
52
|
+
const shouldUseReactRefresh = env.raw.FAST_REFRESH;
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
|
|
56
|
+
bail: isEnvProduction,
|
|
57
|
+
devtool: isEnvProduction
|
|
58
|
+
? shouldUseSourceMap
|
|
59
|
+
? 'source-map'
|
|
60
|
+
: false
|
|
61
|
+
: isEnvDevelopment && 'cheap-module-source-map',
|
|
62
|
+
// WDS v5 injects the HMR client automatically — no need to prepend it here
|
|
63
|
+
entry: paths.appIndexJs,
|
|
64
|
+
output: {
|
|
65
|
+
path: isEnvProduction ? paths.appBuild : undefined,
|
|
66
|
+
pathinfo: isEnvDevelopment,
|
|
67
|
+
filename: isEnvProduction ? 'static/js/[name].[contenthash:8].js' : isEnvDevelopment && 'static/js/bundle.js',
|
|
68
|
+
chunkFilename: isEnvProduction
|
|
69
|
+
? 'static/js/[name].[contenthash:8].chunk.js'
|
|
70
|
+
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
|
71
|
+
publicPath: paths.publicUrlOrPath,
|
|
72
|
+
devtoolModuleFilenameTemplate: isEnvProduction
|
|
73
|
+
? (info) => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/')
|
|
74
|
+
: isEnvDevelopment && ((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
|
|
75
|
+
// Replaces deprecated jsonpFunction
|
|
76
|
+
chunkLoadingGlobal: `webpackJsonp${appPackageJson.name}`,
|
|
77
|
+
globalObject: 'this',
|
|
78
|
+
},
|
|
79
|
+
optimization: {
|
|
80
|
+
minimize: isEnvProduction,
|
|
81
|
+
minimizer: [
|
|
82
|
+
new TerserPlugin({
|
|
83
|
+
terserOptions: {
|
|
84
|
+
parse: { ecma: 8 },
|
|
85
|
+
compress: {
|
|
86
|
+
ecma: 5,
|
|
87
|
+
warnings: false,
|
|
88
|
+
comparisons: false,
|
|
89
|
+
inline: 2,
|
|
90
|
+
},
|
|
91
|
+
mangle: { safari10: true },
|
|
92
|
+
keep_classnames: isEnvProductionProfile,
|
|
93
|
+
keep_fnames: isEnvProductionProfile,
|
|
94
|
+
output: {
|
|
95
|
+
ecma: 5,
|
|
96
|
+
comments: false,
|
|
97
|
+
ascii_only: true,
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
}),
|
|
101
|
+
],
|
|
102
|
+
splitChunks: isEnvProduction
|
|
103
|
+
? {
|
|
104
|
+
chunks: 'all',
|
|
105
|
+
name: false,
|
|
106
|
+
cacheGroups: {
|
|
107
|
+
commons: {
|
|
108
|
+
test: /[\\/]node_modules[\\/]/,
|
|
109
|
+
minSize: 50000,
|
|
110
|
+
name: 'vendors',
|
|
111
|
+
chunks: 'all',
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
: { chunks: 'all', name: false },
|
|
116
|
+
runtimeChunk: {
|
|
117
|
+
name: (entrypoint) => `runtime-${entrypoint.name}`,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
resolve: {
|
|
121
|
+
modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []),
|
|
122
|
+
extensions: paths.moduleFileExtensions
|
|
123
|
+
.map((ext) => `.${ext}`)
|
|
124
|
+
.filter((ext) => useTypeScript || !ext.includes('ts')),
|
|
125
|
+
alias: {
|
|
126
|
+
'react-native': 'react-native-web',
|
|
127
|
+
...(isEnvProductionProfile && {
|
|
128
|
+
'react-dom$': 'react-dom/profiling',
|
|
129
|
+
'scheduler/tracing': 'scheduler/tracing-profiling',
|
|
130
|
+
}),
|
|
131
|
+
...(modules.webpackAliases || {}),
|
|
132
|
+
},
|
|
133
|
+
// Replaces Webpack 4 `node` polyfill shims — disable browser-irrelevant Node built-ins
|
|
134
|
+
fallback: {
|
|
135
|
+
dgram: false,
|
|
136
|
+
fs: false,
|
|
137
|
+
net: false,
|
|
138
|
+
tls: false,
|
|
139
|
+
child_process: false,
|
|
140
|
+
},
|
|
141
|
+
plugins: [
|
|
142
|
+
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
|
|
143
|
+
new TsconfigPathsPlugin(),
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
module: {
|
|
147
|
+
strictExportPresence: true,
|
|
148
|
+
rules: [
|
|
149
|
+
{
|
|
150
|
+
oneOf: [
|
|
151
|
+
// Webpack 5 asset modules replace url-loader and file-loader
|
|
152
|
+
{
|
|
153
|
+
test: /\.avif$/,
|
|
154
|
+
type: 'asset/inline',
|
|
155
|
+
mimetype: 'image/avif',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
|
|
159
|
+
type: 'asset',
|
|
160
|
+
parser: {
|
|
161
|
+
dataUrlCondition: { maxSize: imageInlineSizeLimit },
|
|
162
|
+
},
|
|
163
|
+
generator: {
|
|
164
|
+
filename: 'static/media/[name].[hash:8][ext]',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
|
169
|
+
include: paths.appSrc,
|
|
170
|
+
loader: require.resolve('babel-loader'),
|
|
171
|
+
options: {
|
|
172
|
+
babelrc: false,
|
|
173
|
+
configFile: false,
|
|
174
|
+
presets: [
|
|
175
|
+
[
|
|
176
|
+
require.resolve('@babel/preset-env'),
|
|
177
|
+
{
|
|
178
|
+
targets: 'defaults',
|
|
179
|
+
useBuiltIns: 'usage',
|
|
180
|
+
corejs: 3,
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
[
|
|
184
|
+
require.resolve('@babel/preset-react'),
|
|
185
|
+
{
|
|
186
|
+
runtime: hasJsxRuntime ? 'automatic' : 'classic',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
require.resolve('@babel/preset-typescript'),
|
|
190
|
+
],
|
|
191
|
+
plugins: [
|
|
192
|
+
!!options.relayArtifactDirectory && ['relay', { artifactDirectory: options.relayArtifactDirectory }],
|
|
193
|
+
[
|
|
194
|
+
'babel-plugin-styled-components',
|
|
195
|
+
{
|
|
196
|
+
displayName: !isEnvProduction,
|
|
197
|
+
ssr: false,
|
|
198
|
+
transpileTemplateLiterals: isEnvProduction,
|
|
199
|
+
pure: true,
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
isEnvDevelopment && shouldUseReactRefresh && require.resolve('react-refresh/babel'),
|
|
203
|
+
].filter(Boolean),
|
|
204
|
+
cacheDirectory: true,
|
|
205
|
+
cacheCompression: false,
|
|
206
|
+
compact: isEnvProduction,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
test: /\.(js|mjs)$/,
|
|
211
|
+
exclude: /@babel(?:\/|\\{1,2})runtime/,
|
|
212
|
+
loader: require.resolve('babel-loader'),
|
|
213
|
+
options: {
|
|
214
|
+
babelrc: false,
|
|
215
|
+
configFile: false,
|
|
216
|
+
compact: false,
|
|
217
|
+
presets: [[require.resolve('@babel/preset-env'), { targets: 'defaults' }]],
|
|
218
|
+
cacheDirectory: true,
|
|
219
|
+
cacheCompression: false,
|
|
220
|
+
sourceMaps: shouldUseSourceMap,
|
|
221
|
+
inputSourceMap: shouldUseSourceMap,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
// Catch-all: replaces file-loader
|
|
225
|
+
{
|
|
226
|
+
exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
|
|
227
|
+
type: 'asset/resource',
|
|
228
|
+
generator: {
|
|
229
|
+
filename: 'static/media/[name].[hash:8][ext]',
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
plugins: [
|
|
237
|
+
new HtmlWebpackPlugin({
|
|
238
|
+
title: options.head.title,
|
|
239
|
+
inject: true,
|
|
240
|
+
template: paths.appHtml,
|
|
241
|
+
...(isEnvProduction
|
|
242
|
+
? {
|
|
243
|
+
minify: {
|
|
244
|
+
removeComments: true,
|
|
245
|
+
collapseWhitespace: true,
|
|
246
|
+
removeRedundantAttributes: true,
|
|
247
|
+
useShortDoctype: true,
|
|
248
|
+
removeEmptyAttributes: true,
|
|
249
|
+
removeStyleLinkTypeAttributes: true,
|
|
250
|
+
keepClosingSlash: true,
|
|
251
|
+
minifyJS: true,
|
|
252
|
+
minifyCSS: true,
|
|
253
|
+
minifyURLs: true,
|
|
254
|
+
},
|
|
255
|
+
}
|
|
256
|
+
: undefined),
|
|
257
|
+
}),
|
|
258
|
+
isEnvProduction && shouldInlineRuntimeChunk && new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
|
|
259
|
+
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
|
260
|
+
new ModuleNotFoundPlugin(paths.appPath),
|
|
261
|
+
GitRevisionPlugin,
|
|
262
|
+
new webpack.DefinePlugin(
|
|
263
|
+
Object.assign(env.stringified, {
|
|
264
|
+
PACKAGE_VERSION: JSON.stringify(appPackageJson.version),
|
|
265
|
+
SERVICE: JSON.stringify(appPackageJson.name),
|
|
266
|
+
IS_PROD_MODE: !isEnvProduction,
|
|
267
|
+
VERSION: JSON.stringify(GitRevisionPlugin.version()),
|
|
268
|
+
COMMITHASH: JSON.stringify(GitRevisionPlugin.commithash()),
|
|
269
|
+
BRANCH: JSON.stringify(GitRevisionPlugin.branch()),
|
|
270
|
+
CONSTANTS: JSON.stringify(options.constants),
|
|
271
|
+
I18N_CONFIG: JSON.stringify(options.i18nConfig),
|
|
272
|
+
}),
|
|
273
|
+
),
|
|
274
|
+
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
|
|
275
|
+
isEnvDevelopment && shouldUseReactRefresh && new ReactRefreshWebpackPlugin(),
|
|
276
|
+
isEnvDevelopment && new CaseSensitivePathsPlugin(),
|
|
277
|
+
new WebpackManifestPlugin({
|
|
278
|
+
fileName: 'asset-manifest.json',
|
|
279
|
+
publicPath: paths.publicUrlOrPath,
|
|
280
|
+
generate: (seed, files, entrypoints) => {
|
|
281
|
+
const manifestFiles = files.reduce((manifest, file) => {
|
|
282
|
+
manifest[file.name] = file.path;
|
|
283
|
+
return manifest;
|
|
284
|
+
}, seed);
|
|
285
|
+
const entrypointFiles = entrypoints.main.filter((fileName) => !fileName.endsWith('.map'));
|
|
286
|
+
return { files: manifestFiles, entrypoints: entrypointFiles };
|
|
287
|
+
},
|
|
288
|
+
}),
|
|
289
|
+
// Updated Webpack 5 API — was: new webpack.IgnorePlugin(/pattern/, /context/)
|
|
290
|
+
new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ }),
|
|
291
|
+
useTypeScript &&
|
|
292
|
+
new ForkTsCheckerWebpackPlugin({
|
|
293
|
+
async: isEnvDevelopment,
|
|
294
|
+
typescript: {
|
|
295
|
+
typescriptPath: resolve.sync('typescript', {
|
|
296
|
+
basedir: paths.appNodeModules,
|
|
297
|
+
}),
|
|
298
|
+
configFile: paths.appTsConfig,
|
|
299
|
+
diagnosticOptions: {
|
|
300
|
+
semantic: true,
|
|
301
|
+
syntactic: true,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
}),
|
|
305
|
+
].filter(Boolean),
|
|
306
|
+
performance: false,
|
|
307
|
+
};
|
|
308
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
|
|
3
|
+
import { AppPaths } from './paths';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
evalSourceMapMiddleware,
|
|
7
|
+
ignoredFiles,
|
|
8
|
+
noopServiceWorkerMiddleware,
|
|
9
|
+
redirectServedPathMiddleware as redirectServedPath,
|
|
10
|
+
} from '../utils/devServerMiddleware';
|
|
11
|
+
|
|
12
|
+
export default (proxy: any, allowedHost: any, paths: AppPaths) => {
|
|
13
|
+
const host = process.env.HOST || '0.0.0.0';
|
|
14
|
+
const sockHost = process.env.WDS_SOCKET_HOST;
|
|
15
|
+
const sockPath = process.env.WDS_SOCKET_PATH;
|
|
16
|
+
const sockPort = process.env.WDS_SOCKET_PORT;
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
// Replaces deprecated disableHostCheck
|
|
20
|
+
allowedHosts:
|
|
21
|
+
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true'
|
|
22
|
+
? ('all' as const)
|
|
23
|
+
: ([allowedHost].filter(Boolean) as string[]),
|
|
24
|
+
compress: true,
|
|
25
|
+
// Replaces clientLogLevel, injectClient, sockHost/sockPath/sockPort, overlay
|
|
26
|
+
client: {
|
|
27
|
+
logging: 'none' as const,
|
|
28
|
+
overlay: false,
|
|
29
|
+
webSocketURL: {
|
|
30
|
+
hostname: sockHost,
|
|
31
|
+
pathname: sockPath,
|
|
32
|
+
port: sockPort ? Number(sockPort) : undefined,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
// Replaces contentBase + contentBasePublicPath + watchContentBase
|
|
36
|
+
static: [
|
|
37
|
+
{
|
|
38
|
+
directory: paths.appPublic,
|
|
39
|
+
publicPath: [paths.publicUrlOrPath],
|
|
40
|
+
watch: {
|
|
41
|
+
ignored: ignoredFiles(paths.appSrc),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
hot: true,
|
|
46
|
+
// Replaces transportMode
|
|
47
|
+
webSocketServer: 'ws' as const,
|
|
48
|
+
// Replaces publicPath at root level
|
|
49
|
+
devMiddleware: {
|
|
50
|
+
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
|
51
|
+
},
|
|
52
|
+
host,
|
|
53
|
+
historyApiFallback: {
|
|
54
|
+
disableDotRule: true as const,
|
|
55
|
+
index: paths.publicUrlOrPath,
|
|
56
|
+
},
|
|
57
|
+
// Replaces public
|
|
58
|
+
...(allowedHost && !(!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true')
|
|
59
|
+
? { allowedHosts: [allowedHost] }
|
|
60
|
+
: {}),
|
|
61
|
+
proxy,
|
|
62
|
+
// Replaces before() + after() hooks
|
|
63
|
+
setupMiddlewares(middlewares: any[], devServer: any) {
|
|
64
|
+
devServer.app.use(evalSourceMapMiddleware(devServer));
|
|
65
|
+
|
|
66
|
+
if (fs.existsSync(paths.proxySetup)) {
|
|
67
|
+
require(paths.proxySetup)(devServer.app);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
middlewares.push(
|
|
71
|
+
{ name: 'redirect-served-path', middleware: redirectServedPath(paths.publicUrlOrPath) },
|
|
72
|
+
{ name: 'noop-service-worker', middleware: noopServiceWorkerMiddleware(paths.publicUrlOrPath) },
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return middlewares;
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import zlib from 'zlib';
|
|
4
|
+
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
|
|
7
|
+
function filesize(bytes: number): string {
|
|
8
|
+
if (!Number.isFinite(bytes)) return '0 B';
|
|
9
|
+
const sign = bytes < 0 ? '-' : '';
|
|
10
|
+
const abs = Math.abs(bytes);
|
|
11
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
12
|
+
let i = 0;
|
|
13
|
+
let n = abs;
|
|
14
|
+
while (n >= 1024 && i < units.length - 1) {
|
|
15
|
+
n /= 1024;
|
|
16
|
+
i++;
|
|
17
|
+
}
|
|
18
|
+
const value = i === 0 ? n.toFixed(0) : n.toFixed(2);
|
|
19
|
+
return `${sign}${value} ${units[i]}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type SizeMap = Record<string, number>;
|
|
23
|
+
|
|
24
|
+
export type PreviousFileSizes = {
|
|
25
|
+
root: string;
|
|
26
|
+
sizes: SizeMap;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function canReadAsset(asset: string): boolean {
|
|
30
|
+
return (
|
|
31
|
+
/\.(js|css)$/.test(asset) && !/service-worker\.js/.test(asset) && !/precache-manifest\.[0-9a-f]+\.js/.test(asset)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function gzipSize(buf: Buffer): number {
|
|
36
|
+
return zlib.gzipSync(buf, { level: 6 }).length;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function walkSync(dir: string, out: string[] = []): string[] {
|
|
40
|
+
if (!fs.existsSync(dir)) return out;
|
|
41
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
42
|
+
const full = path.join(dir, entry.name);
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
walkSync(full, out);
|
|
45
|
+
} else if (entry.isFile()) {
|
|
46
|
+
out.push(full);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function removeFileNameHash(buildFolder: string, fileName: string): string {
|
|
53
|
+
return fileName
|
|
54
|
+
.replace(buildFolder, '')
|
|
55
|
+
.replace(/\\/g, '/')
|
|
56
|
+
.replace(/\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/, (_match, p1, _p2, p3, p4) => p1 + (p3 || '') + p4);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getDifferenceLabel(currentSize: number, previousSize: number): string {
|
|
60
|
+
const FIFTY_KILOBYTES = 1024 * 50;
|
|
61
|
+
const difference = currentSize - previousSize;
|
|
62
|
+
const fileSize = !Number.isNaN(difference) ? filesize(difference) : '';
|
|
63
|
+
if (difference >= FIFTY_KILOBYTES) {
|
|
64
|
+
return chalk.red('+' + fileSize);
|
|
65
|
+
} else if (difference < FIFTY_KILOBYTES && difference > 0) {
|
|
66
|
+
return chalk.yellow('+' + fileSize);
|
|
67
|
+
} else if (difference < 0) {
|
|
68
|
+
return chalk.green(fileSize);
|
|
69
|
+
}
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function measureFileSizesBeforeBuild(buildFolder: string): Promise<PreviousFileSizes> {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
try {
|
|
76
|
+
const files = walkSync(buildFolder).filter(canReadAsset);
|
|
77
|
+
const sizes: SizeMap = {};
|
|
78
|
+
files.forEach((file) => {
|
|
79
|
+
try {
|
|
80
|
+
const contents = fs.readFileSync(file);
|
|
81
|
+
const key = removeFileNameHash(buildFolder, file);
|
|
82
|
+
sizes[key] = gzipSize(contents);
|
|
83
|
+
} catch {
|
|
84
|
+
/* ignore */
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
resolve({ root: buildFolder, sizes });
|
|
88
|
+
} catch {
|
|
89
|
+
resolve({ root: buildFolder, sizes: {} });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function printFileSizesAfterBuild(
|
|
95
|
+
webpackStats: any,
|
|
96
|
+
previousSizeMap: PreviousFileSizes,
|
|
97
|
+
buildFolder: string,
|
|
98
|
+
maxBundleGzipSize: number,
|
|
99
|
+
maxChunkGzipSize: number,
|
|
100
|
+
): void {
|
|
101
|
+
const root = previousSizeMap?.root || buildFolder;
|
|
102
|
+
const sizes = previousSizeMap?.sizes || {};
|
|
103
|
+
|
|
104
|
+
const statsArr = webpackStats && typeof webpackStats.stats !== 'undefined' ? webpackStats.stats : [webpackStats];
|
|
105
|
+
|
|
106
|
+
const assets: Array<{ folder: string; name: string; size: number; sizeLabel: string }> = [];
|
|
107
|
+
|
|
108
|
+
statsArr.forEach((stats: any) => {
|
|
109
|
+
if (!stats) return;
|
|
110
|
+
const statsAssets = stats.toJson({ all: false, assets: true }).assets || [];
|
|
111
|
+
statsAssets
|
|
112
|
+
.filter((a: any) => canReadAsset(a.name))
|
|
113
|
+
.forEach((asset: any) => {
|
|
114
|
+
const filePath = path.join(root, asset.name);
|
|
115
|
+
let size = 0;
|
|
116
|
+
try {
|
|
117
|
+
const contents = fs.readFileSync(filePath);
|
|
118
|
+
size = gzipSize(contents);
|
|
119
|
+
} catch {
|
|
120
|
+
size = asset.size || 0;
|
|
121
|
+
}
|
|
122
|
+
const previousSize = sizes[removeFileNameHash(root, filePath)];
|
|
123
|
+
const difference = getDifferenceLabel(size, previousSize);
|
|
124
|
+
assets.push({
|
|
125
|
+
folder: path.join(path.basename(buildFolder), path.dirname(asset.name)),
|
|
126
|
+
name: path.basename(asset.name),
|
|
127
|
+
size,
|
|
128
|
+
sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : ''),
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
assets.sort((a, b) => b.size - a.size);
|
|
134
|
+
|
|
135
|
+
const longestSizeLabelLength = assets.length ? Math.max(...assets.map((a) => stripAnsi(a.sizeLabel).length)) : 0;
|
|
136
|
+
let suggestBundleSplitting = false;
|
|
137
|
+
|
|
138
|
+
assets.forEach((asset) => {
|
|
139
|
+
let { sizeLabel } = asset;
|
|
140
|
+
const sizeLength = stripAnsi(sizeLabel).length;
|
|
141
|
+
if (sizeLength < longestSizeLabelLength) {
|
|
142
|
+
sizeLabel += ' '.repeat(longestSizeLabelLength - sizeLength);
|
|
143
|
+
}
|
|
144
|
+
const isMainBundle = asset.name.indexOf('main.') === 0;
|
|
145
|
+
const maxRecommendedSize = isMainBundle ? maxBundleGzipSize : maxChunkGzipSize;
|
|
146
|
+
const isLarge = maxRecommendedSize && asset.size > maxRecommendedSize;
|
|
147
|
+
if (isLarge && /\.js$/.test(asset.name)) suggestBundleSplitting = true;
|
|
148
|
+
console.log(
|
|
149
|
+
' ' +
|
|
150
|
+
(isLarge ? chalk.yellow(sizeLabel) : sizeLabel) +
|
|
151
|
+
' ' +
|
|
152
|
+
chalk.dim(asset.folder + path.sep) +
|
|
153
|
+
chalk.cyan(asset.name),
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (suggestBundleSplitting) {
|
|
158
|
+
console.log();
|
|
159
|
+
console.log(chalk.yellow('The bundle size is significantly larger than recommended.'));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function stripAnsi(s: string): string {
|
|
164
|
+
// eslint-disable-next-line no-control-regex
|
|
165
|
+
return s.replace(/\x1B\[[0-9;]*m/g, '');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export default { measureFileSizesBeforeBuild, printFileSizesAfterBuild };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class InlineChunkHtmlPlugin {
|
|
4
|
+
constructor(htmlWebpackPlugin, tests) {
|
|
5
|
+
this.htmlWebpackPlugin = htmlWebpackPlugin;
|
|
6
|
+
this.tests = tests || [];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getInlinedTag(publicPath, assets, tag) {
|
|
10
|
+
if (tag.tagName !== 'script' || !(tag.attributes && tag.attributes.src)) {
|
|
11
|
+
return tag;
|
|
12
|
+
}
|
|
13
|
+
const scriptName = publicPath
|
|
14
|
+
? tag.attributes.src.replace(publicPath, '')
|
|
15
|
+
: tag.attributes.src;
|
|
16
|
+
|
|
17
|
+
if (!this.tests.some((test) => scriptName.match(test))) {
|
|
18
|
+
return tag;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const asset = assets[scriptName];
|
|
22
|
+
if (asset == null) {
|
|
23
|
+
return tag;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
tagName: 'script',
|
|
28
|
+
innerHTML: asset.source(),
|
|
29
|
+
closeTag: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
apply(compiler) {
|
|
34
|
+
let publicPath = compiler.options.output.publicPath || '';
|
|
35
|
+
if (publicPath && !publicPath.endsWith('/')) {
|
|
36
|
+
publicPath += '/';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
compiler.hooks.compilation.tap('InlineChunkHtmlPlugin', (compilation) => {
|
|
40
|
+
const tagFunction = (tag) =>
|
|
41
|
+
this.getInlinedTag(publicPath, compilation.assets, tag);
|
|
42
|
+
|
|
43
|
+
const hooks = this.htmlWebpackPlugin.getHooks(compilation);
|
|
44
|
+
hooks.alterAssetTagGroups.tap('InlineChunkHtmlPlugin', (assets) => {
|
|
45
|
+
assets.headTags = assets.headTags.map(tagFunction);
|
|
46
|
+
assets.bodyTags = assets.bodyTags.map(tagFunction);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Remove inlined assets from the output (best-effort)
|
|
50
|
+
compilation.hooks.processAssets.tap(
|
|
51
|
+
{
|
|
52
|
+
name: 'InlineChunkHtmlPlugin',
|
|
53
|
+
stage: compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE || 700,
|
|
54
|
+
},
|
|
55
|
+
(assets) => {
|
|
56
|
+
Object.keys(assets).forEach((assetName) => {
|
|
57
|
+
if (this.tests.some((test) => assetName.match(test))) {
|
|
58
|
+
delete compilation.assets[assetName];
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = InlineChunkHtmlPlugin;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const escapeStringRegexp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
4
|
+
|
|
5
|
+
class InterpolateHtmlPlugin {
|
|
6
|
+
constructor(htmlWebpackPlugin, replacements) {
|
|
7
|
+
this.htmlWebpackPlugin = htmlWebpackPlugin;
|
|
8
|
+
this.replacements = replacements || {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
apply(compiler) {
|
|
12
|
+
compiler.hooks.compilation.tap('InterpolateHtmlPlugin', (compilation) => {
|
|
13
|
+
const hooks = this.htmlWebpackPlugin.getHooks(compilation);
|
|
14
|
+
hooks.afterTemplateExecution.tap('InterpolateHtmlPlugin', (data) => {
|
|
15
|
+
Object.keys(this.replacements).forEach((key) => {
|
|
16
|
+
const value = this.replacements[key];
|
|
17
|
+
data.html = data.html.replace(
|
|
18
|
+
new RegExp('%' + escapeStringRegexp(key) + '%', 'g'),
|
|
19
|
+
value == null ? '' : String(value),
|
|
20
|
+
);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = InterpolateHtmlPlugin;
|