vue-loader
是webpack的加載器,允許您以稱為單文件組件(SFC)的格式創作Vue組件:
<template> <div class="example">{{ msg }}</div> </template> <script> export default { data () { return { msg: 'Hello world!' } } } </script> <style> .example { color: red; } </style>
有許多很酷的功能提供vue-loader
:
- 允許對Vue組件的每個部分使用其他webpack加載器,例如Sass for
<style>
和Pug for<template>
; - 允許
.vue
文件中的自定義塊可以應用自定義加載器鏈; - 處理在模塊依賴項中引用的靜態資產,
<style>
並<template>
使用webpack加載器處理它們; - 模擬每個組件的范圍CSS;
- 在開發過程中保持國家的熱再加載。
簡而言之,webpack的組合vue-loader
為您提供了一個現代,靈活且極其強大的前端工作流程,用於創作Vue.js應用程序。
Vue的CLI
如果您對手動設置webpack不感興趣,建議使用Vue CLI構建項目。Vue CLI創建的項目預先配置了大多數開箱即用的常見開發需求。
如果Vue CLI的內置配置不符合您的需要,請遵循本指南,或者您更願意從頭開始創建自己的webpack配置。
#手動配置
Vue Loader的配置與其他加載器略有不同。除了適用vue-loader
於任何帶擴展名的文件的規則外,請.vue
務必將Vue Loader的插件添加到webpack配置中:
// webpack.config.js const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { module: { rules: [ // ... other rules { test: /\.vue$/, loader: 'vue-loader' } ] }, plugins: [ // make sure to include the plugin! new VueLoaderPlugin() ] }
這個插件是必需的!它負責克隆您定義的任何其他規則並將它們應用於.vue
文件中的相應語言塊。例如,如果您有規則匹配/\.js$/
,則它將應用於文件中的<script>
塊.vue
。
一個更完整的webpack配置示例如下所示:
// webpack.config.js const path = require('path') const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { mode: 'development', module: { rules: [ { test: /\.vue$/, loader: 'vue-loader' }, // this will apply to both plain `.js` files // AND `<script>` blocks in `.vue` files { test: /\.js$/, loader: 'babel-loader' }, // this will apply to both plain `.css` files // AND `<style>` blocks in `.vue` files { test: /\.css$/, use: [ 'vue-style-loader', 'css-loader' ] } ] }, plugins: [ // make sure to include the plugin for the magic new VueLoaderPlugin() ] }
資產URL處理
當Vue Loader <template>
在SFC中編譯塊時,它還會將遇到的任何資產URL轉換為webpack模塊請求。
例如,以下模板代碼段:
<img src="../image.png">
將編譯成:
createElement('img', { attrs: { src: require('../image.png') // this is now a module request } })
默認情況下,將轉換以下標記/屬性組合,並可使用transformAssetUrls選項進行配置。
{ video: ['src', 'poster'], source: 'src', img: 'src', image: 'xlink:href' }
此外,如果您已配置為塊使用css-loader,則<style>
CSS中的資產URL也將以類似的方式處理。
轉換規則
資產URL轉換遵循以下規則:
-
如果URL是絕對路徑(例如
/images/foo.png
),則它將按原樣保留。 -
如果URL以#開頭
.
,則將其解釋為相對模塊請求,並根據文件系統上的文件夾結構進行解析。 -
如果URL以...開頭
~
,則將其解釋為模塊請求。這意味着您甚至可以引用節點模塊內的資產:<img src="~some-npm-package/foo.png">
-
如果URL以
@
,它也被解釋為模塊請求。如果您的webpack配置具有別名@
,這非常有用,默認情況下,該別名指向/src
由其創建的任何項目vue-cli
。
#相關裝載機
因為擴展.png
不是JavaScript模塊,所以您需要配置webpack以使用file-loader或url-loader來正確處理它們。使用Vue CLI創建的項目已預先配置。
#為什么
資產URL轉換的好處是:
-
file-loader
允許您指定復制和放置資產文件的位置,以及如何使用版本哈希命名它以獲得更好的緩存。此外,這也意味着您只需將圖像放在*.vue
文件旁邊,並根據文件夾結構使用相對路徑,而不必擔心部署URL。通過適當的配置,webpack將自動將文件路徑重寫為捆綁輸出中的正確URL。 -
url-loader
允許您有條件地將文件內聯為base-64數據URL(如果它們小於給定閾值)。這可以減少普通文件的HTTP請求數量。如果文件大於閾值,則會自動回退到file-loader
。
使用預處理器
在webpack中,所有預處理器都需要應用相應的加載器。vue-loader
允許您使用其他webpack加載器來處理Vue組件的一部分。它將根據lang
語言塊的屬性和webpack配置中的規則自動推斷要使用的正確加載器。
#SASS
例如,要<style>
使用SASS / SCSS 編譯我們的標記:
npm install -D sass-loader node-sass
在您的webpack配置中:
module.exports = { module: { rules: [ // ... other rules omitted // this will apply to both plain `.scss` files // AND `<style lang="scss">` blocks in `.vue` files { test: /\.scss$/, use: [ 'vue-style-loader', 'css-loader', 'sass-loader' ] } ] }, // plugin omitted }
現在除了能夠之外import 'style.scss'
,我們還可以在Vue組件中使用SCSS:
<style lang="scss"> /* write SCSS here */ </style>
塊中的任何內容都將由webpack處理,就像它在*.scss
文件中一樣。
#上海社會科學院VS SCSS
請注意,默認情況下sass-loader
處理非基於縮進的scss
語法。要使用基於縮進的sass
語法,您需要將選項傳遞給加載器:
// 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: { // you can also read from a file, e.g. `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' ] }
手寫筆
npm install -D stylus stylus-loader
// webpack.config.js -> module.rules { test: /\.styl(us)?$/, use: [ 'vue-style-loader', 'css-loader', 'stylus-loader' ] }
PostCSS
小費
Vue Loader v15默認不再適用PostCSS變換。您需要使用PostCSS postcss-loader
。
npm install -D postcss-loader
// webpack.config.js -> module.rules { test: /\.css$/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader' ] }
PostCSS的配置可以通過postcss.config.js
或postcss-loader
選項完成。有關詳細信息,請參閱postcss-loader docs。
postcss-loader
也可以與上述其他預處理器結合使用。
#巴貝爾
npm install -D babel-core babel-loader
// webpack.config.js -> module.rules { test: /\.js?$/, loader: 'babel-loader' }
Babel的配置可以通過.babelrc
或babel-loader
選項完成。
#不包括node_modules
exclude: /node_modules/
對於babel-loader
適用於.js
文件的JS轉換規則(例如)通常是常見的。由於v15的推斷變化,如果在內部導入Vue SFC node_modules
,其<script>
部分也將被排除在轉換之外。
為了確保將JS轉換應用於Vue SFC node_modules
,您需要使用exclude函數將它們列入白名單:
{ test: /\.js$/, loader: 'babel-loader', exclude: file => ( /node_modules/.test(file) && !/\.vue\.js/.test(file) ) }
#打字稿
npm install -D typescript ts-loader
// webpack.config.js module.exports = { resolve: { // Add `.ts` as a resolvable extension. extensions: ['.ts', '.js'] }, module: { rules: [ // ... other rules omitted { test: /\.ts$/, loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/] } } ] }, // ... plugin omitted }
TypeScipt的配置可以通過tsconfig.json
。另請參閱ts-loader的文檔。
帕格
處理模板有點不同,因為大多數webpack模板加載器如pug-loader
返回模板函數而不是編譯的HTML字符串。pug-loader
我們需要使用一個返回原始HTML字符串的加載器,而不是使用,例如pug-plain-loader
:
npm install -D pug pug-plain-loader
// webpack.config.js -> module.rules { test: /\.pug$/, loader: 'pug-plain-loader' }
然后你可以寫:
<template lang="pug"> div h1 Hello world! </template>
如果您還打算使用它.pug
在JavaScript中將文件作為HTML字符串導入,則需要raw-loader
在預處理加載器之后進行鏈接。但請注意,添加raw-loader
會破壞Vue組件中的使用,因此您需要有兩個規則,其中一個使用a定位Vue文件resourceQuery
,另一個(回退)定位JavaScript導入:
// webpack.config.js -> module.rules { test: /\.pug$/, oneOf: [ // this applies to `<template lang="pug">` in Vue components { resourceQuery: /^\?vue/, use: ['pug-plain-loader'] }, // this applies to pug imports inside JavaScript { use: ['raw-loader', 'pug-plain-loader'] } ] }
作用域CSS
當<style>
標簽具有該scoped
屬性時,其CSS將僅應用於當前組件的元素。這類似於Shadow DOM中的樣式封裝。它有一些警告,但不需要任何polyfill。通過使用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>
#混合本地和全局樣式
您可以在同一組件中包含范圍和非范圍樣式:
<style> /* global styles */ </style> <style scoped> /* local styles */ </style>
#子組件根元素
使用時scoped
,父組件的樣式不會泄漏到子組件中。但是,子組件的根節點將受父級作用域CSS和子級作用域CSS的影響。這是設計的,以便父級可以設置子根元素的樣式以進行布局。
#深度選擇器
如果您希望scoped
樣式中的選擇器“深入”,即影響子組件,則可以使用>>>
組合器:
<style scoped> .a >>> .b { /* ... */ } </style>
以上將編譯成:
.a[data-v-f3f3eg9] .b { /* ... */ }
某些預處理器(如Sass)可能無法>>>
正確解析。在這些情況下,您可以使用/deep/
組合器 - 它是別名,>>>
並且完全相同。
#動態生成的內容
創建的DOM內容v-html
不受范圍樣式的影響,但您仍然可以使用深度選擇器設置它們的樣式。
#也記住
-
范圍樣式不會消除類的需要。由於瀏覽器呈現各種CSS選擇器的方式,
p { color: red }
在作用域時(即與屬性選擇器結合時)會慢很多倍。如果您使用類或ID,例如in.example { color: red }
,那么您幾乎可以消除性能損失。這是一個游樂場,您可以自己測試差異。 -
在遞歸組件中注意后代選擇器!對於帶有選擇器的CSS規則
.a .b
,如果匹配的元素.a
包含遞歸子組件,則.b
該子組件中的所有組件都將與規則匹配。
← 簡介
CSS模塊
CSS模塊是用於模塊化和組合CSS的流行系統。vue-loader
提供與CSS模塊的一流集成,作為模擬范圍CSS的替代方案。
#用法
首先,必須通過傳遞modules: true
給css-loader
:
// webpack.config.js { module: { rules: [ // ... other rules omitted { test: /\.css$/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { // enable CSS Modules modules: true, // customize generated class names localIdentName: '[local]_[hash:base64:8]' } } ] } ] } }
然后,將module
屬性添加到您的<style>
:
<style module> .red { color: red; } .bold { font-weight: bold; } </style>
該module
屬性指示Vue Loader將CSS模塊locals對象作為具有名稱的計算屬性注入組件$style
。然后,您可以在模板中使用動態類綁定:
<template> <p :class="$style.red"> This should be red </p> </template>
由於它是一個計算屬性,它也可以使用以下對象/數組語法:class
:
<template> <div> <p :class="{ [$style.red]: isRed }"> Am I red? </p> <p :class="[$style.red, $style.bold]"> Red and bold </p> </div> </template>
您還可以從JavaScript訪問它:
<script> export default { created () { console.log(this.$style.red) // -> "red_1VyoJ-uZ" // an identifier generated based on filename and className. } } </script>
有關模式詳細信息(如全局異常和組合),請參閱CSS模塊規范。
#選擇使用
如果您只想在某些Vue組件中使用CSS模塊,則可以使用oneOf
規則並檢查module
字符串resourceQuery
:
// webpack.config.js -> module.rules { test: /\.css$/, oneOf: [ // this matches `<style module>` { resourceQuery: /module/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { modules: true, localIdentName: '[local]_[hash:base64:5]' } } ] }, // this matches plain `<style>` or `<style scoped>` { use: [ 'vue-style-loader', 'css-loader' ] } ] }
#與預處理器一起使用
CSS模塊可以與其他預處理器一起使用:
// webpack.config.js -> module.rules { test: /\.scss$/, use: [ 'vue-style-loader', { loader: 'css-loader', options: { modules: true } }, 'sass-loader' ] }
#自定義進樣名稱
您可以<style>
在單個*.vue
組件中包含多個標記。為避免注入樣式相互覆蓋,可以通過為module
屬性賦值來自定義注入的計算屬性的名稱:
<style module="a"> /* identifiers injected as a */ </style> <style module="b"> /* identifiers injected as b */ </style>
熱刷新
“Hot Reload”不僅僅是在編輯文件時重新加載頁面。啟用熱重新加載后,在編輯*.vue
文件時,將交換該組件的所有實例,而無需重新加載頁面。它甚至可以保留您的應用程序和這些交換組件的當前狀態!當您調整組件的模板或樣式時,這可以顯着改善開發體驗。
#州保存規則
-
編輯
<template>
組件時,已編輯組件的實例將重新呈現,保留所有當前的私有狀態。這是可能的,因為模板被編譯成新的渲染函數,不會產生副作用。 -
編輯
<script>
組件的一部分時,將銷毀並重新創建已編輯組件的實例。(保留應用程序中其他組件的狀態)這是因為<script>
可能包含可能產生副作用的生命周期鈎子,因此需要“重新加載”而不是重新呈現以確保一致的行為。這也意味着您需要注意全局副作用,例如組件生命周期鈎子中的計時器。如果您的組件產生全局副作用,有時您可能需要執行整頁重新加載。 -
<style>
熱重載依次運行vue-style-loader
,因此不會影響應用程序狀態。
#用法
搭建項目時vue-cli
,Hot Reload可以開箱即用。
手動設置項目時,在使用項目服務時會自動啟用熱重新加載webpack-dev-server --hot
。
高級用戶可能想要查看內部使用的vue-hot-reload-apivue-loader
。
#禁用熱重新加載
除以下情況外,始終啟用熱重新加載:
- webpack
target
是node
(SSR) - webpack縮小了代碼
process.env.NODE_ENV === 'production'
您可以使用hotReload: false
選項明確禁用熱重新加載:
module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: { hotReload: false // disables Hot Reload } } ] }
功能組件
在*.vue
文件中定義為單文件組件的功能組件也接收適當的模板編譯,Scoped CSS和熱重載支持。
要表示應編譯為功能組件functional
的模板,請將該屬性添加到模板塊。這也允許省略塊中的functional
選項<script>
。
模板中的表達式在功能渲染上下文中進行評估。這意味着需要像props.xxx
在模板中一樣訪問props :
<template functional> <div>{{ props.foo }}</div> </template>
如果需要訪問全局定義的屬性Vue.prototype
,可以在parent
以下位置訪問它們:
<template functional> <div>{{ parent.$someProperty }}</div> </template>
自定義塊
您可以在*.vue
文件中定義自定義語言塊。應用於自定義塊的加載器將根據塊的lang
屬性,塊的標記名稱以及webpack配置中的規則進行匹配。
如果lang
指定了屬性,則自定義塊將作為文件lang
與其擴展名匹配。
您還可以使用resourceQuery
匹配自定義塊的規則lang
。例如,要匹配<foo>
自定義塊:
{ module: { rules: [ { resourceQuery: /blockType=foo/, loader: 'loader-to-use' } ] } }
如果為自定義塊找到匹配規則,則會對其進行處理; 否則將自動忽略自定義塊。
此外,如果自定義塊在所有匹配的加載器處理后將函數導出為最終結果,則將使用*.vue
文件的組件作為參數調用該函數。
#例子
下面是將<docs>
自定義塊注入組件的示例,以便在運行時可用。
為了注入自定義塊內容,我們將編寫一個自定義加載器:
module.exports = function (source, map) { this.callback( null, `export default function (Component) { Component.options.__docs = ${ JSON.stringify(source) } }`, map ) }
現在我們將配置webpack以使用我們的自定義加載器來<docs>
定制塊。
// wepback.config.js module.exports = { module: { rules: [ { resourceQuery: /blockType=docs/, loader: require.resolve('./docs-loader.js') } ] } }
我們現在能夠<docs>
在運行時訪問塊的導入組件的內容。
<!-- ComponentB.vue --> <template> <div>Hello</div> </template> <docs> This is the documentation for component B. </docs>
<!-- ComponentA.vue --> <template> <div> <ComponentB/> <p>{{ docs }}</p> </div> </template> <script> import ComponentB from './ComponentB.vue'; export default { components: { ComponentB }, data () { return { docs: ComponentB.__docs } } } </script>
CSS提取
小費
僅對生產應用CSS提取,以便在開發期間獲得CSS熱重新加載。
#的WebPack 4
npm install -D mini-css-extract-plugin
// webpack.config.js var MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { // other options... module: { rules: [ // ... other rules omitted { test: /\.css$/, use: [ process.env.NODE_ENV !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, 'css-loader' ] } ] }, plugins: [ // ... Vue Loader plugin omitted new MiniCssExtractPlugin({ filename: 'style.css' }) ] }
另請參閱mini-css-extract-plugin文檔。
#的WebPack 3
npm install -D extract-text-webpack-plugin
// webpack.config.js var ExtractTextPlugin = require("extract-text-webpack-plugin") module.exports = { // other options... module: { rules: [ // ... other rules omitted { test: /\.css$/, loader: ExtractTextPlugin.extract({ use: 'css-loader', fallback: 'vue-style-loader' }) } ] }, plugins: [ // ... Vue Loader plugin omitted new ExtractTextPlugin("style.css") ] }
Linting
#ESLint
The official eslint-plugin-vue supports linting both the template and script parts of Vue single file components.
Make sure to use the plugin's included config in your ESLint config:
// .eslintrc.js module.exports = { extends: [ "plugin:vue/essential" ] }
Then from the command line:
eslint --ext js,vue MyComponent.vue
Another option is using eslint-loader so that your *.vue
files are automatically linted on save during development:
npm install -D eslint eslint-loader
Make sure it's applied as a pre-loader:
// webpack.config.js module.exports = { // ... other options module: { rules: [ { enforce: 'pre', test: /\.(js|vue)$/, loader: 'eslint-loader', exclude: /node_modules/ } ] } }
#stylelint
stylelint supports linting style parts of Vue single file components.
Make sure that your stylelint config is right.
Then from the command line:
stylelint MyComponent.vue
Another option is using stylelint-webpack-plugin:
npm install -D stylelint-webpack-plugin
Make sure it's applied as a plugin:
// webpack.config.js const StyleLintPlugin = require('stylelint-webpack-plugin'); module.exports = { // ... other options plugins: [ new StyleLintPlugin({ files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'], }) ] }
測試
-
Vue CLI提供預配置的單元測試和e2e測試設置。
-
如果您對手動設置
*.vue
文件的單元測試感興趣,請參閱@ vue / test-utils的文檔,其中介紹了使用mocha-webpack或Jest進行設置。