webpack系列之AutoWebPlugin多页面应用管理

1,169 阅读4分钟

webpack系列之多页面应用打包通用方案 一文中,介绍了多页面应用打包的实现方案。该方案借助 glob 模块拿到src目录下的多个入口文件,遍历后得到多个模板文件,最后将入口文件和模板文件都暴露出去,在 webpack.config.js 中使用。

在此文中,我们使用另外一种方案实现多页面应用管理。

AutoWebPlugin

AutoWebPlugin 是 web-webpack-plugin 插件的其中一个功能,它可以用来管理多个单页应用。是 html-webpack-plugin 的一个很好的替代品。

AutoWebPlugin 会找出一个目录下所有的目录,把每一个目录看成是一个单页应用,然后分别为每个单页应用生成一个 Chunk 配置和 WebPlugin 配置。即 AutoWebPlugin 支持所有 WebPlugin 支持的功能。

安装

npm i web-webpack-plugin --save-dev

引入 AutoWebPlugin

const { AutoWebPlugin } = require('web-webpack-plugin');

项目目录结构

例如一个项目的源码目录结构如下:

image.png

这也是 AutoWebPlugin 强制性规定的目录结构:

  • 所有单页应用的代码都需要放在一个目录下,例如都放在 pages 目录下;

  • 一个单页应用对应一个单独的文件夹,例如最后生成的 index.html 相关的源代码都在 index 目录下,list.html 和 login.html 同理

  • 每个单页应用的目录下都有一个 index.js 文件作为入口文件

修改 webpack 配置

修改 webpack.config.js 文件如下:

const path = require('path');
// 导入 AutoWebPlugin
const { AutoWebPlugin } = require('web-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 使用 AutoWebPlugin 自动寻找 pages 目录下的所有目录,并把每一个目录看成是一个单页应用
const autoWebPlugin  = new AutoWebPlugin('pages', {
  template: './template.html', // HTML模板文件所在的文件路径
  postEntrys:['./common.css'],// 所有的页面都依赖的共用的css样式文件
  // 提取出所有页面的公共代码
  commonsChunk: { 
    name: 'common'// 提取出公共代码的Chunk名称
  }
});
module.exports = {
  // AutoWebPlugin 会为寻找到的所有单页应用生成对应的入口配置
  // autoWebPlugin.entry方法可以获取到所有由 autoWebPlugin 生成的入口配置
  entry: autoWebPlugin.entry({
    // 这里可以加入你额外需要的 chunk 入口
  }),
  output:{
    filename: '[name]_[chunkhash:8].js',
    path: path.resolve(__dirname, './dist'),
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        use:['babel-loader'],
        exclude: path.resolve(__dirname, 'node_modules'),
      },
      {
        test: /\.css/,
        use: [
           MiniCssExtractPlugin.loader,
           'css-loader'
        ]
      }
    ]
  },
  plugins: [
    autoWebPlugin,
    new MiniCssExtractPlugin({
      filename: '[name]_[contenthash:8].css'
    }),
    // ...
  ]   
}

我们重点来看一下 AutoWebPlugin 的配置:

// 使用 AutoWebPlugin 自动寻找pages目录下的所有目录,把每一个目录看成是一个单页应用
const autoWebPlugin  = new AutoWebPlugin('pages', {
  template: './template.html', // HTML模板文件所在的文件路径
  postEntrys:['./common.css'],// 所有的页面都依赖的共用的css样式文件
  // 提取出所有页面的公共代码
  commonsChunk: { 
    name: 'common'// 提取出公共代码的Chunk名称
  }
});

在实例化 AutoWebPlugin 时,传入了一个 pages 参数和一个用于配置的对象。例如在上面的项目源码目录结构中,AutoWebPlugin 会自动寻找 pages 目录下的 index、list 和 login 目录,并把它们看成是三个单独的单页应用,并且分别为每个单页应用生成一个 Chunk 配置和 WebPlugin 配置。每个单页应用的 Chunk 名称就是文件夹的名称,也就是说 entry: autoWebPlugin.entry() 返回的最终内容是:

{
  index:["./pages/index/index.js","./common.css"],
  list: ["./pages/list/index.js", "./common.css"],
  login:["./pages/login/index.js","./common.css"]
}
  • template:用于设置一个HTML模板文件。即 AutoWebPlugin 自动生成的HTML文件会以其为模板,在这个模板的基础上引入每个单页应用自身不同的CSS文件或者JS文件

template.html 模板文件:

<html>
<head>
  <meta charset="UTF-8">
  <!--该页面所依赖的其它剩下的 CSS 注入的地方-->
  <!--STYLE-->
  <!--注入 google_analytics 中的 JS 代码-->
  <script src="./google_analytics.js?_inline"></script>
  <!--异步加载 Disqus 评论-->
  <script src="https://dive-into-webpack.disqus.com/embed.js" async></script>
</head>
<body>
<div id="app"></div>
<!--该页面所依赖的其它剩下的 JavaScript 注入的地方-->
<!--SCRIPT-->
<!--Disqus 评论容器-->
<div id="disqus_thread"></div>
</body>
</html>

打包后输出的 index.html:

<html>
<head>
  <meta charset="UTF-8">
  <!--该页面所依赖的其它剩下的 CSS 注入的地方-->
  <link rel="stylesheet" href="common_7cc98ad0.css">
  <link rel="stylesheet" href="index_04c08fbf.css">
  <!--注入 google_analytics 中的 JS 代码-->
  <script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');</script>
  <!--异步加载 Disqus 评论-->
  <script src="https://dive-into-webpack.disqus.com/embed.js" async=""></script>
</head>
<body>
<div id="app"></div>
<!--该页面所依赖的其它剩下的 JavaScript 注入的地方-->
<script src="common_39fd8e23.js"></script>
<script src="index_7f22d3cc.js"></script>
<!--Disqus 评论容器-->
<div id="disqus_thread"></div>


</body>
</html>
    

对比 template.html 和 index.html 文件,我们发现,template.html 中的 <!--STYLE--> 就是引入CSS文件的位置,<!--SCRIPT--> 就是引入JS文件的位置,AutoWebPlugin 会自动将页面依赖的资源按照不同的类型注入到 <!--STYLE--><!--SCRIPT--> 所在的位置。

  • postEntrys:用于设置所有页面都依赖的共用css文件

  • commonsChunk:用于提取所有页面的公共代码

输出结果

AutoWebPlugin 配置和其它的 webpack 配置已经配置好了,执行在 package.json 中配置的 build 命令 npm run build,在根目录下生成了一个 dist 文件夹,该文件夹里的文件就是通过 AutoWebPlugin 生成的多个单页应用的文件内容。

image.png

如果后续有新的页面需要开发,只需要在 pages 目录下新建一个目录,目录名称取为输出 HTML 文件的名称,目录下放这个页面相关的代码即可,无需改动构建代码。

项目代码地址:github.com/moozisheng/…