Unverified Commit 698a79db authored by GU Yiling's avatar GU Yiling Committed by GitHub

Merge pull request #1274 from Jinjiang/zh-cn

[docs] Chinese translation
parents 807f1931 b556598e
module.exports = {
title: 'Vue Loader',
description: 'Webpack loader for single-file Vue components',
locales: {
'/': {
lang: 'en-US',
title: 'Vue Loader',
description: 'Webpack loader for single-file Vue components'
},
'/zh/': {
lang: 'zh-CN',
title: 'Vue Loader',
description: '处理 Vue 单文件组件的 Webpack loader'
}
},
serviceWorker: true,
theme: 'vue',
themeConfig: {
repo: 'vuejs/vue-loader',
docsDir: 'docs',
nav: [
{
text: 'Guide',
link: '/guide/'
locales: {
'/': {
label: 'English',
selectText: 'Languages',
editLinkText: 'Edit this page on GitHub',
nav: [
{
text: 'Guide',
link: '/guide/'
},
{
text: 'SFC Spec',
link: '/spec.html'
},
{
text: 'Options Reference',
link: '/options.html'
},
{
text: 'Migrating from v14',
link: '/migrating.md'
}
],
sidebar: [
'/',
'/guide/',
'/guide/asset-url',
'/guide/pre-processors',
'/guide/scoped-css',
'/guide/css-modules',
'/guide/hot-reload',
'/guide/functional',
'/guide/custom-blocks',
'/guide/extract-css',
'/guide/linting',
'/guide/testing'
]
},
{
text: 'SFC Spec',
link: '/spec.html'
},
{
text: 'Options Reference',
link: '/options.html'
},
{
text: 'Migrating from v14',
link: '/migrating.md'
'/zh/': {
label: '简体中文',
selectText: '选择语言',
editLinkText: '在 GitHub 上编辑此页',
nav: [
{
text: '指南',
link: '/zh/guide/'
},
{
text: '单文件组件规范',
link: '/zh/spec.html'
},
{
text: '选项参考',
link: '/zh/options.html'
},
{
text: '如何从 v14 迁移',
link: '/zh/migrating.md'
}
],
sidebar: [
'/zh/',
'/zh/guide/',
'/zh/guide/asset-url',
'/zh/guide/pre-processors',
'/zh/guide/scoped-css',
'/zh/guide/css-modules',
'/zh/guide/hot-reload',
'/zh/guide/functional',
'/zh/guide/custom-blocks',
'/zh/guide/extract-css',
'/zh/guide/linting',
'/zh/guide/testing'
]
}
],
sidebar: [
'/',
'/guide/',
'/guide/asset-url',
'/guide/pre-processors',
'/guide/scoped-css',
'/guide/css-modules',
'/guide/hot-reload',
'/guide/functional',
'/guide/custom-blocks',
'/guide/extract-css',
'/guide/linting',
'/guide/testing'
]
}
}
}
......@@ -2,7 +2,7 @@
When Vue Loader compiles the `<template>` blocks in SFCs, it also converts any encountered asset URLs into **webpack module requests**.
For example, the following template snippet
For example, the following template snippet:
``` vue
<img src="../image.png">
......
# 介绍
:::tip 版本说明
这份文档是为 Vue Loader v15 及以上版本撰写的。如果你正在从 v14 或更早的版本往这里迁移,请查阅[迁移指南](../migrating.md)。如果你正在使用老版本,其对应的文档[在此](https://vue-loader-v14.vuejs.org)
:::
## Vue Loader 是什么?
Vue Loader 是一个 [webpack](https://webpack.js.org/) 的 loader,它允许你以一种名为[单文件组件 (SFCs)](./spec.md)的格式撰写 Vue 组件:
``` 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 loader,例如在 `<style>` 的部分使用 Sass 和在 `<template>` 的部分使用 Pug;
- 允许在一个 `.vue` 文件中使用自定义块,并对其运用自定义的 loader 链;
- 使用 webpack loader 将 `<style>``<template>` 中引用的资源当作模块依赖来处理;
- 为每个组件模拟出 scoped CSS;
- 在开发过程中使用热重载来保持状态。
简而言之,webpack 和 Vue Loader 的结合为你提供了一个现代、灵活且极其强大的前端工作流,来帮助撰写 Vue.js 应用。
# 起步
## Vue CLI
如果你不想手动设置 webpack,我们推荐使用 [Vue CLI](https://github.com/vuejs/vue-cli) 直接创建一个项目的脚手架。通过 Vue CLI 创建的项目会针对多数常见的开发需求进行预先配置,做到开箱即用。
如果 Vue CLI 提供的内建没有满足你的需求,或者你乐于从零开始创建你自己的 webpack 配置,那么请继续阅读这篇指南。
## 手动配置
Vue Loader 的配置和其它的 loader 不太一样。除了通过一条规则将 `vue-loader` 应用到所有扩展名为 `.vue` 的文件上之外,请确保在你的 webpack 配置中添加 Vue Loader 的插件:
``` js
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
module: {
rules: [
// ... 其它规则
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 请确保引入这个插件!
new VueLoaderPlugin()
]
}
```
**这个插件是必须的!**它的职责是将你定义过的其它规则复制并应用到 `.vue` 文件里相应语言的块。例如,如果你有一条匹配 `/\.js$/` 的规则,那么它会应用到 `.vue` 文件里的 `<script>` 块。
一个更完整的 webpack 配置示例看起来像这样:
``` js
// webpack.config.js
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
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-loader'
]
}
]
},
plugins: [
// 请确保引入这个插件来施展魔法
new VueLoaderPlugin()
]
}
```
你也可以在[选项参考](../options.md)查阅所有可用的 loader 选项。
# 处理资源路径
当 Vue Loader 编译单文件组件中的 `<template>` 块时,它也会将所有遇到的资源 URL 转换为 **webpack 模块请求**
例如,下面的模板代码片段:
``` vue
<img src="../image.png">
```
将会被编译成为:
``` js
createElement('img', {
attrs: {
src: require('../image.png') // 现在这是一个模块的请求了
}
})
```
默认下列标签/特性的组合会被转换,且这些组合时可以使用 [transformAssetUrls](../options.md#transformasseturls) 选项进行配置的。
``` js
{
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
```
此外,如果你配置了为 `<style>` 块使用 [css-loader](https://github.com/webpack-contrib/css-loader),则你的 CSS 中的资源 URL 也会被同等处理。
## 转换规则
资源 URL 转换会遵循如下规则:
- 如果路径是绝对路径 (例如 `/images/foo.png`),会原样保留。
- 如果路径以 `.` 开头,将会被看作相对的模块依赖,并按照你的本地文件系统上的目录结构进行解析。
- 如果路径以 `~` 开头,其后的部分将会被看作模块依赖。这意味着你可以用该特性来引用一个 Node 依赖中的资源:
``` html
<img src="~some-npm-package/foo.png">
```
- 如果路径以 `@` 开头,也会被看作模块依赖。如果你的 webpack 配置中给 `@` 配置了 alias,这就很有用了。所有 `vue-cli` 创建的项目都默认配置了将 `@` 指向 `/src`
## 相关的 Loader
因为像 `.png` 这样的文件不是一个 JavaScript 模块,你需要配置 webpack 使用 [file-loader](https://github.com/webpack/file-loader) 或者 [url-loader](https://github.com/webpack/url-loader) 去合理地处理它们。通过 Vue CLI 创建的项目已经把这些预配置好了。
## 为什么
转换资源 URL 的好处是:
1. `file-loader` 可以指定要复制和放置资源文件的位置,以及如何使用版本哈希命名以获得更好的缓存。此外,这意味着 **你可以就近管理图片文件,可以使用相对路径而不用担心部署时 URL 的问题**。使用正确的配置,webpack 将会在打包输出中自动重写文件路径为正确的 URL。
2. `url-loader` 允许你有条件地将文件转换为内联的 base-64 URL (当文件小于给定的阈值),这会减少小文件的 HTTP 请求数。如果文件大于该阈值,会自动的交给 `file-loader` 处理。
# CSS Modules
[CSS Modules](https://github.com/css-modules/css-modules) 是一个流行的,用于模块化和组合 CSS 的系统。`vue-loader` 提供了与 CSS Modules 的一流集成,可以作为模拟 scoped CSS 的替代方案。
## 用法
首先,CSS Modules 必须通过向 `css-loader` 传入 `modules: true` 来开启:
``` js
// webpack.config.js
{
module: {
rules: [
// ... 其它规则省略
{
test: /\.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// 开启 CSS Modules
modules: true,
// 自定义生成的类名
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
```
然后在你的 `<style>` 上添加 `module` 特性:
``` vue
<style module>
.red {
color: red;
}
.bold {
font-weight: bold;
}
</style>
```
这个 `module` 特性指引 Vue Loader 作为名为 `$style` 的计算属性,向组件注入 CSS Modules 局部对象。然后你就可以在模板中通过一个动态类绑定来使用它了:
``` vue
<template>
<p :class="$style.red">
This should be red
</p>
</template>
```
因为这是一个计算属性,所以它也支持 `:class` 的对象/数组语法:
``` vue
<template>
<div>
<p :class="{ [$style.red]: isRed }">
Am I red?
</p>
<p :class="[$style.red, $style.bold]">
Red and bold
</p>
</div>
</template>
```
你也可以通过 JavaScript 访问到它:
``` vue
<script>
export default {
created () {
console.log(this.$style.red)
// -> "red_1VyoJ-uZ"
// 一个基于文件名和类名生成的标识符
}
}
</script>
```
你可以查阅 [CSS Modules 规范](https://github.com/css-modules/css-modules)了解更多细节,诸如 [global exceptions](https://github.com/css-modules/css-modules#exceptions)[composition](https://github.com/css-modules/css-modules#composition) 等。
## 可选用法
如果你只想在某些 Vue 组件中使用 CSS Modules,你可以使用 `oneOf` 规则并在 `resourceQuery` 字符串中检查 `module` 字符串:
``` js
// 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 可以与其它预处理器一起使用:
``` js
// webpack.config.js -> module.rules
{
test: /\.scss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: { modules: true }
},
'sass-loader'
]
}
```
## 自定义的注入名称
`.vue` 中你可以定义不止一个 `<style>`,为了避免被覆盖,你可以通过设置 `module` 属性来为它们定义注入后计算属性的名称。
``` html
<style module="a">
/* 注入标识符 a */
</style>
<style module="b">
/* 注入标识符 b */
</style>
```
# 自定义块
`.vue` 文件中,你可以自定义语言块。应用于一个自定义块的 loader 是基于这个块的 `lang` 特性、块的标签名以及你的 webpack 配置进行匹配的。
如果指定了一个 `lang` 特性,则这个自定义块将会作为一个带有该 `lang` 扩展名的文件进行匹配。
你也可以使用 `resourceQuery` 来为一个没有 `lang` 的自定义块匹配一条规则。例如为了匹配自定义块 `<foo>`
``` js
{
module: {
rules: [
{
resourceQuery: /blockType=foo/,
loader: 'loader-to-use'
}
]
}
}
```
如果找到了一个自定义块的匹配规则,它将会被处理,否则该自定义块会被默默忽略。
此外,如果这个自定义块被所有匹配的 loader 处理之后导出一个函数作为最终结果,则这个 `*.vue` 文件的组件会作为一个参数被这个函数调用。
## Example
这里有一个向组件内注入 `<docs>` 自定义块的示例,且它是在运行时可用的。
为了注入自定义块的内容,我们将会撰写一个自定义 loader:
``` js
module.exports = function (source, map) {
this.callback(
null,
`export default function (Component) {
Component.options.__docs = ${
JSON.stringify(source)
}
}`,
map
)
}
```
现在我们将会配置 webpack 来使用为 `<docs>` 自定义块撰写的自定义 loader。
``` js
// wepback.config.js
module.exports = {
module: {
rules: [
{
resourceQuery: /blockType=docs/,
loader: require.resolve('./docs-loader.js')
}
]
}
}
```
现在我们可以在运行时访问被导入组件的 `<docs>` 块内容了。
``` vue
<!-- ComponentB.vue -->
<template>
<div>Hello</div>
</template>
<docs>
This is the documentation for component B.
</docs>
```
``` vue
<!-- 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 提取
:::tip 提示
请只在生产环境下使用 CSS 提取,这将便于你在开发环境下进行热重载。
:::
## webpack 4
``` bash
npm install -D mini-css-extract-plugin
```
``` js
// 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
})
]
}
```
你还可以查阅 [mini-css-extract-plugin 文档](https://github.com/webpack-contrib/mini-css-extract-plugin)
## webpack 3
``` bash
npm install -D extract-text-webpack-plugin
```
``` js
// 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")
]
}
```
你也可以查阅 [extract-text-webpack-plugin 文档](https://github.com/webpack-contrib/extract-text-webpack-plugin)
# 函数式组件
在一个 `*.vue` 文件中以单文件形式定义的函数式组件,现在对于模板编译、scoped CSS 和热重载也有了良好的支持。
要声明一个应该编译为函数式组件的模板,请将 `functional` 特性添加到模板块中。这样做以后就可以省略 `<script>` 块中的 `functional` 选项。
模板中的表达式会在[函数式渲染上下文](https://cn.vuejs.org/v2/guide/render-function.html#函数式组件)中求值。这意味着在模板中,prop 需要以 `props.xxx` 的形式访问:
``` vue
<template functional>
<div>{{ props.foo }}</div>
</template>
```
你可以在 `parent` 上访问 `Vue.prototype` 全局定义的属性:
``` vue
<template functional>
<div>{{ parent.$someProperty }}</div>
</template>
```
# 热重载
“热重载”不只是当你修改文件的时候简单重新加载页面。启用热重载后,当你修改 `.vue` 文件时,该组件的所有实例将在**不刷新页面**的情况下被替换。它甚至保持了应用程序和被替换组件的当前状态!当你调整模版或者修改样式时,这极大地提高了开发体验。
![hot-reload](http://blog.evanyou.me/images/vue-hot.gif)
## 状态保留规则
- 当编辑一个组件的 `<template>` 时,这个组件实例将就地重新渲染,并保留当前所有的私有状态。能够做到这一点是因为模板被编译成了新的无副作用的渲染函数。
- 当编辑一个组件的 `<script>` 时,这个组件实例将就地销毁并重新创建。(应用中其它组件的状态将会被保留) 是因为 `<script>` 可能包含带有副作用的生命周期钩子,所以将重新渲染替换为重新加载是必须的,这样做可以确保组件行为的一致性。这也意味着,如果你的组件带有全局副作用,则整个页面将会被重新加载。
- `<style>` 会通过 `vue-style-loader` 自行热重载,所以它不会影响应用的状态。
## 用法
当使用脚手架工具 `vue-cli` 时,热重载是开箱即用的。
当手动设置你的工程时,热重载会在你启动 `webpack-dev-server --hot` 服务时自动开启。
高阶用户可能希望移步 `vue-loader` 内部使用的 [vue-hot-reload-api](https://github.com/vuejs/vue-hot-reload-api) 继续查阅。
## 关闭热重载
热重载默认是开启的,除非遇到以下情况:
* webpack 的 `target` 的值是 `node` (服务端渲染)
* webpack 会压缩代码
* `process.env.NODE_ENV === 'production'`
你可以设置 `hotReload: false` 选项来显式地关闭热重载:
``` js
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
hotReload: false // 关闭热重载
}
}
]
}
```
# 代码校验 (Linting)
官方的 [eslint-plugin-vue](https://github.com/vuejs/eslint-plugin-vue) 同时支持在 Vue 单文件组件的模板和脚本部分的代码校验。
请确认在你的 ESLint 配置文件中使用该插件要导入的配置:
``` js
// .eslintrc.js
module.exports = {
extends: [
"plugin:vue/essential"
]
}
```
接下来从命令行运行:
``` bash
eslint --ext js,vue MyComponent.vue
```
另一个选项是使用 [eslint-loader](https://github.com/MoOx/eslint-loader) 那么你的 `*.vue` 文件在开发过程中每次保存的时候就会自动进行代码校验:
``` bash
npm install -D eslint eslint-loader
```
请确保它是作为一个 pre-loader 运用的:
``` js
// webpack.config.js
module.exports = {
// ... 其它选项
module: {
rules: [
{
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /node_modules/
}
]
}
}
```
---
sidebarDepth: 2
---
# 使用预处理器
在 webpack 中,所有的预处理器需要匹配对应的 loader。Vue Loader 允许你使用其它 webpack loader 处理 Vue 组件的某一部分。它会根据 `lang` 特性以及你 webpack 配置中的规则自动推断出要使用的 loader。
## Sass
例如,为了通过 Sass/SCSS 编译我们的 `<style>` 标签:
``` bash
npm install -D sass-loader node-sass
```
在你的 webpack 配置中:
``` js
module.exports = {
module: {
rules: [
// ... 忽略其它规则
// 普通的 `.scss` 文件和 `*.vue` 文件中的
// `<style lang="scss">` 块都应用它
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
]
},
// 插件忽略
}
```
现在,除了能够 `import 'style.scss'`,我们还可以在 Vue 组件中使用 SCSS:
``` html
<style lang="scss">
/* 在这里撰写 SCSS */
</style>
```
这个块里的任何内容都会被 webpack 当作在一个 `*.scss` 文件中一样被处理。
### Sass vs SCSS
注意 `sass-loader` 会默认处理不基于缩进的 `scss` 语法。为了使用基于缩进的 `sass` 语法,你需要向这个 loader 传递选项:
``` js
// webpack.config.js -> module.rules
{
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
indentedSyntax: true
}
}
]
}
```
### 共享全局变量
`sass-loader` 也支持一个 `data` 选项,这个选项允许你在所有被处理的文件之间共享常见的变量,而不需要显式地导入它们:
``` js
// webpack.config.js -> module.rules
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// 你也可以从一个文件读取,例如 `variables.scss`
data: `$color: red;`
}
}
]
}
```
## Less
``` bash
npm install -D less less-loader
```
``` js
// webpack.config.js -> module.rules
{
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
}
```
## Stylus
``` bash
npm install -D stylus stylus-loader
```
``` js
// webpack.config.js -> module.rules
{
test: /\.styl(us)?$/,
use: [
'vue-style-loader',
'css-loader',
'stylus-loader'
]
}
```
## PostCSS
::: tip
Vue Loader v15 不再默认应用 PostCSS 变换。你需要通过 `postcss-loader` 使用 PostCSS。
:::
``` bash
npm install -D postcss-loader
```
``` js
// webpack.config.js -> module.rules
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: { importLoaders: 1 }
},
'postcss-loader'
]
}
```
PostCSS 的配置可以通过 `postcss.config.js``postcss-loader` 选项来完成。其更多细节请查阅 [postcss-loader 文档](https://github.com/postcss/postcss-loader)
`postcss-loader` 也可以和上述其它预处理器结合使用。
## Babel
``` bash
npm install -D babel-core babel-loader
```
``` js
// webpack.config.js -> module.rules
{
test: /\.js?$/,
loader: 'babel-loader'
}
```
Babel 的配置可以通过 `.babelrc``babel-loader` 选项来完成。
## TypeScript
``` bash
npm install -D typescript ts-loader
```
``` js
// webpack.config.js
module.exports = {
resolve: {
// 将 `.ts` 添加为一个可解析的扩展名。
extensions: ['.ts', '.js']
},
module: {
rules: [
// ... 忽略其它规则
{
test: /\.ts$/,
loader: 'ts-loader',
options: { appendTsSuffixTo: [/\.vue$/] }
}
]
},
// ...plugin omitted
}
```
TypeScript 的配置可以通过 `tsconfig.json` 来完成。你也可以查阅 [ts-loader](https://github.com/TypeStrong/ts-loader) 的文档。
## Pug
模板的处理会稍微有些不同,因为绝大对数 webpack 的模板类 loader,诸如 `pug-loader`,会返回一个模板函数而不是一个编译好的 HTML 字符串。所以我们需要使用一个返回原始的 HTML 字符串的 loader,例如 `pug-plain-loader`,而不是使用 `pug-loader`
``` bash
npm install -D pug pug-plain-loader
```
``` js
// webpack.config.js -> module.rules
{
test: /\.pug$/,
loader: 'pug-plain-loader'
}
```
然后你可以写:
``` html
<template lang="pug">
div
h1 Hello world!
</template>
```
如果你还打算使用它在 JavaScript 中将 `.pug` 文件作为字符串导入,你需要在这个预处理 loader 之后链上 `raw-loader`。注意添加 `raw-loader` 会破坏 Vue 组件内的用法,所以你需要定义两条规则,其中一条指向使用了一个 `resourceQuery` 的 Vue 文件,另一条指向 (回退到) JavaScript 导入:
``` js
// 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 只作用于当前组件中的元素。这类似于 Shadow DOM 中的样式封装。它有一些注意事项,但不需要任何 polyfill。它通过使用 PostCSS 来实现以下转换:
``` html
<style scoped>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
```
转换结果:
``` html
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
```
## 混用本地和全局样式
你可以在一个组件中同时使用有 scoped 和非 scoped 样式:
``` html
<style>
/* 全局样式 */
</style>
<style scoped>
/* 本地样式 */
</style>
```
## 子组件的根元素
使用 `scoped` 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件的 scoped CSS 和子组件的 scoped CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
## 深度作用选择器
如果你希望 `scoped` 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 `>>>` 操作符:
``` html
<style scoped>
.a >>> .b { /* ... */ }
</style>
```
上述代码将会编译成:
``` css
.a[data-v-f3f3eg9] .b { /* ... */ }
```
有些像 Sass 之类的预处理器无法正确解析 `>>>`。这种情况下你可以使用 `/deep/` 操作符取而代之——这是一个 `>>>` 的别名,同样可以正常工作。
## 动态生成的内容
通过 `v-html` 创建的 DOM 内容不受 scoped 样式影响,但是你仍然可以通过深度作用选择器来为他们设置样式。
## 还有一些要留意
- **Scoped 样式不能代替 class**。考虑到浏览器渲染各种 CSS 选择器的方式,当 `p { color: red }` 是 scoped 时 (即与特性选择器组合使用时) 会慢很多倍。如果你使用 class 或者 id 取而代之,比如 `.example { color: red }`,性能影响就会消除。你可以在[这块试验田](https://stevesouders.com/efws/css-selectors/csscreate.php)中测试它们的不同。
- **在递归组件中小心使用后代选择器!** 对选择器 `.a .b` 中的 CSS 规则来说,如果匹配 `.a` 的元素包含一个递归子组件,则所有的子组件中的 `.b` 都将被这个规则匹配。
# 测试
- [Vue CLI](https://github.com/vuejs/vue-cli) 提供了预配置的单元测试和 e2e 测试安装。
- 如果你有兴趣为 `*.vue` 文件手动设置单元测试,请查询 [@vue/test-utils](https://vue-test-utils.vuejs.org/zh-cn/) 的文档,这份文档涵盖了对 [mocha-webpack](https://vue-test-utils.vuejs.org/zh-cn/guides/testing-SFCs-with-mocha-webpack.html)[Jest](https://vue-test-utils.vuejs.org/zh-cn/guides/testing-SFCs-with-jest.html) 的设置。
---
sidebar: auto
sidebarDepth: 2
---
# 从 v14 迁移
::: tip 注意
我们正在升级 Vue CLI 3 beta 的过程中,并使用了 webpack 4 + Vue Loader 15,所以如果你计划升级到 Vue CLI 3 的话,可能需要等待。
:::
## 值得注意的不兼容变更
### 现在你需要一个插件
Vue Loader 15 现在需要配合一个 webpack 插件才能正确使用:
``` js
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
// ...
plugins: [
new VueLoaderPlugin()
]
}
```
### Loader 推导
现在 Vue Loader 15 使用了一个不一样的策略来推导语言块使用的 loader。
`<style lang="less">` 举例:在 v14 或更低版本中,它会尝试使用 `less-loader` 加载这个块,并在其后面隐式地链上 `css-loader``vue-style-loader`,这一切都使用内联的 loader 字符串。
在 v15 中,`<style lang="less">` 会完成把它当作一个真实的 `*.less` 文件来加载。因此,为了这样处理它,你需要在你的主 webpack 配置中显式地提供一条规则:
``` js
{
module: {
rules: [
// ... 其它规则
{
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
}
]
}
}
```
这样做的好处是这条规则同样应用在 JavaScript 里普通的 `*.less` 导入中,并且你可以为这些 loader 配置任何你想要的选项。在 v14 或更低版本中,如果你想为一个推导出来的 loader 定制选项,你不得不在 Vue Loader 自己的 `loaders` 选项中将它重复一遍。在 v15 中你再也没有必要这么做了。
v15 也允许为 loader 使用非序列化的选项,这种选项在之前的版本中是无法使用的。
### 模板预处理
v14 或更低版本使用 [consolidate](https://github.com/tj/consolidate.js/) 来编译 `<template lang="xxx">`。v15 现在取而代之的是使用 webpack loader 为它们应用预处理器。
注意有些模板的 loader 会导出一个编译好的模板函数而不是普通的 HTML,诸如 `pug-loader`。为了向 Vue 的模板编译器传递正确的内容,你必须换用一个输出普通 HTML 的 loader。例如,为了支持 `<template lang="pug">`,你可以使用 [pug-plain-loader](https://github.com/yyx990803/pug-plain-loader)
``` js
{
module: {
rules: [
{
test: /\.pug$/,
loader: 'pug-plain-loader'
}
]
}
}
```
如果你还打算使用它在 JavaScript 中将 `.pug` 文件作为字符串导入,你需要在这个预处理 loader 之后链上 `raw-loader`。注意添加 `raw-loader` 会破坏 Vue 组件内的用法,所以你需要定义两条规则,其中一条指向使用了一个 `resourceQuery` 的 Vue 文件,另一条指向 (回退到) JavaScript 导入:
``` js
{
module: {
rules: [
{
test: /\.pug$/,
oneOf: [
// 这条规则应用到 Vue 组件内的 `<template lang="pug">`
{
resourceQuery: /^\?vue/,
use: ['pug-plain-loader']
},
// 这条规则应用到 JavaScript 内的 pug 导入
{
use: ['raw-loader', 'pug-plain-loader']
}
]
}
]
}
}
```
### 样式注入
现在客户端的样式注入会在最前面注入所有的样式以确保开发模式和提取模式下行为的一致性。
注意它们注入的顺序是不能保证的,所以你撰写的 CSS 应该避免依赖插入的顺序。
### PostCSS
Vue Loader v15 不再默认应用 PostCSS 变换。想要使用 PostCSS,请像配置普通 CSS 文件那样配置 `postcss-loader`
### CSS Modules
CSS Modules 现在需要通过 `css-loader` 选项显式地配置。`<style>` 标签上的 `module` 特性仍然需要用来局部注入到组件中。
好消息是你现在可以在同一处配置 `localIdentName` 了:
``` js
{
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: 'vue-style-loader'
},
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
```
如果你只想在某些 Vue 组件中使用 CSS Modules,你可以使用 `oneOf` 规则并在 `resourceQuery` 字符串中检查 `module` 字符串:
``` js
{
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 提取
用法和你为普通 CSS 的配置一样。示例用法在 [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin)
``` js
{
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader'
},
{
test: /\.css$/,
// 或 `ExtractTextWebpackPlugin.extract(...)`
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'output.css'
})
]
}
```
## 服务端渲染的依赖排除
在服务端渲染中,我们通常使用 `webpack-node-externals` 来从服务端构建中排除 npm 依赖。如果你需要从一个 npm 依赖导入 CSS,之前的方案是使用像这样的一个白名单:
``` js
// webpack 配置
externals: nodeExternals({
whitelist: /\.css$/
})
```
使用 v15,导入 `<style src="dep/foo.css">` 现在会在请求的末尾追加 resourceQuery 字符串,所以你需要将上述内容更新为:
``` js
externals: nodeExternals({
whitelist: [/\.css$/, /\?vue&type=style/]
})
```
## 废弃的选项
下列选项已经被废弃了,它们应该使用普通的 webpack 模块的规则来配置:
- `loader`
- `preLoaders`
- `postLoaders`
- `postcss`
- `cssSourceMap`
- `buble`
- `extractCSS`
- `template`
下列选项已经被废弃了,它们应该使用新的 `compilerOptions` 选项来配置:
- `preserveWhitespace` (使用 `compilerOptions.preserveWhitespace`)
- `compilerModules` (使用 `compilerOptions.modules`)
- `compilerDirectives` (使用 `compilerOptions.directives`)
下列选项已经被改名了:
- `transformToRequire` (现在改名为 `transformAssetUrls`)
下列选项已经被改为 `resourceQuery`
- `shadowMode` (现在使用内联资源查询语句,例如 `foo.vue?shadow`)
:::tip
想查阅新选项的完整列表,请移步[选项参考](./options.md)
:::
---
sidebar: auto
---
# 选项参考
## transformAssetUrls
- 类型:`{ [tag: string]: string | Array<string> }`
- 默认值:
``` js
{
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
```
在模板编译过程中,编译器可以将某些特性转换为 `require` 调用,例如 `src` 中的 URL。因此这些目标资源可以被 webpack 处理。例如 `<img src="./foo.png">` 会找到你文件系统中的 `./foo.png` 并将其作为一个依赖包含在你的包里。
## compiler
- 类型:`VueTemplateCompiler`
- 默认值:`require('vue-template-compiler')`
覆写用来编译单文件组件中 `<template>` 块的默认编译器。
## compilerOptions
- 类型:`Object`
- 默认值:`{}`
模板编译器的选项。当使用默认的 `vue-template-compiler` 的时候,你可以使用这个选项来添加自定义编译器指令、模块或通过 `{ preserveWhitespace: false }` 放弃模板标签之间的空格。
详情查阅 [`vue-template-compiler` 选项参考](https://github.com/vuejs/vue-docs-zh-cn/blob/master/vue-template-compiler/README.md#选项).
## transpileOptions
- 类型:`Object`
- 默认值:`{}`
为渲染函数的生成码配置从 ES2015+ 到 ES5 的转译选项。这里的[转译器](https://github.com/vuejs/vue-template-es2015-compiler)是一份 [Buble](https://github.com/Rich-Harris/buble) 的 fork,因此你可以在[这里](https://buble.surge.sh/guide/#using-the-javascript-api)查阅可用的选项。
模板渲染函数编译支持一个特殊的变换 `stripWith` (默认启用),它会删除生成的渲染函数中的 `with` 用法,使它们兼容严格模式。
## optimizeSSR
- 类型:`boolean`
- 默认值:当 webpack 配置中包含 `target: 'node'``vue-template-compiler` 版本号大于等于 2.4.0 时为 `true`
开启 Vue 2.4 服务端渲染的编译优化之后,渲染函数将会把返回的 vdom 树的一部分编译为字符串,以提升服务端渲染的性能。在一些情况下,你可能想要明确地将其关掉,因为该渲染函数只能用于服务端渲染,而不能用于客户端渲染或测试环境。
## hotReload
- 类型:`boolean`
- 默认值:在开发环境下是 `true`,在生产环境下或 webpack 配置中有 `target: 'node'` 的时候是 `false`
- 允许的值:`false` (`true` 会强制热重载,即便是生产环境或 `target: 'node'` 时)
是否使用 webpack 的[模块热替换](https://webpack.js.org/concepts/hot-module-replacement/)在浏览器中应用变更而**不重载整个页面**
用这个选项 (值设为 `false`) 在开发环境下关闭热重载特性。
## productionMode
- 类型:`boolean`
- 默认值:`process.env.NODE_ENV === 'production'`
强制指定为生产环境,即禁止 loader 注入只在开发环境有效的代码 (例如 hot-reload 相关的代码)。
---
title: 单文件组件规范
sidebar: auto
---
# Vue 单文件组件 (SFC) 规范
## 简介
`.vue` 文件是一个自定义的文件类型,用类 HTML 语法描述一个 Vue 组件。每个 `.vue` 文件包含三种类型的顶级语言块 `<template>``<script>``<style>`,还允许添加可选的自定义块:
``` vue
<template>
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data () {
return {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
color: red;
}
</style>
<custom1>
This could be e.g. documentation for the component.
</custom1>
```
`vue-loader` 会解析文件,提取每个语言块,如有必要会通过其它 loader 处理,最后将他们组装成一个 ES Module,它的默认导出是一个 Vue.js 组件选项的对象。
`vue-loader` 支持使用非默认语言,比如 CSS 预处理器,预编译的 HTML 模版语言,通过设置语言块的 `lang` 属性。例如,你可以像下面这样使用 Sass 语法编写样式:
``` vue
<style lang="sass">
/* write Sass! */
</style>
```
更多细节可以在[使用预处理器](./guide/pre-processors.md)中找到。
## 语言块
### 模板
- 每个 `.vue` 文件最多包含一个 `<template>` 块。
- 内容将被提取并传递给 `vue-template-compiler` 为字符串,预处理为 JavaScript 渲染函数,并最终注入到从 `<script>` 导出的组件中。
### 脚本
- 每个 `.vue` 文件最多包含一个 `<script>` 块。
- 这个脚本会作为一个 ES Module 来执行。
- 它的**默认导出**应该是一个 Vue.js 的[组件选项对象](https://cn.vuejs.org/v2/api/#选项-数据)。也可以导出由 `Vue.extend()` 创建的扩展对象,但是普通对象是更好的选择。
- 任何匹配 `.js` 文件 (或通过它的 `lang` 特性指定的扩展名) 的 webpack 规则都将会运用到这个 `<script>` 块的内容中。
### 样式
- 默认匹配:`/\.css$/`
- 一个 `.vue` 文件可以包含多个 `<style>` 标签。
- `<style>` 标签可以有 `scoped` 或者 `module` 属性 (查看 [scoped CSS](./guide/scoped-css.md)[CSS Modules](./guide/css-modules.md)) 以帮助你将样式封装到当前组件。具有不同封装模式的多个 `<style>` 标签可以在同一个组件中混合使用。
- 任何匹配 `.css` 文件 (或通过它的 `lang` 特性指定的扩展名) 的 webpack 规则都将会运用到这个 `<style>` 块的内容中。
### 自定义块
可以在 `.vue` 文件中添加额外的自定义块来实现项目的特定需求,例如 `<docs>` 块。`vue-loader` 将会使用标签名来查找对应的 webpack loader 来应用在对应的块上。webpack loader 需要在 `vue-loader` 的选项 `loaders` 中指定。
更多细节,查看[自定义块](./guide/custom-blocks.md)
### Src 导入
如果喜欢把 `.vue` 文件分隔到多个文件中,你可以通过 `src` 属性导入外部文件:
``` vue
<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>
```
需要注意的是 `src` 导入遵循和 webpack 模块请求相同的路径解析规则,这意味着:
- 相对路径需要以 `./` 开始
- 你可以从 NPM 依赖中导入资源:
``` vue
<!-- import a file from the installed "todomvc-app-css" npm package -->
<style src="todomvc-app-css/index.css">
```
在自定义块上同样支持 `src` 导入,例如:
``` vue
<unit-test src="./unit-test.js">
</unit-test>
```
## 语法高亮 / IDE 支持
目前有下列 IDE/编辑器 支持语法高亮:
- [Sublime Text](https://github.com/vuejs/vue-syntax-highlight)
- [VS Code](https://marketplace.visualstudio.com/items?itemName=octref.vetur)
- [Atom](https://atom.io/packages/language-vue)
- [Vim](https://github.com/posva/vim-vue)
- [Emacs](https://github.com/AdamNiederer/vue-mode)
- [Brackets](https://github.com/pandao/brackets-vue)
- [JetBrains IDEs](https://plugins.jetbrains.com/plugin/8057) (WebStorm、PhpStorm 等)
非常感谢其他编辑器/IDE 所做的贡献!如果在 Vue 组件中没有使用任何预处理器,你可以把 `.vue` 文件当作 HTML 对待。
## 注释
在语言块中使用该语言块对应的注释语法 (HTML、CSS、JavaScript、Jade 等)。顶层注释使用 HTML 注释语法:`<!-- comment contents here -->`
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment