leiwuhen-67's blog leiwuhen-67's blog
首页
    • 《Vue》笔记
    • 《React》笔记
    • 《NodeJs》笔记
    • 《CSS》笔记
    • 《Redis》笔记
    • 基础入门
    • 《Mock》笔记
    • 《MySQL》笔记
    • 《Git》相关
影音视听
收藏
关于
GitHub (opens new window)

我的公众号

首页
    • 《Vue》笔记
    • 《React》笔记
    • 《NodeJs》笔记
    • 《CSS》笔记
    • 《Redis》笔记
    • 基础入门
    • 《Mock》笔记
    • 《MySQL》笔记
    • 《Git》相关
影音视听
收藏
关于
GitHub (opens new window)
  • React

    • 使用React脚手架快速搭建项目
    • hooks之useEffect
    • React之事件绑定及简写方式
    • React之props传值并对其进行限制
    • React之Refs的基本使用
    • React之生命周期钩子
    • React之key的使用
    • React之代理服务器配置
    • React之封装全局Loading组件
    • React之消息的发布-订阅(pubsub-js)
    • React之Redux的基本使用
    • React之react-redux的基本使用
    • React之redux的数据持久化存储
    • React之路由懒加载
    • React之Render Props的使用
    • React之createBrowserRouter
    • React之路径别名@配置
    • React之craco打包优化配置
    • React之项目国际化
    • React之postcss-pxtorem移动端适配
    • React之使用vite创建项目
    • React之ts类型标注汇总
    • React之使用 ant design搭建后台管理之踩坑
    • React之路由切换动画
    • React之使用vite创建组件库并发布到npm
    • React之项目打包部署到nginx
    • React之自定义组件添加className与style
  • React Native

  • 《React》笔记
  • React
心欲无痕
2024-04-02

React之craco打包优化配置

随着项目规模的增加,当文件越来越多、引入的第三方组件库越来越多的时候,如果使用脚手架默认配置的话,打包出来的项目体积会变得越来越大,为了解决这个问题,需要我们去自定义 webpack 配置。

这里有两种方法,第一种是执行 npm run eject 暴露出 webpack 的配置项,然后更改里面的配置文件(不推荐)。第二种方法是使用第三方库 @craco/craco,这里使用的是第二种

需求是开启 gzip 压缩,关闭 sourcemap 文件生成,js 分模块打包,开启 tree-shaking,路径别名配置,cdn 外部资源不打包等

1、安装相关依赖

npm install @craco/craco

// 由于这些插件只是在打包的时候需要,生产环境下不需要,因此我们安装到开发环境下
npm install uglifyjs-webpack-plugin@2 compression-webpack-plugin@6 css-minimizer-webpack-plugin@1 terser-webpack-plugin@4 -D --force
1
2
3
4

2、在项目根目录下创建 craco.config.js 配置文件

// craco.config.js
const path=require( 'path' );
// Webpack 4及以下版本使用该插件
// 用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
// const UglifyJsPlugin=require( "uglifyjs-webpack-plugin" );

// 安装版本5或6,高版本会报错
const CompressionWebpackPlugin=require( 'compression-webpack-plugin' ); 

// 安装1版本的,高版本会报错
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); 

// 如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本,否则配置sourceMap时会报错
// Webpack 5及以上版本使用这个
// 用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
const TerserPlugin = require("terser-webpack-plugin"); 

// 用于打包性能分析
// const { BundleAnalyzerPlugin }=require( "webpack-bundle-analyzer" )

module.exports = {
  webpack: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
    plugins: [
    	// 打包性能分析
    	// new BundleAnalyzerPlugin({
    	// 	openAnalyzer: false,     // 是否在默认浏览器中自动打开报告
     	//    analyzerMode: 'static',  // 生成分析报告report.html
    	// })
      // 建议安装5或6版本,过高会报错
      new CompressionWebpackPlugin( {
        algorithm: 'gzip',
        test: /\.js$|\.html$|\.json$|\.css/,
        threshold: 10240, // 只有大小超过10k的资源会被处理
        minRatio: 0.8, // 最小压缩比达到0.8时才会被压缩
        deleteOriginalAssets: false, // 是否删除原文件,默认为false
      } ),
      /*
      	Webpack 5及以上版本
        用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
      */
      new TerserPlugin( {
        parallel: true,
        sourceMap: false,
        terserOptions: {
          compress: {
            drop_console: true,
            drop_debugger: true
          },
        },
      } ),
      // 压缩css代码
      new CssMinimizerPlugin(
        {
          parallel: true, // 使用多进程并行执行任务来提高构建效率
          sourceMap: false, // 不生成map文件
        }
      ),

      // Webpack 4及以下版本
      // new UglifyJsPlugin({
      //   uglifyOptions: {
      //     compress: {
      //       drop_debugger: true,
      //       drop_console: true, //生产环境自动删除console
      //     },
      //     warnings: false,
      //   },
      //   sourceMap: false,
      //   parallel: true, //使用多进程并行运行来提高构建速度。默认并发运行数:os.cpus().length - 1。
      // } ),
    ],
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            name (module) {
              // node_modules/packageName
              const packageName = module.context.match(
                /[\\/]node_modules[\\/](.*?)([\\/]|$)/
              )[1]
              return `npm.${packageName.replace("@", "")}`
            },
          },
        }
      },
      runtimeChunk: true, // 避免文件的频繁变更导致浏览器缓存失效
      usedExports: true, // 开启tree-shaking
      minimize: true,
    },
    // 不生成map文件
    devtool: false,
    // 配置cdn外部资源不打包
    externals: {
      'react': 'React',
      'react-dom': 'ReactDOM',
    }
  },
};
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

上述配置也可更改如下:

const path=require( 'path' );
// Webpack 4及以下版本使用该插件
// 用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
// const UglifyJsPlugin=require( "uglifyjs-webpack-plugin" );

// 如果webpack版本不够高,则建议安装版本5或6,否则高版本会报错
const CompressionWebpackPlugin=require( 'compression-webpack-plugin' ); 

// 如果webpack版本不够高,则建议安装1版本的,否则高版本会报错
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); 

// 如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本,否则配置sourceMap时会报错
// Webpack 5及以上版本使用这个
// 用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
const TerserPlugin=require( "terser-webpack-plugin" ); 


module.exports = {
  webpack: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
    configure: ( webpackConfig, { env, paths } ) => {
      const isEnvProduction = env === 'production';
      webpackConfig.devtool = false; // 不生成map文件
      if ( isEnvProduction ) { 
        // 用于js代码压缩和混淆的插件,减小js代码体积,提高加载速度,保护代码不被轻易篡改
        webpackConfig.plugins.push(
          new CompressionWebpackPlugin( {
            algorithm: 'gzip',
            test: /\.js$|\.html$|\.json$|\.css/,
            threshold: 10240, // 只有大小超过10k的资源会被处理
            minRatio: 0.8, // 最小压缩比达到0.8时才会被压缩
            deleteOriginalAssets: false, // 是否删除原文件,默认为false
          } )
        )
        webpackConfig.plugins.push(
          new TerserPlugin({
            parallel: true,
            terserOptions: {
              compress: {
                drop_console: true,
                drop_debugger: true,
              },
            },
          })
        )
        webpackConfig.plugins.push(
          new CssMinimizerPlugin(
            {
              parallel: true, // 使用多进程并行执行任务来提高构建效率
            }
          )
        )

        webpackConfig.optimization = {
          splitChunks: {
            chunks: 'all',
            maxInitialRequests: Infinity,
            minSize: 20000,
            cacheGroups: {
              vendor: {
                test: /[\\/]node_modules[\\/]/,
                name ( module, chunks, cacheGroupKey ) {
                  const moduleFileName = module
                    .identifier()
                    .split('/').reduceRight((item) => item);
                  const allChunksNames = chunks
                    .map( ( chunk ) => chunk.name )
                    .join( ',' );
                  return `${cacheGroupKey}-${allChunksNames}-${moduleFileName}`
                }
              }
            },
          },
          runtimeChunk: true,
          usedExports: true,
          minimize: true,
        }

		// 配置cdn外部资源不打包
        webpackConfig.externals = {
        	'react': 'React',
      		'react-dom': 'ReactDOM',
      		'echarts': 'echarts'
        }
      }
      return webpackConfig
    },
  }
};

// 如果想cdn外部资源不打包还需要在index.html文件中引入相应的三方包
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

此时,配置已完成,可以愉快的玩耍了

编辑 (opens new window)
上次更新: 7/1/2024, 4:56:33 PM
React之路径别名@配置
React之项目国际化

← React之路径别名@配置 React之项目国际化→

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式