找回密码
 注册
首页 ≡≡网络技术≡≡ WEB前端 Webpack构建多页应用Mpa(三):文件结构和自动化打包 ...

框架 Webpack构建多页应用Mpa(三):文件结构和自动化打包

灰儿 2022-8-2 16:43:24
我们需要实现的是一个多页面应用,到目前为止,我们还没有讲到如何创建多页面?以及如何规划文件存放结构?

一、概述
我们在做SPA单页面应用时,往往会使用一些现成的框架脚手架来做,框架本身已经提供了整套的解决方案,如页面切换、页面结构规划、公共文件结构规划等。

那么一个MPA,也需要考虑同样的问题,下面我们逐一来分析

需要解决的问题
比如有个应用有A、B、C三个页面,页面相互独立

1、如何跳转: 页面间跳转用 <a href="B.html">B页面</a> 这种连接跳转
2、如何新建页面: 把每个页面对应的html、js、css都统一放在同一个文件夹
3、如何引入公共html代码(后面教程解决) : 页面会有相同的header.html、footer.html、sidebat.html,统一引入
4、如何使用公共的js方法和css样式(后面教程解决): 单独创建文件夹,用于存放公共的js和css文件
5、如何引入常用的第三方js库(后面教程解决)

二、开发
下面我们开始一步步实现,let’s go…

1、创建多页面
创建页面A:
在src目录下新建文件夹A,并在A中新建三个文件index.html、index.js、index.css,这里的三个文件是用于显示页面A,是页面A的独有文件;

src/A/index.html 代码如下:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.     <title>A页面</title>
  8. </head>
  9. <body>
  10.     A页面
  11. </body>
  12. </html>
复制代码

src/A/index.js 代码如下:
  1. import "./index.css";
  2. console.log("A页面");
复制代码

src/A/index.css 代码如下:
  1. body{
  2.     background-color: gray;
  3. }
复制代码

同样方法,再创建页面B和页面C,把上面代码所有A、页面A字样分别替换成当前页面的文字,方便区分;

src目录下的文件结构如图:
10.png

2、配置webpack.config.js
我们想要最终打包输出的文件结构也和src下一样,想象以下如果要访问页面A,那么只要打开 http://域名/A 就可以。

1.entry:修改成多页面入口形式
这里采用json对象形式,key表示chunk名字,在output字段中可以用[name]占位符获得,用于设置输入的文件路径。
context字段用于配置entry的上下文父路径,之后entry路径是在context目录下配置子路径;
  1. context: path.resolve(__dirname, 'src'),
  2.         entry: {
  3.         A: "./A/index.js",
  4.         B: "./B/index.js",
  5.         C: "./C/index.js"
  6.     },
复制代码

3.output:将各个页面的js文件生成到各自页面目录中
[name]占位符用于获取entry中设置的key,__dirname是node自带的系统变量,表示当前文件的绝对路径;
  1. output: {
  2.        filename: "[name]/index.js",
  3.        path: path.resolve(__dirname, "dist"),
  4.        chunkFilename: "[name]/index.js"                //异步导入时,用chunkFilename字段来命名
  5.    },
复制代码

5.生成多个页面的html代码
由于有3个页面,那么这里就要定义3个页面的输出,其中chunks参数很重要,需要引用对应页面的chunk,这里的chunk其实对应entry中的key;
这里顺便说下webpack一些名字的概念(自己的理解):

bundle:bundle 由许多不同的模块生成,包含已经经过加载和编译过程的源文件的最终版本。
chunk:由入口或代码切割决定的过程代码块;
module:模块,在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。 Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
  1. plugins: [
  2.       ...
  3.        new HtmlWebpackPlugin({
  4.            filename: "./A/index.html",
  5.            template: "./A/index.html",
  6.            chunks: ["A"]
  7.        }),
  8.        new HtmlWebpackPlugin({
  9.            filename: "./B/index.html",
  10.            template: "./B/index.html",
  11.            chunks: ["B"]
  12.        }),
  13.        new HtmlWebpackPlugin({
  14.            filename: "./C/index.html",
  15.            template: "./C/index.html",
  16.            chunks: ["C"]
  17.        })
  18.        ...
  19.    ]
复制代码

7.生成多个页面的css代码,并单独打包
chunkFilename字段是为异步加载的Chunk命名
  1. plugins: [
  2.                 ...
  3.         new MiniCssExtractPlugin({
  4.             filename: "[name]/index.css",
  5.             chunkFilename: "[name]/index.css"        //异步导入时,用chunkFilename字段来命名
  6.         })
  7.     ]
复制代码

到这里就配置完成了,我们执行npm run dev打包,看到dist下生成的目录结构如下:
11.png

执行http-server dist,打开A、B、C三个页面如下:
12.png

页面访问一切正常!!!!
阶段性成功!

到这里我们我们思考,这里是三个页面,如果以后有更多的页面,是否也有一个个加HtmlWebpackPlugin的配置呢,岂不是很麻烦,所以,我们还要根据src下的文件夹结构,自动生成HtmlWebpackPlugin配置;

3、根据src目录动态生成配置项
我们的目标是根据src下的文件夹,自动添加HtmlWebpackPlugin配置,达到自动生成dist下页面文件的目的;

我们想要自动化生成entry和htmlwebpackplugins,其实只要能拿到src目录下的文件夹列表就可以。这里就需要先安装一个glob插件(npm i -D glob),用于获取文件夹列表。

自动生成配置代码如下:
  1. function getMpa() {
  2.     const entry = {},
  3.         htmlwebpackplugins = [];
  4.     const entryfiles = glob.sync(path.resolve(__dirname, "./src/*/index.js"));
  5.     entryfiles.forEach(function (item) {
  6.         const folder = item.match(/\/src\/(\w+)\/index\.js$/)[1];
  7.         entry[folder] = `./${folder}/index.js`;
  8.         htmlwebpackplugins.push(new HtmlWebpackPlugin({
  9.             title: `${folder}页面`,
  10.             filename: `./${folder}/index.html`,
  11.             template: `./${folder}/index.html`,
  12.             chunks: [folder],//以数组的形式指定由html-webpack-plugin负责加载的chunk文件(打包后生成的js文件),不指定的话就会加载所有的chunk。
  13.             inject: "body",//指示把加载js文件用的<script>插入到哪里,默认是插到<body>的末端,如果设置为'head',则把<script>插入到<head>里。
  14.             minify: true,//生成压缩后的HTML代码。
  15.         }));
  16.     });
  17.     return { entry, htmlwebpackplugins };
  18. }
复制代码

分析以上代码:

glob.sync方法获取src下的所有子目录
遍历子目录,生成所有页面的entry和htmlwebpackplugins
导出两个配置项
再次执行打包npm run dev,我们看到dist目录下生成的文件结构还是和之前一模一样,达到了自动化的要求。

下面的教程我们将继续完善,最终附上一份到本节教程截止,webpack.config.js和package.json
webpack.config.js 代码如下:
  1. const path = require("path");
  2. const HtmlWebpackPlugin = require("html-webpack-plugin");
  3. const { CleanWebpackPlugin } = require("clean-webpack-plugin");
  4. const MiniCssExtractPlugin = require('mini-css-extract-plugin');
  5. const glob = require("glob");

  6. function getMpa() {
  7.     const entry = {},
  8.         htmlwebpackplugins = [];
  9.     const entryfiles = glob.sync(path.resolve(__dirname, "./src/*/index.js"));
  10.     entryfiles.forEach(function (item) {
  11.         const folder = item.match(/\/src\/(\w+)\/index\.js$/)[1];

  12.         entry[folder] = `./${folder}/index.js`;

  13.         htmlwebpackplugins.push(new HtmlWebpackPlugin({
  14.             title: `${folder}页面`,
  15.             filename: `./${folder}/index.html`,
  16.             template: `./${folder}/index.html`,
  17.             chunks: [folder],//以数组的形式指定由html-webpack-plugin负责加载的chunk文件(打包后生成的js文件),不指定的话就会加载所有的chunk。
  18.             inject: "body",//指示把加载js文件用的<script>插入到哪里,默认是插到<body>的末端,如果设置为'head',则把<script>插入到<head>里。
  19.             minify: true,//生成压缩后的HTML代码。
  20.         }));
  21.     });
  22.     return { entry, htmlwebpackplugins };
  23. }

  24. const { entry, htmlwebpackplugins } = getMpa();

  25. module.exports = {
  26.     context: path.resolve(__dirname, 'src'),
  27.     entry,
  28.     output: {
  29.         filename: "[name]/index.js",
  30.         path: path.resolve(__dirname, "dist"),
  31.         chunkFilename: "[name]/index.js"
  32.     },
  33.     mode: "development",
  34.     module: {
  35.         rules: [
  36.             {
  37.                 test: /\.css$/,
  38.                 use: [MiniCssExtractPlugin.loader, "css-loader"]
  39.             }
  40.         ]
  41.     },
  42.     plugins: [
  43.         ...htmlwebpackplugins,
  44.         new CleanWebpackPlugin(),
  45.         new MiniCssExtractPlugin({
  46.             filename: "[name]/index.css",
  47.             chunkFilename: "[name]/index.css"
  48.         })
  49.     ]
  50. };
复制代码

package.json 代码如下:
  1. {
  2.   "name": "mpa",
  3.   "version": "1.0.0",
  4.   "description": "",
  5.   "main": "index.js",
  6.   "dependencies": {
  7.     "webpack": "^4.46.0",
  8.     "webpack-cli": "^4.7.0"
  9.   },
  10.   "devDependencies": {
  11.     "clean-webpack-plugin": "^3.0.0",
  12.     "css-loader": "^5.2.6",
  13.     "glob": "^7.1.7",
  14.     "html-webpack-plugin": "^4.3.0",
  15.     "mini-css-extract-plugin": "^1.6.0",
  16.     "style-loader": "^2.0.0"
  17.   },
  18.   "scripts": {
  19.     "dev": "npx webpack",
  20.     "test": "echo "Error: no test specified" && exit 1"
  21.   },
  22.   "author": "",
  23.   "license": "ISC"
  24. }

复制代码


您需要登录后才可以回帖 登录 | 注册
学习中心
站长自定义文字内容,利用碎片时间,随时随地获取优质内容。
Q设计语言 了解更多
Q Design 提供商家设计所需的指导与资源,帮商家快速完成产品设计、降低生产成本。
学习中心
站长自定义文字内容,利用碎片时间,随时随地获取优质内容。
Q设计语言 了解更多
Q Design 提供商家设计所需的指导与资源,帮商家快速完成产品设计、降低生产成本。