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

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

AutoWebPlugin

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

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

安装

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

引入 AutoWebPlugin

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

项目目录结构

例如一个项目的源码目录结构如下:
image.png
这也是 AutoWebPlugin 强制性规定的目录结构:

  • 所有单页应用的代码都需要放在一个目录下,例如都放在 pages 目录下;
  • 一个单页应用对应一个单独的文件夹,例如最后生成的 index.html 相关的源代码都在 index 目录下,list.html 和 login.html 同理
  • 每个单页应用的目录下都有一个 index.js 文件作为入口文件

修改 webpack 配置

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

  1. const path = require('path');
  2. // 导入 AutoWebPlugin
  3. const { AutoWebPlugin } = require('web-webpack-plugin');
  4. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  5. // 使用 AutoWebPlugin 自动寻找 pages 目录下的所有目录,并把每一个目录看成是一个单页应用
  6. const autoWebPlugin = new AutoWebPlugin('pages', {
  7. template: './template.html', // HTML模板文件所在的文件路径
  8. postEntrys:['./common.css'],// 所有的页面都依赖的共用的css样式文件
  9. // 提取出所有页面的公共代码
  10. commonsChunk: {
  11. name: 'common'// 提取出公共代码的Chunk名称
  12. }
  13. });
  14. module.exports = {
  15. // AutoWebPlugin 会为寻找到的所有单页应用生成对应的入口配置
  16. // autoWebPlugin.entry方法可以获取到所有由 autoWebPlugin 生成的入口配置
  17. entry: autoWebPlugin.entry({
  18. // 这里可以加入你额外需要的 chunk 入口
  19. }),
  20. output:{
  21. filename: '[name]_[chunkhash:8].js',
  22. path: path.resolve(__dirname, './dist'),
  23. },
  24. module: {
  25. rules: [
  26. {
  27. test: /\.js$/,
  28. use:['babel-loader'],
  29. exclude: path.resolve(__dirname, 'node_modules'),
  30. },
  31. {
  32. test: /\.css/,
  33. use: [
  34. MiniCssExtractPlugin.loader,
  35. 'css-loader'
  36. ]
  37. }
  38. ]
  39. },
  40. plugins: [
  41. autoWebPlugin,
  42. new MiniCssExtractPlugin({
  43. filename: '[name]_[contenthash:8].css'
  44. }),
  45. // ...
  46. ]
  47. }

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

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

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

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

template.html 模板文件:

  1. <html>
  2. <head>
  3. <meta charset="UTF-8">
  4. <!--该页面所依赖的其它剩下的 CSS 注入的地方-->
  5. <!--STYLE-->
  6. <!--注入 google_analytics 中的 JS 代码-->
  7. <script src="./google_analytics.js?_inline"></script>
  8. <!--异步加载 Disqus 评论-->
  9. <script src="https://dive-into-webpack.disqus.com/embed.js" async></script>
  10. </head>
  11. <body>
  12. <div id="app"></div>
  13. <!--该页面所依赖的其它剩下的 JavaScript 注入的地方-->
  14. <!--SCRIPT-->
  15. <!--Disqus 评论容器-->
  16. <div id="disqus_thread"></div>
  17. </body>
  18. </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 文件的名称,目录下放这个页面相关的代码即可,无需改动构建代码。

项目代码地址:https://github.com/moozisheng/moozi-multiple-spa-manage