-
Notifications
You must be signed in to change notification settings - Fork 0
/
webpack.base.esm.mjs
11505 lines (10980 loc) · 609 KB
/
webpack.base.esm.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
157
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
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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* Project: web-project-template
* FileDirPath: webpack.base.esm.mjs
* Author: 12278
* Email: 1227839175@qq.com
* IDE: WebStorm
* CreateDate: 2022-01-01 00:00:00 星期六
*/
/**
* 该文件里的配置都是webpack中公共部分的配置,供webpack.dev.mjs、webpack.local.mjs、webpack.production.mjs、webpack.test.mjs使用。
*/
/**
* 可能需要修改的地方!
*
* 1、当需要将代码转换成兼容比较旧的平台时,需要修改:
* 变量browserslist。
* 变量esbuildMinify_target。
* 变量vue_loader_options_transpileOptions_target。
* package.json中的browserslist字段,值同变量browserslist。
* tsconfig.json中的compilerOptions.module、compilerOptions.target。
* tsconfig.webpack.json中的compilerOptions.module、compilerOptions.target。
* webpack的配置项:experiments、target、output.environment。
* 变量babel_targets中的esmodules选项、browsers选项。
* @babel/preset-env中的forceAllTransforms选项。
* vue-loader:options.transpileOptions.transforms。
* 变量esbuildMinifyConfig.format。
*
* 变量isUseESBuildLoader、变量isSPA、webpack的配置项:output.chunkLoadingGlobal、变量assetsWebpackPluginConfig中的配置、文件夹configures下的文件GlobalParameters.esm.mjs中的配置、变量cleanWebpackPluginConfig.cleanOnceBeforeBuildPatterns。
* 变量assetsWebpackPluginConfig.metadata:display、version。
* 变量moduleConfig里的cssLoader_url_import_IgnoreArr变量。
* 变量experimentsConfig.buildHttp中的allowedCondition变量。
*
* 2、如果本机总物理内存较小,记得改小jsWorkerPoolConfig.workerNodeArgs、forkTsCheckerWebpackPluginConfig.typescript.memoryLimit中设置的值。
* PS:本来想通过代码来动态的根据本机空闲内存来设置,但是不知为何会报错,只能写死设置。
*
* 3、本配置中的路径字符都是以Windows平台为主,没做其他系统平台的兼容,如果需要在其他系统平台使用,注意针对性修改如“./”、“//”、“\\”、“/”、“\”之类的路径。
*/
/**
* 关于webpack、babel的注意事项,可能导致编译后的代码报错或输出的代码非期望代码!!!
* 1、当babel启用removeConsole、removeDebugger这两个插件选项后,某些情况下会有意外的编译输出,详见如下:
* 说明:
* 如果在诸如console.log()中编写某些跟项目逻辑业务有关的代码,那么当启用removeConsole、removeDebugger时,会导致最后输出的代码中因删除了诸如console.log(),从而导致其中的某些跟项目逻辑业务有关的代码也被删除,最终使生产的代码出现非所愿期望的代码输出,从而报错。
* 所以,诸如console.log()中不要做任何逻辑处理(哪怕是:++index这种最简单的逻辑),只作为纯日志输出。
* 例如:
* let index = 0, arr001 = [ 'qqq', 'www', ], str001 = '';
*
* for( const item of arr001 ){
* str001 + = item;
*
* console.log( `index--->${ ++index }` );
* }
* 当没有启用removeConsole、removeDebugger时,执行上述代码后,index的值为3,但是如果启用removeConsole、removeDebugger,则index的值为0,那么显然这不是期望的。
*
* 对于上述的两个选项,当前配置是这样的,“webpack.test.mjs”中是false,webpack.production.mjs是true。
*/
'use strict';
import {
createReadStream,
readFileSync,
} from 'node:fs';
import {
cpus,
} from 'node:os';
import {
basename,
dirname,
join,
resolve,
} from 'node:path';
import {
argv,
} from 'node:process';
import {
fileURLToPath,
} from 'node:url';
import chalk from 'chalk';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import ESBuild from 'esbuild';
import ImageMinimizerPlugin from 'image-minimizer-webpack-plugin';
import JSON5 from 'json5';
import JsonMinimizerPlugin from 'json-minimizer-webpack-plugin';
import less from 'less';
import Mime from 'mime';
import package_json from './package.json' with { type: 'json', };
import postcss from 'postcss';
import * as DartSass from 'sass';
import Stylus from 'stylus';
import TerserPlugin from 'terser-webpack-plugin';
// import ThreadLoader from 'thread-loader';
import Toml from 'toml';
import tsconfig_webpack_json from './tsconfig.webpack.json' with { type: 'json', };
import webpack from 'webpack';
import Yaml from 'yamljs';
import DefinePluginConfig from './configures/DefinePluginConfig.esm.mjs';
import entryConfig from './configures/EntryConfig.esm.mjs';
import {
devServerGlobalParameters,
httpRequestHeaders,
HttpResponseHeadersFun,
} from './configures/GlobalParameters.esm.mjs';
import HTMLWebpackPluginConfig from './configures/HTMLWebpackPluginConfig.esm.mjs';
import {
CreateLogger,
} from './configures/Logger.esm.mjs';
import proxyConfig from './configures/ProxyConfig.esm.mjs';
/**
* 该函数返回值完全等价于“CommonJS modules”中的“__dirname”,是一个字符串,Windows系统下型如:G:\WebStormWS\xx\tools。<br />
*
* @param {string} import_meta_url 只传入import.meta.url即可,默认值(哈哈哈,这个默认值设置的有点多余,纯粹只是为了规避传空报错):import.meta.url,必需。
*
* @returns {string} 返回值完全等价于“CommonJS modules”中的“__dirname”,是一个字符串,Windows系统下型如:G:\WebStormWS\xx\tools。
*/
function Get__dirname( import_meta_url = import.meta.url ){
return dirname( Get__filename( import_meta_url ) );
}
/**
* 该函数返回值完全等价于“CommonJS modules”中的“__filename”,是一个字符串,Windows系统下型如:G:\WebStormWS\xx\7788.mjs。<br />
*
* @param {string} import_meta_url 只传入import.meta.url即可,默认值(哈哈哈,这个默认值设置的有点多余,纯粹只是为了规避传空报错):import.meta.url,必需。
*
* @returns {string} 返回值完全等价于“CommonJS modules”中的“__filename”,是一个字符串,Windows系统下型如:G:\WebStormWS\xx\7788.mjs。
*/
function Get__filename( import_meta_url = import.meta.url ){
return fileURLToPath( import_meta_url );
}
/**
* 表示项目文件夹根目录,不是磁盘根目录。<br />
*
* @type {string}
*/
const __dirname = Get__dirname( import.meta.url ),
/**
* env_platform的值是字符串,有4个值:'dev_server'、'local_server'、'test'、'production',来源是CLI参数中的“--env”参数值,注意“--env”参数是允许多个的哦。<br />
* 1、但是必须有这么一个“--env”参数设置,这4个之中的其中一个即可:--env platform=dev_server、--env platform=local_server、--env platform=test、--env platform=production。<br />
*
* @type {string|undefined}
*/
env_platform = ( argv => {
const envArr = [];
argv.forEach( ( item, index ) => {
if( item === '--env' ){
envArr.push( argv.at( index + 1 ) );
}
} );
if( envArr.length === 0 ){
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中没找到“--env”参数。注意“--env”参数是允许多个的哦。' );
}
const platformArr = [];
envArr.forEach( item => {
if( item.startsWith( 'platform=' ) ){
platformArr.push( item );
}
} );
if( platformArr.length === 0 ){
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中必须有这么一个“--env”参数设置,这4个之中的其中一个即可:--env platform=dev_server、--env platform=local_server、--env platform=test、--env platform=production。注意“--env”参数是允许多个的哦。' );
}
else if( platformArr.length > 1 ){
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中的“--env”参数设置,以“platform=”开头的值有且只能有一个,该值一般是这4个中的一个:platform=dev_server、platform=local_server、platform=test、platform=production。注意“--env”参数是允许多个的哦。' );
}
const str = platformArr.at( 0 ).replace( 'platform=', '' ).trim();
if( [
'dev_server',
'local_server',
'test',
'production',
].includes( str ) ){
return str;
}
else{
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中的“--env”参数设置,以“platform=”开头的值,在“platform=”之后紧跟的只能是这4个中的一个:dev_server、local_server、test、production。注意“--env”参数是允许多个的哦。' );
}
} )( argv ),
/**
* isProduction的值为true时表示生产环境,反之开发环境,该值依赖CLI参数中的“--mode”参数值。<br />
* 1、有效的“--mode”参数设置是:--mode development(用于开发)、--mode production(用于生产)。<br />
*
* @type {boolean}
*/
isProduction = ( argv => {
const num1 = argv.findIndex( c => c === '--mode' );
if( num1 !== -1 ){
const str1 = argv.at( num1 + 1 );
if( String( str1 ) === 'development' ){
return false;
}
else if( String( str1 ) === 'production' ){
return true;
}
else{
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中紧跟在“--mode”之后的,只能是development(用于开发)、production(用于生产)。有效的“--mode”参数设置是:--mode development、--mode production。' );
}
}
else{
console.log( chalk.cyan( `\n${ JSON.stringify( argv ) }\n` ) );
throw new Error( 'CLI参数中没找到“--mode”参数。' );
}
} )( argv ),
/**
* 是否将项目设置成单页面应用程序(SPA),true表示单页面应用程序(SPA),false表示多页面应用程序(MPA)。<br />
*
* @type {boolean}
*/
isSPA = false,
/**
* true表示启用esbuild-loader来转译js、ts,false表示用babel来转译js、ts,esbuild-loader是不需要thread-loader来加速的!它自己已经是很快很快很快了。<br />
* 1、如果需要兼容到低端平台,即转译到ES5、ES3的话,还是使用babel来转译,将isUseESBuildLoader设置成false。<br />
* 2、如果是兼容到新的现代浏览器,也就是支持ES6的平台,那么还是用esbuild吧,它有这方面的优越性,但就是对ES5不是很友好。<br />
* 3、目前esbuild对有些处于提案阶段的实验性语法还不能支持,所以,如果需要兼顾前面两点,那还是要继续使用babel来转译的。<br />
* 4、截至2022年11月08日,基于最新的esbuild版本做测试,其只能支持对静态的导入、导出的代码做“Tree Shaking”,动态的还不支持,而webpack在“Tree Shaking”做的会比它好,希望其未来能做到跟webpack一样的“Tree Shaking”功能吧。<br />
*
* @type {boolean}
*/
isUseESBuildLoader = false,
/**
* 是否在控制台输出Babel的插件调试日志。<br />
* 1、会使用“console.log”输出由preset-env启用的polyfill和转换插件,并且会输出哪些目标需要它。<br />
* 2、比如输出日志中有:proposal-class-static-block { chrome < 94, firefox < 93, opera < 80, safari }。<br />
* 说明:表示当编译目标为chrome < 94, firefox < 93, opera < 80, safari这些时,会启用“proposal-class-static-block”。<br />
*
* @type {boolean}
*/
isBabelDebug = false,
/**
* 当启用实验性选项experiments.buildHttp时,是否要处理CSS文件中的远程资源URL。true表示处理,false表示不处理,将其原样保留在代码中。<br />
* 1、远程资源的加载是需要耗时下载的,所以,webpack的编译时间也受其影响。<br />
*
* @type {boolean}
*/
isHandle_experiments_buildHttp_in_CSSLoader = true,
/**
* 不通过webpack处理css中以如下设置的值开头的url。
*
* @returns {string[]}
*/
cssLoader_url_import_IgnoreHandle = ( experimentsConfig, isHandle_experiments_buildHttp_in_CSSLoader ) => {
return [
'../static/',
'//',
...( () => {
return ( ( 'buildHttp' in experimentsConfig ) && isHandle_experiments_buildHttp_in_CSSLoader )
? []
: [
'http',
];
} )(),
];
},
/**
* 允许以哪些开头的远程链接。<br />
*
* @type {string[]}
*/
allowedCondition = [
'http',
// 'https://www.xxx.com/',
];
console.log( chalk.cyan( `\n当前使用“${ isUseESBuildLoader
? 'ESBuild'
: 'Babel' }”处理“JS”、“TS”等等脚本!!!\n` ) );
/**
* 目标浏览器版本。
*
* @type {string[]}
*/
const browserslist = [
// PC端完全支持ES 5的主流浏览器 Start
// 'Chrome >= 23',
// 'Firefox >= 21',
// ie 9不支持ECMAScript 5的"use strict",但是ie 10真正的完全支持ECMAScript 5了。
// 'ie >= 9',
// 'Safari >= 6',
// Opera 15开始改用基于Chromium 28的,也是从15开始其内核跟Chrome一致了。
// 'Opera >= 15',
// PC端完全支持ES 5的主流浏览器 End
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 Start
// 'Chrome >= 58',
// 'Firefox >= 54',
// 这里的Edge是指旧版的微软Edge(版本从12到18),它是用微软的浏览器引擎EdgeHTML和他们的Chakra JavaScript引擎构建的。
// 'Edge >= 14',
// 'Safari >= 10',
// 'Opera >= 55',
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 End
// PC端各主流浏览器的最新版本,至20240518。Start
'Chrome >= 125',
// 这里的Edge是指新版的微软Edge,其基于Chromium,带有Blink和V8引擎,后来其最新的版本号,也基本跟Chrome版本号保持一致了。
'Edge >= 125',
'Firefox >= 126',
'Safari >= 17',
'Opera >= 110',
// PC端各主流浏览器的最新版本,至20240518。End
// 移动端各主流浏览器的最新版本,至20240518。Start
'ChromeAndroid >= 125',
// 从Android 4.4后Android WebView直接跟Chrome同步。
'Android >= 125',
'FirefoxAndroid >= 126',
'iOS >= 17',
// 移动端各主流浏览器的最新版本,至20240518。End
],
/**
* 每个目标环境都是一个环境名称,后跟一个版本号。当前支持以下环境名称:<br />
* 1、chrome、edge、firefox、hermes、ie、ios、node、deno、opera、rhino、safari。<br />
* 2、还可以是这样的:es2020、esnext、node12、node12.19.0、es5、es6、deno1.0。<br />
*
* @type {string[]}
*/
esbuildMinify_target = [
// PC端完全支持ES 5的主流浏览器 Start
// 'chrome23',
// 'firefox21',
// ie 9不支持ECMAScript 5的"use strict",但是ie 10真正的完全支持ECMAScript 5了。
// 'ie9',
// 'safari6',
// Opera 15开始改用基于Chromium 28的,也是从15开始其内核跟Chrome一致了。
// 'opera15',
// PC端完全支持ES 5的主流浏览器 End
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 Start
// 'chrome58',
// 'firefox54',
// 这里的Edge是指旧版的微软Edge(版本从12到18),它是用微软的浏览器引擎EdgeHTML和他们的Chakra JavaScript引擎构建的。
// 'edge14',
// 'safari10',
// 'opera55',
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 End
'es2023',
// PC端各主流浏览器的最新版本,至20240518。Start
'chrome125',
'edge125',
'firefox126',
'safari17',
'opera110',
// PC端各主流浏览器的最新版本,至20240518。End
// 移动端各主流浏览器的最新版本,至20240518。Start
'ios17',
// 移动端各主流浏览器的最新版本,至20240518。End
],
/**
* 目标浏览器版本。<br />
* 1、支持的标识符有:<br />
* android、chrome、deno(支持的最低版本为'1.0')、edge、electron、firefox、ie、ios、node、opera、rhino、safari、samsung,其他的会报错。<br />
* 具体见:node_modules/@babel/helper-compilation-targets/lib/options.js。<br />
* 2、也支持其他的别名标识符,但是不建议用别名标识符,因为如果设置了这些别名会报错(因为相关代码貌似并没使用这个别名映射):<br />
* and_chr(对应:chrome)、and_ff(对应:firefox)、ios_saf(对应:ios)、ie_mob(对应:ie)、op_mob(对应:opera)。<br />
* 其他的别名会报错。<br />
* 具体见:node_modules/@babel/core/lib/config/validation/option-assertions.js。<br />
*
* @type {object}
*/
vue_loader_options_transpileOptions_target = {
// PC端完全支持ES 5的主流浏览器 Start
// chrome: 23,
// firefox: 21,
// ie 9不支持ECMAScript 5的"use strict",但是ie 10真正的完全支持ECMAScript 5了。
// ie: 9,
// safari: 6,
// Opera 15开始改用基于Chromium 28的,也是从15开始其内核跟Chrome一致了。
// opera: 15,
// PC端完全支持ES 5的主流浏览器 End
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 Start
// chrome: 58,
// firefox: 54,
// 这里的Edge是指旧版的微软Edge(版本从12到18),它是用微软的浏览器引擎EdgeHTML和他们的Chakra JavaScript引擎构建的。
// edge: 14,
// safari: 10,
// opera: 55,
// PC端完全支持ES 6(ECMAScript 2015)的主流浏览器 End
// PC端各主流浏览器的最新版本,至20240518。Start
chrome: 125,
edge: 125,
firefox: 126,
safari: 17,
opera: 110,
// PC端各主流浏览器的最新版本,至20240518。End
// 移动端各主流浏览器的最新版本,至20240518。Start
/*从Android 4.4后Android WebView直接跟Chrome同步。*/
android: 125,
ios: 17,
// 移动端各主流浏览器的最新版本,至20240518。End
},
/**
* 编译目标配置。
*
* @type {object}
*/
babel_targets = {
...vue_loader_options_transpileOptions_target,
/**
* 您还可以针对支持ES模块的浏览器,当指定esmodules目标时,它将与browsers目标和browserslist的目标相交。您可以将此方法与<script type="module"></script>结合使用,以有条件地向用户提供较小的脚本。<br />
* 1、值类型:boolean,true表示输出支持ES的模块化的代码。<br />
* 2、当esmodules选项为true时,下面的browsers选项将会被忽略。<br />
*/
// esmodules: true,
// 如果要针对Safari的技术预览版进行编译,可以指定safari: 'tp',当前先使用vue_loader_options_transpileOptions_target中的safari版本。
// safari: 'tp',
/**
* 1、值类型:string、Array<string>。使用browserslist选择浏览器的查询:last 2 versions, > 5%, safari tp。<br />
* 2、当上面的esmodules选项为true时,下面的browsers选项将会被忽略。<br />
*/
browsers: browserslist,
// 注意:uglify选项已被弃用,并将在下一个主要版本中删除。
// uglify: null,其实我也不知道这个选项的值类型。
};
// autoprefixer共有三种类型的控制注释:
// /* autoprefixer: (on|off) */:在注释前后“启用/禁用”整个块的所有Autoprefixer翻译。
// /* autoprefixer: ignore next */:仅为下一个属性或下一个规则选择器或规则参数(但不规则/规则正文)禁用自动前缀。
// /* autoprefixer grid: (autoplace|no-autoplace|off) */:控制Autoprefixer如何处理整个块的网格转换:
// autoplace:启用带有自动放置支持的网格翻译。
// no-autoplace:在禁用自动放置支持的情况下启用网格转换,但不支持自动放置(该值是值on的别名,但是值on是一个已弃用的值)。
// off:禁用所有网格翻译。
/**
* @type {object}
*/
const autoprefixerConfig = {
// 如果CSS未压缩,Autoprefixer应该使用Visual Cascade。默认值:true。
cascade: true,
// Autoprefixer应该添加前缀。默认为true。
add: true,
// 应该Autoprefixer[删除过时的]前缀。默认为true。
remove: false,
// Autoprefixer应该为@supports参数添加前缀。默认为true。
supports: true,
// 值类型:boolean、string,Autoprefixer应该为flexbox属性添加前缀。使用“no-2009”值,Autoprefixer将只为规范的最终版本和IE 10版本添加前缀。默认为true。
flexbox: true,
/**
* 处理grid布局,有效值为:false、'autoplace'、'no-autoplace'。
* 1、默认值为false,防止Autoprefixer输出CSS Grid翻译。<br />
* 2、在您的项目根目录中运行npx autoprefixer --info以检查选择了哪些浏览器以及将为哪些属性添加前缀。<br />
*/
// autoplace:启用Autoprefixer网格翻译并包括自动放置支持。您还可以在CSS中使用魔术注释:/* autoprefixer grid: autoplace */。
// no-autoplace:该选项值是已弃用的选项值true的别名,启用Autoprefixer网格翻译,但不支持自动放置。您还可以在CSS中使用/* autoprefixer grid: no-autoplace */。
// 将自动放置集成到现有项目中的绝对最佳方法是默认关闭自动放置,然后在需要时使用控制注释启用它。这种方法不太可能导致网站上的某些东西损坏。
// 也就是在CSS文件的最顶部使用/* autoprefixer grid: no-autoplace */来关闭自动放置,但是在需要的地方使用/* autoprefixer grid: autoplace */来开启自动放置。
grid: 'autoplace',
// 不要在Browserslist配置中引发未知浏览器版本的错误。默认为false。
ignoreUnknownVersions: false,
},
/**
* @type {object}
*/
esbuildMinifyConfig = {
// 有效值有:'js'、'jsx'、'ts'、'tsx'、'css'、'json'、'text'、'base64'、'file'、'dataurl'、'binary'、'copy'、'default'。
loader: 'js',
minifyWhitespace: true,
minifyIdentifiers: true,
minifySyntax: true,
/**
* “法律注释(legal comment)”被认为是JS中的任何语句级注释或CSS中包含@license或@preserve或以//!或者/*!开头的任何规则级注释。<br />
* 1、默认情况下,这些注释保留在输出文件中,因为这遵循了代码原作者的意图。<br />
* 2、有效值说明:<br />
* 'none':不要保留任何法律评论。<br />
* 'inline':保留所有法律评论。<br />
* 'eof':将所有法律注释移至文件末尾。<br />
* 'linked':将所有法律评论移至.LEGAL.txt文件并使用评论链接到它们。<br />
* 'external':将所有法律评论移至.LEGAL.txt文件,但不要链接到它们。<br />
*/
legalComments: 'none',
// 值有:'ascii'、'utf8'。
charset: 'utf8',
color: true,
// 这将设置生成的JavaScript文件的输出格式。当前可以配置三个可能的值:iife、cjs、esm。
format: 'esm',
/**
* 1、esbuild的“tree shaking”只能删除声明级别的死代码。<br />
* 2、请注意,esbuild的“tree shaking”实现依赖于ECMAScript模块导入和导出语句的使用,它不适用于CommonJS模块。<br />
* 3、用于“tree shaking”的“side effects(副作用)”检测是保守的,这意味着esbuild仅在能够确保没有隐藏的副作用时才将可移除的代码视为死代码。<br />
*/
// 4、可以使用/* @__PURE__ */注释,明确表示该表达式是无副作用的,由于注释的原因,这被认为是无副作用的,如果未使用,将被删除。
/*
// 例子:
let gammaTable = 无副作用的注释 (() => {
// 此处跳过副作用检测。
let table = new Uint8Array(256);
for (let i = 0; i < 256; i++)
table[i] = Math.pow(i / 255, 2.2) * 255;
return table;
})();
*/
treeShaking: isProduction,
/**
* 代码拆分仍然是一项正在进行的工作。
* 它目前只适用于esm输出格式,也就是说当选项“format”的值为'esm'时,该选项有效。
* 还有一个已知的跨代码拆分块的导入语句的排序问题。你可以关注跟踪问题,以了解关于这个功能的更新。
* 详细见:https://esbuild.github.io/api/#splitting
*/
splitting: true,
// 详细见:https://esbuild.github.io/api/#ignore-annotations
ignoreAnnotations: false,
// 有效值有:browser、node、neutral。
platform: 'browser',
keepNames: true,
mangleQuoted: false,
// 日志限制可以更改为另一个值,也可以通过将其设置为0来完全禁用。这将显示所有日志消息。
logLimit: 0,
/**
* 当使用babel转换JS语法时,drop选项(相当于babel的removeConsole、removeDebugger)不使用,其同样的功能交给babel预设处理,这里就不用重复设置了。但是如果使用esbuild转换JS时,还是要启用drop选项的。<br />
*
* 注意:<br />
* 如果在诸如console.log()中编写某些跟项目逻辑业务有关的代码,那么当启用removeConsole、removeDebugger时,会导致最后输出的代码中因为删除了诸如console.log(),从而导致其中的某些跟项目逻辑业务有关的代码也被删除,最终使生产的代码出现非所愿期望的代码输出,从而报错。<br />
* 所以,诸如console.log()中不要做任何逻辑处理(哪怕是:++index这种最简单的逻辑),只作为纯日志输出。<br />
* 例如:<br />
* let index = 0, arr001 = [ 'qqq', 'www', ], str001 = '';
*
* for( const item of arr001 ){
* str001 + = item;
*
* console.log( `index--->${ ++index }` );
* }
* 当没有启用removeConsole、removeDebugger时,执行上述代码后,index的值为3,但是如果启用removeConsole、removeDebugger,则index的值为0,那么显然这不是期望的。<br />
*
* 对于drop选项,当前配置是这样的,“webpack.test.mjs”中不设置drop选项(对应的是不删除操作),webpack.production.mjs中设置drop选项(对应的是删除操作)。<br />
*/
...( () => {
return isUseESBuildLoader
? {
...( () => {
if( env_platform === 'dev_server' ){
return {};
}
else if( env_platform === 'local_server' ){
return {};
}
else if( env_platform === 'test' ){
return {};
}
else if( env_platform === 'production' ){
return {
drop: [
'debugger',
'console',
],
};
}
else{
return {};
}
} )(),
}
: {};
} )(),
target: esbuildMinify_target,
// 有效值有:silent、error、warning、info、debug、verbose。
logLevel: 'error',
logOverride: {
'assign-to-constant': 'error',
'assign-to-import': 'error',
'call-import-namespace': 'error',
'commonjs-variable-in-esm': 'error',
'delete-super-property': 'error',
'duplicate-case': 'error',
'duplicate-object-key': 'error',
'empty-import-meta': 'error',
// 浮点相等的定义使得NaN永远不等于任何东西,所以"x === NaN"总是返回假。您需要使用“isNaN(x)”来测试NaN。
'equals-nan': 'error',
// 浮点相等定义为0和-0相等,因此"x === -0"返回true。您需要使用“Object.is(x, -0)”来测试-0。
'equals-negative-zero': 'error',
'equals-new-object': 'error',
'html-comment-in-js': 'error',
// 表达式“typeof x”实际上在JavaScript中计算为“object”,而不是“null”。你需要使用“x === null”来测试null。
'impossible-typeof': 'error',
'indirect-require': 'error',
'private-name-will-throw': 'error',
'semicolon-after-return': 'warning',
// 代码“!x in y”被解析为“(!x) in y”。您需要插入括号才能获得“!(x in y)”。
'suspicious-boolean-not': 'error',
// 当文件是ECMAScript模块[this-is-undefined-in-esm],因此顶级“this”将被替换为undefined。
'this-is-undefined-in-esm': 'warning',
// 此“import”表达式不会被捆绑(import(foo)),因为参数不是字符串文字。
'unsupported-dynamic-import': 'warning',
'unsupported-jsx-comment': 'error',
// 正则表达式标志“d”在配置的目标环境(“chrome50”)中不可用。此正则表达式文字已转换为“new RegExp()”构造函数以避免生成带有语法错误的代码。但是,您需要为“RegExp”包含一个polyfill您的代码在运行时具有正确的行为。
'unsupported-regexp': 'warning',
'unsupported-require-call': 'warning',
'css-syntax-error': 'error',
'invalid-@charset': 'error',
'invalid-@import': 'warning',
'invalid-@layer': 'warning',
'invalid-calc': 'error',
'js-comment-in-css': 'warning',
'unsupported-@charset': 'error',
'unsupported-@namespace': 'error',
'unsupported-css-property': 'warning',
'unsupported-css-nesting': 'error',
'ambiguous-reexport': 'warning',
'different-path-case': 'silent',
'ignored-bare-import': 'error',
'ignored-dynamic-import': 'silent',
'import-is-undefined': 'error',
'require-resolve-not-external': 'error',
'package.json': 'error',
'tsconfig.json': 'error',
},
},
/**
* 详细见:
* node_modules/@types/html-minifier-terser/index.d.ts:15
*
* @type {object}
*/
HTMLMinifyConfig = {
// 以区分大小写的方式处理属性(对自定义HTML标签有用)。
caseSensitive: false,
// 从布尔属性中省略属性值。
collapseBooleanAttributes: false,
// 不要在display:inline;之间留下任何空格。折叠时的元素。必须与collapseWhitespace=true结合使用。
collapseInlineTagWhitespace: true,
// 折叠有助于文档树中文本节点的空白。
collapseWhitespace: true,
// 总是折叠到1个空格(永远不要完全删除它)。必须collapseWhitespace=true结合使用。
conservativeCollapse: false,
// 处理解析错误而不是中止。
continueOnParseError: false,
// 尽可能使用直接Unicode字符。
decodeEntities: false,
// 根据HTML5规范解析输入。
html5: true,
// 插入HTML解析器生成的标签。
includeAutoGeneratedTags: true,
// 在单例元素上保留斜杠。
keepClosingSlash: true,
// 缩小样式元素和样式属性中的CSS(使用clean-css)。
minifyCSS: isProduction,
// 缩小脚本元素和事件属性中的JavaScript(使用Terser)。
minifyJS: isProduction,
// 缩小各种属性中的URL(使用relateurl来处理的)。
minifyURLs: false,
// 切勿在关闭元素的标记之前添加换行符。
noNewlinesBeforeTagClose: false,
// 当标签之间的空格包含换行符时,总是折叠到1个换行符(永远不要完全删除它)。必须与collapseWhitespace=true结合使用。
preserveLineBreaks: false,
// 防止属性值的转义。
preventAttributesEscaping: false,
// 通过minifier处理条件注释的内容。
processConditionalComments: false,
// 尽可能删除属性周围的引号。
removeAttributeQuotes: false,
// 去除HTML注释。
removeComments: true,
// 删除所有具有纯空格值的属性。
removeEmptyAttributes: false,
// 删除所有内容为空的元素。
removeEmptyElements: false,
// 删除可选标签。
removeOptionalTags: false,
// 当值与默认值匹配时删除属性。
removeRedundantAttributes: false,
// 从脚本标签中删除type="text/javascript"其他类型属性值保持不变。
removeScriptTypeAttributes: false,
// 从样式和链接标签中删除type="text/css"其他类型属性值保持不变。
removeStyleLinkTypeAttributes: false,
// 尽可能删除属性之间的空格。请注意,这将导致HTML无效!
removeTagWhitespace: false,
// 按频率排序属性。
sortAttributes: false,
// 按频率对样式类进行排序。
sortClassName: false,
// 修剪ignoreCustomFragments周围的空白。
trimCustomFragments: false,
// 用短 (HTML5) 文档类型替换文档类型。
useShortDoctype: false,
},
/**
* @type {object}
*/
postcssCalcConfig = {
// 默认值为5,允许您定义十进制数的精度。
precision: 6,
// 默认值为false,允许您在输出中保留calc() 用法,以便浏览器自己处理小数精度。
preserve: true,
// 默认值为false,当calc()未减少为单个值时添加警告。
warnWhenCannotResolve: false,
// 默认值为false,允许将calc()用作媒体查询声明的一部分。
mediaQueries: true,
// 默认值为false,允许将calc()用作选择器的一部分。
selectors: true,
},
/**
* @type {array}
*/
watchIgnoredArr = [
resolve( __dirname, './.git/' ),
resolve( __dirname, './.idea/' ),
resolve( __dirname, './assist_tools/' ),
resolve( __dirname, './backups/' ),
resolve( __dirname, './bats/' ),
resolve( __dirname, './configures/' ),
resolve( __dirname, './dist/' ),
resolve( __dirname, './log/' ),
resolve( __dirname, './node_modules/' ),
resolve( __dirname, './notes/' ),
resolve( __dirname, './read_me/' ),
resolve( __dirname, './simulation_servers/' ),
resolve( __dirname, './test/' ),
resolve( __dirname, './ts_compiled/' ),
resolve( __dirname, './webpack_location/' ),
resolve( __dirname, './webpack_records/' ),
],
/**
* 默认情况下,它只影响按需块,因为更改初始块会影响HTML文件应包含以运行项目的脚本标记。<br />
* 1、Webpack将根据这些条件自动拆分块:<br />
* 可以共享新块或模块来自node_modules文件夹。<br />
* 新块将大于20kb(在min+gz 之前)。<br />
* 按需加载块(Async块)时的最大并行请求数将低于或等于30。<br />
* 初始页面加载时的最大并行请求数将低于或等于30。<br />
* 2、当试图满足上述最后2个条件时,首选更大的块。<br />
* 3、选择默认配置以适应Web性能最佳实践,但您的项目的最佳策略可能会有所不同。如果您要更改配置,您应该衡量更改的效果,以确保有真正的好处。<br />
* 4、从webpack 5开始,不再允许将条目名称传递给{cacheGroup}.test并将现有块的名称用于{cacheGroup}.name。<br />
*
* @type {object}
*/
splitChunksConfig = {
/**
* 默认情况下,webpack将使用块的来源和名称生成名称(例如:vendor~main.js)。此选项允许您指定用于生成名称的分隔符。<br />
* 1、值类型:string,默认值:'~'。<br />
*/
automaticNameDelimiter: '__',
/**
* 这表明将选择对哪些块进行优化。<br />
* 1、值类型:string(只有3个有效值:'all'、'async'、'initial')、chunk => boolean,默认值:'all'。<br />
* 2、当提供值为'all',可能特别强大,因为这意味着即使在异步和非异步块之间也可以共享块。<br />
* 3、该选项也可以在splitChunks.fallbackCacheGroup中使用。<br />
*/
chunks: 'all',
/**
* 按需加载(Async块)时的最大并行请求数。<br />
* 1、值类型:number,默认值:30。<br />
*/
maxAsyncRequests: 100,
/**
* 入口点的最大并行请求数。
* 1、值类型:number,默认值:30。<br />
*/
maxInitialRequests: 100,
/**
* 使用数字限制文件大小时,有哪些类型的文件可以受数字限制文件大小。<br />
* 1、值类型:[string],默认值:[ 'javascript', 'unknown', ]。<br />
*/
defaultSizeTypes: [
// '...'值大概是表示扩展吧!
'...',
// 'css/mini-extract'值来自node_modules/mini-css-extract-plugin/types/utils.d.ts:37。
'css/mini-extract',
'javascript',
'css',
'unknown',
'webassembly',
],
/**
* 在拆分之前,模块必须在块之间共享的最少次数。<br />
* 1、值类型:number,默认值:1。<br />
*/
minChunks: 1,
/**
* 在为按maxSize分割的部分创建名称时防止暴露路径信息。<br />
* 1、值类型:boolean,默认值:false。<br />
*/
hidePathInfo: isProduction,
/**
* 要生成新的拆分块的最小大小(以字节为单位)。<br />
* 1、值类型:number(默认值:20000)、{ [index: string]: number }。<br />
*/
minSize: 800 * 1024,
/**
* 生成新的拆分块所需的主块(包)的最小大小减少(以字节为单位)。这意味着如果拆分成1个新的拆分块不会将主块(捆绑)的大小减少给定的字节数,那么即使它满足splitChunks.minSize值,它也不会被拆分。<br />
* 1、值类型:number(默认值:0)、{ [index: string]: number }。<br />
* 2、splitChunks.minSizeReduction和splitChunks.minSize都需要满足才能生成新的拆分块。<br />
*/
minSizeReduction: 0,
/**
* 设置1个强制拆分的大小阈值,超过这个阈值就强制拆分。其他限制(minRemainingSize、maxAsyncRequests、maxInitialRequests)的大小阈值都被忽略(以字节为单位)。<br />
* 1、值类型:number,默认值:50000。<br />
* 2、该选项也可以用于splitChunks.cacheGroups.{cacheGroup}.enforceSizeThreshold。<br />
*/
enforceSizeThreshold: 1 * 1024 * 1024,
/**
* 在webpack 5中引入了splitChunks.minRemainingSize选项,通过确保拆分后剩余的块的最小大小高于限制来避免零大小的模块。<br />
* 1、值类型:number,默认值:0。<br />
* 2、在“开发”模式下默认为0。对于其他情况,splitChunks.minRemainingSize默认为splitChunks.minSize的值,因此除了需要深度控制的极少数情况外,不需要手动指定。<br />
* 3、该选项也可以用于splitChunks.cacheGroups.{cacheGroup}.minRemainingSize。<br />
* 4、splitChunks.minRemainingSize仅在剩余单个块时生效。<br />
*/
minRemainingSize: isProduction
? 100 * 1024
: 0,
/**
* 按模块层将模块分配给缓存组。<br />
* 1、值类型:RegExp、string、function。<br />
* 2、该选项也可以用于splitChunks.cacheGroups.{cacheGroup}.layer。<br />
*/
// layer: null,其实我也不知道这个选项的默认值是什么。
/**
* 使用maxSize告诉webpack尝试将大于maxSize字节的块拆分为更小的部分。<br />
* 1、值类型:number,默认值:0。<br />
* 2、该选项也可用于每个缓存组optimization.splitChunks.cacheGroups[x].maxSize或后备缓存组optimization.splitChunks.fallbackCacheGroup.maxSize 。<br />
* 3、零件的大小至少为minSize,该算法是确定性的,对模块的更改只会产生局部影响。<br />
* 4、这样它在使用长期缓存时可用并且不需要记录。maxSize只是一个提示,当模块大于maxSize或拆分会违反minSize时可能会违反。<br />
* 5、当块已经有名称时,每个部分都会从该名称中获得一个新名称。根据optimization.splitChunks.hidePathInfo的值,它将添加从第一个模块名称或它的哈希派生的键。<br />
* 6、maxSize选项旨在与HTTP/2和长期缓存一起使用。它增加了请求计数以获得更好的缓存。它还可以用于减小文件大小以加快重建速度。<br />
* 7、maxSize的优先级高于maxInitialRequest/maxAsyncRequests。实际优先级是maxInitialRequest/maxAsyncRequests < maxSize < minSize。<br />
* 8、设置maxSize的值会同时设置maxAsyncSize和maxInitialSize的值。<br />
*/
maxSize: 1 * 1024 * 1024,
/**
* maxAsyncSize和maxSize之间的区别在于maxAsyncSize只会影响按需加载块。<br />
* 1、值类型:number,默认值:0。<br />
*/
// maxAsyncSize: 1 * 1024 * 1024,
/**
* maxInitialSize和maxSize的区别在于maxInitialSize只会影响初始加载块。<br />
* 1、值类型:number,默认值:0。<br />
*/
// maxInitialSize: 1 * 1024 * 1024,
/**
* 拆分块的名称。提供false将保持块的相同名称,因此它不会不必要地更改名称。这是生产构建的推荐值。<br />
* 1、提供字符串或函数允许您使用自定义名称。指定一个字符串或一个总是返回相同字符串的函数会将所有常见的模块和供应商合并到一个块中。<br />
* 2、这可能会导致更大的初始下载并减慢页面加载速度。<br />
* 3、如果您选择指定一个函数,您可能会发现chunk.name和chunk.hash属性(其中chunk是chunks数组的一个元素)在为您的块选择名称时特别有用。<br />
* 4、如果splitChunks.name与入口点名称匹配,则入口点将被删除。<br />
*/
// name: false,
/**
* 找出模块使用哪些导出来破坏导出名称,省略未使用的导出并生成更高效的代码。当它为true时:分析每个运行时使用的导出,当它是“global”时:全局分析所有运行时组合的导出。<br />
* 1、值类型:boolean,默认值:true。<br />
*/
usedExports: true,
/**
* 缓存组可以继承和/或覆盖splitChunks.*的任何选项;但是test、priority和reuseExistingChunk只能在缓存组级别进行配置。要禁用任何默认缓存组,请将它们设置为false。<br />
*/
cacheGroups: ( () => {
/**
* 单页模式下的代码拆分策略。
*/
const SPACacheGroups = {
VendorsCSS: {
/**
* 控制此缓存组选择哪些模块。省略它会选择所有模块。它可以匹配绝对模块资源路径或块名称。当块名称匹配时,块中的所有模块都会被选中。<br />
* 1、值类型:( module, { chunkGraph, moduleGraph, } ) => boolean、RegExp、string。<br />
* 2、当选择使用函数作为test选项的值时,函数的第1个参数module有如下参数:<br />
* module.resource:1个描述模块所在文件在磁盘上的绝对路径字符串。<br />
* module.type:1个描述模块类型的字符串,如:'javascript/auto'。<br />
* 3、请注意使用`[\\/]`作为跨平台兼容性的路径分隔符。<br />
*/
test: /node_modules[\\/].*\.css$/i,
// 值类型:function、RegExp、string,允许按模块类型将模块分配给缓存组。
...( () => {
return isProduction
? {
type: 'css/mini-extract',
}
: {};
} )(),
name: 'VendorsCSS',
},
VendorsJS: ( arr => {
return {
test: new RegExp( `node_modules[\\\\/](?!${ arr.map( item => item + '[\\\\/]' ).join( '|' ) }).*\\.(js)$`, 'i' ),
name: 'VendorsJS',
};
} )( [
'axios',
'echarts',
'jquery',
'swiper',
'vue',
'vue-router',
'vuex',
'element-ui',
'element-plus',
] ),
EchartsJS: {
test: /node_modules[\\/]echarts[\\/].*\.(js)$/i,
name: 'EchartsJS',
},
Vendors001JS: ( arr => {
return {
test: new RegExp( `node_modules[\\\\/](${ arr.map( item => item + '[\\\\/]' ).join( '|' ) }).*\\.(js)$`, 'i' ),
name: 'Vendors001JS',
};
} )( [
'axios',
'jquery',
'swiper',
] ),
VueFamilyJS: ( arr => {
return {
test: new RegExp( `node_modules[\\\\/](${ arr.map( item => item + '[\\\\/]' ).join( '|' ) }).*\\.(js)$`, 'i' ),
name: 'VueFamilyJS',
};
} )( [
'vue',
'vue-router',
'vuex',
] ),
ElementUIJS: ( arr => {
return {
test: new RegExp( `node_modules[\\\\/](${ arr.map( item => item + '[\\\\/]' ).join( '|' ) }).*\\.(js)$`, 'i' ),
name: 'ElementUIJS',
};
} )( [
'element-ui',
'element-plus',
] ),
};
/**
* 多页模式下的代码拆分策略。
*/
const MPACacheGroups = {
VendorsCSS: ( arr => {
return {
/**
* 控制此缓存组选择哪些模块。省略它会选择所有模块。它可以匹配绝对模块资源路径或块名称。当块名称匹配时,块中的所有模块都会被选中。<br />
* 1、值类型:( module, { chunkGraph, moduleGraph, } ) => boolean、RegExp、string。<br />
* 2、当选择使用函数作为test选项的值时,函数的第1个参数module有如下参数:<br />
* module.resource:1个描述模块所在文件在磁盘上的绝对路径字符串。<br />
* module.type:1个描述模块类型的字符串,如:'javascript/auto'。<br />
* 3、请注意使用`[\\/]`作为跨平台兼容性的路径分隔符。<br />
*/
test: new RegExp( `node_modules[\\\\/](?!${ arr.map( item => item + '[\\\\/]' ).join( '|' ) }).*\\.css$`, 'i' ),
// 值类型:function、RegExp、string,允许按模块类型将模块分配给缓存组。
...( () => {
return isProduction