错过了Vue CLI2,还要错过Vue CLI3?
在Vue CLI出现之前,你可能要花费好几天的时间搭建项目的开发环境,如果你事先不了解webpack,你可能会又花费大把的时间熟悉webpack。就这样,一周过去了,你的项目还没有真正启动起来。 为了让开发者从纠结配置中解放出来,专注于撰写应用程序。Vue CLI也就因此而产生。它不仅确保了各种构建工具能够基于智能的默认配置即可平稳衔接,还提供了配置调整的灵活性。
Vue CLI历史Vue CLI到目前为止经历了两个大版本,CLI 2 和 CLI 3。很多人可能会好奇从 CLI 2升级到CLI 3会有哪些新的改变,接下来就一边回顾CLI 2,一边为大家解读CLI 3的新特性。
创建一个项目CLI 2和CLI 3第一个区别是npm包的包名,CLI 3并没有沿用CLI 2的vue-cli,而是另起为@vue/cli。创建项目方面也发生了变化,CLI 2 可以选择根据模板初始化项目,而CLI 3并未重新开发模板,如果开发者想要像CLI 2一样使用模板初始化项目,可全局安装一个桥接工具@vue/cli-init。
1、CLI 2 全局安装并创建项目
npm install -g vue-cli
# 或者
npm install -g vue-cli@x.x.x // 指定安装某一版本
vue init template-name project-name
# 例如:vue init webpack vue-test
注意:这里的CLI 2是2.9.6。
template-name :表示模板名称,可以通过vue list查看可用的模板,在这里官方提供了6种模板,分别为:
browserify——一个全面的Browserify vueify 的模板,运行起来带有热重载,保存时 lint 校验,单元测试。
browserify-simple——一个简单Browserify vueify的模板,不包含其他功能,让你快速的搭建vue的开发环境。
pwa——一个基于webpack模板的渐进式的网页应用程序模板。
simple——一个最简单的单页应用模板。
webpack——一个全面的webpack vue-loader的模板,运行起来带有热重载,保存时 lint 校验和CSS扩展。
webpack-simple——一个简单webpack vue-loader的模板,能让你快速搭建一个vue的开发环境。
图1 官方提供的6种模板
初始化过程中会确认项目的项目名、作者等信息,大家可根据需求自行修改。
2、CLI 3全局安装并创建一个项目
npm install -g @vue/cli
# 或者
yarn global add @vue/cli
# 创建项目
vue create project-name
# 例如:vue create vue-3.0-demo
# 或
# 使用init 初始化项目
npm install -g @vue/cli-init
# `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同
vue init webpack vue-3.0-demo
当我们用CLI 3的方式创建项目,输入vue create vue-3.0-demo命令后,你会发现在创建项目的路上总是有位“记者大哥”横路拦截,问你这问你那,你还必须做出选择。
故事就从你输入vue create vue-3.0-demo后悄悄开始了...
记者大哥:“欢迎进入CLI 3的世界,首先你得选取一个 preset。选择默认的设置可以快速创建一个新项目的原型,而手动设置则提供了更多的选择。你是选择默认配置,还是手动选择特性呢?”
你:(心里活动:“来都来了,为何不看看记者大哥到底搞什么鬼”)“我选择了手动选择属性”
图2 手动选取特性
你:什么鬼?还给我来个多选题!首先Babel是必要的,不然拿什么来转换ES6语法,Typescript?不会,略过。渐进式的程序应用,暂时也不涉及这个。Router勾上,作为一个移动M站,得有人来管理路由呀。Vuex一个状态管理器,后期要用再加上吧,反正也跑不了。css 预处理器,习惯使用Less,也加一。Linter / Formatter也加一,作为一个团队,没有人统一代码风格可不行。最后两个分别是单元测试和端对端测试,这里我就不加上了,没用过,期待今后有大神分享。
选择完特性后,你以为就结束了,没想到,一步选错步步要你选。
对于css预处理器方面,你毅然决然选择了Less; 但linter / formatter 配置,你懵逼了。这都是什么??记者大哥介绍了一下:
ESLint 是一个语法规则和代码风格的检查工具,可以检测出你代码中潜在的问题,可以保证写出语法正确和风格统一的代码。
图3 选择linter配置
ESLint with error prevention only——只检测错误。
ESLint Airbnb config——独角兽公司的Airbnb,有人评价说“这是一份最合理的Javascript编码规范”,它几乎涵盖了Javascript的各个方面。
ESLint Standard config——standardJs一份强大的Javascript编码规范,自带linter和自动代码纠正。没有配置。自动格式化代码。可以在编码早期发现规范问题和低级错误。
ESLint Prettier—— Prettier 作为代码格式化工具,能够统一整个团队的代码风格。
等他介绍完,你心里大概有点谱了,这里你选择了 ESLint Standard config。
lint有两种检查时机,一是用户保存文件的时候,二是用户提交文件到git的时候。你就选了Lint on save,有错及时解决嘛。
终于“记者大哥”告诉你接下来这个问题是最后一个问题咯。
记者大哥:你是喜欢把Babel、ESLint等配置信息全放在package.json文件里呢,还是单独文件管理?
你:一个一个文件比较好,根据文件名就知道这是谁的配置,方便维护。
记者大哥:那你是否想把今天你手动选择的preset保存为未来项目的preset呢?
你:
说好的最后一个呢!!
......保存!
happy end~~
温馨提示:如果你是用window,在进行创建项目的时候,最好使用cmd,在cmd里你可以通过箭头上下选择和空格选中。如果你用git bash 可能会出现箭头和空格都没有请选择和选中作用。
这里通过一个漫长的对话我们自定义的一个preset,此时如果你需要创建新工程,这时候你就会发现多了一个preset,就是最初你自己设置的。你可以选择自己之前保存preset的,也可以再次开启“采访模式”。
图4 新添的preset
CLI 2 的项目结构图5 vue cli 2.9.6项目结构
对于CLI 2这个项目结构,主要的也是最重要的在于bulid和config者两个目录。bulid是项目构建的相关代码,config是项目开发环境配置。
接下来就先从webpack.base.conf.js开始依次介绍build和config两个目录下的相关功能。
webpack.base.conf.jswebpack.base.conf.js是webpack的基础配置,是dev和prod的公共配置文件。
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
path——该模块提供了一些用于处理文件路径的小工具
utils——给整个CLI提供方法
config——开发环境的配置
vueLoaderConfig——分析是否是生产环境,然后将根据不同的环境来加载配置功能
在这个文件里一共实现了两个方法。一是合并path路径的,另一个是创建Eslint的Rules。而剩余部分就是webpack的基础配置,这里简化了webpack结构,简化的结果其实就是webpack的一个骨架,如果在配置上遇到问题,可去webpack查证。
...
module.exports = {
entry: {}, // 编译入口文件
output: {}, // 编译输出路径
resolve: {}, // 一些解决方案配置
module: {
// 不同类型文件加载器配置
rules: []
},
...
// 这些选项用于配置polyfill或mock某些node.js全局变量和模块。
// 这可以使最初为nodejs编写的代码可以在浏览器端运行
node: {...}
}
关于path有兴趣的可前往node学习,接下来重点介绍下utils.js,config和vue-loader.conf。
utils.jsutils.js文件中总共实现了4个方法:assetsPath、cssLoaders、styleLoaders、createNotifierCallback。
assetsPath——返回不同环境下的static目录位置
cssLoaders——为不同的css预处理器提供一个统一的生成方式
styleLoaders——为那些独立的style文件创建加载器配置
createNotifierCallback——以类似浏览器的通知的形式展示信息
configconfig关键文件是index.js。这个文件是开发环境和生产环境的基本配置。在这个文件里开发者可在dev设置开发环境的静态路径、本地服务器配置项、Eslint、SourceMaps和代理,也可在build设置生产环境是否开启gzip压缩,以及压缩后缀名的设置等。
...
module.exports = {
dev: {...},
build: {...}
}
vue-loader.conf这个文件的内容相对比较少。首先,vue文件中的css loader将在生产环境下把css文件抽取到一个独立的文件中;其次是根据不同的环境,引入不同的source map配置文件;最后设置是否开启缓存破坏。
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
关于webpack公共配置讲完了,接下来我们就一起学习下在dev和prod环境各自的配置吧。
webpack.dev.conf.js这个文件引入了webpack-merge,意在将公共配置文件和dev配置合并。从代码里我们可以发现,dev环境又新增了一些配置项。
给独立的style文件添加了sourceMap功能,有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。
引入devtool。
配置devServer,包括热部署、代理、启动程序的时候自动在浏览器打开主页面等。
新增一些插件,包括热替换、webpack.NamedModulesPlugin在热加载时直接返回更新文件名、html-webpack-plugin生成html文件等。
最后一个函数是为了确保启动程序时,如果端口被占用时,会通过portfinder来发布新的端口。
...
const devWebpackConfig = merge(baseWebpackConfig, {
module: { ... },
devtool: config.dev.devtool,
devServer: { ... },
plugins: [ ... ]
})
module.exports = new Promise((resolve, reject) = { ... })
webpack.prod.conf.js相比 webpack.dev.conf.js,这个文件多引入了几个依赖,主要是为了压缩CSS和JS。在文件配置上多了一个output,将js文件打包成多个chuck,用hash值命名,来解决缓存策略。
到这里CLI 2的整个配置也就接近尾声了。剩下的还有check-version.js和bulid.js两个文件。
check-version.js这个文件主要是用来检测当前环境中的node和npm版本和我们需要的是否一致的。
bulid.js这个文件刚开始通过check-versions判断当前的node和npm版本号,如果现有的npm或者node的版本比定义的版本低,则生成一段警告。接下来,先删除打包目标目录下的文件,再进行打包,直至打包完成。
我们走马观花的学习了CLI 2的配置,估计大家也都累了。那接下来就来一段采访吧~~期待不,哈哈。
CLI 3的项目结构图6 CLI 3项目结构
从CLI 3的整个项目结构我们可以发现,这个结构很简单,没有相关的配置文件或复杂的目录结构。CLI 3仅生成构建应用程序所需的文件,让使用者不用关心这些工具的具体配置,从而降低了工具的使用难度。
其实通过阅读CLI 3的官方文档,你可能已经知道,官方内置了一个CLI服务(@vue/cli-service),作为一个开发环境的依赖,局部安装在@vue/cli创建的项目中。如果你真想修改webpack的相关配置,可在项目的根目录下(和package.json同级)创建一个vue.config.js配置文件,这个文件一旦存在就会被@vue/cli-service自动加载。也可直接使用package.json中的vue字段。
一个没有好奇心的程序猿,不是一个更好的程序猿。
如果你已经满足于官方的介绍,那也就到此结束漫长的阅读之旅啦(偷偷告诉你后面还有新特性的精彩内容)。如果你也像我一样,充满了好奇心,就跟我再去探索一番。
从CLI 2到CLI 3,初期可能没有官方文档。如果你真想探个究竟,可以从启动项目入手。
CLI 2启动方式是webpack-dev-server --inline --progress --config build/webpack.dev.conf.js这里用webpack-dev-server搭一个服务。
--inline:启动inline模式来自动刷新页面
--progress:显示打包的进度
--config build/webpack.dev.conf.js:指定要用的是哪个配置文件
CLI 3启动方式是vue-cli-service serve
vue-cli-service就是CLI服务,你可全局搜索一下,位于node_modules\@vue\cli-service\bin
vue-cli-service.js#!/usr/bin/env node
const semver = require('semver')
const { error } = require('@vue/cli-shared-utils')
const requiredVersion = require('../package.json').engines.node
...
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
const rawArgv = process.argv.slice(2)
const args = require('minimist')(rawArgv)
const command = args._[0]
service.run(command, args, rawArgv).catch(err = {
error(err)
process.exit(1)
})
这个文件首先是判断了当前node的版本和vue-cli-service要求的版本是否一致,如果版本太低就得升级node版本。
紧接着就起了个服务,这个服务是位于lib/Service。
Service.js...
loadUserOptions () {
// vue.config.js
let fileConfig, pkgConfig, resolved, resovledFrom
const configPath = (
process.env.VUE_CLI_SERVICE_CONFIG_PATH ||
path.resolve(this.context, 'vue.config.js')
)
...
// package.vue
pkgConfig = this.pkg.vue
...
if (fileConfig) {
if (pkgConfig) {
...
}
resolved = fileConfig
resovledFrom = 'vue.config.js'
} else if (pkgConfig) {
resolved = pkgConfig
resovledFrom = ''vue' field in package.json'
} else {
resolved = this.inlineOptions || {}
resovledFrom = 'inline options'
}
...
return resolved
}
}
...
在loadUserOptions这个函数中,你可以看到官方提到的vue.config.js。 这个函数主要是加载用户的配置。如果vue.config.js和package.json的vue字段同时存在,会忽略package.json的vue字段配置,而选取vue.config.js的配置。
这里粗略介绍了何处加载了 vue.confg.js 文件,有兴趣可以继续深究。经过安装CLI、创建项目到整个项目结构介绍,我们可以大致了解了两者的区别。接下来大家一起围观一下CLI 3给我们带来的哪些新特性吧~~~
新特新CLI插件的出现据我所知,在CLI 3之前是没有CLI插件这个概念的,人们在开发Vue项目时,若是需要实现功能都是引用npm的相关包。CLI 3的出现,带来了CLI插件这个概念,也带来了统一的命名方式:@vue/cli-plugin-(内建插件)/ vue-cli-plugin-(社区插件)开头。
图7 CLI 3出现前包名
图8 CLI插件
即刻创建原型有时候你想快速创建一个原型,不需要添加一大堆样板。Vue CLI就提供了一个运行原型的开发服务器。
要想使用这个开发服务器,前提是安装@vue/cli-service-global
npm install -g @vue/cli-service-global
你可以用IDE创建.vue文件,并添加vue代码。如果你对命令行掌握良好,也能轻松创建。
echo 'hello world' src/views/HelloWorld.vue
然后将HelloWorld.vue 修改为标准的vue文件结构就行。
template
div hello world! /div
/template
紧接着你就可以运行vue serve src/views/HelloWorld.vue 就能看效果啦~
图9 快速原型开发
配置时无需Eject如果你曾经是一位React的忠实用户,或许使用过create-react-app(react的脚手架),那你对eject的理解可能就很深刻了。可惜小女不才,早期与React只有一面之缘,也就没此机会接触create-react-app。为了理解eject到底是何物,我查看了react的相关文档,终于明白了。 在react中,使用CRA( create-react-app简称)创建完项目,我们可以在package.json看到这里一个script命令。
'scripts': {
'eject': 'react-scripts eject'
}
执行完npm run eject会将封装在CRA里的配置全部反编译到当前项目,换句话就是把之前好不容易藏好了config文件暴露出来了,用户也就获取到了控制权,想怎么改随你。这样react-scripts就以文件的形式存在于项目中,就无法升级啦。
# eject 后项目根目录下会出现 config 文件夹,里面就包含了 webpack 配置
config
├── env.js
├── jest
│ ├── cssTransform.js
│ └── fileTransform.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.prod.js // 生产环境配置
└── webpackDevServer.config.js
好在CLI 3并没有像CRA一样,开发者你要是想自己修改配置,也是可以的,我不需要你eject,你想改就去vue.config.js里改吧。
如果你想看看默认的webpack配置,可执行vue inspect查看,默认情况下,会将配置输出到控制台,你也可以将结果指向一个文件,例如:vue inspect webpack.config.js。
新特性到此就介绍完毕了。
参考资料
cli.vuejs.org/zh/guide/
npmjs/package/vue-cli
zhaozhiming.github.io/blog/2018/01/08/create-react-app-override-webpack-config/
segmentfault/a/1190000012581869#articleHeader5
css88/archives/8405
关于奇舞周刊《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。