vue-cli2 和vue-cli3的对比

2,197 阅读14分钟

分享一篇不错的文章,摘自:www.360doc.com/content/18/…


www.360doc.com/content/18/…

Vue CLI 产生的背景

在Vue CLI出现之前,你可能要花费好几天的时间搭建项目的开发环境,如果你事先不了解webpack,你可能会又花费大把的时间熟悉webpack。就这样,一周过去了,你的项目还没有真正启动起来。 为了让开发者从纠结配置中解放出来,专注于撰写应用程序。Vue CLI也就因此而产生。它不仅确保了各种构建工具能够基于智能的默认配置即可平稳衔接,还提供了配置调整的灵活性。

Vue CLI历史

Vue CLI到目前为止经历了两个大版本,CLI 2 和 CLI 3。很多人可能会好奇从 CLI 2升级到CLI 3会有哪些新的改变,接下来就一边回顾CLI 2,一边为大家解读CLI 3的新特性。


vue-cli的版本查看

vue -V


创建一个项目

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.js

webpack.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.js

utils.js文件中总共实现了4个方法:assetsPath、cssLoaders、styleLoaders、createNotifierCallback。

  • assetsPath——返回不同环境下的static目录位置

  • cssLoaders——为不同的css预处理器提供一个统一的生成方式

  • styleLoaders——为那些独立的style文件创建加载器配置

  • createNotifierCallback——以类似浏览器的通知的形式展示信息

config

config关键文件是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.cssSourceMapmodule.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 nodeconst 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。

新特性到此就介绍完毕了。


参考资料

  • https://cli.vuejs.org/zh/guide/

  • https://npmjs.com/package/vue-cli

  • http://zhaozhiming.github.io/blog/2018/01/08/create-react-app-override-webpack-config/

  • https://segmentfault.com/a/1190000012581869#articleHeader5

  • http://www.css88.com/archives/8405

关于奇舞周刊

《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。