vite vue-router history模式打包部署。运维:👍

vite vue-router history模式打包部署

本文前提是前端使用vite + vue-router@4,部署是用nginx

内容较多,如果想直接看如何配置,点击直达

背景小故事

众所周知,使用vue开发时逃不掉url后面的#号,也就是vue-routerhash模式,比如http://example.com/#/home, 不论什么原因想要去掉#时,我们就得考虑使用histtory模式了。

使用vue-router@4创建history模式路由,大致代码如下👇

js 复制代码
const router = createRouter({
    history: createWebHistory(),
})

对于前端而言,无论是history模式还是hash模式其实和我画页面没有任何影响,但是当我们辛辛苦苦开发完,准备打包部署的时候问题就随之而来了

随之而来的问题

前端打包交给运维部署的时候,会发现和之前一样的部署方式却404了,为什么呢?这里就涉及到hash模式和history模式的区别了。

  1. hash模式 简单来说,它是基于浏览器的锚点实现的,#号后的url变化不会向服务器发送请求
  2. history模式 url的变化都会向服务器发送一个请求,如果服务器没有做处理,对应的url找不到对应的资源返回,那么就会页面404

大家都知道,前端打包文件中(一般情况下)只包含了一个index.html文件和其他如jscss等资源文件,所以当history模式的url变化时,在服务器上找不到与之对应的资源,就会404了。

说的有点抽象,给大家举个例子:

同一个页面的urlhash模式是http://example.com/#/home,那么访问后到服务器时#号后面的内容是不会发送到服务器的,那么就是访问/根目录,/后面没有内容,就会默认访问index.html页面,打的包中正好有index.html文件,那么就一点问题也没有。但如果是history模式,此时的urlhttp://example.com/home,那么这个url代表的意思就是(服务端没做其他操作的前提下)访问服务器根目录下的home目录下的index.html文件,但我们知道正常打的包根本就没有这个home目录,那就理所当然的404

解决办法来了

正如vue-router官网上所说

要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面

所以我们在nginx做如下配置,相关链接

nginx 复制代码
# nginx 相关配置
location / {
  try_files $uri $uri/ /index.html;
}

这里用到了try_files配置,简单说下它的作用:它首先匹配url有没有对应的资源(即上面的$uri),如果有则返回;如果没有,则继续查找url目录下(即上面的$uri/)有没有默认的index.html文件,如果还没有,最后返回根目录下的index.html(即上面的/index.html)。其实在这里,我们想要的就是让它无脑返回根目录下的index.html(因为我们只有这个可访问文件)

这个时候,我们把打的包扔到nginx根目录 下,并且加上如上配置,访问如http://example.com/home页面就一切正常了。

但到这里结束了吗?不,这才刚刚开始...

新的问题

经过上面几步的操作,我们确实能访问到使用history模式的页面了,但这有个前提:把我们的页面部署在根目录 下。如果是部署在子目录下,那又不能正常显示了。

比如,我们把网页部署在/wj目录下(下文出现的所有wj指的都是这个二级目录名称),并把前端打的包扔在了服务器上的/wj目录下,期望访问http://example.com/wj/home能正常访问,那么按照经验,我们把nginx的配置修改成如下:

nginx 复制代码
# nginx 修改后配置
location /wj {
  try_files $uri $uri/ /wj/index.html;
}

nginx -s reload 后你会发现一个新问题

html文件其实正常返回了,但是资源文件都404了,检查资源文件的请求路径,发现根本没有请求到真实的资源地址,因为我们的资源文件都是在/wj目录下,图中请求的是根目录下的资源文件,那当然没有了。

新的解决办法

书接上回,资源路径请求错误,聪明的小伙伴应该知道要改哪里了,对的,就是vite的配置中有个base配置,可以配置开发或生产环境服务的公共基础路径,官网配置链接

所以我们将vite.config.js的配置修改成如下

js 复制代码
// vite.config.js
{
	base: '/wj/'
    // 其他代码省略
}

再重新打包部署,你会发现

所有请求都200都正常,但页面却白屏,百思不得其解。

但我们仔细分析,我们此时访问的路径是http://localhost:8008/wj/survey/edit,但是我们vue-router定义的路由其实是http://localhost:8008/survey/edit,差了一个/wj,当你用/wj/survey/edit匹配路由的时候是匹配不到的,因为你定义的路由是/survey/edit

这时候聪明的你肯定想到什么了,没错,vue-router也有一个对应的base设置,官网配置链接,所以我们修改对应配置如下

js 复制代码
const router = createRouter({
    history: createWebHistory('/wj/')
})

重新打包上传,你会发现一切正常,非常完美,大功告成!

不同环境的打包

不是大功告成,不是非常完美了吗?怎么还有?

别急,且看下文

确实到这一步已经能完美运行了,但不同环境的打包怎么办?手动改一次代码打包一次?不可能也不应该吧。

比如在我司测试环境是使用Jenkins自动化部署的,它是直接部署到根目录 下的,如果按照上面的步骤,把vite, vue-routerbase改成固定值的话,自动部署后页面就不能正常访问了。所以我们要能根据不同环境切换不同的base,这里采用的方式是使用vite环境变量和模式来切换,具体方式如下:

创建 3 个.env文件,分别为.env.dev(测试Jenkins环境), .env.development(开发环境), .env.production(生产环境)

xml 复制代码
# .env.dev
VITE_BASE_URL=/
xml 复制代码
# .env.development
VITE_BASE_URL=/wj/
xml 复制代码
# .env.production
VITE_BASE_URL=/wj/

定义了不同环境时的环境变量,那么只要在vue-routervite config对应位置使用环境变量替换原来的固定值即可

js 复制代码
const router = createRouter({
    // 这里由原来的 '/wj/' 固定值改为import.meta.env.VITE_BASE_URL替换
    history: createWebHistory(import.meta.env.VITE_BASE_URL)
})

vite.config.js中略有不同,大致代码如下:

js 复制代码
import { defineConfig, loadEnv } from 'vite'

export default ({ mode }) => {
	// 使用loadEnv获取环境变量
    const env = loadEnv(mode, process.cwd())
    const BASE_URL = env.VITE_BASE_URL

    return defineConfig({
        base: BASE_URL, // 使用loadEnv获取VITE_BASE_URL替换原来的固定值 '/wj/'
        // ...省略其他代码
    })
}

修改package.json文件,加入不同环境的打包命令

json 复制代码
"build-prod": "vue-tsc && vite build",
"build-dev": "vue-tsc && vite build --mode dev",

分别对应打包生产环境,打包测试环境的包

另外还有一点,测试环境Jenkins自动化部署时记得修改nginx配置,只要在其中加入如下配置即可:

nginx 复制代码
location / {
	try_files $uri $uri/ /index.html;
}

因为测试环境是部署在根目录下,所以nginx直接使用这个配置就行,不需要其他修改。

至此,就大结局了。

总结

总结一下history模式部署时需要改动的地方

如果是部署在根目录 下,只需要改nginx配置如下即可,前端配置无需修改

nginx 复制代码
location / {
	try_files $uri $uri/ /index.html;
}

如果是部署在二级目录 下(如部署在/wj目录),修改内容如下

  • nginx配置
nginx 复制代码
# nginx 修改后配置
location /wj {
  try_files $uri $uri/ /wj/index.html;
}
  • vue-router配置
js 复制代码
const router = createRouter({
    history: createWebHistory('/wj/')
})
  • vite.config配置
js 复制代码
// vite.config.js
{
	base: '/wj/'
    // 其他代码省略
}
相关推荐
熊的猫1 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人3 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人3 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR3 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香3 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai3 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书