Vue CLI HTML 和靜態(tài)資源

2020-03-13 15:10 更新

HTML

Index 文件

public/index.html 文件是一個會被 html-webpack-plugin 處理的模板。在構(gòu)建過程中,資源鏈接會被自動注入。另外,Vue CLI 也會自動注入 resource hint (preload/prefetch、manifest 和圖標(biāo)鏈接 (當(dāng)用到 PWA 插件時) 以及構(gòu)建過程中處理的 JavaScript 和 CSS 文件的資源鏈接。

插值

因為 index 文件被用作模板,所以你可以使用 lodash template 語法插入內(nèi)容:

  • <%= VALUE %> 用來做不轉(zhuǎn)義插值;
  • <%- VALUE %> 用來做 HTML 轉(zhuǎn)義插值;
  • <% expression %> 用來描述 JavaScript 流程控制。

除了被 html-webpack-plugin 暴露的默認(rèn)值之外,所有客戶端環(huán)境變量也可以直接使用。例如,BASE_URL 的用法:

<link rel="icon" href="<%= BASE_URL %>favicon.ico">

更多內(nèi)容可以查閱:

Preload

<link rel="preload"> 是一種 resource hint,用來指定頁面加載后很快會被用到的資源,所以在頁面加載的過程中,我們希望在瀏覽器開始主體渲染之前盡早 preload。

默認(rèn)情況下,一個 Vue CLI 應(yīng)用會為所有初始化渲染需要的文件自動生成 preload 提示。

這些提示會被 @vue/preload-webpack-plugin 注入,并且可以通過 chainWebpack 的 config.plugin('preload') 進(jìn)行修改和刪除。

Prefetch

<link rel="prefetch"> 是一種 resource hint,用來告訴瀏覽器在頁面加載完成后,利用空閑時間提前獲取用戶未來可能會訪問的內(nèi)容。

默認(rèn)情況下,一個 Vue CLI 應(yīng)用會為所有作為 async chunk 生成的 JavaScript 文件 (通過動態(tài) import() 按需 code splitting 的產(chǎn)物) 自動生成 prefetch 提示。

這些提示會被 @vue/preload-webpack-plugin 注入,并且可以通過 chainWebpack 的 config.plugin('prefetch') 進(jìn)行修改和刪除。

示例:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    // 移除 prefetch 插件
    config.plugins.delete('prefetch')

    // 或者
    // 修改它的選項:
    config.plugin('prefetch').tap(options => {
      options[0].fileBlacklist = options[0].fileBlacklist || []
      options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
      return options
    })
  }
}

當(dāng) prefetch 插件被禁用時,你可以通過 webpack 的內(nèi)聯(lián)注釋手動選定要提前獲取的代碼區(qū)塊:

import(/* webpackPrefetch: true */ './someAsyncComponent.vue')

webpack 的運(yùn)行時會在父級區(qū)塊被加載之后注入 prefetch 鏈接。

提示

Prefetch 鏈接將會消耗帶寬。如果你的應(yīng)用很大且有很多 async chunk,而用戶主要使用的是對帶寬較敏感的移動端,那么你可能需要關(guān)掉 prefetch 鏈接并手動選擇要提前獲取的代碼區(qū)塊。

不生成 index

當(dāng)基于已有的后端使用 Vue CLI 時,你可能不需要生成 index.html,這樣生成的資源可以用于一個服務(wù)端渲染的頁面。這時可以向 vue.config.js 加入下列代碼:

// vue.config.js
module.exports = {
  // 去掉文件名中的 hash
  filenameHashing: false,
  // 刪除 HTML 相關(guān)的 webpack 插件
  chainWebpack: config => {
    config.plugins.delete('html')
    config.plugins.delete('preload')
    config.plugins.delete('prefetch')
  }
}

然而這樣做并不是很推薦,因為:

  • 硬編碼的文件名不利于實(shí)現(xiàn)高效率的緩存控制。
  • 硬編碼的文件名也無法很好的進(jìn)行 code-splitting (代碼分段),因為無法用變化的文件名生成額外的 JavaScript 文件。
  • 硬編碼的文件名無法在現(xiàn)代模式下工作。

你應(yīng)該考慮換用 indexPath 選項將生成的 HTML 用作一個服務(wù)端框架的視圖模板。

構(gòu)建一個多頁應(yīng)用

不是每個應(yīng)用都需要是一個單頁應(yīng)用。Vue CLI 支持使用 vue.config.js 中的 pages 選項構(gòu)建一個多頁面的應(yīng)用。構(gòu)建好的應(yīng)用將會在不同的入口之間高效共享通用的 chunk 以獲得最佳的加載性能。

處理靜態(tài)資源

靜態(tài)資源可以通過兩種方式進(jìn)行處理:

  • 在 JavaScript 被導(dǎo)入或在 template/CSS 中通過相對路徑被引用。這類引用會被 webpack 處理。
  • 放置在 public 目錄下或通過絕對路徑被引用。這類資源將會直接被拷貝,而不會經(jīng)過 webpack 的處理。

從相對路徑導(dǎo)入

當(dāng)你在 JavaScript、CSS 或 *.vue 文件中使用相對路徑 (必須以 . 開頭) 引用一個靜態(tài)資源時,該資源將會被包含進(jìn)入 webpack 的依賴圖中。在其編譯過程中,所有諸如 <img src="...">、background: url(...) 和 CSS @import 的資源 URL 都會被解析為一個模塊依賴。

例如,url(./image.png) 會被翻譯為 require('./image.png'),而:

<img src="./image.png">

將會被編譯到:

h('img', { attrs: { src: require('./image.png') }})

在其內(nèi)部,我們通過 file-loader 用版本哈希值和正確的公共基礎(chǔ)路徑來決定最終的文件路徑,再用 url-loader 將小于 4kb 的資源內(nèi)聯(lián),以減少 HTTP 請求的數(shù)量。

你可以通過 chainWebpack 調(diào)整內(nèi)聯(lián)文件的大小限制。例如,下列代碼會將其限制設(shè)置為 10kb:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('images')
        .use('url-loader')
          .loader('url-loader')
          .tap(options => Object.assign(options, { limit: 10240 }))
  }
}

URL 轉(zhuǎn)換規(guī)則

  • 如果 URL 是一個絕對路徑 (例如 /images/foo.png),它將會被保留不變。
  • 如果 URL 以 . 開頭,它會作為一個相對模塊請求被解釋且基于你的文件系統(tǒng)中的目錄結(jié)構(gòu)進(jìn)行解析。
  • 如果 URL 以 ~ 開頭,其后的任何內(nèi)容都會作為一個模塊請求被解析。這意味著你甚至可以引用 Node 模塊中的資源:<img src="~some-npm-package/foo.png">
  • 如果 URL 以 @ 開頭,它也會作為一個模塊請求被解析。它的用處在于 Vue CLI 默認(rèn)會設(shè)置一個指向 <projectRoot>/src 的別名 @。(僅作用于模版中)

public 文件夾

任何放置在 public 文件夾的靜態(tài)資源都會被簡單的復(fù)制,而不經(jīng)過 webpack。你需要通過絕對路徑來引用它們。

注意我們推薦將資源作為你的模塊依賴圖的一部分導(dǎo)入,這樣它們會通過 webpack 的處理并獲得如下好處:

  • 腳本和樣式表會被壓縮且打包在一起,從而避免額外的網(wǎng)絡(luò)請求。
  • 文件丟失會直接在編譯時報錯,而不是到了用戶端才產(chǎn)生 404 錯誤。
  • 最終生成的文件名包含了內(nèi)容哈希,因此你不必?fù)?dān)心瀏覽器會緩存它們的老版本。

public 目錄提供的是一個應(yīng)急手段,當(dāng)你通過絕對路徑引用它時,留意應(yīng)用將會部署到哪里。如果你的應(yīng)用沒有部署在域名的根部,那么你需要為你的 URL 配置 publicPath 前綴:

  • 在 public/index.html 或其它通過 html-webpack-plugin 用作模板的 HTML 文件中,你需要通過 <%= BASE_URL %> 設(shè)置鏈接前綴:<link rel="icon" href="<%= BASE_URL %>favicon.ico">
  • 在模板中,你首先需要向你的組件傳入基礎(chǔ) URL:data () { return { publicPath: process.env.BASE_URL } } 然后:<img :src="`${publicPath}my-image.png`">

何時使用 public 文件夾

  • 你需要在構(gòu)建輸出中指定一個文件的名字。
  • 你有上千個圖片,需要動態(tài)引用它們的路徑。
  • 有些庫可能和 webpack 不兼容,這時你除了將其用一個獨(dú)立的 <script> 標(biāo)簽引入沒有別的選擇。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號