webpack代码拆分

31次阅读

共计 2907 个字符,预计需要花费 8 分钟才能阅读完成。

1、为什么要进行代码拆分?

我们先引入一个应用场景,然后对这个场景进行分析,了解为什么需要拆分代码。
首先,安装第三方库 lodash,然后在 代码分割.js中引入并编写业务代码。

// 导入第三方库
const _ = require('lodash')

// 业务逻辑代码
console.log(_.join(['a', 'b', 'c']))

接着,配置 webpack.config.js 进行打包

const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  entry: './ 代码分割.js',
  output: {path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {loader: 'babel-loader'}
      }
    ],
    
  },
  plugins: [new CleanWebpackPlugin() // 会删除上次构建的文件,然后重新构建
  ]
}

打包完后会生成一个名为 main.bundle.js 文件,我们在 index.html 中引入,打开浏览器执行。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script src="./build/main.bundle.js"></script>
</body>
</html>

浏览器控制台会输出 a,b,c
如果我们改动 index.js 中的业务代码,改为:

// 导入第三方库
const _ = require('lodash')

// 业务逻辑代码
console.log(_.join(['a', 'b', 'c'], '***'))

控制台结果变为:a***b***c

现在我们抛出一个问题,当我们把引入的第三方库和业务代码放在一起打包,这样会有什么问题?

假设上面第三方库 lodash 大小为 1M,业务代码为 1M,假设打包后的 main.bundle.js 为 2M

浏览器每次打开 index.html 时,都需要去加载 main.bundle.js,然后执行业务代码。加载 2M 代码是很耗时的,但是浏览器有缓存机制,第二次加载同一文件时会从缓存中读取,刷新页面时网页加载速度更快。但是事与愿违,我们的业务代码更新很频繁,导致无论是首次加载还是再次加载都会很慢,那如何去解决这个问题呢?

答案很明显,第三方库 lodash 代码基本上是不会变的,如果我们能够将业务代码和第三方库代码分开加载,那么第三方库的加载就可用到缓存机制,整个页面的加载时间也会缩短。

在多个 js 文件都引入了同样的库或者代码的场景下也是可以进行拆分,避免重复加载。

在 webpack4 之前是使用 commonsChunkPlugin 来拆分公共代码,v4 之后被废弃,并使用 splitChunksPlugins

在使用 splitChunksPlugins 之前,首先要知道 splitChunksPlugins 是 webpack 主模块中的一个细分模块,无需 npm 引入,只需要配置即可。

const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  entry: './ 代码分割.js',
  output: {path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
    filename: '[name].bundle.js', // 代码打包后的文件名
    publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {loader: 'babel-loader'}
      }
    ]
  },
  // 拆分代码配置项
  optimization: {
    splitChunks: {chunks: 'all'}
  },
  plugins: [new CleanWebpackPlugin() // 会删除上次构建的文件,然后重新构建
  ]
}

我们使用 cnpm run dev 在开发模式下打包文件,开发模式下打包不会压缩文件,方便查看

可以看到代码拆分成了两个文件,打开 main.bundle.js 文件可以看到里卖弄存放的都是业务代码,没有 lodash 的代码

打开 vendors~main.js 文件可以看到 lodash 代码都在里面

这样就完成了代码拆分,拆分完的两个文件都要引入到 index.html 中

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script src="./build/vendors~main.js"></script>
  <script src="./build/main.bundle.js"></script>
</body>
</html>

浏览器执行 index.html 文件控制台结果:a***b***c

上面采用拆分代码的模式是 all,另外还有 async、initial,我们来了解一下

  • async: 只优化动态加载的代码,其他类型的代码正常打包。
  • initial: 针对原始 bundle 代码进行优化。
  • all: 针对所有代码进行优化。
  • function(chunk)自定义拆分函数

详情可以参考:
https://github.com/wayou/wayou.github.io/issues/40
https://medium.com/dailyjs/webpack-4-splitchunks-plugin-d9fbbe091fd0
分割出来的文件名为 vendors~main.js,怎么来的,我们来分析一下

2、如何拆分代码?

参考文章:

正文完
 0