👊超给力的webpack实战三之vue单页面和多页面配置

前言

这是一个系列专栏,将会更新一系列 webpack 的实战内容,主要围绕着旧前端项目现代化,以及现代化前端项目的再优化。

下面开始第三篇:vue单页面和多页面配置

上篇文章写到将 vue 框架引入老旧前端项目,完成了一个页面的改造。将其中一个页面用 vue 框架运行了起来。但是项目不止一个页面,其他页面也都需要改造成 vue 页面。

一旦改造第二个页面,就需要面临一个问题:第二个页面是和第一个页面放在一个 vue 项目里,还是分开成两个 vue 页面,做成两个 vue 项目呢?

前者是单页面应用 SPA,后者是多页面应用 MPA

SPA 全称 Single Page Application,即单页面应用。它所需的资源,如 HTML、CSS 和 JS 等,在一个页面中就加载完成,对于 SPA 来说,页面的切换就是组件或视图之间的切换。

MPA多页面应用 MultiPage Application ,指有多个独立页面的应用(多个html页面),每个页面必须重新加载js、css等相关资源。页面之间跳转,需要重新加载整页资源。页面跳转,是在不同的 HTML 之间跳转。

上面两种方案都行,都有其道理和存在的业务场景,所以这篇文章就将两个方案都去实现

MPA 的实现

MPA 是MultiPage Application,每个页面是单独的 html 文件,所以改造的第二个页面 login.html的思路是,第二个页面和第一个页面采用不同的 vue 入口,也就是说两个没有关系的页面。

MPA改造的方便之处是,在引入 vue 框架的操作,可以完全复制第一个页面的操作,比如新建 main.js, App.vue 等。

先看看 login.html 内容:

其中只有 css 样式文件的引入,并没有 JS 的逻辑

首先,将 html 里的内容和 css 里的内容全都 copy 过来,将 body 中的元素拷贝至 template 中。css 样式有两个,一个是公共样式,一个是页面单独的样式。我们将页面独立的 css 文件的内容拷贝至 style 标签中,公共样式在入口文件处引入。

这里有个地方需要注意,图片的路径需要更改,现在我们的路径是这样的:

除了 DOM 中的路径,css 中也有图片的应用,路径也需要更改:

其次创建入口文件main.js

这里的路径也需要注意。main.js 内容和 home 页面内容基本一致

到这里是不是感觉比较简单,但真正复杂的是 webpack 配置,需要为两个页面做单独处理

测试 login

首先我们先尝试将 login 页面跑起来,把它当作是一个单页应用:

javascript 复制代码
module.exports = {
  entry: resolve("./src/pages/Login/main.js"),
  module:{
    rules:[
      {
				test: /\.(png|jpe?g)$/i,
				type: "asset/resource",
			}
    ]
  },
  plugins:[
    new HtmlWebpackPlugin({
			template: resolve("./src/pages/Login/index.html"),
		}),
  ]
}

这里,我们需要修改三个地方:

  1. 构建入口为src/pages/Login/main.js
  2. 添加图片的 loader 配置,因为 DOM 中引用了图片
  3. 修改 html 模版路径

启动看看:

和改造前的 login 页面对比下:

发现背景图片没有加载出来,打开控制台看看是什么情况,初步猜测是图片没有加载成功,但是打开 netWork 一看,图片正常获取的:

然后查看页面元素,发现 body 高度是 0:

但是改造前的页面 body 高度却不是 0:

而且有明显的 css 样式定义height:100%;

回到代码 style 标签处,发现这里有个 scope,应该是这个问题。把这个 scope 删掉看看:

果然有用!

scoped会对当前组件内的所有 DOM 添加一个额外的 tag 属性,像这样: css 样式选择器生成的时候,就会带上这个 tag,像这样:

这样就能实现组件内的独立样式了,不会污染其他组件的样式。

但是 scoped 只对组件内的 DOM 添加 tag 属性,所以刚才对 html,body 的样式设置失效了

OK,现在 login.html 改造测试成功,接下来就修改 webpack,将 login 以及 home 页面结合成一个项目--MAP

改造 webpack

现在文件夹结构是这个样子,两个页面的文件分别放在各自的文件夹内:

下面来修改配置文件的 entry 和 output:

javascript 复制代码
{
  entry: {
		home: resolve("./src/pages/Home/main.js"),
		login: resolve("./src/pages/Login/main.js"),
	},
	output: {
		path: resolve("./dist"),
		filename: "[name].js",
	},
  
}

将入口改成两个,分别是两个页面的入口文件。并且输出的文件名称改成动态的,根据 entry 对象的 key 所决定。

然后增加一个 html-webpack-plugin 配置:

javascript 复制代码
{
  plugins:[
    new HtmlWebpackPlugin({
			template: resolve("./src/pages/Home/index.html"),
			filename: "home.html",
			chunks: ["home"],
		}),
		new HtmlWebpackPlugin({
			template: resolve("./src/pages/Login/index.html"),
			filename: "login.html",
			chunks: ["login"],
		}),
  ]
}

一个 plugin 处理 index 页面,另一个处理 login 页面。其中 chunks 的作用是指定对应页面构建后的 js 文件。如果不配置 chunks,就会出现 login.html 同时引入 index.js 以及 login.js 的情况

最后一个,配置 devServer:

javascript 复制代码
{
  devServer: {
		// 省略部分代码
		historyApiFallback: {
			rewrites: [
				{ from: /^(\/)?$/, to: "/home.html" },
				{ from: /^\/home$/, to: "/home.html" },
				{ from: /^\/login$/, to: "/login.html" },
			],
		},
}

因为有两个页面,如果不配置historyApiFallback,那么启动 webpack-dev-server 后,无论路径是什么,返回浏览器的永远是默认的 index.html。

其中 rewrites 的作用是识别路径,如果路径符合正则,那就返回对应的 html 文件。

上面配置的效果是,如果路径是/login,那就返回 login.html,其他的一律返回home.html

先访问/``/home:

然后访问/login

完全符合预期!!

SPA 的实现

SPASingle Page Application单页应用,而这正是前端框架思想的最经典应用。单页应用意思是用一个 html 文件,效果上实现多个页面。页面之间的切换实际上只是页面的组件切换。

下面我们将 index.html 以及 login.html 合并,来实现一个单页应用

首先准备两个页面的组件,然后用 vue-router 进行切换。由于之前已经做好了两个页面的 vue 化,可以直接复用两个页面的 App.vue。App.vue 中包含了对应页面所有的内容

接下来准备 vue-router 的内容:

  1. 安装依赖:npm i vue-router@3, 由于我们使用的是 vue@2,所以要指定 vue-router 的版本
  2. 写路由文件:router/routes.js
javascript 复制代码
import Home from "../pages/Home/App.vue";
import Login from "../pages/Login/App.vue";

const routes = [
	{
		path: "/",
		component: Home,
		children: [{ path: "home", component: Home }],
	},
	{
		path: "/login",
		component: Login,
	},
];

export default routes;

准备了三个路由,如果路径是//home,那就会渲染 Home 页面;如果路径是/login,就会渲染 Login 页面

路由出口文件:router/index.js,采用historymode

javascript 复制代码
import VueRouter from "vue-router";
import Vue from "vue";
import routes from "./routes";

Vue.use(VueRouter);

export default new VueRouter({
	mode: "history",
	routes: routes,
});

然后准备 Vue 应用的入口文件

首先是 src/App.vue:

vue 复制代码
<template>
		<router-view></router-view>
</template>

<script>
export default {};
</script>

<style></style>

一个空文件,主要是给 vue-router 做 render 用

然后是 src/main.js

javascript 复制代码
import Vue from "vue";
import router from "./router";
import App from "./App.vue";
import "../css/public.css"; // 这个公共样式文件别忘了

new Vue({
	render: (h) => h(App),
	router: router,
}).$mount("#root");

最后是 webpack 的单页应用配置文件,单页应用的配置文件比多页应用简单多了,大家在网上看到的配置 99%都是单页应用,所以我就不详细讲,只把重点部分标注出来

javascript 复制代码
module.exports = {
  //入口和出口都是单页应用
  entry: resolve("./src/main.js"),
	output: {
		path: resolve("dist"),
		filename: "index.js",
	},
  devServer: {
		// 直接设置为true即可,不需要配置rewrite
		historyApiFallback: true,
	},
  plugins:[
    // html-webpack-plugin也只需要一个就可以
    new HtmlWebpackPlugin({
			template: resolve("./public/index.html"),
			filename: "index.html",
		})
  ]
}

搞定!!

下面来测试一下,启动项目:npm run dev

打开/以及/home页面:

没问题,下面来看看/login页面

也没问题!!

现在文件夹结构是这样子:

这个项目还有其他的页面,可以采用其中一个实现方案将其他的页面一并改造了

总结

老前端项目改造,从 webpack 的引入,再到 vue 框架的引入,再到多页应用或者单页应用的实现,对于一个老项目的改造到这里就差不多接近尾声了,看这文件夹就是个完完全全的现代前端项目。

但对于一个现代前端项目来说,项目中的 webpack 配置是不够看的,下篇文章来分享对项目性能优化的内容,敬请期待。

相关推荐
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9152 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
阑梦清川2 小时前
在鱼皮的模拟面试里面学习有感
学习·面试·职场和发展
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍