vue-cli4 之 vue-loader 工作流程

先整體過一遍 vue-cli4 處理單文件組件 (SFCs)的大致過程

webpack并不認(rèn)識.vue后綴的單文件組件,因此需要強(qiáng)大的 vue-loader 來處理。

首先,vue-loader 通過@vue/component-compiler-utils解析.vue源代碼,為每個語言塊生成一個導(dǎo)入(可以將每個塊看作一個“虛擬模塊”),這一步實際返回的模塊代碼看起來像這樣:

// import <template> 塊
import render from 'source.vue?vue&type=template'
// import <script> 塊
import script from 'source.vue?vue&type=script'
export * from 'source.vue?vue&type=script'
// import <style> 塊
import 'source.vue?vue&type=style&index=1'

script.render = render
export default script

VueLoaderPlugin插件會基于webpack配置的每個模塊規(guī)則, 創(chuàng)建針對 Vue 相應(yīng)語言塊請求的克隆版本。vue-cli 已經(jīng)為.js文件配置了 babel-loader 和 cache-loader,因此這個規(guī)則也會被復(fù)制并應(yīng)用到導(dǎo)入的<script>模塊。同樣地, import 的<style> 塊會按需應(yīng)用 sass-loader、css-loader、vue-style-loader 等預(yù)處理器、 <template> 的部分則會交由 pug-plain-loader 和 raw-loader 處理。

在webpack內(nèi)部,一個import script from 'source.vue?vue&type=script'的模塊請求會被擴(kuò)展為:

import script from 'babel-loader!vue-loader!source.vue?vue&type=script'

如果對 “用 import 方式指定文件loader相關(guān)規(guī)則” 不清楚,可以參閱【 webpack 之 Loader 詳解內(nèi)聯(lián)方式(inline) 部分】和 【loader使用之內(nèi)聯(lián)方式】。

相似地, 假設(shè)為 *.scss 文件配置了 style-loader + css-loader + sass-loader,

<style scoped lang="scss">
...
</style>

經(jīng)由 vue-loader 解析后返回:

import 'source.vue?vue&type=style&index=1&scoped&lang=scss'

跟著被webpack擴(kuò)展為:

import 'style-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss'

像這樣,vue-loader 經(jīng)多重處理,使 Vue 組件同時可以使用其它loader,然后用自己的專用 loader 鏈處理每個語言塊,最終將這些塊組裝到一個ES Module中。它的默認(rèn)導(dǎo)出是一個包含 Vue.js 組件選項的對象。

<style><template> 中引用的資源會被當(dāng)作模塊依賴來處理

模版,即<template>的內(nèi)容將被提取并以模版字符串的形式傳遞給 vue-template-compiler,預(yù)處理為 JavaScript 渲染函數(shù),并最終注入到從 <script> 導(dǎo)出的組件中。
Vue Loader 編譯<template>塊時,會將遇到的資源URL轉(zhuǎn)為 webpack 模塊請求。即將資源作為模塊 require() 進(jìn)來。
比如模版中有如下代碼片段,

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

會被編譯成:

createElement('img', {
  attrs: {
    src: require('../image.png') // 現(xiàn)在這是一個模塊的請求了
  }
})

任何匹配 .css (或通過 <style> 的 lang 特性指定的擴(kuò)展名) 文件的 webpack 規(guī)則都將會運(yùn)用到 <style> 塊的內(nèi)容中。

<style scoped>塊內(nèi)部的 CSS 只作用于當(dāng)前組件中的元素,在應(yīng)用css-loader之前,它會先通過postcss-loader進(jìn)行以下轉(zhuǎn)換來實現(xiàn)樣式的本地化:

<style scoped>
.example {
  color: red;
}
</style>

<template>
  <div class="example">hi</div>
</template>

轉(zhuǎn)換結(jié)果:

<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

<style>塊都會經(jīng)過 css-loader 處理,來把其中 @import 和 url() 的資源URL轉(zhuǎn)為模塊請求。如果是<style lang='sass'>,在 css-loader 之前還要先執(zhí)行 sass-loader,把 sass 文件轉(zhuǎn)換 成 css。

// 把 `@import` 或`url()` 變成 `require()`
url(../image.png) => require('../image.png')

webpack 會在 import 或 "load(加載)" 模塊時預(yù)處理文件。而資源URL經(jīng)解析轉(zhuǎn)換后指向的文件(如.png)仍然不是js模塊,就需要 url-loaderfile-loader 進(jìn)一步處理了。
vue-cli4 的默認(rèn)配置中,當(dāng)資源小于4kb( url-loader 配置項 limit 定義的值 )就會被轉(zhuǎn)換成內(nèi)聯(lián)的 base-64 URL,這會大大減少小文件的 HTTP 請求數(shù)。而如果文件大于該閾值,會自動交給 file-loader 處理。
源碼詳見./node_modules/@vue/cli-service/lib/config/base.js

file-loader 可以指定要復(fù)制/放置資源文件的目標(biāo)位置,以及使用版本哈希命名這些文件以獲得更好的緩存。此外,還會在打包輸出中自動重寫文件路徑為正確的 URL(文件訪問路徑)。這意味著你可以按自己的喜好管理輸出文件的目錄或文件名,并且可以在開發(fā)時使用相對路徑,完全不用擔(dān)心部署時 URL 會出問題。

樣式的最后處理:非生產(chǎn)環(huán)境,vue-style-loader 會往 head 標(biāo)簽中注入多個 style 標(biāo)簽。而生產(chǎn)環(huán)境,mini-css-extract-plugin插件會將 CSS 樣式提取到單獨(dú)的文件中,為每個包含 CSS 的 JS 文件創(chuàng)建一個 .css 文件,并且支持 CSS 和 SourceMaps 的按需加載。

關(guān)于 file-loader 的具體配置,請移步 file-loader 配置詳解以及資源相對路徑處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容