webpack4抽包及多页面引入小记

826 阅读4分钟

如今我们打包和工程化,大部分是webpack进行,webpack的更新迭代速度也是很可观的,官网如今已经更新到4.40.2版本,同样的相关的配置也都在简化,具体的配置就不在赘述。

网上有很多大佬都记录了从webpack3升级到webpack4踩得坑,有兴趣和需要的小伙伴可以自行度娘下,在此只简单记录下公共文件抽离的配置及引入。

项目是自己练习简单搭建的,看下基本结构,只简单写下涉及到的结构:

|---- 根目录
  |---- node_modules
  |---- src
    |---- css
    |---- images
    |---- js        //各个模块引入的js文件
      |---- a.js
      |---- b.js
    |---- App.vue   //vue主页面
    |---- index.js  //index页面需要的js
    |---- file.js   //file页面需要的js
  |---- index.html  //多页面index页
  |---- file.html   //多页面file页
  |---- webpack.config.js      //基础webpack配置
  |---- webpack.dev.config.js  //开发配置
  |---- webpack.prod.config.js //生产配置
  |---- webpack.dll.config.js  //抽包配置

基本的页面就不上代码了,都是基本结构,两个入口js都共同引入了a.js和b.js文件,index.html只引入index.js,file.html只引入file.js文件,模拟一个多页面的效果。

基本webpack不在赘述,使用基本配置打包后我们会发现index.js文件会很大,而且打包速度很慢,因为我们引入了vue以及公共的js文件,现在我们开始对文件进行分离。主要使用两个配置功能,DllPlugin:抽离vue,vuex等;optimization:抽离公共引入的文件。

先看下基本抽包配置:webpack.dll.config.js

const path = require('path')
const Webpack = require('webpack')

module.exports = {
  mode: 'production',
  entry: {
    vue: ['vue']
  },
  output: {
    filename: '[name].dll.js',
    path: path.resolve(__dirname, '.dll'),
    library: '[name]',
    libraryTarget: 'var'
  },
  plugins: [
    new Webpack.DllPlugin({
      name: '[name]',
      path: path.resolve(__dirname, './dll', '[name].manifest.json'),
      context: __dirname
    })
  ]
}

基本配置完成后,我们可以直接在webpack.prod.config.js里使用DllReferencePlugin引入,但是这种方法不够灵活,我们采用遍历方法,把dll里边的文件自动引入。同时我们使用optimization抽离公共文件及引用。

//=====webpack.config.js

......引入插件略
const plugins = [
  new CleanWebpackPlugin(),
  new HtmlWebpackPlugin({
    template: './index.html',
    filename: 'index.html',
    chunks: ['index']
  })
]
//获取抽包文件,自动添加到html页面中
const files = fs.readdirSync(path.resolve(__dirname, './dll'));
files.forEach(file => {
  if(/.*\.dll\.js/.test(file)){
    plugins.push(
      new AddAssentHtmlWebpackPlugin({
        filepath: path.resolve(__dirname, './dll', file)
      })
    )
  }
  if(/.*\.manifest.json/.test(file)){
    plugins.push(
    new Webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll', file)
    })
  )
}})

module.exports = {
  entry: {
    index: './src/index.js',
    file: './src/file.js'
  }, 
  output: {
    filename: '[name].js', 
    path: path.resolve(__dirname, 'build'),
    publicPath: '/' 
  },
  plugins: plugins,
  optimization: {
    //各个模块的引用和加载逻辑单独抽出,嵌入每个entry
    runtimeChunk: {
      name: 'manifest'
    },
    //抽离各个模块的公共引用文件
    splitChunks: {
      cacheGroups: {
        common: {
          chunks: 'initial',   //开始就要抽离公共模块
          minSize: 0,
          minChunks: 2
        }
      }
    }
  }
  .......其他配置略
}

对于单页面应用我们这么配置是没问题的,优先执行下抽包命令“webpack --config webpack.dll.config.js”,然后执行打包命令,可以成功打包。但是此时问题出现了,我们打开页面,发现页面并不是我们预期的效果,而且并没有什么报错。通过查看网络请求我们发现我们通过optimization抽出的公共文件没有成功引入,此处也是一个小坑。

此时我们去看package.json里的html-webpack-plugin,发现版本依旧是3点几的版本,有大佬说这是webpack的遗留问题,此插件没有更新,我们需要手动更新到4版本,‘npm install html-webpack-plugin@4.0.0-alpha.2’,再执行命令打开,发现问题解决了;

上面是对单页面的处理,如果我们涉及的是多页面的情况呢,有小伙伴可能会说多引用几次HtmlWebpackPlugin不就可以了吗,确实如此。但是操作也不够灵活,此处,我们也把这个插件的引用写活(此处我是根据js文件判断的名字,实际可以根据导航、路由等其他方式判断),对基本配置进行修改

//=====webpack.config.js

......引入插件略
const plugins = [
  new CleanWebpackPlugin()
]

//获取js文件,动态的添加到htmlwebpackplugin页面中
const jsFiles = fs.readdirSync(path.resolve(__dirname, './src'))
jsFiles.forEach(js=>{
  if(/.*\.js/.test(js)){
    let jsName = js.split('.')[0]
    plugins.push(
      new HtmlWebpackPlugin({
        template: `./${jsName}.html`,
        filename: `${jsName}.html`, 
        minify: {
          removeAttributeQuotes: true,
          collapseWhitespace: true
        },
        inject: true,
        hash: true,
        chunks: [`${jsName}`]
      })
    )
}})
//获取抽包文件,自动添加到html页面中
const files = fs.readdirSync(path.resolve(__dirname, './dll'));
files.forEach(file => {
  if(/.*\.dll\.js/.test(file)){
    plugins.push(
      new AddAssentHtmlWebpackPlugin({
        filepath: path.resolve(__dirname, './dll', file)
      })
    )
  }
  if(/.*\.manifest.json/.test(file)){
    plugins.push(
    new Webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, './dll', file)
    })
  )
}})

module.exports = {
  entry: {
    index: './src/index.js',
    file: './src/file.js'
  }, 
  output: {
    filename: '[name].js', 
    path: path.resolve(__dirname, 'build'),
    publicPath: '/' 
  },
  plugins: plugins,
  optimization: {
    //各个模块的引用和加载逻辑单独抽出,嵌入每个entry
    runtimeChunk: {
      name: 'manifest'
    },
    //抽离各个模块的公共引用文件
    splitChunks: {
      cacheGroups: {
        common: {
          chunks: 'initial',   //开始就要抽离公共模块
          minSize: 0,
          minChunks: 2
        }
      }
    }
  }
  .......其他配置略
}

这样我们就可以根据文件内容自动配置html相关名字和引用了,即使后面再增加页面,我们只需要增加对应的文件即可,不用再重新进行配置。

webpack配置可以说是博大精深,各人有各人的配置方法,但是我们的目的是一样的,加快打包和运行时的加载速度。文章写得比较急,有错误和不足的地方希望各位多多指点,大家共同学习~