Webpack 多入口配置

发布于 2024-04-27  1026 次阅读


1. 目标分析

  1. 一个项目中保存了多个 HTML 模版,不同的模版有不同的入口,并且有各自的 router、store 等;
  2. 不仅可以打包出不同 HTML,而且开发的时候也可以顺利进行调试;
  3. 不同入口的文件可以引用同一份组件、图片等资源,也可以引用不同的资源;

2. 准备工作

首先我们 vue init webpack multi-entry-vue 使用 vue-cli 创建一个 webpack 模版的项。文件结构如下:

.
├── build
├── config
├── src
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── router
│   │   └── index.js
│   ├── App.vue
│   └── main.js 
├── static
├── README.md
├── index.html
├── package-lock.json
└── package.json

这里顺便介绍在不同系统下生成目录树的方法:

  1. mac 系统命令行生成目录树的方法 tree -I node_modules --dirsfirst ,这个命令的意思是,不显示 node_modules 路径的文件,并且以文件夹在前的排序方式生成目录树。如果报没有找到 tree 命令的错,安装 tree 命令行 brew install tree 即可。
  2. windows 系统在目标目录下使用 tree /f 1.txt 即可把当前目录树生成到一个新文件 1.txt 中。

首先我们简单介绍一下 Webpack 的相关配置项,这些配置项根据使用的 Webpack 模版不同,一般存放在 webpack.config.js 或 webpack.base.conf.js 中:

const path = require('path')
module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'output-file.js',
    publicPath: '/'
  },
  module: {},        // 文件的解析 loader 配置
  plugins: [],       // 插件,根据需要配置各种插件
  devServer: {}      // 配置 dev 服务功能
}

这个配置的意思是,进行 Webpack 后,会在命令的执行目录下新建 dist 目录(如果需要的话),并将打包 src 目录下的 main.js 和它的依赖,生成 output-file.js 放在 dist 目录中。

下面稍微解释一下相关配置项:

  1. entry: 入口文件配置项,可以为字符串、对象、数组。 以上面的对象形式为例,app 是入口名称,如果 output.filename 中有 [name] 的话,就会被替换成 app
  2. context: 是 webpack 编译时的基础目录,用于解析 entry 选项的基础目录(绝对路径),entry 入口起点会相对于此目录查找,相当于公共目录,下面所有的目录都在这个公共目录下面。
  3. output: 出口文件的配置项。
  4. output/path: 打包文件输出的目录,比如上面的 dist,那么就会将输出的文件放在当前目录同级目录的 dist 文件夹下,没有这个文件夹就新建一个。 可以配置为 path.resolve(__dirname, './dist/${Date.now()}/') (md 语法不方便改成模板字符串,请自行修改)方便做持续集成。
  5. output.filename: 输出的文件名称,[name] 的意为根据入口文件的名称,打包成相同的名称,有几个入口,就可以打包出几个文件。 比如入口的 key 为 app,打包出来就是 app.js,入口是 my-entry,打包出来就是 my-entry.js
  6. output.publicPath: 静态资源的公共路径,可以记住这个公式: 静态资源最终访问路径 = output.publicPath + 资源loader或插件等配置路径。 举个例子,publicPath 配置为 /dist/,图片的 url-loader 配置项为 name: 'img/[name].[ext]' ,那么最终打包出来文件中图片的引用路径为 output.publicPath + 'img/[name].[ext]' = '/dist/img/[name].[ext]'

本文由于是入口和出口相关的配置,所以内容主要围绕着 entry 、output 和一个重要的 webpack 插件 html-webpack-plugin,这个插件是跟打包出来的 HTML 文件密切相关,主要有下面几个作用:

  1. 根据模版生成 HTML 文件;
  2. 给生成的 HTML 文件引入外部资源比如 linkscript 等;
  3. 改变每次引入的外部文件的 Hash,防止 HTML 引用缓存中的过时资源;

下面我们从头一步步配置一个多入口项目。

3. 开始配置

3.1 文件结构改动

在 src 目录下将 main.js 和 App.vue 两个文件各复制一下,作为不同入口,文件结构变为:

.
├── build
│   ├── build.js
│   ├── check-versions.js
│   ├── logo.png
│   ├── utils.js
│   ├── vue-loader.conf.js
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js    # 主要配置目标
│   └── webpack.prod.conf.js   # 主要配置目标
├── config
│   ├── dev.env.js
│   ├── index.js
│   └── prod.env.js
├── src
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   ├── router
│   │   └── index.js
│   ├── App.vue
│   ├── App2.vue       # 新增的入口
│   ├── main.js
│   └── main2.js       # 新增的入口
├── static
├── README.md
├── index.html
└── package.json

3.2 简单配置

要想从不同入口,打包出不同 HTML,我们可以改变一下 entry 和 output 两个配置,

// build/webpack.prod.conf.js

module.exports = {
  entry: {
    entry1: './src/main.js',
    entry2: './src/main2.js'
  },
  output: {
    filename: '[name].js',
    publicPath: '/'
  },
    plugins: [
        new HtmlWebpackPlugin({
            template: "index.html",  // 要打包输出哪个文件,可以使用相对路径
            filename: "index.html"   // 打包输出后该html文件的名称
        })
    ]
}

根据上面一小节我们知道,webpack 配置里的 output.filename 如果有 [name] 意为根据入口文件的名称,打包成对应名称的 JS 文件,那么现在我们是可以根据两个入口打包出 entry.js 和 entry2.js

此时我们 npm run build 打包出一个引用了这两个文件的 index.html,那么如何打包出不同 HTML 文件,分别应用不同入口 JS 文件呢,此时我们需要借助于 HtmlWebpackPlugin 这个插件。

HtmlWebpackPlugin 这个插件,new 一个,就打包一个 HTML 页面,所以我们在 plugins 配置里 new 两个,就能打包出两个页面来。

3.3 打包出不同的 HTML 页面

我们把配置文件改成下面这样:

// build/webpack.prod.conf.js

module.exports = {
  entry: {
    entry: './src/main.js',   // 打包输出的chunk名为entry
    entry2: './src/main2.js'  // 打包输出的chunk名为entry2
  },
  output: {
    filename: '[name].js',
    publicPath: '/'
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: 'entry.html',  // 要打包输出的文件名
      template: 'index.html',  // 打包输出后该html文件的名称
      chunks: ['manifest', 'vendor', 'entry']  // 输出的html文件引入的入口chunk
      // 还有一些其他配置比如minify、chunksSortMode和本文无关就省略,详见github
    }),
    new HtmlWebpackPlugin({
      filename: 'entry2.html',
      template: 'index.html',
      chunks: ['manifest', 'vendor', 'entry2']
    })
  ]
}

上面一个配置要注意的是 chunks,如果没有配置,那么生成的 HTML 会引入所有入口 JS 文件,在上面的例子就是,生成的两个 HTML 文件都会引入 entry.js 和 entry2.js,所以要使用 chunks 配置来指定生成的 HTML 文件应该引入哪个 JS 文件。配置了 chunks 之后,才能达到不同的 HTML 只引入对应 chunks 的 JS 文件的目的。

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

  1. vendor 是指提取涉及 node_modules 中的公共模块;
  2. manifest 是对 vendor 模块做的缓存;

欢迎欢迎~热烈欢迎~