一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
单页应用和多页应用,你分清楚了吗?
我们先来看单页应用。
百度百科介绍如下:
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
什么意思呢? 就是它只有一个 html 文件,页面内容的变化是通过 js 控制的。可以理解为,点击不同的菜单,js 就会控制 html 中加载的 dom 内容。
由于它第一次加载的时候,它需要加载一个比较大的 JS 文件,所以,它的缺点就是首页加载比较慢。但是切换界面的时候,它不需要重新发起请求,所以它切换很快。
就我目前的开发经验而言,单页应用应用于许多大型的管理系统,这些管理系统表单多、数据处理复杂、相似的部分多、需要更快的响应速度,这种情况下,单页应用更加合适。
那么多页应用呢?
多页应用(MultiPage Application,MPA),它有许多个 html 文件,每次页面跳转的时候,它都会重新从服务器获取一个新的 html,冰加载对应的 js、css。相应的,它的优点是首页加载快,页面切换相对较慢。
它主要应用是一些公司官网、新闻网站。这些网站设计要求高,相似度相对较低,交互少,对首页加载速度要求高,多页应用更加适合于这类场景。
我以前写多页应用,多是用 bootstrap + jquery,写起来并不舒服。 但是随着技术的发展,我们现在完全可以使用 react 来写,然后通过配置 webpack,顺利的写出我们想要的多页应用。
你知道怎么用 react 写多页应用吗?
如果你看过我 webpack 专栏的其他文章,你可能会发现,我已经配置好了一个基础的单页应用。点击此处获取代码。
我们就在这个项目的基础上来完成从单页到多页应用的转变吧。
在了解多页应用概念的基础上,我们可以得出,如果想要实现一个多页应用,我们需要达到以下四个要求。
1.多个 html。
2.多个 js。
3.多个 html 能够引入对应的 js。
4.多个 html 能够跳转。
既然是使用多个 html 、多个 js ,那么单页应用的入口文件也不需要了,我们建立如下文件结构:
我新建了 page 文件夹,并在 page 文件夹下新建了 firstPage、home、secondPage,代表每个界面。然后分别建立了如图四个文件。暂时我们用两个文件夹 home、 firstPage 来实现功能。
firstPage 文件结构如下:
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>Document</title>
</head>
<body>
<div id="first_page"></div>
</body>
</html>
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './index.jsx';
ReactDOM.render(<App />,document.querySelector("#first_page"))
index.jsx
import React from 'react';
import Style from './index.less';
export default class Index extends React.Component{
render(){
return <div className={Style.first_page}>FIRST-PAGE</div>
}
}
index.less
.first_page{
color:blue
}
home 文件 结构如下:
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>Document</title>
</head>
<body>
<div id="home"></div>
</body>
</html>
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './index.jsx';
ReactDOM.render(<App />,document.querySelector("#home"))
index.jsx
import React from 'react';
import Style from './index.less';
export default class Index extends React.Component{
render(){
return <div className={Style.home}>
<div><a href = "./firstPage.html">to FirstPage</a></div>
HOME-1</div>
}
}
index.less
.home{
color:rgb(143, 24, 24);
}
这两个文件夹内容大致相似,我在 home/index.jsx 下添加了一个跳转链接,用于测试多页跳转。
将基础的测试文件添加完成后,我们需要修改 webpack 的配置。
打开 webpack.common.js 文件,配置如下:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode:'development',
// entry: ["@babel/polyfill",path.resolve(__dirname,'./src/index.js')],
entry:{firstPage:'./src/page/firstPage/index.js',home:'./src/page/home/index.js'},
output:{
filename: '[name].[chunkhash].js',
path:path.resolve(__dirname,'./dist'),
},
//...
plugins:[ // 配置插件
new CleanWebpackPlugin() ,
new MiniCssExtractPlugin({ // 添加插件
filename: '[name].[chunkhash].css'
}),
new HtmlWebpackPlugin({
template: './src/page/firstPage/index.html',
filename:'firstPage.html',// 输出的 html 文件名称
chunks:['firstPage'],// 引入内容的入口文件,和 entry 的 firstPage 对应。
scriptLoading: 'blocking',// 加载方式
}),
new HtmlWebpackPlugin({
template: './src/page/home/index.html',
filename:'index.html',// 设置为默认访问页
chunks:['home'],
scriptLoading: 'blocking',
}),
],
//...
}
主要修改的点为: 入口文件,以及 new HtmlWebpackPlugin 相关配置。
核心思想很简单,我们通过配置多个 入口文件来获得多个 js 文件,然后将多个 html 文件引入对应的 js 和 css 即可。由于 css 文件是在 js 文件中引入的,所以如果想让 html 文件引入对应的 js,指定对应的入口 js 文件 key 即可。
这个时候我们使用 npm run build 打包一下,可以在 dist 目录中发现如下文件:
查看 index.html 及其引入的 css 文件,发现它与 page 文件中的内容一致。
ctrl + C 停掉项目后,我们使用 npm run start 启动项目,得到如下界面:
点击 to FirstPage
可以看到,成功跳转了,和我们写原生的差不多嘛。这个时候,我们就可以愉快的使用 react 开发多页应用了。
让我们再减少一点重复的工作量吧!
我们发现,entry 的配置和 new HtmlWebpackPlugin 的配置实在是太罗嗦了!太多相似点了!
而多个文件引入的路径也是非常相似的,唯一不同的只是它的的文件夹名字不同!
这,有破绽啊!
以下内容参照博客:blog.csdn.net/scorpio_h/a…
npm i glob -D
在根目录下添加 config.js。
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const setMPA = () =>{
const entry = {};
const hemlWebpackPlugins = [];
const entryFiles = glob.sync("./src/page/**/*.js");// 拿到符合条件的文件路径数组
console.log('entryFiles',entryFiles);
Object.keys(entryFiles).map(index=>{
const entryFile = entryFiles[index];
const match = entryFile.match(/src\/page\/(.*)\/index\.js/);// 匹配到文件名
const pageName = match && match[1];
entry[pageName] = entryFile;
hemlWebpackPlugins.push(
new HtmlWebpackPlugin({
template: `./src/page/${pageName}/index.html`,
filename:`${pageName === 'home'?'index':pageName}.html`,// 这里让 home.html 输出为 index.html
chunks:[pageName],
scriptLoading: 'blocking',
}),
)
})
console.log(entry,hemlWebpackPlugins)
return { entry,hemlWebpackPlugins };
}
module.exports = setMPA;
修改 webpack.common.js 如下:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const setMPA = require('./config.js');
const { entry,hemlWebpackPlugins } = setMPA();
module.exports = {
mode:'development',
entry:entry,
//...
plugins:[ // 配置插件
new CleanWebpackPlugin() ,
new MiniCssExtractPlugin({ // 添加插件
filename: '[name].[chunkhash].css'
}),
...hemlWebpackPlugins,
],
//...
}
运行后,发现于之前的代码效果一致! 这个时候,我们只要直接按照固定的文件形式去 page 下新建文件夹,即可对应相应界面,无需额外配置啦。
示例代码
以上配置内容,都已经上传到线上仓库。
https://gitee.com/is-wang-fugui-rich/learn_mpa.git
如果对你有帮助,记得给我点个赞噢~