Webpack构建多页应用Mpa:文件结构和自动化打包
Posted IT飞牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Webpack构建多页应用Mpa:文件结构和自动化打包相关的知识,希望对你有一定的参考价值。
本系列教程整体完成后,会完成一个可用的MPA应用,教程实际就是整个MPA的实现过程的记录。
如果是想了解单项功能的实现,请继续往下看;如果是想了解整个MPA的开发和思考过程,建议从 Webpack构建多页应用Mpa(一):阐述设计概要 教程开始看起…
我们需要实现的是一个多页面应用,到目前为止,我们还没有讲到如何创建多页面?以及如何规划文件存放结构?
一、概述
我们在做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库(后面教程解决)
二、开发
接上一篇教程,继续完善MPA...
下面我们开始一步步实现,let’s go…
1、创建多页面
创建页面A:
在src
目录下新建文件夹A
,并在A中新建三个文件index.html
、index.js
、index.css
,这里的三个文件是用于显示页面A,是页面A的独有文件;
src/A/index.html 代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>A页面</title>
</head>
<body>
A页面
</body>
</html>
src/A/index.js 代码如下:
import "./index.css";
console.log("A页面");
src/A/index.css 代码如下:
body{
background-color: gray;
}
同样方法,再创建页面B和页面C,把上面代码所有A
、页面A
字样分别替换成当前页面的文字,方便区分;
src目录下的文件结构如图:
2、配置webpack.config.js
我们想要最终打包输出的文件结构也和src下一样,想象以下如果要访问页面A
,那么只要打开 http://域名/A
就可以。
- entry:修改成多页面入口形式
这里采用json对象
形式,key表示chunk名字,在output字段中可以用[name]
占位符获得,用于设置输入的文件路径。
context
字段用于配置entry
的上下文父路径,之后entry路径是在context
目录下配置子路径;
context: path.resolve(__dirname, 'src'),
entry: {
A: "./A/index.js",
B: "./B/index.js",
C: "./C/index.js"
},
- output:将各个页面的js文件生成到各自页面目录中
[name]
占位符用于获取entry中设置的key,__dirname
是node自带的系统变量,表示当前文件的绝对路径;
output: {
filename: "[name]/index.js",
path: path.resolve(__dirname, "dist"),
chunkFilename: "[name]/index.js" //异步导入时,用chunkFilename字段来命名
},
- 生成多个页面的html代码
由于有3个页面,那么这里就要定义3个页面的输出,其中chunks参数很重要,需要引用对应页面的chunk,这里的chunk其实对应entry中的key;
这里顺便说下webpack一些名字的概念(自己的理解):
- bundle:bundle 由许多不同的模块生成,包含已经经过加载和编译过程的源文件的最终版本。
- chunk:由入口或代码切割决定的过程代码块;
- module:模块,在 Webpack ⾥⼀切皆模块,⼀个模块对应着⼀个⽂件。 Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
直达:webpack官网术语表
推荐文章:Webpack 理解 Chunk
plugins: [
...
new HtmlWebpackPlugin({
filename: "./A/index.html",
template: "./A/index.html",
chunks: ["A"]
}),
new HtmlWebpackPlugin({
filename: "./B/index.html",
template: "./B/index.html",
chunks: ["B"]
}),
new HtmlWebpackPlugin({
filename: "./C/index.html",
template: "./C/index.html",
chunks: ["C"]
})
...
]
- 生成多个页面的css代码,并单独打包
chunkFilename
字段是为异步加载的Chunk命名
plugins: [
...
new MiniCssExtractPlugin({
filename: "[name]/index.css",
chunkFilename: "[name]/index.css" //异步导入时,用chunkFilename字段来命名
})
]
到这里就配置完成了,我们执行npm run dev
打包,看到dist
下生成的目录结构如下:
执行http-server dist
,打开A、B、C三个页面如下:
页面访问一切正常!!!!
阶段性成功!
到这里我们我们思考,这里是三个页面,如果以后有更多的页面,是否也有一个个加
HtmlWebpackPlugin
的配置呢,岂不是很麻烦,所以,我们还要根据src下的文件夹结构,自动生成HtmlWebpackPlugin
配置;
3、根据src目录动态生成配置项
我们的目标是根据
src
下的文件夹,自动添加HtmlWebpackPlugin
配置,达到自动生成dist
下页面文件的目的;
我们想要自动化生成entry
和htmlwebpackplugins
,其实只要能拿到src
目录下的文件夹列表就可以。这里就需要先安装一个glob
插件(npm i -D glob
),用于获取文件夹列表。
自动生成配置代码如下:
function getMpa() {
const entry = {},
htmlwebpackplugins = [];
const entryfiles = glob.sync(path.resolve(__dirname, "./src/*/index.js"));
entryfiles.forEach(function (item) {
const folder = item.match(/\\/src\\/(\\w+)\\/index\\.js$/)[1];
entry[folder] = `./${folder}/index.js`;
htmlwebpackplugins.push(new HtmlWebpackPlugin({
title: `${folder}页面`,
filename: `./${folder}/index.html`,
template: `./${folder}/index.html`,
chunks: [folder],//以数组的形式指定由html-webpack-plugin负责加载的chunk文件(打包后生成的js文件),不指定的话就会加载所有的chunk。
inject: "body",//指示把加载js文件用的<script>插入到哪里,默认是插到<body>的末端,如果设置为'head',则把<script>插入到<head>里。
minify: true,//生成压缩后的HTML代码。
}));
});
return { entry, htmlwebpackplugins };
}
分析以上代码:
glob.sync
方法获取src
下的所有子目录- 遍历子目录,生成所有页面的entry和htmlwebpackplugins
- 导出两个配置项
再次执行打包npm run dev
,我们看到dist
目录下生成的文件结构还是和之前一模一样,达到了自动化的要求。
下面的教程我们将继续完善,最终附上一份到本节教程截止,webpack.config.js
和package.json
webpack.config.js 代码如下:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const glob = require("glob");
function getMpa() {
const entry = {},
htmlwebpackplugins = [];
const entryfiles = glob.sync(path.resolve(__dirname, "./src/*/index.js"));
entryfiles.forEach(function (item) {
const folder = item.match(/\\/src\\/(\\w+)\\/index\\.js$/)[1];
entry[folder] = `./${folder}/index.js`;
htmlwebpackplugins.push(new HtmlWebpackPlugin({
title: `${folder}页面`,
filename: `./${folder}/index.html`,
template: `./${folder}/index.html`,
chunks: [folder],//以数组的形式指定由html-webpack-plugin负责加载的chunk文件(打包后生成的js文件),不指定的话就会加载所有的chunk。
inject: "body",//指示把加载js文件用的<script>插入到哪里,默认是插到<body>的末端,如果设置为'head',则把<script>插入到<head>里。
minify: true,//生成压缩后的HTML代码。
}));
});
return { entry, htmlwebpackplugins };
}
const { entry, htmlwebpackplugins } = getMpa();
module.exports = {
context: path.resolve(__dirname, 'src'),
entry,
output: {
filename: "[name]/index.js",
path: path.resolve(__dirname, "dist"),
chunkFilename: "[name]/index.js"
},
mode: "development",
module: {
rules: [
{
test: /\\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
}
]
},
plugins: [
...htmlwebpackplugins,
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: "[name]/index.css",
chunkFilename: "[name]/index.css"
})
]
};
package.json 代码如下:
{
"name": "mpa",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"webpack": "^4.46.0",
"webpack-cli": "^4.7.0"
},
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^5.2.6",
"glob": "^7.1.7",
"html-webpack-plugin": "^4.3.0",
"mini-css-extract-plugin": "^1.6.0",
"style-loader": "^2.0.0"
},
"scripts": {
"dev": "npx webpack",
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"author": "",
"license": "ISC"
}
以上是关于Webpack构建多页应用Mpa:文件结构和自动化打包的主要内容,如果未能解决你的问题,请参考以下文章
Webpack构建多页应用Mpa:实现基础框架,单独打包样式文件
如何将 Webpack 4 SplitChunksPlugin 与 HtmlWebpackPlugin 一起用于多页应用程序?