前言
当我们在使用 Vue.js 构建单页应用时,路由是一个非常重要的概念。Vue Router 是 Vue.js 官方的路由管理工具,支持多种路由模式,包括 hash 模式和 history 模式。
在不同的模式下,如何正确配置 output.publicPath 是一个关键的问题,它决定了静态资源的访问路径。本文将介绍如何在不同模式下正确配置 Vue 路由的 output.publicPath,希望能帮助读者更好地理解 Vue 路由。
故事的开始
有一天,让张三用脚手架创建一个脚手架,稍微配置一下。然后张三想了一下,果断百度,结果把output.publicPath配置成了'./'
my-project/
├── public/
│ ├── index.html
│ └── favicon.ico
├── src/
│ ├── main.js
│ ├── App.vue
│ ├── router.js
│ └── views/
│ ├── Home.vue
│ └── About.vue
│ └── Content.vue
├── package.json
└── webpack.config.js
当完成整个项目,张三把路由hash模式,改成了history。
遇到报错
有一天,王五点着页面,五哥从/home跳转到了/about,从/about跳转到/content/2,,通过params参数查询id为2的内容,当五哥看完文章,点击跳转/home页面的时候,跳转不了了,五哥打开控制台,报错了。Vue Router - Failed to resolve async component after reloading page
journey
title 点击页面
section /home
点击跳转/about路由: 5: yes
section /about
点击跳转/content/2: 5: yes
section /content/2
返回home页面: 5: yes
section /home
error找不到文件: 2: no
解决
将vue.config.js中的publicPath不设置,或者设置为'/',publicPath的默认值为'/'
原因
那为什么修改一下publicPath就好了呢,这事得从output.publicPath说起
publicPath有什么用
在 Webpack 中,output 中的 publicPath 选项用于指定 webpack 在加载 js、css、图片等资源时的 URL 前缀,也就是说,指定了 publicPath 后,Webpack 在处理资源时会自动在 URL 前面添加 publicPath 的值。
例如,设置 publicPath 为 "/dist/",那么加载 js 文件的 URL 就会变成 http://example.com/dist/main.js,而不是默认的http://example.com/main.js
这个选项的主要作用是为了解决静态资源的路径问题,比如在开发环境中,静态资源的路径是相对于 HTML 文件所在的目录的,而在生产环境中,静态资源的路径是相对于域名的根目录的。通过设置 publicPath,Webpack 可以自动处理这些路径的问题,从而使代码更加可移植、可复用。
绝对路径和相对路径
现在有两个路径127.0.0.1:8000/home和127.0.0.1:8000/content/2。
| 页面路径 | 相对路径(./) | 绝对路径(/) |
|---|---|---|
| 127.0.0.1:8000/home | 127.0.0.1:8000/ | 127.0.0.1:8000/ |
| 127.0.0.1:8000/content/2 | 127.0.0.1:8000/content/ | 127.0.0.1:8000/ |
也就是说,设置为./不同url下,./所表示的路径是不一样的,但设置为/绝对路径,在不同url下,/所表示的路径都是一样的。
当页面从127.0.0.1:8000/home跳转到127.0.0.1:8000/content/2的时候,再跳回127.0.0.1:8000/home,如果设置为./此时就是要跳转127.0.0.1:8000/content/home页面,但是没有对应的路由组件哇,报错,如果设置为/此时要跳转的路径就是127.0.0.1:8000/home正确跳转
hash模式和history模式
现在是不是有一个疑问,为什么hash模式没有问题,但是history就有问题了?
在哈希模式下,URL 中的哈希值(#)会被浏览器当作客户端内部的锚点来处理,浏览器不会将哈希值的部分发送到服务器端。因此,在哈希模式下,URL 中的哈希值不会影响到资源的加载路径。所以,无论 publicPath 的值是相对路径还是绝对路径,都不会出现路由切换时静态资源加载失败的问题。
也就是说在hash模式下,无论是相对路径还是绝对路径,./和/对应的都是 #之前的路径,而history模式下,./对应的路径会随着url的变化而变化
在使用Webpack进行打包的情况下,路由组件被打包后会生成对应的 chunk 文件,其文件名通常为 [name].[hash].js。其中,[name] 为路由组件的名称,[hash] 为文件内容的 hash 值。例如,如果路由组件名称为 Home,则对应的打包后的文件名可能为 Home.1234567.js。而这个 chunk 文件的路径就是 publicPath + 'Home.' + [hash] + '.js'。
由于在路由跳转的过程中,并不会重新打包已经加载过的组件,而是复用已经加载过的组件实例。下面看一下webpack怎么说
例如
当从/home跳转到 /about/2 路由,再跳转到 /home 路由时,由于在路由跳转的过程中,并不会重新打包已经加载过的组件,而是复用已经加载过的组件实例。在这个过程中,页面的切换只是通过改变 URL 来触发路由匹配和组件的渲染。因此,在从 /about/2 跳转到 /home 的过程中,home 组件并不会重新打包和加载,而是复用已经加载过的 home 组件实例。,路由模式为 history,而此时 publicPath 的值为 ./,所以浏览器会在当前路径下寻找 /home 对应的文件。但是当前路径实际上是 /about,所以浏览器会在 /about 目录下寻找 /home 对应的文件,而该文件不存在,导致出现找不到组件的错误。就会出现找不到对应chunk的情况。
最后,看一下vue-cli文档关于publicPath的配置怎么说