0%

Vite Vue3 多页面开发环境路由重定向

  1. 需求
  2. 思路与实现
    1. 简单实现
    2. 做成插件
  3. 参考

需求

开发一个多页面项目,使用npm init vue@3简单初始化后修改目录结构,包含一个根页面和两个独立的其他页面(分别放在不同的文件夹下并设置独立的入口),如下图所示。

image-20220609035203231

参考官网的多页面配置,可以通过npm run build构建、npm run preview预览,在浏览器中正确浏览,当输入http://localhost:4567/document(最后可以有斜杠也可由没有),能够正确显示不同文件夹中的页面内容。vite的配置(vite.config.ts)如下所示,两个地方:root改为根页面所在目录,build.rollupOptions.input添加相应的入口页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { fileURLToPath, URL } from 'url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
root: path.resolve(__dirname, 'src/views'),
base: '/',
build: {
outDir: path.resolve(__dirname, 'dist'),
assetsDir: 'assets',
rollupOptions: {
input: {
index: path.resolve(__dirname, 'src/views/index.html'),
download: path.resolve(__dirname, 'src/views/download/index.html'),
document: path.resolve(__dirname, 'src/views/document/index.html')
}
}
},
plugins: [
vue()
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})

但在开发环境下npm run dev,直接输入http://localhost:4567/document无法正常访问,显示的还是首页,只有加上/,也就是http://localhost:4567/document/,才能正确访问。为了使前者也能正确访问,需要做进一步的配置。

思路与实现

简单实现

实现的思路很简单,就是做一个重定向,要进行重定向就要自己写一个插件plugins,实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
plugins: [
vue(),
{
name: 'my-test-plugin',
configureServer(server) {
const route = '/document';
server.middlewares.use(route, (req, res, next) => {
if (req.url === '/' && req.originalUrl === route) {
res.writeHead(302, { Location: `${route}/` });
return res.end();
}
next();
});
}
}
],

很简单,使用http的重定向状态302在路由的最后加上一个斜杠/就可以了。详细的开发服务器参考可以看官方文档(文末链接),这里用到的中间件接口和connect一致,相较于express用起来难受一些,没有直接可调用的重定向接口(redirect)。

做成插件

devServerRouter.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import type { PluginOption } from 'vite';

type objRouterItem = {
oldPath: string;
newPath: string;
}

type devServerRouterItem = string | objRouterItem | [string, string];

/**
* 路由替换,采用全字匹配
* ['/a', '/b'] => ['/a/', '/b/'],
* [['/a', '/a/'], ['/b', '/b/']]
* [{oldPath: '/a', newPath: '/a.html'}]
*/
export default (items: devServerRouterItem[]): PluginOption => {
return {
name: 'vite-plugin-devServer-router',
configureServer(server) {
items.forEach(item => {
let oldPath: string;
let newPath: string;
if (typeof item === 'string') {
oldPath = item;
newPath = item[item.length - 1] !== '/' ? `${item}/` : item; // 末尾不为/,则改为目录
} else if (Array.isArray(item)) {
oldPath = item[0];
newPath = item[1];
} else {
oldPath = item.oldPath;
newPath = item.newPath;
}
if (oldPath !== newPath) {
server.middlewares.use(oldPath, (req, res, next) => {
// 只匹配全字
if (req.url === '/' && (req.originalUrl && req.originalUrl === oldPath)) {
// 重定向
res.writeHead(302, {
Location: newPath
});
return res.end();
}
next();
});
}
});
}
};
};

调用(vite.config.ts)

1
2
3
4
5
6
7
8
9
10
11
import { defineConfig } from 'vite'
import devServerRouter from './src/plugins/devServerRouter'

export default defineConfig({
plugins: [
devServerRouter([
['/download', '/download/'],
['/document', '/document/']
])
],
})

参考

插件 API | Vite 官方中文文档 (vitejs.dev)

JavaScript API | Vite 官方中文文档 (vitejs.dev)