各位靓仔靓女们,晚上好!我是你们的老朋友,今天咱们聊聊 Vue CLI 多页应用(MPA)的那些事儿。
先声明,我不是什么“编程专家”,只是个在代码堆里摸爬滚打多年的老兵。咱们今天就是唠嗑,把 MPA 这玩意儿扒个底朝天,争取让大家听完能上手就干!
开场白:单页应用(SPA)虽好,但 MPA 也有春天!
现在 SPA 好像成了主流,各种框架都在推。SPA 确实爽,用户体验好,切换流畅。但是!它也有缺点,比如 SEO 不友好,首屏加载慢等等。这时候,MPA 就有了用武之地。
MPA 简单粗暴,每个页面都是独立的,SEO 友好,首屏加载也快。当然,它也有缺点,比如页面切换可能会有白屏,公共资源不好管理等等。所以,选择 SPA 还是 MPA,要根据你的项目实际情况来决定。
第一章:Vue CLI 搭建 MPA 项目:手把手教你填坑!
Vue CLI 搭建 MPA 项目,其实很简单,但是一不小心就会掉坑里。咱们一步一步来,保证大家不迷路。
-
安装 Vue CLI:
如果你还没装 Vue CLI,先把它装上:
npm install -g @vue/cli # OR yarn global add @vue/cli -
创建项目:
vue create my-mpa-project选择
Manually select features,然后选择Babel、Router、Vuex、CSS Pre-processors、Linter / Formatter这些常用的功能(当然,你可以根据自己的需求选择)。然后选择
Use history mode for router?,这里我们选择No,因为 MPA 不需要 history 模式。CSS 预处理器可以选一个你喜欢的,比如
Sass/SCSS (with dart-sass)。Linter / Formatter 可以选择
ESLint + Standard config或者ESLint + Prettier。最后选择
Lint on save和Commit。 -
配置
vue.config.js:这是 MPA 的关键!在项目的根目录下,创建一个
vue.config.js文件,然后写入以下配置:module.exports = { pages: { index: { entry: 'src/pages/index/main.js', template: 'public/index.html', filename: 'index.html', title: 'Index Page', chunks: ['chunk-vendors', 'chunk-common', 'index'] }, about: { entry: 'src/pages/about/main.js', template: 'public/about.html', filename: 'about.html', title: 'About Page', chunks: ['chunk-vendors', 'chunk-common', 'about'] } }, // 其他配置... };这个
pages对象就是 MPA 的核心配置。每个 key 代表一个页面,比如index和about。每个页面都有以下属性:entry:入口文件,每个页面都有一个独立的入口文件。template:HTML 模板文件,每个页面都可以有自己的模板。filename:输出的文件名,比如index.html和about.html。title:页面的标题,会设置<title>标签。chunks:指定要包含的 chunk,比如chunk-vendors、chunk-common和index。
-
创建页面目录和文件:
按照
vue.config.js里的配置,创建对应的目录和文件:src/ pages/ index/ main.js App.vue about/ main.js App.vue public/ index.html about.htmlmain.js负责初始化 Vue 实例,App.vue是页面的根组件。 -
修改
public/index.html和public/about.html:在 HTML 文件里,修改
<title>标签,并添加<div id="app"></div>:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Index Page</title> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>about.html类似,只需要修改<title>标签即可。 -
启动项目:
npm run serve # OR yarn serve现在,你应该能看到两个页面了:
http://localhost:8080/index.html和http://localhost:8080/about.html。
第二章:MPA 项目优化:让你的应用飞起来!
MPA 项目搭建起来了,但是性能优化也很重要。咱们来聊聊 MPA 项目的优化策略。
-
公共资源提取:
MPA 项目里,很多资源都是公共的,比如 Vue、Vue Router、Vuex、Element UI 等等。如果每个页面都引入这些资源,会造成资源浪费。所以,我们需要把这些公共资源提取出来,放到一个单独的 chunk 里。
在
vue.config.js里,配置chainWebpack:module.exports = { pages: { // ... }, chainWebpack: config => { config.optimization.splitChunks({ cacheGroups: { vendors: { name: 'chunk-vendors', test: /[\/]node_modules[\/]/, priority: -10, chunks: 'initial' }, common: { name: 'chunk-common', minChunks: 2, priority: -20, chunks: 'initial', reuseExistingChunk: true } } }); } };这个配置会把
node_modules里的代码提取到chunk-vendors.js里,把被多个页面引用的代码提取到chunk-common.js里。然后在
pages配置里,指定每个页面都要包含chunk-vendors和chunk-common:module.exports = { pages: { index: { // ... chunks: ['chunk-vendors', 'chunk-common', 'index'] }, about: { // ... chunks: ['chunk-vendors', 'chunk-common', 'about'] } }, // ... }; -
资源预加载:
在 MPA 项目里,页面切换的时候,浏览器会重新加载资源。如果资源比较大,会造成白屏。所以,我们需要对资源进行预加载,让浏览器提前下载资源。
在
vue.config.js里,配置chainWebpack:module.exports = { pages: { // ... }, chainWebpack: config => { config.plugin('preload-index') .use(require('@vue/preload-webpack-plugin'), [{ rel: 'preload', include: 'initial', fileBlacklist: [/.map$/, /chunk-vendors..*/, /chunk-common..*/] }]); config.plugin('preload-about') .use(require('@vue/preload-webpack-plugin'), [{ rel: 'preload', include: 'initial', fileBlacklist: [/.map$/, /chunk-vendors..*/, /chunk-common..*/] }]); config.plugin('prefetch-index') .use(require('@vue/preload-webpack-plugin'), [{ rel: 'prefetch', include: 'asyncChunks', fileBlacklist: [/.map$/] }]); config.plugin('prefetch-about') .use(require('@vue/preload-webpack-plugin'), [{ rel: 'prefetch', include: 'asyncChunks', fileBlacklist: [/.map$/] }]); } };这个配置会使用
@vue/preload-webpack-plugin插件,对初始加载的资源进行preload,对异步加载的资源进行prefetch。preload:告诉浏览器尽快加载资源,优先级比较高。prefetch:告诉浏览器在空闲的时候加载资源,优先级比较低。
-
图片优化:
图片是网页里最占体积的资源之一。所以,我们需要对图片进行优化,减小图片的大小。
- 选择合适的图片格式: PNG 适合存储颜色较少的图片,JPEG 适合存储颜色较多的图片,WebP 适合存储各种类型的图片。
- 压缩图片: 可以使用各种图片压缩工具,比如 TinyPNG、ImageOptim 等等。
- 使用 CDN: 把图片放到 CDN 上,可以加快图片的加载速度。
- 懒加载: 对于不在首屏显示的图片,可以使用懒加载,只有当图片进入可视区域的时候才加载。
-
Gzip 压缩:
Gzip 是一种常用的压缩算法,可以减小网页的大小,加快网页的加载速度。
在
vue.config.js里,配置configureWebpack:const CompressionWebpackPlugin = require('compression-webpack-plugin'); module.exports = { pages: { // ... }, configureWebpack: config => { config.plugins.push( new CompressionWebpackPlugin({ filename: '[path][base].gz', algorithm: 'gzip', test: /.(js|css|html|svg)$/, threshold: 10240, minRatio: 0.8, deleteOriginalAssets: false }) ); } };这个配置会使用
compression-webpack-plugin插件,对js、css、html、svg等文件进行 Gzip 压缩。需要注意的是,你需要配置服务器,让服务器支持 Gzip 解压。
-
代码分割:
除了提取公共资源,我们还可以对代码进行更细粒度的分割。比如,可以把每个页面的组件都分割成单独的 chunk。
Vue CLI 默认会对异步组件进行代码分割。如果你的组件不是异步组件,可以使用
import()函数进行动态导入:// 异步组件 const MyComponent = () => import('./MyComponent.vue'); // 动态导入 import('./MyComponent.vue').then(module => { const MyComponent = module.default; });使用动态导入的组件,会被分割成单独的 chunk。
-
路由懒加载:
如果你的 MPA 项目里,某个页面比较大,可以使用路由懒加载,只有当用户访问这个页面的时候才加载。
在 Vue Router 里,使用
import()函数进行动态导入:const routes = [ { path: '/about', component: () => import('./pages/about/App.vue') } ];这样,只有当用户访问
/about页面的时候,才会加载about页面的组件。 -
缓存:
利用浏览器缓存可以有效减少资源加载时间。可以设置 HTTP 缓存头,例如
Cache-Control和Expires,来控制浏览器缓存行为。 对于静态资源,可以设置较长的缓存时间,对于动态资源,可以设置较短的缓存时间或者使用ETag和Last-Modified来进行缓存验证。此外,还可以使用 Service Worker 来实现更高级的缓存策略,例如离线访问。
第三章:MPA 项目的坑:小心别踩雷!
MPA 项目虽然简单,但是也有一些坑需要注意。
-
publicPath配置:如果你的 MPA 项目部署在子目录下,比如
https://example.com/my-app/,你需要配置publicPath,否则资源路径会出错。在
vue.config.js里,配置publicPath:module.exports = { publicPath: '/my-app/' }; -
跨域问题:
如果你的 MPA 项目需要访问其他域名的 API,可能会遇到跨域问题。
解决跨域问题的方法有很多,比如 JSONP、CORS、代理等等。
在 Vue CLI 里,可以使用
devServer.proxy配置代理:module.exports = { devServer: { proxy: { '/api': { target: 'http://api.example.com', changeOrigin: true, pathRewrite: { '^/api': '' } } } } };这样,所有以
/api开头的请求都会被代理到http://api.example.com。 -
页面间通信:
MPA 项目里,每个页面都是独立的,页面间通信比较麻烦。
常用的页面间通信方法有:
- URL 参数: 通过 URL 参数传递数据。
localStorage: 使用localStorage存储数据。postMessage: 使用postMessageAPI 进行跨域通信。- Vuex: 如果你的项目比较复杂,可以使用 Vuex 进行状态管理。
第四章:总结:MPA 项目的优势与劣势
咱们来总结一下 MPA 项目的优势和劣势:
| 优势 | 劣势 |
|---|---|
| SEO 友好 | 页面切换可能会有白屏 |
| 首屏加载快 | 公共资源不好管理 |
| 每个页面都是独立的,易于维护 | 页面间通信比较麻烦 |
| 适合简单的、静态的网站 | 不适合复杂的、交互性强的网站 |
| 可以使用不同的技术栈来构建不同的页面 | 构建过程可能比 SPA 复杂,需要更多配置 |
尾声:选择适合你的才是最好的!
好了,今天的讲座就到这里了。希望大家对 Vue CLI MPA 项目有了更深入的了解。记住,没有最好的技术,只有最适合你的技术。选择 SPA 还是 MPA,要根据你的项目实际情况来决定。
如果大家还有什么问题,欢迎随时提问。祝大家编程愉快! Bye Bye!