1+ const { paths } = require ( 'react-app-rewired' ) ;
2+ const HtmlWebpackPlugin = require ( 'html-webpack-plugin' ) ;
3+ const path = require ( 'path' ) ;
4+ const fs = require ( 'fs' ) ;
5+ const globby = require ( 'globby' ) ;
6+ const appDirectory = fs . realpathSync ( process . cwd ( ) ) ;
7+ const resolveApp = relativePath => path . resolve ( appDirectory , relativePath ) ;
8+ // const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
9+
10+ module . exports = function override ( config , env ) {
11+ // 入口文件路径
12+ // const entriesPath = globby.sync([resolveApp('src') + '/*/index.js']);
13+ const entriesPath = globby . sync ( [ resolveApp ( 'src' ) + '/*/index.tsx' ] , { cwd : process . cwd ( ) } ) ;
14+ paths . entriesPath = entriesPath ;
15+
16+ // 获取指定路径下的入口文件
17+ function getEntries ( ) {
18+ const entries = { } ;
19+ const files = paths . entriesPath ;
20+ files . forEach ( filePath => {
21+ let tmp = filePath . split ( '/' ) ;
22+ let name = tmp [ tmp . length - 2 ] ;
23+ if ( env === 'production' ) {
24+ entries [ name ] = [
25+ require . resolve ( 'react-app-polyfill/stable' ) ,
26+ filePath ,
27+ ] ;
28+ } else {
29+ entries [ name ] = [
30+ require . resolve ( 'react-app-polyfill/stable' ) ,
31+ require . resolve ( 'react-dev-utils/webpackHotDevClient' ) ,
32+ filePath ,
33+ ] ;
34+ }
35+ } ) ;
36+ return entries ;
37+ }
38+
39+ // 入口文件对象
40+ const entries = getEntries ( ) ;
41+
42+ // 配置 HtmlWebpackPlugin 插件, 指定入口文件生成对应的 html 文件
43+ let htmlPlugin ;
44+ if ( env === 'production' ) {
45+ htmlPlugin = Object . keys ( entries ) . map ( item => {
46+ return new HtmlWebpackPlugin ( {
47+ inject : true ,
48+ template : paths . appHtml ,
49+ filename : item + '.html' ,
50+ chunks : [ item ] ,
51+ minify : {
52+ removeComments : true ,
53+ collapseWhitespace : true ,
54+ removeRedundantAttributes : true ,
55+ useShortDoctype : true ,
56+ removeEmptyAttributes : true ,
57+ removeStyleLinkTypeAttributes : true ,
58+ keepClosingSlash : true ,
59+ minifyJS : true ,
60+ minifyCSS : true ,
61+ minifyURLs : true ,
62+ } ,
63+ } ) ;
64+ } ) ;
65+ } else {
66+ htmlPlugin = Object . keys ( entries ) . map ( item => {
67+ return new HtmlWebpackPlugin ( {
68+ inject : true ,
69+ template : paths . appHtml ,
70+ filename : item + '.html' ,
71+ chunks : [ item ] ,
72+ } ) ;
73+ } ) ;
74+ }
75+
76+ if ( env === 'production' ) {
77+ for ( let i = 0 ; i < config . plugins . length ; i ++ ) {
78+ let item = config . plugins [ i ] ;
79+
80+ // 更改输出的样式文件名
81+ if ( item . constructor . toString ( ) . indexOf ( 'class MiniCssExtractPlugin' ) > - 1 ) {
82+ item . options . filename = 'static/css/[name].[chunkhash:8].css' ;
83+ item . options . chunkFilename = 'static/css/[name].chunk.[chunkhash:8].css' ;
84+ }
85+
86+ // SWPrecacheWebpackPlugin: 使用 service workers 缓存项目依赖
87+ if ( item . constructor . toString ( ) . indexOf ( 'function GenerateSW' ) > - 1 ) {
88+ // 更改输出的文件名
89+ item . config . precacheManifestFilename = 'precache-manifest.[chunkhash:8].js' ;
90+ }
91+ }
92+
93+ // 更改生产模式输出的文件名
94+ config . output . filename = 'static/js/[name].[chunkhash:8].js' ;
95+ config . output . chunkFilename = 'static/js/[name].chunk.[chunkhash:8].js' ;
96+
97+ } else {
98+ // 更改开发模式输出的文件名
99+ config . output . filename = 'static/js/[name].js' ;
100+ config . output . chunkFilename = 'static/js/[name].chunk.js' ;
101+ }
102+
103+ // 修改入口
104+ config . entry = entries ;
105+
106+ // 修改 HtmlWebpackPlugin 插件
107+ for ( let i = 0 ; i < config . plugins . length ; i ++ ) {
108+ let item = config . plugins [ i ] ;
109+ if ( item . constructor . toString ( ) . indexOf ( 'class HtmlWebpackPlugin' ) > - 1 ) {
110+ config . plugins . splice ( i , 1 ) ;
111+ }
112+ }
113+
114+ config . plugins . push ( ...htmlPlugin ) ;
115+
116+ // 分析打包内容
117+ // config.plugins.push(new BundleAnalyzerPlugin());
118+
119+ // 设置别名路径
120+ config . resolve . alias = {
121+ ...config . resolve . alias ,
122+ '@src' : paths . appSrc , // 在使用中有些 Eslint 规则会报错, 禁用这部分代码的 Eslint 检测即可
123+ } ;
124+
125+ // 修改代码拆分规则,详见 webpack 文档:https://webpack.js.org/plugins/split-chunks-plugin/#optimization-splitchunks
126+ config . optimization = {
127+ splitChunks : {
128+ // 将所有入口点共同使用到的、次数超过 2 次的模块,创建为一个名为 commons 的代码块
129+ // 这种配置方式可能会增大初始的捆绑包,比如有些公共模块在首页其实并未用到,但也会打包进来,会降低首页的加载性能
130+ // 建议将非必需模块使用 import() 的方式动态加载,提升页面的加载速度
131+ // cacheGroups: {
132+ // commons: {
133+ // name: 'commons',
134+ // chunks: 'initial',
135+ // minChunks: 2
136+ // }
137+ // }
138+
139+ // 将所有使用到的 node_modules 中的模块包打包为 vendors 代码块。(不推荐)
140+ // 这种方式可能会产生一个包含所有外部依赖包的较大代码块,建议只包含核心框架和工具函数代码,其他依赖项动态加载
141+ // cacheGroups: {
142+ // commons: {
143+ // test: /[\\/]node_modules[\\/]/,
144+ // name: 'vendors',
145+ // chunks: 'all'
146+ // }
147+ // }
148+
149+ cacheGroups : {
150+ // 通过正则匹配,将 react react-dom echarts-for-react 等公共模块拆分为 vendor
151+ // 这里仅作为示例,具体需要拆分哪些模块需要根据项目需要进行配置
152+ // 可以通过 BundleAnalyzerPlugin 帮助确定拆分哪些模块包
153+ vendor : {
154+ test : / [ \\ / ] n o d e _ m o d u l e s [ \\ / ] ( r e a c t | r e a c t - d o m | e c h a r t s - f o r - r e a c t ) [ \\ / ] / ,
155+ name : 'vendor' ,
156+ chunks : 'all' , // all, async, and initial
157+ } ,
158+
159+ // 将 css|less 文件合并成一个文件, mini-css-extract-plugin 的用法请参见文档:https://www.npmjs.com/package/mini-css-extract-plugin
160+ // MiniCssExtractPlugin 会将动态 import 引入的模块的样式文件也分离出去,将这些样式文件合并成一个文件可以提高渲染速度
161+ // 其实如果可以不使用 mini-css-extract-plugin 这个插件,即不分离样式文件,可能更适合本方案,但是我没有找到方法去除这个插件
162+ styles : {
163+ name : 'styles' ,
164+ test : / \. c s s | l e s s $ / ,
165+ chunks : 'all' , // merge all the css chunk to one file
166+ enforce : true
167+ }
168+ } ,
169+ } ,
170+ } ;
171+
172+ return config ;
173+ } ;
0 commit comments