脚手架vue-cli(3.x)
vue-cli是一个基于vue.js进行快速开发的完整系统,提供下面几个功能:
- 通过
@vue/cli
搭建交互式的项目脚手架。 - 通过
@vue/cli
+@vue/cli-service-global
快速开始零配置原型开发。 - 一个运行时依赖 (@vue/cli-service),该依赖:
- 可升级;
- 基于 webpack 构建,并带有合理的默认配置;
- 可以通过项目内的配置文件进行配置;
- 可以通过插件进行扩展。
- 一个丰富的官方插件集合,集成了前端生态中最好的工具。
- 一套完全图形化的创建和管理 Vue.js 项目的用户界面。
vue-cli是由以下几个部分组成:
- cli(@vue/cli)
- cli服务(@vue/cli-service)
- cli插件
CLI (@vue/cli
) 是一个全局安装的 npm 包,提供了终端里的 vue
命令,这些命令都是在全局安装之后才可以使用的,例如:使用 vue serve 启动项目需要在npm install -g @vue/cli-service-global之后才可以。
- vue create 创建一个vue项目
- vue serve 启动vue项目
- vue ui 进入vue可视化管理界面
当我们没有全局安装vue时,可以借助npm 进行vue项目的启动和打包等操作,例如: npm run serve 启动vue项目; npm run build打包vue项目; 同时在启动react项目的时候使用的是npm start; 在打包react项目的时候也是使用的npm run build; 但是创建react项目的是使用的react自己的脚手架create-react-app; vue使用的命令是vue create。
CLI 服务 (@vue/cli-service
) 是一个开发环境依赖。它是一个 npm 包,局部安装在每个 @vue/cli
创建的项目中。
- 加载其它 CLI 插件的核心服务;
- 一个针对绝大部分应用优化过的内部的 webpack 配置;
- 项目内部的
vue-cli-service
命令,提供serve
、build
和inspect
命令。
如果你熟悉 create-react-app 的话,@vue/cli-service
实际上大致于 react-scripts
,尽管功能集合不一样。
对应的vue项目的package.json中内容如下:
{
......
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}
......
}
CLI 插件是向你的 Vue 项目提供可选功能的 npm 包,例如 Babel/TypeScript 转译、ESLint 集成、单元测试和 end-to-end 测试等。Vue CLI 插件的名字以 @vue/cli-plugin-
(内建插件) 或 vue-cli-plugin-
(社区插件) 开头,非常容易使用。
对应的vue项目的package.json中内容如下:
{
......
"devDependencies": {
"@vue/cli-plugin-babel": "^3.5.0",
"@vue/cli-plugin-eslint": "^3.5.0",
"@vue/cli-service": "^3.5.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.8.0",
"eslint-plugin-vue": "^5.0.0",
"less": "^3.0.4",
"less-loader": "^4.1.0",
"vue-template-compiler": "^2.5.21"
}
......
}
脚手架的安装
关于旧版本,如果你已经全局安装了旧版本vue-cli(1.x或者2.x)的话,需要先卸载,npm uninstall vue-cli -g,现在是3.x的脚手架@vue/cli。
安装@vue/cli
npm intsall @vue/cli -g
安装完成之后可以使用vue --version 查看版本的信息以及是否安装成功;
脚手架的基础使用
可以使用vue serve和vue build对单个*.vue文件进行快速原型开发,但是需要安装一个额外的全局扩展:
npm install -g @vue/cli-service-global
vue serve
的缺点就是它需要安装全局依赖,这使得它在不同机器上的一致性不能得到保证。因此这只适用于快速原型开发。
vue serve常用的几个参数:
Usage: serve [options] [entry]
在开发环境模式下零配置为 .js 或 .vue 文件启动一个服务器
-o, --open 打开浏览器
-c, --copy 将本地 URL 复制到剪切板
-h, --help 输出用法信息
其中 [entry]是入口文件,入口可以是 main.js、index.js、App.vue 或 app.vue 中的一个。你也可以显式地指定入口文件。
vue build常用的几个参数
Usage: build [options] [entry]
在生产环境模式下零配置构建一个 .js 或 .vue 文件
-t, --target <target> 构建目标 (app | lib | wc | wc-async, 默认值:app)
-n, --name <name> 库的名字或 Web Components 组件的名字 (默认值:入口文件名)
-d, --dest <dir> 输出目录 (默认值:dist)
-h, --help 输出用法信息
vue create创建一个新的项目
比如说创建一个新项目: vue create hello-world,当你使用vue create 创建一个项目时会提示你选择一个preset(预设),你可以选默认的包含了基本的 Babel + ESLint 设置的 preset,或者vue-router, vuex, less, babel, eslint的preset,也可以选“手动选择特性”来选取需要的特性。
默认设置非常合适快速的常见一个新项目,当你选择手动创建时,你需要自己选择需要的依赖:
如果你决定手动选择特性,在操作提示的最后你可以选择将已选项保存为一个将来可复用的 preset。
当我们在使用npm install安装依赖的时候,下载依赖往往会非常的慢,此时我们需要修改一下,npm的下载源,可以改为淘宝的下载源:
首先查看当前的npm源是什么:
npm config get registry
上面的源已经设置为淘宝的源,设置淘宝镜像:
npm config set registry https://registry.npm.taobao.org
也可以进行临时修改,只生效一次:
npm install 包的名字 --registry https://registry.npm.taobao.org
vue create 常用的参数查看:
选项:
-p, --preset <presetName> 忽略提示符并使用已保存的或远程的预设选项
-d, --default 忽略提示符并使用默认预设选项
-i, --inlinePreset <json> 忽略提示符并使用内联的 JSON 字符串预设选项
-m, --packageManager <command> 在安装依赖时使用指定的 npm 客户端
-r, --registry <url> 在安装依赖时使用指定的 npm registry
-g, --git [message] 强制 / 跳过 git 初始化,并可选的指定初始化提交信息
-n, --no-git 跳过 git 初始化
-f, --force 覆写目标目录可能存在的配置
-c, --clone 使用 git clone 获取远程预设选项
-x, --proxy 使用指定的代理创建项目
-b, --bare 创建项目时省略默认组件中的新手指导信息
-h, --help 输出使用帮助信息
vue ui 图形化界面管理项目
使用vue ui 进入图形化管理界面
vue ui
插件和preset(预设)
Vue CLI 使用了一套基于插件的架构。如果你查阅一个新创建项目的 package.json
,就会发现依赖都是以 @vue/cli-plugin-
开头的。插件可以修改 webpack 的内部配置,也可以向 vue-cli-service
注入命令。在项目创建的过程中,绝大部分列出的特性都是通过插件来实现的。
现有的项目中安装插件,安装一个新的插件可以使用:
vue add @vue/eslint
注意:
vue add
的设计意图是为了安装和调用 Vue CLI 插件。这不意味着替换掉普通的 npm 包。对于这些普通的 npm 包,你仍然需要选用包管理器。
其实在项目开发中我们一般会使用npm进行的依赖包的管理:
npm install 包名 --save 在生产环境中使用(package.json中的scripts下)
npm install 包名 --save-dev 在开发环境中安装(package.json中的devDependencies下)
npm install 安装package.json中的所有的依赖
npm uninstall [<name><version>][-g]/[--save][-dev] 卸载安装的某个包
npm update [<name><version>][-g]/[--save][-dev] 更新安装的某个包
npm init 初始化package.json文件
在使用vue add时:
vue add @vue/eslint
# 这个命令将 @vue/eslint 解析为完整的包名 @vue/cli-plugin-eslint,然后从 npm 安装它,调用它的生成器。这个和之前的用法等价
vue add @vue/cli-plugin-eslint
如果想安装第三方的,例如: @foo/vue-cli-plugin-bar
vue add @foo/bar
vue-router
和 vuex
的情况比较特殊——它们并没有自己的插件,但是你仍然可以这样添加它们:
vue add router
vue add vuex
如果出于一些原因你的插件列在了该项目之外的其它 package.json
文件里,你可以在自己项目的 package.json
里设置 vuePlugins.resolveFrom
选项指向包含其它 package.json
的文件夹。例如,如果你有一个 .config/package.json
文件,那么package.json里面要进行这样大的修改:
{
"vuePlugins": {
"resolveFrom": ".config"
}
}
如果你需要在项目里直接访问插件 API 而不需要创建一个完整的插件,你可以在 package.json
文件中使用 vuePlugins.service
选项:
{
"vuePlugins": {
"service": ["my-commands.js"]
}
}
preset(预设)
一个 Vue CLI preset 是一个包含创建新项目所需预定义选项和插件的 JSON 对象,让用户无需在命令提示中选择它们。
在 vue create
过程中保存的 preset 会被放在你的 home 目录下的一个配置文件中 (~/.vuerc
)。你可以通过直接编辑这个文件来调整、添加、删除保存好的 preset。
进入./vuerc查看里面的内容:
下面就是preset的一个列子:
{
"useTaobaoRegistry": false,
"presets": {
"y": {
"useConfigFiles": true,
"plugins": {
"@vue/cli-plugin-babel": {},
"@vue/cli-plugin-eslint": {
"config": "standard",
"lintOn": [
"save"
]
}
},
"router": true,
"routerHistoryMode": true,
"vuex": true,
"cssPreprocessor": "less"
}
},
"latestVersion": "3.6.3",
"lastChecked": 1555467470124
}
CLI 服务
在运行项目的时候执行npm run serve其实相当于执行了 vue-cli-service serve命名;
vue-cli-service serve命令
用法:vue-cli-service serve [options] [entry]
选项:
--open 在服务器启动时打开浏览器
--copy 在服务器启动时将 URL 复制到剪切版
--mode 指定环境模式 (默认值:development)
--host 指定 host (默认值:0.0.0.0)
--port 指定 port (默认值:8080)
--https 使用 https (默认值:false)
vue-cli-service serve
命令会启动一个开发服务器 (基于 webpack-dev-server) 并附带开箱即用的模块热重载 (Hot-Module-Replacement)。
命令行参数 [entry]
将被指定为唯一入口,而非额外的追加入口。尝试使用 [entry]
覆盖 config.pages
中的 entry
将可能引发错误。
vue-cli-service build命令
用法:vue-cli-service build [options] [entry|pattern]
选项:
--mode 指定环境模式 (默认值:production)
--dest 指定输出目录 (默认值:dist)
--modern 面向现代浏览器带自动回退地构建应用
--target app | lib | wc | wc-async (默认值:app)
--name 库或 Web Components 模式下的名字 (默认值:package.json 中的 "name" 字段或入口文件名)
--no-clean 在构建项目之前不清除目标目录
--report 生成 report.html 以帮助分析包内容
--report-json 生成 report.json 以帮助分析包内容
--watch 监听文件变化
vue-cli-service build
会在 dist/
目录产生一个可用于生产环境的包,带有 JS/CSS/HTML 的压缩,和为更好的缓存而做的自动的 vendor chunk splitting。它的 chunk manifest 会内联在 HTML 里。
这里还有一些有用的命令参数:
--modern
使用现代模式构建应用,为现代浏览器交付原生支持的 ES2015 代码,并生成一个兼容老浏览器的包用来自动回退。--target
允许你将项目中的任何组件以一个库或 Web Components 组件的方式进行构建。更多细节请查阅构建目标。--report
和--report-json
会根据构建统计生成报告,它会帮助你分析包中包含的模块们的大小。
vue-cli-service inspect命令
用法:vue-cli-service inspect [options] [...paths]
选项:
--mode 指定环境模式 (默认值:development)
你可以使用 vue-cli-service inspect
来审查一个 Vue CLI 项目的 webpack config。
缓存和并行处理
cache-loader
会默认为 Vue/Babel/TypeScript 编译开启。文件会缓存在node_modules/.cache
中——如果你遇到了编译方面的问题,记得先删掉缓存目录之后再试试看。thread-loader
会在多核 CPU 的机器上为 Babel/TypeScript 转译开启。
浏览器兼容性
browserslist
你会发现有 package.json
文件里的 browserslist
字段 (或一个单独的 .browserslistrc
文件),指定了项目的目标浏览器的范围。
Polyfill
一个默认的 Vue CLI 项目会使用 @vue/babel-preset-app,它通过 @babel/preset-env
和 browserslist
配置来决定项目需要的 polyfill。
默认情况下,它会把 useBuiltIns: 'usage'
传递给 @babel/preset-env
,这样它会根据源代码中出现的语言特性自动检测需要的 polyfill。这确保了最终包里 polyfill 数量的最小化。然而,这也意味着如果其中一个依赖需要特殊的 polyfill,默认情况下 Babel 无法将其检测出来。
如果有依赖需要 polyfill,你有几种选择:
- 如果该依赖基于一个目标环境不支持的 ES 版本撰写: 将其添加到
vue.config.js
中的transpileDependencies
选项。这会为该依赖同时开启语法语法转换和根据使用情况检测 polyfill。 - 如果该依赖交付了 ES5 代码并显式地列出了需要的 polyfill: 你可以使用
@vue/babel-preset-app
的 polyfills 选项预包含所需要的 polyfill。注意 es6.promise 将被默认包含,因为现在的库依赖 Promise 是非常普遍的。
// babel.config.js
module.exports = {
presets: [
['@vue/app', {
polyfills: [
'es6.promise',
'es6.symbol'
]
}]
]
}
现在模式
Vue CLI 提供了一个“现代模式”帮你解决这个问题。以如下命令为生产环境构建:
vue-cli-service build --modern
Vue CLI 会产生两个应用的版本:一个现代版的包,面向支持 ES modules 的现代浏览器,另一个旧版的包,面向不支持的旧浏览器。
- 现代版的包会通过
<script type="module">
在被支持的浏览器中加载;它们还会使用<link rel="modulepreload">
进行预加载。 - 旧版的包会通过
<script nomodule>
加载,并会被支持 ES modules 的浏览器忽略。 - 一个针对 Safari 10 中
<script nomodule>
的修复会被自动注入。
对于一个 Hello World 应用来说,现代版的包已经小了 16%。在生产环境下,现代版的包通常都会表现出显著的解析速度和运算速度,从而改善应用的加载性能。
HTML 和静态资源
index文件
public/index.html
文件是一个会被 html-webpack-plugin 处理的模板。在构建过程中,资源链接会被自动注入。另外,Vue CLI 也会自动注入 resource hint (preload/prefetch
、manifest 和图标链接 (当用到 PWA 插件时) 以及构建过程中处理的 JavaScript 和 CSS 文件的资源链接。
插值
因为 index 文件被用作模板,所以你可以使用 lodash template 语法插入内容:
<%= VALUE %>
用来做不转义插值;<%- VALUE %>
用来做 HTML 转义插值;<% expression %>
用来描述 JavaScript 流程控制。
除了被 html-webpack-plugin
暴露的默认值之外,所有客户端环境变量也可以直接使用。例如,BASE_URL
的用法:
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
preload
是一种 resource hint,用来指定页面加载后很快会被用到的资源,所以在页面加载的过程中,我们希望在浏览器开始主体渲染之前尽早 preload。默认情况下,一个 Vue CLI 应用会为所有初始化渲染需要的文件自动生成 preload 提示。
prefetch
是一种 resource hint,用来告诉浏览器在页面加载完成后,利用空闲时间提前获取用户未来可能会访问的内容。
不生成 index
当基于已有的后端使用 Vue CLI 时,你可能不需要生成 index.html
,这样生成的资源可以用于一个服务端渲染的页面。这时可以向 vue.config.js
加入下列代码:
// vue.config.js
module.exports = {
// 去掉文件名中的 hash
filenameHashing: false,
// 删除 HTML 相关的 webpack 插件
chainWebpack: config => {
config.plugins.delete('html')
config.plugins.delete('preload')
config.plugins.delete('prefetch')
}
}
css相关
引用静态资源
所有编译后的 CSS 都会通过 css-loader 来解析其中的 url()
引用,并将这些引用作为模块请求来处理。这意味着你可以根据本地的文件结构用相对路径来引用静态资源。另外要注意的是如果你想要引用一个 npm 依赖中的文件,或是想要用 webpack alias,则需要在路径前加上 ~
的前缀来避免歧义。更多细节请参考处理静态资源。
预处理器
你可以在创建项目的时候选择预处理器 (Sass/Less/Stylus)。如果当时没有选好,内置的 webpack 仍然会被预配置为可以完成所有的处理。你也可以手动安装相应的 webpack loader:
# Sass
npm install -D sass-loader node-sass
# Less
npm install -D less-loader less
# Stylus
npm install -D stylus-loader stylus
然后你就可以导入相应的文件类型,或在 *.vue
文件中这样来使用:
<style lang="scss">
$color: red;
</style>
自动化导入
如果你想自动化导入文件 (用于颜色、变量、mixin……),你可以使用 style-resources-loader。这里有一个关于 Stylus 的在每个单文件组件和 Stylus 文件中导入 ./src/styles/imports.styl
的例子:
// vue.config.js
const path = require('path')
module.exports = {
chainWebpack: config => {
const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
types.forEach(type => addStyleResource(config.module.rule('stylus').oneOf(type)))
},
}
function addStyleResource (rule) {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
path.resolve(__dirname, './src/styles/imports.styl'),
],
})
}
CSS Modules
你可以通过 <style module>
以开箱即用的方式在 *.vue
文件中使用 CSS Modules。
如果想在 JavaScript 中作为 CSS Modules 导入 CSS 或其它预处理文件,该文件应该以 .module.(css|less|sass|scss|styl)
结尾:
import styles from './foo.module.css'
// 所有支持的预处理器都一样工作
import sassStyles from './foo.module.scss'
如果你想去掉文件名中的 .module
,可以设置 vue.config.js
中的 css.modules
为 true
:
// vue.config.js
module.exports = {
css: {
modules: true
}
}
如果你希望自定义生成的 CSS Modules 模块的类名,可以通过 vue.config.js
中的 css.loaderOptions.css
选项来实现。所有的 css-loader
选项在这里都是支持的,例如 localIdentName
和 camelCase
:
// vue.config.js
module.exports = {
css: {
loaderOptions: {
css: {
localIdentName: '[name]-[hash]',
camelCase: 'only'
}
}
}
}
webpack 相关
简单的配置方式
调整 webpack 配置最简单的方式就是在 vue.config.js
中的 configureWebpack
选项提供一个对象:
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
new MyAwesomeWebpackPlugin()
]
}
}
该对象将会被 webpack-merge 合并入最终的 webpack 配置。
如果你需要基于环境有条件地配置行为,或者想要直接修改配置,那就换成一个函数 (该函数会在环境变量被设置之后懒执行)。该方法的第一个参数会收到已经解析好的配置。在函数内,你可以直接修改配置,或者返回一个将会被合并的对象:
// vue.config.js
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
}
}