vue多页实践-开发
环境
- node v12.5.0
- 系统 win
- vuecli @vue/cli 4.5.15
- ide WebStorm 2021.1 x64
本文是将vue-cli创建的spa应用改造为多页应用。
我们可以把多页应用理解为由多个单页构成的应用,而何谓多个单页呢?其实你可以把一个单页看成是一个 html 文件,那么多个单页便是多个 html 文件,多页应用便是由多个 html 组成的应用,如下图所示:
- 文章 示例代码仓库 建议先大概看一遍文章-在看示例代码。
开始改造
更改目录
- 多页应用的每个单页都可以拥有单页应用 src 目录下的文件及功能
- 在
src
下新建pages
文件夹,将public文件夹中 index.html、src 文件夹中 App.vue、main.js
复制到相应的应用文件夹内修改文件名称,然后删除即可。 - 创建如下图所示文件目录,文件夹的名称不做要求但需要同名的入口js、html文件边配置多页会用到。
- 拿index文件夹来举例说明
index.js
相当于main.js
index.html
相当于 public文件夹中index.html
index.vue
相当于 src 文件夹中App.vue
src
下的router、store
文件夹保留与否 看具体场景,是所用应用共用一个还是需要分开。比如应用的router、store
文件差别很大,那就需要分开或者使用命名空间,如果几乎一样那就可以共用一个文件(数据不共享)。
更改 vue.config.js
- 这里先看下 vuecli 文档
- 单页应用中入口文件默认指定
main.js
,多页应用入口文件则包含了page1.js、page2.js、index.js
等,数量取决于 pages 文件夹下目录的个数,动态生成 pages 对象是一个很好的选择。
动态获取 pages 对象
- 安装
yarn add glob
扫描文件夹,并返回我们需要的文件
const path = require('path')
const glob = require('glob')
// 配置pages多页面获取当前文件夹下的html和js
function getEntry (globPath) {
const entries = {}
let basename
let tmp
let pathname
glob.sync(globPath).forEach(function (entry) {
basename = path.basename(entry, path.extname(entry))
tmp = entry.split('/').splice(-3)
pathname = basename // 正确输出js和html的路径
entries[pathname] = {
entry: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[1] + '.js',
template: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[2],
title: tmp[2],
filename: tmp[2],
chunks: ['chunk-vendors', 'chunk-common', tmp[1]]
}
})
return entries
}
const pages = getEntry('./src/pages/**?/*.html')
- 获取到的对象 可以在
vue.config.js
进行打印 - 在
vue.config.js
中的module.exports
对象写入多页配置(也就是比单页多了一个 pages 配置)
配置动态引入js css文件
- 配置动态引入需要使用
html-webpack-plugin
插件,多页会存在多个配置 只配置一个就会抛错 如下图。
- 错误也让人摸不着头脑
- 可以这样做
- html使用动态配置的 js,css 图中红框为模板语法具体查看文档
完整的配置
const path = require('path')
const glob = require('glob')
// 配置pages多页面获取当前文件夹下的html和js
function getEntry (globPath) {
const entries = {}
let basename
let tmp
let pathname
glob.sync(globPath).forEach(function (entry) {
basename = path.basename(entry, path.extname(entry))
tmp = entry.split('/').splice(-3)
pathname = basename // 正确输出js和html的路径
entries[pathname] = {
entry: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[1] + '.js',
template: 'src/' + tmp[0] + '/' + tmp[1] + '/' + tmp[2],
title: tmp[2],
filename: tmp[2],
chunks: ['chunk-vendors', 'chunk-common', tmp[1]]
}
})
return entries
}
const pages = getEntry('./src/pages/**?/*.html')
module.exports = {
pages,
publicPath: '/',
outputDir: 'dist',
assetsDir: 'assets',
filenameHashing: true,
lintOnSave: true,
productionSourceMap: false,
devServer: {
index: 'index.html', // 默认启动serve 打开的页面
host: '0.0.0.0',
port: 8889,
https: false,
hotOnly: false,
proxy: null
},
chainWebpack: config => {
Object.keys(pages).forEach(entryName => {
// 配置动态引入js、css
config
.plugin(`html-${entryName}`)
.tap(args => {
args[0].cdn = []
return args
})
config.plugins.delete(`prefetch-${entryName}`)
})
}
}
运行-打包
上述配置运行 npm run serve
会运行所有应用
+ index 访问 `http://localhost:8889/#/`
+ page1 访问 `http://localhost:8889/page1/#/`
+ page2 访问 `http://localhost:8889/page2/#/`
上述的配置运行 运行npm run build
会打包所有应用
- 打包后访问应用(使用node库 http-server), 默认会访问index.html 所以除了 index 外其他应用访问需要指定 html文件
- index 访问
http://localhost:8889/#/
- page1 访问
http://localhost:8889/page1.html/#/
- page2 访问
http://localhost:8889/page2.html/#/
- index 访问
- 所以使用路径做一些判断的时候需要自行处理 比如 使用字符换替换
html
等无关字符。
打包单一应用-以page1文件夹为例
- 多个页面
pages
多个配置,同理可得 单个应用pages
只有一个配置。 - 这样也就需要有一个配置的地方,这里使用env文件配置。
- 根目录新建
.env、.env.dev_page1、.env.pro_page1
并写入对应数据。.env
所有环境都被载入 在默认打包所有应用时使用.env.dev_page1
dev 本地开发时加载.env.pro_page1
pro 打包后加载
- 更改
package.json
的scripts
配置
- 修改
vue.config.js
完整代码可在示例仓库中找到
优化
- 上述 动态配置js,css写死了两示例,同样可以将数据配置在 .env文件中,指定环境加载指定文件
- 多个入口js文件,引入文件 配置重复,可以提取出一个公共的js,导出一个初始化 vue 的函数,将store、router传进去做初始化。
- 其他压缩打包体积等不在 本文讨论范围 (各位想必都有一手绝活!!!)
参考文章
转载自:https://juejin.cn/post/7053979399716077576