最近在试水 Vue CLI 3,并且尝试配置一个多页面(多应用)项目出来,期间又遇到各种路径问题,于是...于是有了下面的唠叨。
以下都是基于 Vue CLI 3 来举例说明的,使用 2.x 版本的其实也类似
首先,参考 ,并通过自己的实践,可以总结出以下内容
静态资源可以通过两种方式进行处理:
1、以下情况下,资源不会被 webpack 处理,而是被直接拷贝:
放置在 public 目录下,即使未被使用。
通过绝对路径被引用,即以 / 开头的路径。
2、以下情况下,资源会被 webpack 处理(URL的resolve、minify、uglify、转 base64 等):
使用 JavaScript 导入。
在 template/CSS 中通过相对路径(即以 . 开头或直接以文件(夹)名开头)被引用。
URL 以 ~ 开头,其后的任何内容都会作为一个模块请求被解析。
URL 以 @ 开头,它也会作为一个模块请求被解析(@ 是在 webpack 设置的 alias)。
我们应该根据实际情况去选择我们要引用的资源是否要被处理,然后用对应的、正确的方式去引用它们以达到目的。以下对使用绝对路径和相对路径的方法和注意事项进行描述。
使用绝对路径
默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上(对应选项 baseUrl: 'https://www.jb51.net/'),例如 https://www.my-app.com/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.my-app.com/my-app/,则设置 baseUrl 为 /my-app/。正因为以上的可能情况,我们应该在打算引用纯静态资源(那些不被webpack处理的资源,一般就是 public 目录下的资源)的时候,都确保使用 baseUrl 作为 URL 的开头,以下列举在不同文件中配合 baseUrl 选项写绝对路径的使用方法和注意事项:
在入口html文件中使用
我们可以使用语法插入 baseUrl:
<link href="<%= BASE_URL %>favicon.ico" >
在 *.vue 中使用
我们可以通过 Vue CLI 提供的客户端环境变量 process.env.BASE_URL 来获取 baseUrl:
/* 在需要的组件中定义 baseUrl,然后在 <template> 下使用 */ <template> <div> <img :src="imgUrl"> <img :src="`${baseUrl}imgs/my_image.png`"> </div> </template> <script> export default { name: 'App', data() { return { baseUrl: process.env.BASE_URL, isBigImg: Math.random() > 0.5 } } computed: { // 动态地获取不同的静态资源 imgUrl() { if (this.isBigImg) { return `${baseUrl}imgs/my_image_big.png` } else { return `${baseUrl}imgs/my_image.png` } } } }; </script> /* 个人建议可以在全局定义,减去在每个组件内定义的麻烦 Vue.prototype.$baseUrl = process.env.BASE_URL // 在 <template> 下使用 <img :src="`${$baseUrl}imgs/my_image.png`">
在其他 js 模块中使用
import axios from 'axios'; const baseUrl = process.env.BASE_URL; axios.defaults.baseURL = `${baseUrl}api/`
在样式文件中使用(以 sass/scss 为例)
因为 sass 文件中无法获取环境变量或 webpack 内的配置,于是最直接的方法就是自定义一个变量,然后在每个需要使用到它的文件引用它。
// config.scss $baseUrl: "https://www.jb51.net/"; // icon.scss @import "config" .icon-test { display: inline-block; background: url($baseUrl + 'imgs/icon_test.png') no-repeat; width: 10px; height: 10px; }
这样做还是有比较大的麻烦:
如果生产环境和开发环境的 baseUrl 不同,每次转换环境去编译都要去手动修改这个变量,十分之麻烦而且可能出现错误;
两处地方相同的定义,不方便代码的维护;
在后续讲到的关于 相对路径 的坑会涉及到,每次引用 config.scss 的路径并不一定是一样的,且很容易出现编译错误;
那么,有没有什么办法能避免人工操作、避免多次的定义并且避免使用可能潜在错误的引用呢?幸亏的确是有的! ,可以为全局注入变量或样式文件;
// vue.config.js const baseUrl = process.env.NODE_ENV === 'production' ? '/sub/' : 'https://www.jb51.net/'; module.exports = { baseUrl, css: { loaderOptions: { sass: { data: `$baseUrl: "${baseUrl}";` } } } }
这样我们就可以在全局的 `sass` 文件中使用 `$baseUrl` 这个变量了,而且在只定义一次的情况下,能根据编译环境变化而变化。
使用相对路径
使用相对路径也会存在一些坑,接下来会列举常见的关于相对路径的坑与解决方法:
JavaScript 动态引用资源,编译没报错,但页面上请求返回 404
有时候我们需要使用 JavaScript 动态的引用某些资源,且希望这些资源被 webpack 一同打包,我们先看这种做法:
computed: { background () { return `./bgs/${this.id}.jpg` } }