介紹
- 容許爲 Vue 組件的每一個部分使用其它的 webpack loader,例如在 <style> 的部分使用 Sass 和在 <template> 的部分使用 Pug(模板引擎)
- 容許在一個 .vue 文件中使用自定義塊,並對其運用自定義的 loader 鏈;
起步
- Vue Loader 的配置和其它的 loader 不太同樣。除了經過一條規則將 vue-loader 應用到全部擴展名爲 .vue 的文件上以外,請確保在你的 webpack 配置中添加 Vue Loader 的插件
// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
mode: 'development',
module: {
rules: [ // 應該是自上而下依次處理
{
test: /\.vue$/,
loader: 'vue-loader'
},
// 它會應用到普通的 `.js` 文件
// 以及 `.vue` 文件中的 `<script>` 塊
{
test: /\.js$/,
loader: 'babel-loader'
},
// 它會應用到普通的 `.css` 文件
// 以及 `.vue` 文件中的 `<style>` 塊
{
test: /\.css$/,
use: [
'vue-style-loader', // 用來提供css的熱重載
'css-loader' // 用來處理css中的資源路徑爲模塊,同時支持CSS Modules(<style module>)
]
}
]
},
plugins: [
// 請確保引入這個插件來施展魔法。它的職責是將你定義過的其它規則複製並應用到 .vue 文件裏相應語言的塊。例如,若是你有一條匹配 /\.js$/ 的規則,那麼它會應用到 .vue 文件裏的 <script> 塊。
new VueLoaderPlugin()
]
}
處理資源路徑
- 當 Vue Loader 編譯單文件組件中的 <template> 塊時,它也會將全部遇到的資源 URL 轉換爲 webpack 模塊請求。
<img src="../image.png">
// 編譯成
createElement('img', {
attrs: {
src: require('../image.png') // 如今這是一個模塊的請求了
}
})
- 默認下列標籤/特性的組合會被轉換,且這些組合時可使用 transformAssetUrls 選項進行配置的。
{
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
- 若是你配置了爲 <style> 塊使用 css-loader,則你的 CSS 中的資源 URL 也會被同等處理。
轉換規則
- 若是路徑是絕對路徑 (例如 /images/foo.png),會原樣保留。
- 若是路徑以 . 開頭,將會被看做相對的模塊依賴,並按照你的本地文件系統上的目錄結構進行解析。
- 若是路徑以 ~ 開頭,其後的部分將會被看做模塊依賴。這意味着你能夠用該特性來引用一個 Node 依賴中的資源
- 若是路徑以 @ 開頭,也會被看做模塊依賴。若是你的 webpack 配置中給 @ 配置了 alias,這就頗有用了。全部 vue-cli 建立的項目都默認配置了將 @ 指向 /src。
相關的 Loader
- 由於像 .png 這樣的文件不是一個 JavaScript 模塊,你須要配置 webpack 使用 file-loader 或者 url-loader 去合理地處理它們。經過 Vue CLI 建立的項目已經把這些預配置好了。
- file-loader 能夠指定要複製和放置資源文件的位置,以及如何使用版本哈希命名以得到更好的緩存。此外,這意味着 你能夠就近管理圖片文件,可使用相對路徑而不用擔憂部署時 URL 的問題。使用正確的配置,webpack 將會在打包輸出中自動重寫文件路徑爲正確的 URL。
- url-loader 容許你有條件地將文件轉換爲內聯的 base-64 URL (當文件小於給定的閾值),這會減小小文件的 HTTP 請求數。若是文件大於該閾值,會自動的交給 file-loader 處理。
使用預處理器
- style中會根據 lang 特性以及你 webpack 配置中的規則自動推斷出要使用的 loader
Sass
npm install -D sass-loader node-sass
module.exports = {
module: {
rules: [
// ... 忽略其它規則
// 普通的 `.scss` 文件和 `*.vue` 文件中的
// `<style lang="scss">` 塊都應用它
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
]
},
// 插件忽略
}
Sass vs SCSS
- SCSS是Sass 3引入的新語法,爲了向css3靠攏
- sass-loader 會默認處理不基於縮進的 scss 語法。爲了使用基於縮進的 sass 語法,你須要向這個 loader 傳遞選項:
// webpack.config.js -> module.rules
{
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
indentedSyntax: true
}
}
]
}
共享全局變量
- sass-loader 也支持一個 data 選項,這個選項容許你在全部被處理的文件之間共享常見的變量,而不須要顯式地導入它們:
// webpack.config.js -> module.rules
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// 你也能夠從一個文件讀取,例如 `variables.scss` ?
data: `$color: red;`
}
}
]
}
Less
npm install -D less less-loader
// webpack.config.js -> module.rules
{
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
}
Stylus
npm install -D stylus stylus-loader
// webpack.config.js -> module.rules
{
test: /\.styl(us)?$/,
use: [
'vue-style-loader',
'css-loader',
'stylus-loader'
]
}
PostCSS
- PostCSS 的配置能夠經過 postcss.config.js 或 postcss-loader 選項來完成。postcss-loader 也能夠和上述其它預處理器結合使用。
- Vue Loader v15 再也不默認應用 PostCSS 變換。你須要經過 postcss-loader 使用 PostCSS。
npm install -D postcss-loader
// webpack.config.js -> module.rules
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
'postcss-loader'
]
}
Babel
- Babel 的配置能夠經過 .babelrc 或 babel-loader 選項來完成。
npm install -D babel-core babel-loader
// webpack.config.js -> module.rules
{
test: /\.js?$/,
loader: 'babel-loader'
}
排除 node_modules
- 若是你導入一個 node_modules 內的 Vue 單文件組件,它的 <script> 部分在轉譯時將會被排除在外。
- 爲了確保 JS 的轉譯應用到 node_modules 的 Vue 單文件組件,你須要經過使用一個排除函數將它們加入白名單:
{
test: /\.js$/,
loader: 'babel-loader',
exclude: file => (
/node_modules/.test(file) &&
!/\.vue\.js/.test(file) // 正則匹配.vue.js後綴的文件,是由於.vue被vue loader處理後js會生成後綴未.vue.js的js吧
)
}
TypeScript
- TypeScript 的配置能夠經過 tsconfig.json 來完成。
npm install -D typescript ts-loader
// webpack.config.js
module.exports = {
resolve: {
// 將 `.ts` 添加爲一個可解析的擴展名。
extensions: ['.ts', '.js']
},
module: {
rules: [
// ... 忽略其它規則
{
test: /\.ts$/,
loader: 'ts-loader',
options: { appendTsSuffixTo: [/\.vue$/] }
}
]
},
// ...plugin omitted
}
pug
- 模板的處理會稍微有些不一樣,由於絕大對數 webpack 的模板類 loader,諸如 pug-loader,會返回一個模板函數而不是一個編譯好的 HTML 字符串
- 一個返回原始的 HTML 字符串的 loader,例如 pug-plain-loader
// .vue中
<template lang="pug">
div
h1 Hello world!
</template>
// webpack中
npm install -D pug pug-plain-loader
// webpack.config.js -> module.rules
{
test: /\.pug$/,
loader: 'pug-plain-loader'
}
- 你還打算使用它在 JavaScript 中將 .pug 文件做爲字符串導入,你須要在這個預處理 loader 以後鏈上 raw-loader
// webpack.config.js -> module.rules
{
test: /\.pug$/,
oneOf: [ // 規則數組,當規則匹配時,只使用第一個匹配規則。
// 這條規則應用到 Vue 組件內的 `<template lang="pug">`
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// 這條規則應用到 JavaScript 內的 pug 導入
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}
Scoped CSS
- 當 <style> 標籤有 scoped 屬性時,它的 CSS 只做用於當前組件中的元素。它經過使用 PostCSS 來實現如下轉換(不是說再也不默認使用嗎?)
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
// 轉換爲
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
混用本地和全局樣式
- 能夠在一個組件中同時使用有 scoped 和非 scoped 樣式
子組件的根元素
- 使用 scoped 後,父組件的樣式將不會滲透到子組件中。不過一個子組件的根節點會同時受其父組件的 scoped CSS 和子組件的 scoped CSS 的影響。這樣設計是爲了讓父組件能夠從佈局的角度出發,調整其子組件根元素的樣式。
深度做用選擇器
- 若是你但願 scoped 樣式中的一個選擇器可以做用得「更深」,例如影響子組件,你可使用 >>> 操做符。有些像 Sass 之類的預處理器沒法正確解析 >>>。這種狀況下你可使用 /deep/ 操做符取而代之
<style scoped>
.a >>> .b { /* ... */ }
</style>
// 編譯爲
.a[data-v-f3f3eg9] .b { /* ... */ }
動態生成的內容
- 經過 v-html 建立的 DOM 內容不受 scoped 樣式影響,可是你仍然能夠經過深度做用選擇器來爲他們設置樣式。
注意事項
- 當 p { color: red } 是 scoped 時 (即與特性選擇器組合使用時) 會慢不少倍。若是你使用 class 或者 id 取而代之,好比 .example { color: red },性能影響就會消除。
CSS Modules
- vue-loader 提供了與 CSS Modules 的一流集成,能夠做爲模擬 scoped CSS 的替代方案。
- CSS Modules經過對css中選擇器的編譯,來實現該種選擇器在全局中的惟一性
用法
- 經過向 css-loader 傳入 modules: true 來開啓(vue-cli默認開啓)
// webpack.config.js
{
module: {
rules: [
// ... 其它規則省略
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// 開啓 CSS Modules
modules: true,
// 自定義生成的類名
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
- module 特性指引 Vue Loader 做爲名爲 $style 的計算屬性,向組件注入 CSS Modules 局部對象。而後你就能夠在模板中經過一個動態類綁定來使用它了:
<style module> // 在你的 <style> 上添加 module 特性
.red {
color: red;
}
.bold {
font-weight: bold;
}
</style>
<template>
<p :class="$style.red"> // "red_1VyoJ-uZ"由開啓時自定義生成的類名決定
This should be red
</p>
</template>
可選用法
- 若是你只想在某些 Vue 組件中使用 CSS Modules,你可使用 oneOf 規則並在 resourceQuery 字符串中檢查 module 字符串(vue-cli好像默認開啓,只有style擁有module屬性纔會是模塊化樣式)
// webpack.config.js -> module.rules
{
test: /\.css$/,
oneOf: [
// 這裏匹配 `<style module>`
{
resourceQuery: /module/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:5]'
}
}
]
},
// 這裏匹配普通的 `<style>` 或 `<style scoped>`
{
use: [
'vue-style-loader',
'css-loader'
]
}
]
}
和預處理器配合使用
- CSS Modules 能夠與其它預處理器一塊兒使用
// webpack.config.js -> module.rules
{
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { modules: true }
},
'sass-loader'
]
}
自定義的注入名稱
<div :class='a.about'></div>
<style module="a">
/* 注入標識符 a */
</style>
熱重載
- 當你修改 .vue 文件時,該組件的全部實例將在不刷新頁面的狀況下被替換。它甚至保持了應用程序和被替換組件的當前狀態!當你調整模版或者修改樣式時,這極大地提升了開發體驗。
狀態保留規則
- 當編輯一個組件的 <template> 時,這個組件實例將就地從新渲染,並保留當前全部的私有狀態。可以作到這一點是由於模板被編譯成了新的無反作用的渲染函數。(template實際上被渲染爲render函數,應該是沒法比較函數之間的異同的,經過比較兩個函數返回的v-node樹的異同,來判斷哪些節點須要銷燬,熱更新的效果應該和渲染的原理同樣;只是生成新的渲染,它自己對傳入的參數值沒有任何改動,因此不會影響到其餘元素的渲染效果,能夠作到無反作用。生命週期鉤子可能會在執行過程當中改變這些變量,因此必須整個組件銷燬重建,來觸發這些生命週期函數;當傳入值prop改變時,組件內部沒有變更,不會引發反作用,依然採用構建v-node樹進行比較最小替換的方式)
- 當編輯一個組件的 <script> 時,這個組件實例將就地銷燬並從新建立。(應用中其它組件的狀態將會被保留) 是由於 <script> 可能包含帶有反作用的生命週期鉤子,因此將從新渲染替換爲從新加載是必須的,這樣作能夠確保組件行爲的一致性。這也意味着,若是你的組件帶有全局反作用,則整個頁面將會被從新加載。
- <style> 會經過 vue-style-loader 自行熱重載,因此它不會影響應用的狀態。style的改變彷佛不會改變this.$style指向的對象,否則應該觸發組件銷燬重建的
用法
- 當手動設置你的工程時,熱重載會在你啓動 webpack-dev-server --hot 服務時自動開啓。
關閉熱重載
- 熱重載默認是開啓的,除非遇到如下狀況
- webpack 的 target 的值是 node (服務端渲染)
- webpack 會壓縮代碼(生產環境?)
- process.env.NODE_ENV === 'production'
- 能夠設置 hotReload: false 選項來顯式地關閉熱重載:
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
hotReload: false // 關閉熱重載
}
}
]
}
自定義塊
- 在 .vue 文件中,你能夠自定義語言塊。應用於一個自定義塊的 loader 是基於這個塊的 lang 特性、塊的標籤名以及你的 webpack 配置進行匹配的。若是找到了一個自定義塊的匹配規則,它將會被處理,不然該自定義塊會被默默忽略。若是這個自定義塊被全部匹配的 loader 處理以後導出一個函數做爲最終結果,則這個 *.vue 文件的組件會做爲一個參數被這個函數調用。
- 使用 resourceQuery 來爲一個沒有 lang 的自定義塊匹配一條規則。例如爲了匹配自定義塊 <docs>:
//自定義loader用以處理docs標籤
module.exports = function (source, map) {
this.callback(
null,
`export default function (Component) { // loader導出的函數,Component指向.vue文件(.vue文件的options好像被實例this繼承,沒有在其餘文檔看到,這個對象包含什麼?)
Component.options.__docs = ${
JSON.stringify(source)
}
}`,
map
)
}
// webpack配置
{
module: {
rules: [
{
resourceQuery: /blockType=docs/,
loader: require.resolve('./docs-loader.js')
}
]
}
}
// 子組件使用(@/components/HelloWorld.vue)
<docs>
This is the documentation for component B.
</docs>
// 父組件引用
import HelloWorld from '@/components/HelloWorld.vue'
HelloWorld.__docs => JSON.stringify('This is the documentation for component B.')
CSS 提取
- 請只在生產環境下使用 CSS 提取,這將便於你在開發環境下進行熱重載。(vue-cli中,開發環境css經過js動態寫入head中,生產環境則會依據build和check分別打包)
webpack 4
npm install -D mini-css-extract-plugin
// webpack.config.js
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// 其它選項...
module: {
rules: [
// ... 忽略其它規則
{
test: /\.css$/,
use: [
process.env.NODE_ENV !== 'production'
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
// ... 忽略 vue-loader 插件
new MiniCssExtractPlugin({
filename: style.css
})
]
}
webpack 3
- 這裏應該須要對不一樣開發環境配置不一樣的webpack配置
npm install -D extract-text-webpack-plugin
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// 其它選項...
module: {
rules: [
// ...其它規則忽略
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
})
}
]
},
plugins: [
// ...vue-loader 插件忽略
new ExtractTextPlugin("style.css")
]
}
代碼校驗
ESLint
- 官方的 eslint-plugin-vue 同時支持在 Vue 單文件組件的模板和腳本部分的代碼校驗。只須要在你的 ESLint 配置文件中使用該插件要導入的配置:
// .eslintrc.js
module.exports = {
extends: [
"plugin:vue/essential"
]
}
eslint --ext js,vue MyComponent.vue
- 使用 eslint-loader開發過程當中每次保存的時候就會自動進行代碼校驗
npm install -D eslint eslint-loader
// webpack.config.js
module.exports = {
// ... 其它選項
module: {
rules: [
{
enforce: 'pre', // 請確保它是做爲一個 pre-loader 運用的,loader的種類,影響執行的順序,執行書序分爲:後置(post)、行內(normal)、普通(inline)、前置(pre)
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/
}
]
}
}
stylelint
- 支持在 Vue 單文件組件的樣式部分的代碼校驗。(vue-cli好像默認沒裝)
- 命令行校驗
stylelint MyComponent.vue
npm install -D stylelint-webpack-plugin
/ webpack.config.js
const StyleLintPlugin = require('stylelint-webpack-plugin');
module.exports = {
// ... 其它選項
plugins: [
new StyleLintPlugin({
files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'],
})
]
}