likes
comments
collection
share

webpack多文件入口配置

作者站长头像
站长
· 阅读数 15

问题

公司项目是基于vue的中后台管理类型的系统,同时在系统中还有一个H5页面用于在移动端查看信息。

所以项目中需要混杂pc端和移动端代码,考虑到pc端依赖很多,为防止移动端的包也包含这些移动端依赖,故选择了分成两个项目开发。

在项目即将完成时,开发任务不是很多,苦于两个项目切换着开发确实很难受,于是萌生了将两个项目合并为一个项目的想法。

目标

但是合并时,我们需要考虑几个问题:

  • 一次启动,h5和pc端都可以正常访问开发

  • 移动端包体积不能受到pc端包依赖影响

  • 一次打包可打出移动端和pc端两个包

基于以上几个问题,我想到了webpack的多入口打包特性,于是经过大概一天的探索,最终完美将两端代码合并在一个项目中。

实践

公司的项目是基于vue-cli创建的webpack3的模板开发的,webpack配置文件如下,想必大家都已经非常清楚了。

webpack多文件入口配置

配置多文件入口的第一步是修改webpack的entry字段,在webpack.base.conf.js文件中:

module.exports = {
  context: path.resolve(__dirname, '../'),
  // 这里就是webpack的入口文件
  entry: {
    app: './src/main.js',
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  module: {},
  plugins: [],
  devServer:{}
}

首先在项目根目录下创建src-h5,与src目录齐平,其中放入移动端代码(其实就是另一个src),附图如下:

webpack多文件入口配置

webpack多文件入口配置

之后将移动端的入口文件加入到webpack的入口文件配置处,如下所示:

module.exports = {
  // 这里就是webpack的入口文件
  entry: {
    app: './src/main.js',
    h5: './src-h5/main.js'
  },
  output: {},
  module: {},
  plugins: [],
  devServer:{}
}

入口文件配置好了,那如何打包出不同的html页面呢,这里就需要HtmlWebpackPlugin这个插件的帮助了,HtmlWebpackPlugin 这个插件,new 一个,就打包一个 HTML 页面,所以我们在 plugins 配置里 new 两个,就能打包出两个页面来。

有了以上的知识,我们打开webpack.dev.conf.js文件,在其中找到plugins选项,如下所示:

modules.exports = {
  plugins:[
    ...
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      // 是否将生成的静态资源插入模板中
      inject: true
    }),
    ...
  ]
}

其上代码只会生成一个index.html文件,依照前面说的我们来修改下这个配置,生成一个index-h5.html文件,如下修改:

modules.exports = {
  plugins:[
    ...
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      // 是否将生成的静态资源插入模板中
      inject: true,
      // 输出的html文件引入的入口chunk
      chunks: ['manifest', 'vendor', 'app']
    }),
    new HtmlWebpackPlugin({
      filename: 'index-h5.html',
      template: 'index-h5.html',
      // 是否将生成的静态资源插入模板中
      inject: true,
      // 输出的html文件引入的入口chunk
      chunks: ['manifest', 'vendor', 'h5']
    }),
    ...
  ]
}

如上配置,配置中需要注意的配置项是chunks,此配置项表示的是生成的html文件需要引入的chunk名称,如果不配置该字段的话,那么在生成的两个html文件中会把所有的chunk都引入,导致路由错乱问题。

大家可以看到除了我们打包生成的 chunk 文件 app.jsh5.js 之外,还有 manifestvendor 这两个,这里稍微解释一下这两个 chunk

1.vendor 是指提取涉及 node_modules 中的公共模块;

2.manifest 是对 vendor 模块做的缓存;

需要注意一点,在module的rules字段解析js文件的配置中加入resolve('src-h5')代码,转换其中的es6代码。

module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('src-h5'),resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      }
    ]
}

配置完成后,运行npm run dev启动代码,浏览器输入http://localhost:8080/可以正常访问pc端项目,输入http://localhost:8080/index-h5.html/可以访问移动端项目。

ok!大功告成。

打包试试~~

打包一看,大跌眼镜。

打包出来的移动端包将pc端的依赖文件都打包进来了,这使得原本功能很少的移动端,现在变得异常臃肿,而且加载缓慢,这并不是我们想要的,那如何解决呢?

当然是让移动端的包只包含移动端的依赖。

想要分包,就得依赖webpack的CommonsChunkPlugin插件,该插件就是用来提取项目的公共依赖的,也是生成vendormanifest文件的家伙。

所以,我们来到webpack.prod.conf.js文件,其中配置如下:

module.exports = {
  plugins:[
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    }),
  ]
}

CommonsChunkPlugin可配置的属性如下:

  • name:可以是已经存在的chunk(一般指入口文件)对应的name,那么就会把公共模块代码合并到这个chunk上;否则,会创建名字为name的commons chunk进行合并

  • filename:指定commons chunk的文件名

  • chunks:指定source chunk,即指定从哪些chunk当中去找公共模块,省略该选项的时候,默认就是entry chunks

  • minChunks:既可以是数字,也可以是函数,还可以是Infinity,具体用法和区别下面会说

注意加粗的配置项chunks,他表示当前抽离的公共配置是从哪个入口去找的,现在我们的项目是多入口,我们只需要告诉webpack哪些依赖需要从PC端入口去查找,那些依赖需要从移动端入口去查找,并生成对应的vendor文件,这样就能将移动端和pc端依赖分开,按需引入。修改配置如下:

modules.exports = {
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks (module) {
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      },
       // 设置公共包入口来源为app
      chunks:['app']
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'h5-vendor',
      minChunks (module) {
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      },
      // 设置公共包入口来源为h5
      chunks:['h5']
    }),
  ]
}

注意这里我们配置了一个vendor.js和h5-vendor.js文件,chunks分别配置为app和h5,依照上面的介绍,这里的vendor.js文件中提取的公共模块是app入口的公共依赖,而h5-vendor.js文件中提取的公共模块是h5入口的公共依赖,这样我们就将移动端和pc端的依赖分开了。

提取出了各自的公共模块,我们也需要在html中引入,配置HtmlWebpackPlugin插件如下:

modules.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      filename: process.env.NODE_ENV === 'testing'
        ? 'index.html'
        : config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      chunksSortMode: 'dependency',
      chunks: ['manifest', 'vendor', 'app'] // 注意引入vendor
    }),
    new HtmlWebpackPlugin({
      filename: 'index-h5.html',
      template: 'index-h5.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      chunksSortMode: 'dependency',
      chunks: ['manifest', 'h5-vendor', 'h5'] // 引入移动端依赖vendor
    }),  
  ]
}

再次尝试打包,这次真的是大功告成了,pc端和移动端的依赖各自打包到各自的vendor文件中,移动端首屏加载页快了,又可以愉快的摸鱼了~~~~

转载自:https://juejin.cn/post/6968722488666619935
评论
请登录