詳解vue中靜態資源的路徑問題(深度好文)

前言: webpack中的require解析

首先明確一點,在項目中的webpack.config.js等項目配置文件中使用的require屬於nodejs範疇,而進入index.js後,加載的組件中的require都屬於webpack的解析範疇。css

開始前,我們先聊聊webpack中require的用法。html

您可能以爲這有什麼,不就是直接require(url)直接引用嗎,若是您這麼想,那可就過小看require了。vue

let url = "@/assets/images/carousel/logo.svg"
require(url)    //報錯

let url = "logo.svg"
require("@/assets/images/carousel/"+url); //正確

很詭異是否是? 我相信你第一次見到後會不自覺的說句f**k。node

這是由於你修改頁面後,webpack進行編譯,等待編譯完,須要進行工程的打包,而後打包正確,才能熱加載運行並刷新頁面。
若是require中傳入的是個變量,它有多是計算機系統中的任何目錄下的任何文件,那麼在打包靜態資源時它有可能會將你的電腦整個磁盤遍歷一遍(它很傻)。因此至少須要給出在哪一個路徑下,這樣才能精確的將那個路徑下的對應文件打包,而後在代碼運行時,直接用對應文件名生成正則匹配(由於打包後的文件,可能有hash值。不能直接查文件名),找到後,加載到代碼中。webpack

因此,請記住 儘量詳細的指定require中的路徑,而後拼接變量web


接下來講下打包後的路徑問題
webpack將項目中的靜態資源編譯打包後,生成的路徑已經不是原來的那個路徑了。如
src/assets/image/logo.jpg
編譯後可能變成
dist/public/image/logo.1d997ea3.jpgvue-cli

而經過require("src/assets/image/logo.jpg"),會自動找到並加載dist/public/image/logo.1d997ea3.jpg文件npm

1、<template>部分的路徑處理

Vue Loader 在編譯單文件組件中的 <template> 塊時,它也會將全部遇到的資源 URL 轉換爲 webpack 模塊請求。(這樣咱們就不必手動調用require了,而是交給vue-loader處理了)ide

vue-loader默承認以處理的標籤/特性的組合以下:svg

{
  video: ['src', 'poster'],
  img: 'src',   //即img元素上的src屬性
  source: 'src',  //source元素上的src屬性
  image: 'xlink:href'
}

面對上面的標籤組合,vue-loader會自動進行資源url的轉換。

轉換規則:
a、若是路徑是絕對路徑,會被原樣保留。如/src/assets/image/login/title.png

//代碼
<template>
   <img src="/src/assets/image/login/title.png" alt="">
</template>

//渲染後html頁面
<img data-v-70c98a68="" src="/src/assets/image/login/title.png" alt="">
//固然這個圖片是沒法展現的,由於編譯後title.png已不在src/assets/image/login下了

b、若是路徑以 . 開頭,將會被看做相對的模塊依賴。如 ./titlea.png

//代碼
<img src="./titlea.png" alt="">

//渲染後html頁面
<img data-v-70c98a68="" src="/static/img/titlea.1e9fa570.png" alt="">

c、若是路徑以 @ 開頭,也會被看做模塊依賴。若是你的 webpack 配置中給 @ 配置了 alias,這就頗有用了。全部 vue-cli 建立的項目都默認配置了將 @ 指向 /src

//代碼
<img src="@/assets/image/login/title.png" alt="">

//渲染後html頁面
<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">

d、若是路徑以 ~ 開頭,其後的部分將會被看做模塊依賴,既能夠加載含有別名的靜態資源,又能夠加載node-modules中的資源。如

//代碼
<img src="~@/assets/image/login/title.png" alt="">
//渲染後html頁面
<img data-v-70c98a68="" src="/static/img/title.1e9fa570.png" alt="">


//代碼
<img src="~[npm包名]/xxx/logo.png" alt="">
//渲染後的html頁面
<img data-v-70c98a68="" src="/static/img/logo.2f53e458.png" alt="">

2、<style>部分的路徑處理

因爲vue-loader在處理style時,採用的是style-loader,因此可能 和上面<template>部分的轉換規則不太同樣。
在vue-loader的內部使用了以下的配置(不必定配置,也有可能經過js直接給rules賦值):

//在vue-loader的內部使用css-loader
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: 'css-loader',
        options: {  
          url: true, //默認選項
        },
      },
    ],
  },
};

url爲true時,則意味着能夠將url中的字符串經過require()加載進來。

轉換規則

//代碼
<style scoped>
.login-wrap {
  background-image: url("/src/assets/image/login/title.png");
}
</style>

//渲染後css
.login-wrap[data-v-70c98a68] {
  background-image: url(/src/assets/image/login/title.png);
}

一樣不會顯示,編譯後的路徑不是這個
b、若是路徑以 . 開頭,將會被看做相對的模塊依賴。如 ./titlea.png

//代碼
<style scoped>
.login-wrap {
  background-image: url("./titlea.png");
}
</style>

//渲染後css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/titlea.1e9fa570.png);
}

c、若是路徑以 ~ 開頭,其後的部分將會被看做模塊依賴,便可以加載含有別名的靜態資源,又能夠加載node-modules中的資源。如

//代碼
<style scoped>
.login-wrap {
  background-image: url("~[npm包名]/logo.png");
}
</style>

//渲染後css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/logo.e05643fc.png);
}




//代碼
<style scoped>
.login-wrap {
  background-image: url("~@/assets/image/login/bg.png");
}
</style>

//渲染後css
.login-wrap[data-v-70c98a68] {
  background-image: url(/static/img/bg.1d997ea3.png);
}

注意: 和上面的<template>相比,惟獨少了直接用@開頭的方式url("@/assett/logo.png"),因此下面寫法是錯誤的

//代碼
<style scoped>
.login-wrap {
  background-image: url("@/assets/image/login/bg.png");
}
</style>

感謝各位看客的閱讀,因爲在項目中遇到了這樣的困然,再加上同事也常常問我什麼緣由,故而填坑,以避免其餘人踩坑。

相關文章
相關標籤/搜索