Vue CLI3搭建的項(xiàng)目中路徑相關(guān)問題的解決
這是開頭
最近在試水 Vue CLI 3,并且嘗試配置一個(gè)多頁面(多應(yīng)用)項(xiàng)目出來,期間又遇到各種路徑問題,于是...于是有了下面的嘮叨。
以下都是基于 Vue CLI 3 來舉例說明的,使用 2.x 版本的其實(shí)也類似
首先,參考 官方文檔對靜態(tài)資源處理的說明,并通過自己的實(shí)踐,可以總結(jié)出以下內(nèi)容
靜態(tài)資源可以通過兩種方式進(jìn)行處理:
1、以下情況下,資源不會被 webpack 處理,而是被直接拷貝:
- 放置在 public 目錄下,即使未被使用。
- 通過絕對路徑被引用,即以 / 開頭的路徑。
2、以下情況下,資源會被 webpack 處理(URL的resolve、minify、uglify、轉(zhuǎn) base64 等):
- 使用 JavaScript 導(dǎo)入。
- 在 template/CSS 中通過相對路徑(即以 . 開頭或直接以文件(夾)名開頭)被引用。
- URL 以 ~ 開頭,其后的任何內(nèi)容都會作為一個(gè)模塊請求被解析。
- URL 以 @ 開頭,它也會作為一個(gè)模塊請求被解析(@ 是在 webpack 設(shè)置的 alias)。
我們應(yīng)該根據(jù)實(shí)際情況去選擇我們要引用的資源是否要被處理,然后用對應(yīng)的、正確的方式去引用它們以達(dá)到目的。以下對使用絕對路徑和相對路徑的方法和注意事項(xiàng)進(jìn)行描述。
使用絕對路徑
默認(rèn)情況下,Vue CLI 會假設(shè)你的應(yīng)用是被部署在一個(gè)域名的根路徑上(對應(yīng)選項(xiàng) baseUrl: '/'
),例如 https://www.my-app.com/
。如果應(yīng)用被部署在一個(gè)子路徑上,你就需要用這個(gè)選項(xiàng)指定這個(gè)子路徑。例如,如果你的應(yīng)用被部署在 https://www.my-app.com/my-app/,則設(shè)置 baseUrl 為 /my-app/。正因?yàn)橐陨系目赡芮闆r,我們應(yīng)該在打算引用純靜態(tài)資源(那些不被webpack處理的資源,一般就是 public 目錄下的資源)的時(shí)候,都確保使用 baseUrl 作為 URL 的開頭,以下列舉在不同文件中配合 baseUrl 選項(xiàng)寫絕對路徑的使用方法和注意事項(xiàng):
在入口html文件中使用
我們可以使用lodash template 語法插入 baseUrl:
<link rel="icon" href="<%= BASE_URL %>favicon.ico" rel="external nofollow" >
在 *.vue 中使用
我們可以通過 Vue CLI 提供的客戶端環(huán)境變量 process.env.BASE_URL 來獲取 baseUrl:
/* 在需要的組件中定義 baseUrl,然后在 <template> 下使用 */ <template> <div id="app"> <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: { // 動態(tài)地獲取不同的靜態(tài)資源 imgUrl() { if (this.isBigImg) { return `${baseUrl}imgs/my_image_big.png` } else { return `${baseUrl}imgs/my_image.png` } } } }; </script> /* 個(gè)人建議可以在全局定義,減去在每個(gè)組件內(nèi)定義的麻煩 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 = `http://www.example.com${baseUrl}api/`
在樣式文件中使用(以 sass/scss 為例)
因?yàn)?sass 文件中無法獲取環(huán)境變量或 webpack 內(nèi)的配置,于是最直接的方法就是自定義一個(gè)變量,然后在每個(gè)需要使用到它的文件引用它。
// config.scss $baseUrl: "/"; // icon.scss @import "config" .icon-test { display: inline-block; background: url($baseUrl + 'imgs/icon_test.png') no-repeat; width: 10px; height: 10px; }
這樣做還是有比較大的麻煩:
- 如果生產(chǎn)環(huán)境和開發(fā)環(huán)境的 baseUrl 不同,每次轉(zhuǎn)換環(huán)境去編譯都要去手動修改這個(gè)變量,十分之麻煩而且可能出現(xiàn)錯(cuò)誤;
- 兩處地方相同的定義,不方便代碼的維護(hù);
- 在后續(xù)講到的關(guān)于 相對路徑 的坑會涉及到,每次引用 config.scss 的路徑并不一定是一樣的,且很容易出現(xiàn)編譯錯(cuò)誤;
那么,有沒有什么辦法能避免人工操作、避免多次的定義并且避免使用可能潛在錯(cuò)誤的引用呢?幸虧的確是有的! sass-loader 提供了一個(gè) data 選項(xiàng),可以為全局注入變量或樣式文件;
// vue.config.js const baseUrl = process.env.NODE_ENV === 'production' ? '/sub/' : '/'; module.exports = { baseUrl, css: { loaderOptions: { sass: { data: `$baseUrl: "${baseUrl}";` } } } }
這樣我們就可以在全局的 `sass` 文件中使用 `$baseUrl` 這個(gè)變量了,而且在只定義一次的情況下,能根據(jù)編譯環(huán)境變化而變化。
使用相對路徑
使用相對路徑也會存在一些坑,接下來會列舉常見的關(guān)于相對路徑的坑與解決方法:
JavaScript 動態(tài)引用資源,編譯沒報(bào)錯(cuò),但頁面上請求返回 404
有時(shí)候我們需要使用 JavaScript 動態(tài)的引用某些資源,且希望這些資源被 webpack 一同打包,我們先看這種做法:
computed: { background () { return `./bgs/${this.id}.jpg` } }
我們會發(fā)現(xiàn)打包沒報(bào)錯(cuò),但是在頁面上可以發(fā)現(xiàn)這些資源的請求都是 404。這是因?yàn)轭愃?./bgs/${this.id}.jpg 這樣的動態(tài)字符串在打包階段不會被 webpack 識別為依賴,資源也就不會被打包了。為了讓 webpack 識別這些依賴,我們可以這樣做:
computed: { background () { return require('./bgs/' + this.id + '.jpg') } }
通過使用 require() 讓 webpack 將括號內(nèi)的 URL 識別為一個(gè)依賴并傳入對應(yīng)的 loader 進(jìn)行處理。
要特別注意,以上的例子中,./bgs/ 目錄下的所有圖片都會被打包,因?yàn)?webpack 無法得知頁面在運(yùn)行時(shí)會使用哪張圖片,所以 webpack 會把所有的圖片都打包了。
在 sass 中使用相對路徑引用圖片或字體文件,編譯報(bào)錯(cuò)
先來看一個(gè)例子:
// 文件目錄 // src // |--assets // | | // | |-fonts // | | |- iconfont.eot // | | // | |-css // | | // | |-iconfont.scss // | // |--app.vue
// iconfont.scss @font-face { font-family: "iconfont"; src: url("../fonts/iconfont.eot"); ... }
// app.vue <style lang="scss"> @import './assets/css/iconfont.scss' </style>
往往我們在打包的時(shí)候會報(bào)錯(cuò)(以上例子會報(bào)錯(cuò)),說找不到 iconfont.eot。 sass-loader 文檔中有對 url() 進(jìn)行了單獨(dú)的說明:
Since Sass/libsass does not provide url rewriting, all linked assets must be relative to the output.
If you're just generating CSS without passing it to the css-loader, it must be relative to your web root.
If you pass the generated CSS on to the css-loader, all urls must be relative to the entry-file (e.g. main.scss).
大致意思就是, sass-loader 并不提供 url 的重寫,所有的 scss 文件被 sass-loader 處理成最終的 CSS 后(編譯過程中 url 不會被重寫即保持原樣),再傳遞給 css-loader 處理。也就是說,所有的 url 都是相對于輸出的!在 Vue CLI 搭建的項(xiàng)目中,它們都是相對于使用這些 scss 文件的 vue 文件的。對于上例,是相對于 app.vue 的,因此報(bào)錯(cuò)。我們會很自然的會希望路徑的引用是相對于 scss 文件本身的,sass-loader 文檔中也給出了解決方案:
Add the missing url rewriting using the resolve-url-loader. Place it before the sass-loader in the loader chain.
Library authors usually provide a variable to modify the asset path. bootstrap-sass for example has an $icon-font-path. Check out this working bootstrap example.
第一個(gè)方法:使用 resolve-url-loader 來彌補(bǔ) sass-loader 缺失的 url 重寫功能,注意要放到 sass-loader 以前調(diào)用。
第二個(gè)方法:Library 作者一般都會提供變量,用來設(shè)置資源路徑,如 bootstrap-sass 可以通過 $icon-font-path 來設(shè)置。參見this working bootstrap example。
這樣看來解決的思路有兩種:
- 寫 url 的時(shí)候就寫 vue 文件相對于資源的路徑。這種方法較為暴力,當(dāng)項(xiàng)目層級復(fù)雜了之后容易寫錯(cuò)路徑(加上現(xiàn)有的編輯器、IDE應(yīng)該認(rèn)為你寫的路徑是錯(cuò)誤的)。當(dāng)同個(gè) scss 文件被多個(gè)不同層級的 vue 文件引用的時(shí)候,這種暴力的方法就行不通了!
- 使用第三方庫補(bǔ)充 sass-loader 的路徑重寫功能,讓路徑的引用是相對于當(dāng)前 scss 文件本身的。這個(gè)方法能較好的解決問題。
在這里提供一下我喜歡的方法。與其考慮 讓路徑的引用是相對于 scss 文件本身 或 讓路徑直接相對于 vue 文件,我們可以換個(gè)思路,讓所有路徑都是以根目錄往下找,并讓 webpack 對路徑進(jìn)行重寫,但是直接用 /src/ 這種絕對路徑的寫法會讓這些資源不被 webpack 打包。在前文提及到的,webpack 有個(gè)強(qiáng)大的機(jī)制,也就是 ~,通過在 url 前面添加 ~ 可以告訴 webpack 要把它當(dāng)做一個(gè)模塊來處理,也就是會被 webpack 打包。配合 webpack 提供的別名 @(/src),我們可以對上例做修改:
// iconfont.scss @font-face { font-family: "iconfont"; src: url("~@/assets/fonts/iconfont.eot"); ... }
這樣子,通過 webpack 對模塊的處理,可以正確通過編譯!這樣做的好處是可大大避免書寫相對路徑可能產(chǎn)生的錯(cuò)誤,每次只需“無腦”從根目錄往下找就是了,又可以減小依賴、減少配置項(xiàng)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue3.0 項(xiàng)目搭建和使用流程
- 如何搭建一個(gè)完整的Vue3.0+ts的項(xiàng)目步驟
- Vue項(xiàng)目環(huán)境搭建詳細(xì)總結(jié)
- vue-cli3搭建項(xiàng)目的詳細(xì)步驟
- 用Vue-cli搭建的項(xiàng)目中引入css報(bào)錯(cuò)的原因分析
- 詳解使用vue腳手架工具搭建vue-webpack項(xiàng)目
- VSCode搭建vue項(xiàng)目的實(shí)現(xiàn)步驟
- vue-cli3.0 腳手架搭建項(xiàng)目的過程詳解
- 使用Vue-cli 3.0搭建Vue項(xiàng)目的方法
- vite+vue3項(xiàng)目初始化搭建的實(shí)現(xiàn)步驟
相關(guān)文章
詳解使用vue腳手架工具搭建vue-webpack項(xiàng)目
本篇文章主要介紹了詳解使用vue腳手架工具搭建vue-webpack項(xiàng)目,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05Vue數(shù)據(jù)更新但頁面沒有更新的多種情況問題及解決
這篇文章主要介紹了Vue數(shù)據(jù)更新但頁面沒有更新的多種情況問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07vue里使用create,mounted調(diào)用方法的正確姿勢說明
這篇文章主要介紹了vue里使用create,mounted調(diào)用方法的正確姿勢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04微前端qiankun主應(yīng)用與子應(yīng)用之間的跳轉(zhuǎn)示例
這篇文章主要為大家介紹了微前端qiankun主應(yīng)用與子應(yīng)用之間的跳轉(zhuǎn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08解決vue報(bào)錯(cuò):Do?not?mutate?vuex?store?state?outside?mutati
這篇文章主要介紹了解決vue報(bào)錯(cuò):Do?not?mutate?vuex?store?state?outside?mutation?handlers問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05