Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpack 5.0 项目优化方案实践 #27

Open
hawx1993 opened this issue Jan 4, 2023 · 0 comments
Open

Webpack 5.0 项目优化方案实践 #27

hawx1993 opened this issue Jan 4, 2023 · 0 comments

Comments

@hawx1993
Copy link
Owner

hawx1993 commented Jan 4, 2023

webpack 5.0新特性

借鉴网上的图,大致窥探一下webpack5.0的一些新特性。

image.png

包依赖分析

在拆包之前,我们通常都会使用一些插件去分析我们的包模块的依赖,webpack-bundle-analyzer 就是一款不错的插件,通过webpack-bundle-analyzer 我们可以合理分析依赖情况

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  entry: ['./src/index.tsx'],
  plugins: [
    new Webpack.HotModuleReplacementPlugin(),
    new BundleAnalyzerPlugin(),
  ],
});

image.png

Webpack 代码拆分

我们可以使用splitChunks 进行精细控制代码分割,也就是俗称的拆包。
使用splitChunks 我们可以提取公共代码,防止代码被重复打包,拆分过大的js文件,合并零散的js文件等:

splitChunks拆包

1、使用splitChunks 提取共有代码,拆分业务代码与第三方库

 optimization: {
    splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,// 分割出去的代码最小体积 0为不限制
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$|.less$/,
          chunks: 'all',// 将所有的重复模块抽离出来
          enforce: true,
        },
        vendor: {
          name: 'vendor',
          test: (module) =>
            /(react|react-dom|react-router-dom/.test(
              module.context,
            ),
          chunks: 'initial',// 引入组件的方式:同步加载,异步加载:'async'
          priority: 11,
        },
        libs: {
          name: 'libs',
          test: (module) => /(moment|antd|lodash)/.test(module.context),
          chunks: 'all',
          priority: 14,
        },
        common: {
          chunks: 'async',
          test: /[\\/] node_modules[\\ / ] /,
          name: 'common',
          minChunks: 3,// 被几个代码块引用才会分割
          maxAsyncRequests: 5,
          maxSize: 1000000,
          priority: 10,
        },
      },
    },
  },

动态加载

import('./math').then(math => {
  console.log(math.add(1,2))
})

const math = lazy(() => import('./math'))

拆分tailwindcss

未移除之前,vendors.js有22mb大小:

image.png

tailwind.config.js 中配置移除项:

// tailwind.config.js
 purge: {
    // Learn more on https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css
    enabled: true,
    content: [
      './src/components/**/*.tsx',
      './src/context/**/*.tsx',
      './src/layouts/**/*.tsx',
      './src/pages/**/*.tsx',
    ],
  },

移除之后,bundle文件体积大小如下:

image.png

Tree shaking移除未使用的js代码

production模式实际上是由TerserPlugin来处理的,默认开启压缩也是基于此插件处理。tree-shaking 需要基于es6模块化语法。我们可以直接通过手动的方式告诉webpack, 哪些东西是不需要处理的,可以通过package.json去配置副作用:

{
  "sideEffects": [
    "*.css" // 指定不需要shaking处理的文件
  ]
}

为什么需要基于es6 模块语法呢?

因为ES Module在js编译阶段就可以确定模块之间的依赖关系(import),并不需要执行就可以确认模块的导入、导出。所以我们并不需要代码执行就可以根据ESM确定模块之间的规则从而实现Tree Shaking,我们称之为静态分析特性。

Webpack 资源持久化缓存

每个打包的资源文件有唯一的hash值,即“文件指纹”。修改后只有受影响的文件hash变化,就可以做到“增量式更新”。可以避免部署过程中,存在更新的时间间隔。也不会出现用户浏览器某些使用到的文件是旧的缓存文件,某些使用的是新的文件。

{
    plugins: [
       new MiniCssExtractPlugin({
          filename: '[name]_[contenthash:8].css',// contenthash 根据css内容去计算hash值
          chunkFilename: '[name].[contenthash].css',
      }),
    ],
   output: {
       filename: '[name].[hash].bundle.js',
       chunkFilename: '[name].[chunkhash:8].bundle.js'
   }   
}

使用contenthash,这样每个资源文件都会有自己的独立的hash值。这样我们对局部的修改只会影响到局部文件,而不需要进行整体的变更和部署

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant