vue-cli3插件初体验

vue-cli3发布自2018年8月,距离现在还不是特别久,最好搭建项目刚好用到,所以写下这篇文章,记录一下踩坑经历。

vue的作者说过,vue-cli的本质是模

版的拉取,太多的配置导致了模版的难以维护,所以重构后的版本提供了插件的功能,一个插件对应一个功能,这样避免了多个模版,也使得cli维护性得到提高,这也是本篇文章的核心介绍内容。

我对cli3的理解是,一方面扩展了cli2的核心能力 ,一方面封装了webpack逻辑和配置。在过去要去做一个cli,通常需要阅读cli2的代码,cli2的核心模块分别是 generator,prompts,template,git-repo,并用同样的方法去做一个cli,这样其实成本不小,cli3的插件就是提供了这样一种能力,你用他的规则,去做一个npm包,并发到仓库,就可以获得这种能力。

首先,先介绍一下vue-cli3,他的发布带了哪些新功能呢?我总结一下,大概有以下5点:

1.功能丰富。这点相信大家都很好理解,他实在太好用了,模版里包含了大多数业界比较新的功能,可以一键集成typescripts等类型定义工具, eslint/tslint等语法检验工具,风格规范,prettier,husky等格式化工具,还有postcss、pwa、vue-cli-server等等。

2.提高封装性和扩展性。这点指的是vue-cli-server,在过去webpack的逻辑和配置在项目里独立维护,各个项目之间就像孤岛,vue-cli-server就像一个纽带,连接起了各个项目,为项目升级webpack提供便利性,并且通过一份配置,提供个性化配置。

这里顺带扯一下vue.config.js, 这个东西就是用来个性化配置webpack的,他提供了很多的配置项,具体可以看官方文档:

https://cli.vuejs.org/zh/config/

我们挑几个常用的来讲:

configureWebpack,这个几乎是用的比较多的,简单的方法,可以通过配置的方式配置,如下所示:

module.exports = {configureWebpack: {plugins: [new MyAwesomeWebpackPlugin()]}
}复制代码


这份配置,最终会被合并到原来的配置里,不会覆盖。

复杂的方法,可以往这个字段传一个函数,如下所示:

module.exports = {configureWebpack: config => {if (process.env.NODE_ENV === 'production') {// 为生产环境修改配置...} else {// 为开发环境修改配置...}}
}复制代码

这样就可以在一个函数里做一些简单的逻辑,config是webpack config,你可以直接修改config对象,也可以返回一个对象,这个对象最终也会被合并会webpack对象。

第三种方式,是通过webpack-chain来链式调用,代码如下所示:

module.exports = {chainWebpack: config => {config.module.rule('vue').use('vue-loader').loader('vue-loader').tap(options => {// 修改它的选项...return options})}
}复制代码

3.提供图形化管理界面,最所周知,gui易懂,cli高效,vue在降低学习门槛这方面,已经是非常好了。

通过vue ui指令,可以查看编译各个模块的情况,模块依赖情况,插件的情况,非常便于管理。

4.便捷性。vue-cli-server不仅支持项目的编译,也支持单文件的编译,具体的方法可以看官网介绍。

5.提供了cli的核心能力,也就是问询,模版渲染,文件生成这几大核心功能。具体的示意图可以看如下:


以上是cli2的核心模块,需要引用hbs,inquirer.js,metalsmit等基本模块,cli3的插件机制基本帮我们封装好了,我们只需要根据插件的规范,就可以获取这种能力。

由于有的读者可能对cli2的流程比较陌生,所以我想简单描述一下cli2的工作流程,如下图所示:


首先,cli2提供init指令,执行这个指令,会去远程拿模版文件,并拉到本地用户目录的.vue-template的文件夹,然后通过meta里问题,去问你,然后生成最终模版到你执行命令的目录。

说完vue-cli2,我们来看看vue-cli3的插件是怎么样的?

首先根据插件的位置,我们分成了cli插件,和service插件。cli的插件有完整的开发目录,所能做的事情也比较多一点,service插件是一份js文件,导出一个函数。

cli插件的目录如下所示:


具体的用发可以在官网了解到:

https://cli.vuejs.org/zh/dev-guide/plugin-dev.html#cli-%E6%8F%92%E4%BB%B6

那么他们是怎么工作的呢?

cli的代码主要在@vue/cli 下面,他的大概的流程如下图所示:


@vue/cli/bin/vue.js:

program.command('add <plugin> [pluginOptions]').description('install a plugin and invoke its generator in an already created project').option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)').allowUnknownOption().action((plugin) => {require('../lib/add')(plugin, minimist(process.argv.slice(3)))})program.command('invoke <plugin> [pluginOptions]').description('invoke the generator of a plugin in an already created project').option('--registry <url>', 'Use specified npm registry when installing dependencies (only for npm)').allowUnknownOption().action((plugin) => {require('../lib/invoke')(plugin, minimist(process.argv.slice(3)))})复制代码

首先,执行vue指令,会执行@vue/cli/bin/vue.js,这里定义了vue add , vue invoke,vue build,vue serve,等指令,可以看出,add指令其实是包含invoke指令的,add指令主要是安装一个包,并且触发generator.js,invoke主要是触发generator.js。

然后再来看@vue/cli/lib/add.js,

  const packageManager = loadOptions().packageManager || (hasProjectYarn(context) ? 'yarn' : 'npm')await installPackage(context, packageManager, options.registry, packageName)复制代码

  const generatorPath = resolveModule(`${packageName}/generator`, context)if (generatorPath) {invoke(pluginName, options, context)} else {log(`Plugin ${packageName} does not have a generator to invoke`)}复制代码

add.js主要安装包,然后执行invoke模块,我们再看看invoke模块做了什么。

@vue/cli/lib/invoke.js

  const generator = new Generator(context, {pkg,plugins: [plugin],files: await readFiles(context),completeCbs: createCompleteCbs,invoking: true})复制代码

invoke里主要实例化generator类,然后把你的插件当成参数传给类,generator类算是vue-cli的核心类了。

@vue/cli/lib/generator.js

  plugins.forEach(({ id, apply, options }) => {const api = new GeneratorAPI(id, this, options, rootOptions)apply(api, options, rootOptions, invoking)})复制代码

这个类主要负责执行你的插件,然后把generatorapi作为参数传入插件的generator.js导出的函数。

具体的vue-cli插件的开发是怎么样的呢,我写了一个demo,用在模拟多项目的ci模版管理,通常每个项目都有一份.gitlab-ci.yml模版,所以我们一般可以抽出一个公共的ci模版来管理,这里我用cli插件来管理,真正的项目可能不具备可行性,这里我只是用来写一个例子。



目录结构大概如上所示,执行vue add foo后,就会出现propmts对话框,然后选择答案后,就会根据配置生成模版到你的根目录下。


_gitlab-ci.yml ,根据问题选择是否用私有npm仓库:

 script:<%_ if (options.config === 'npm') { _%>- nrm add companynpm http://xxx.y.cn:XXXXX/- nrm use companynpm<%_ } _%>复制代码

prompts.js,主要一些问题的设计:

module.exports = [{name: 'config',type: 'list',message: `是否需要切换内部源:`,choices: [{name: '需要',value: 'npm',short: ''},{name: '不需要',value: 'npm',short: ''}]}
]复制代码

generator.js 这个模块很简单,直接渲染模版

module.exports = (api, options, rootOptions) => {// 复制并用 ejs 渲染 `./template` 内所有的文件api.render('./template')
}复制代码

service插件主要放在项目本地,是一份js代码,然后导出一个函数,通过package.json配置指向这个js文件的路径,


service主要依赖的代码在@vue/cli-service里,首先先执行@vue/cli-service/bin/vue-cli-service.js文件,


const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd()).....service.run(command, args, rawArgv).catch(err => {error(err)process.exit(1)
})复制代码

该文件实例化Service类,这个类是service插件的核心类,然后再执行run方法。

再来看看@vue/cli-service/lib/Service.js的代码:

首先构造函数执行resolvePlugin,把官方提供的插件和项目里的插件都加载进来,

constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {}) {this.plugins = this.resolvePlugins(plugins, useBuiltIn)
}复制代码

resolvePlugin这个函数主要在这里引入本地的插件:

resolvePlugins (inlinePlugins, useBuiltIn) {// Local pluginsif (this.pkg.vuePlugins && this.pkg.vuePlugins.service) {const files = this.pkg.vuePlugins.serviceif (!Array.isArray(files)) {throw new Error(`Invalid type for option 'vuePlugins.service', expected 'array' but got ${typeof files}.`)}plugins = plugins.concat(files.map(file => ({id: `local:${file}`,apply: loadModule(file, this.pkgContext)})))}return plugins
}复制代码

run方法又会执行init方法,在该方法内部执行插件:

init (mode = process.env.VUE_CLI_MODE) {// apply plugins.this.plugins.forEach(({ id, apply }) => {apply(new PluginAPI(id, this), this.projectOptions)}
}复制代码


那么service插件要如何来实践,我们来看如下的例子:

首先在package.json配置一下,指向本地的插件my-service.js

  "vuePlugins": {"service": ["my-service.js"]}复制代码

my-service.js的代码如下所示:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpack = require('webpack');module.exports = (api, projectOptions) => {api.registerCommand('analyze',{description: 'start analyze server',},(args) => {// 注册 `vue-cli-service analyze`let options = projectOptions.pluginOptions.demoOptionsconsole.log(options);// resolve webpack configconst webpackConfig = api.resolveWebpackConfig();webpackConfig.plugins.push(new BundleAnalyzerPlugin());webpack(webpackConfig,(err,stats)=>{if(!err) console.log('打包成功')})},);
};复制代码

该插件主要扩展vue-cli-service的指令,加了analyze指令,这个指令主要会向webpack的配置增加一个BundleAnalyzerPlugin的插件,用来分析包的大小,当然,这里也是没有太大的现实可行性的,vue-cli 提供了vue ui的Gui界面让你看到打包后各个模块的大小,或者cli的命令,vue-cli-service build --report,也能生一个报告,效果也是一样。


至此,vue-cli和service插件的使用和实现都介绍完了,如果有哪里写的不到位,希望各位大神能提出指正。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ios设计登录功能_亲爱的产品设计师,这是iOS 14的新功能

ios设计登录功能On June 22, 2020 Apple previewed iOS 14 for the first time. As always there are quite some changes you should know about as a product designer like widgets, pickers, app clips, permissions and more.2020年6月22日&#xff0c;Apple首次预览iOS 1…

c++ int 转 short_C/C++结构体内存对齐

在面试或工作中&#xff0c;经常会遇到内存对齐的问题。这里结合我的理解谈一谈对内存对齐的理解。1. 为什么要内存对齐&#xff0c;不对齐会怎么样&#xff1f;内存中存放数据是为了给CPU使用&#xff0c;CPU访问内存数据时会受到地址总线宽度的限制&#xff0c;也就是一次能从…

对于日访问量达到1W IP的处理方法

转自&#xff1a;http://www.java123.net/56026-2.html 对于日访问量达到1W IP的处理方法 一、1万ip真是不高&#xff1a; 1.常用数据用缓存&#xff0c;减轻数据库压力。 2.详细页数据生成静态页面。 二、10000算是相当小的了,不需要什么特殊的处理机制,只要符合最一般的…

数据契约(DataContract)

WCF第一要素就是契约: 服务契约用于声明可用于远程访问的类型。在Interface或class开始处使用服务契约标签. [ServiceContract] Public interface Iservice { } 接口调用契约的好处: 1. 同一服务类型可以实现多个不相干的服务契约. 2. 有利于版本升级 3. 按照…

jakob slam_Jakob Nielsen针对用户界面设计的第二种可用性启发法

jakob slamIn the pursuit of providing great user experiences, it’s imperative that digital products are evaluated. A 为了提供出色的用户体验&#xff0c;必须对数字产品进行评估。 一个 heuristic evaluation is essential to delivering great user experiences. I…

微软Office 365正式上架Mac App Store

今天&#xff0c;Office 365正式在Mac App Store上架&#xff0c;Mac用户可以轻松下载Word&#xff0c;Outlook&#xff0c;Excel&#xff0c;PowerPoint&#xff0c;OneNote以及整套微软的热门应用程序。用户还可以从应用程序内订购Office 365。苹果全球开发者关系高级主管Sha…

一文搞懂浏览器原理

大家好&#xff0c;我是若川。最近这几年&#xff0c;云计算的普及和 HTML5 技术的快速发展&#xff0c;越来越多的应用转向了浏览器 / 服务器&#xff08;B/S&#xff09;架构&#xff0c;这种改变让浏览器的重要性与日俱增&#xff0c;视频、音频、游戏几大核心场景也都在逐渐…

python处理excel可视化_python如何将excel数据处理可视化

python将excel数据处理可视化的方法&#xff1a;首先安装xlrd与xlwt库&#xff0c;进行表格读取&#xff1b;然后使用pyecharts生成Echarts图表的类库&#xff1b;最后安装Echarts读取Excel数据及显示即可。python将excel数据处理可视化的方法&#xff1a;Excel表操作python操作…

dataframe中将一列数据切分成多列

为什么80%的码农都做不了架构师&#xff1f;>>> 原sheet中数据 目的 将【备注】列切分成【key】列和【value】列 Python sheet[key] sheet[备注].str.extract(r(_.*(?\u503c))) sheet[value] sheet[备注].str.extract(r((?<).*))结果 参考 pandas.Series.st…

matplotlib可视化_EDA:Geopandas,Matplotlib和Bokeh中的可视化

matplotlib可视化Nowadays, everyone is immersed with plenty of data from news sources, cellphones, laptops, workplaces, and so on. Data conveys with tons of information from different data variables like date, string, numeric, and geographical format. How t…

(转)结婚那天,妈问我:坐在角落里象两个要饭模样的人是谁?

人人看到的文章 很感人~~~~结婚那天&#xff0c;妈问我&#xff1a;坐在角落里象两个要饭模样的人是谁&#xff1f; 我看过去的时候&#xff0c;有个老头正盯着我&#xff0c;旁边还有个老太太&#xff0c;发现我看着他们时赶忙低下头。我不认识他们但也不象要饭的&#xff0c;…

nginx-1.13.x源码安装

Nginx 安装配置【依赖库】[ zlib ]&#xff08;下载&#xff09;http://download.chinaunix.net/download.php?id24013&ResourceID12241 [ pcre ]apt-get install libpcre-dev[ openssl ]&#xff08;下载&#xff09;http://download.chinaunix.net/download.php?id3937…

小技巧!CSS 整块文本溢出省略特性探究

大家好&#xff0c;我是若川。欢迎加我微信 ruochuan12&#xff0c;长期交流学习。今天的文章很有意思&#xff0c;讲一讲整块文本溢出省略打点的一些有意思的细节。点击下方卡片关注我&#xff0c;或者查看源码系列文章。文本超长打点我们都知道&#xff0c;到今天&#xff08…

linux配置ip地址 suse_SUSE Linux下设置IP的两种方法

第一种SUSE Linux IP设置方法ifconfig eth0 192.168.1.22 netmask 255.255.255.0 uproute add default gw 192.168.1.2释义&#xff1a;#IP配置&#xff0c;包括子网掩码,看情况修改eth0和192.168.1.22#网关修改 ,看情况修改192.168.1.2第二种SUSE Linux IP设置方法在suse操作系…

寒假作业3:抓老鼠啊

7-1 抓老鼠啊~亏了还是赚了&#xff1f; &#xff08;20 分&#xff09; 某地老鼠成灾&#xff0c;现悬赏抓老鼠&#xff0c;每抓到一只奖励10元&#xff0c;于是开始跟老鼠斗智斗勇&#xff1a;每天在墙角可选择以下三个操作&#xff1a;放置一个带有一块奶酪的捕鼠夹(T)&…

笔记本移交_创建完美的设计移交

笔记本移交重点 (Top highlight)Design specifications (specs) are guidelines that developers will use to implement a design. Think of an architect providing building blueprints to the construction team. Many designers think of specs as mindless zombie work. …

大手笔,送¥1599的Apple AirPods Pro和独家礼物等

大家好&#xff0c;我是若川。为感谢公众号读者们长久以来的支持&#xff0c;本次我联合几位前端界大佬给大家送超级福利了。除了联合福利之外&#xff0c;每位前端大佬还带了专属礼品送给大家&#xff0c;所有抽奖均可重复参与、可重复中奖&#xff0c;详情见下文每个公众号的…

jQuery1.4新特性

1. 传参给 jQuery(…) 之前&#xff0c;jQuery可以通过 attr 方法设置元素的属性&#xff0c;既可传属性的名和值&#xff0c;也可以是包含几组特定 属性名值对 的 对象。在 jQuery 1.4 中&#xff0c;你可以把一个参数对象作为第二个参数传给 jQuery 函数本身&#xff0c;同时…

python pack unpack_golang 仿python pack/unpack

package includesimport ("bytes""encoding/binary""fmt"_"os""strconv""strings")type Protocolstruct{Format []string}//封包func (p *Protocol) Pack(args ...interface{}) []byte{la :len(args)ls :len(p.Fo…

JavaScript递归应用与实践

递归简单来说就是函数内调用自生的一种方法&#xff0c;形如&#xff1a; function foo(){foo() } 复制代码下面我列举一些常用的递归应用。 1. 求和&#xff0c;例如求1234...100之和 分析如下&#xff1a; sum(100)sum(99)100 sum(99)sum(98)99 ... sum(1)sum(0)1 复制代码代…