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模式路由,大致代码如下👇

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 相关配置
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 修改后配置
location /wj {
  try_files $uri $uri/ /wj/index.html;
}

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

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

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

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

新的解决办法

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

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

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

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

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

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

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

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

const router = createRouter({
    history: createWebHistory('/wj/')
})

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

不同环境的打包

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

别急,且看下文

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

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

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

# .env.dev
VITE_BASE_URL=/
# .env.development
VITE_BASE_URL=/wj/
# .env.production
VITE_BASE_URL=/wj/

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

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

vite.config.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文件,加入不同环境的打包命令

"build-prod": "vue-tsc && vite build",
"build-dev": "vue-tsc && vite build --mode dev",

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

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

location / {
	try_files $uri $uri/ /index.html;
}

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

至此,就大结局了。

总结

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

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

location / {
	try_files $uri $uri/ /index.html;
}

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

  • nginx配置
# nginx 修改后配置
location /wj {
  try_files $uri $uri/ /wj/index.html;
}
  • vue-router配置
const router = createRouter({
    history: createWebHistory('/wj/')
})
  • vite.config配置
// vite.config.js
{
	base: '/wj/'
    // 其他代码省略
}

原文链接:https://juejin.cn/post/7264783369878388796 作者:俊男哥的bug

(0)
上一篇 2023年8月9日 上午11:07
下一篇 2023年8月10日 上午10:00

相关推荐

发表回复

登录后才能评论