ホイールを作るのに3日くれたら
この記事を読むと、次のような新しい理解が得られます。
-
プラグインを個別にパッケージ化して公開する方法
-
チームまたは個人に適したコンポーネントライブラリのセットを開発する方法
なぜコンポーネントライブラリを構築する必要があるのですか?
ここでは、私の側からの例を簡単に示します。
同事甲
:Xiaoyi、このxxxコンポーネントをパッケージ化しましたか?
同事乙
:はい、以前にパッケージ化しました。yyyプロジェクトで見つけることができます。
BはプロジェクトAのリモートウェアハウスアドレスを指定し、Aはプロジェクト全体をプルし、XiaoBによってパッケージ化されたxxxコンポーネントを見つけて使用しました。しかしすぐに、私の同僚AがXiao Bに言った、私が望む効果はあなたのパッケージとは少し異なりますが、私はあなたのコードに非常に精通していません。再梱包を手伝ってもらえますか...
それで、シャオ・イーは沈黙に陥りました...
Xiaoyiとして、彼はなぜ会社がこれほど多くの同様のプロジェクトを持っているのかを考えているに違いありませんが、完全で独立したコンポーネントライブラリはありません。このようなコンポーネントライブラリのセットがある場合、チームが開発するときに、コンポーネントライブラリから必要なコンポーネントを見つけることはできません。これは、チーム開発の効率を高めるための定性的な離陸です。
プラグインとコンポーネント
私の意見では、プラグインの範囲には、プラグインのサブセットとして理解できるコンポーネントが含まれています。
一般的に、プラグインはグローバルに導入され、オンデマンドで導入されるかどうかに関係なく、コンポーネントの使用にはグローバルとローカルの両方が含まれます。
element-uiを例にとると、これはプラグインであり、私たちが言ったことでもあり组件库
ますが、その中の各小さなモジュールは、チェックボックス複数選択ボックスコンポーネント、テーブルテーブルコンポーネントなどのコンポーネントです。
それらは、特定の機能についてより多くの使用と開発の考慮事項を持っている必要があります。これは、次の3つの主要な側面にすぎません。
样式
:さまざまな使用シナリオでのこのコンポーネントのステータス、サイズ、色などを指します
功能
:現在のビジネスを満足させながら発生する可能性のある新しい要求を検討する
规范
:コードはクリーンで高品質である必要がありますが、パフォーマンスも必要です
独自のプラグインをパッケージ化して配布する方法
より簡潔で直感的な紹介のために、ボタンプラグインをカプセル化して公開します。(ボタンだけで、理解しやすくなります)
まず、単一のファイルbtn.vueを作成する必要があります。
<template>
<div class='yuiBtn' :style="computedStyle" @click="sayHi(hi)">
{{btnName}}
</div>
</template>
<script>
export default {
name:'yuiBtn',
data () {
return {
}
},
props:{
btnName:{
type: String,
default: 'YuiBtn'
},
btnWidth:{
type: Number,
default: 60
},
btnHeight:{
type: Number,
default: 20,
},
hi:{
type: String,
default: '余大帅'
}
},
computed:{
computedStyle(){
return {
height: this.btnHeight +'px',
lineHeight:this.btnHeight +'px',
width: this.btnWidth + 'px'
}
}
},
methods:{
sayHi(name) {
alert(`hi,${name}~`)
}
}
}
</script>
<style lang='scss' scoped>
.yuiBtn{
text-align: center;
border: 1px solid #000000;
}
</style>
复制代码
次に、インストールメソッドを追加する必要があります。なぜインストールされているのかを聞かないでください。プラグインvue-Routerとvuexのソースコードを見ると、にインストールメソッドがあることがわかります。彼ら。例として、vue-Routerを深く掘り下げます。
我们之所以能在vue项目中直接使用<router-view><router-link>
,就是因为vue-Router
中的install
方法里已经帮我们全局注册这两个组件,而我们运行Vue.use(VueRouter)
的时候便是执行的vue-Router
的install
方法。
继续讲我们的插件install,以下是vue官网给出的插件install方法的模板,满足了多种需求。
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
复制代码
但是上述install方法中的功能并不合适我们现在想要的具象的UI组件。
因此需要以下写法,通过Vue.component()
方法全局注册即可:
// index.js
import YuiBtn from './btn.vue'
const myPlugin = {
install(Vue) {
Vue.component('YuiBtn', YuiBtn)
}
}
export default myPlugin
复制代码
没错开发插件到这就完事了,但是为了发布插件,你还得初始化一个npm包,并将我们刚刚写的插件放入其中。基本步骤如下:
- 初始化包
npm init
复制代码
- 修改package.json中的入口文件信息:
"main": "index.js",
- 执行发包脚本
npm publish
复制代码
如果你没有npm官网账号,还得事先注册奥;未登录 npm 账号的情况下,会要求你进行登录。
展示下,这个简单的插件的目录结构:
发布成功后呢,那我就得恭喜你成为了一名插件开发者了。
关于使用的话,很简单咯:
先安装,我以目前的简易按钮插件为例(你现在就可以在项目中测试这个按钮的功能
):
npm install yui-btn
复制代码
再引入:
// main.js
import yuibtn from 'yui-btn'
Vue.use(yuibtn)
复制代码
最后使用
// xx.vue
<YuiBtn />
复制代码
如果还是有疑问的,可以看下源码,github地址,点击这里 查看源码
补充一下发布插件的一些看法,有一些文章中介绍通过vue-cli
初始化一个项目,然后开发插件,再发布。但是这会有个问题,你发布的插件的package.josn中的依赖信息将会是当前这个项目的依赖信息,显然这是不妥的。因此我的操作就是新建一个npm包,再移植插件代码,最后发布。
但是从另一个角度看的话,也是可以接受的--那就是开发组件库。如果当前项目就是针对于要开发的组件库而言的,那么依赖信息便不会显得过于累赘,同时仅限于vue的项目。 并且组件库涉及到分块打包等的问题,需要搭配webpack,而正好vue-cli内置了webapck。
如何封装并发布组件库
其实看完插件的开发与发布,你就应该明白了组件库的开发会是一个什么样的流程了。我前面也说过,组件库就是插件。
但是组件库是由众多组件集合而成的仓库
,我们需要考虑到版本更新以及组件库在实际项目开发中的按需引入等问题:
所以大致可以从以下这几个方面考虑并开发组件库:
-
UI设计
-
主题色控制
-
代码规范
-
版本管理
-
按需加载
-
优化打包
-
单元测试
-
文档说明
最合适想尝试搭建组件库的新手的方法如下:我们可以从最简单的方式开始搭建个人组件库,那就是不管37 21只看考虑组件全部引入的情况。以vue/cli 5.0.4
为脚手架搭建项目,就按之前开发基础插件那样的话,我们很快就可以发布一个最简易版本的组件库demo:
新创建一个文件夹packages用来存放我们后期需要增加的组件,并为每个组件创建单独的文件夹。目录结构如下:
和之前写的单个插件类似,唯一不同的就是需要遍历执行vue.component()
.
我们的index.js
如下:
import Button from './yui-button/btn.vue';
import Input from './yui-input/inp.vue';
const components = [
Button,
Input
];
const install = function(Vue) {
components.forEach(component => {
Vue.component(component.name, component);
});
}
export default {
install
};
复制代码
然后在package.json中设置 "main":"./packages/index.js",
就可以发布->安装->使用了。
当然前面只是最简单的版本,接下来开始完善之前提出的要求。
首先是代码规范的问题,我们一开始通过vue-cli创建的时候就可以选择eslint校验风格,所以无需多虑。
按需加载
是非常关键的一步,其实就是对引入资源的优化,避免打包时将组件库中没用到的组件也打包了。大多个人组件库都是参照element-UI
给出的方案: 给之前写好的组件各自增设install方法,打包的时候以多入口的形式,将组件各自打包。发布之后,需要在项目中按需引入组件库中的组件,并安装配置
babel-plugin-import插件。
。 这一步,我参考了掘金-悲伤日记
写的一篇文章 深入 vue 组件库的按需引入。相关代码会在下面总结中展示。
组件库搭建上其他方面的完善个人感觉比较容易上手,查阅相关的资料和工具库文档不难实现。但由于时间有限,我准备面试的时间不够了!!!非常遗憾,暂时没法继续探索下去了,下次的更新脚手架的时候,应该就是更完整版本的了。
总结
下面四个问题是我在简易版的组件库模板开发过程中觉得有些疑问的地方,搞懂这几个问题能帮助我们更好得搭建组件库:
1.组件库的目录结构?
我给出的是最新版的vue-cli搭建出来并调整的目录结构,具体还得看你用的是哪个版本。
组件库根目录格式如下:
packages文件夹目录:
2.如何配置打包(生产)环境和组件库开发环境?
根据process.env.NODE_ENV
当前所处的环境,我们可以增设两个配置文件,由环境决定使用哪个配置文件:
config.dev.js
我们需要修改根目录中的src文件夹名,以防止后续开发组件库中出现同名的src,而导致发布代码时文件被忽略。照理说打包之后应该也没啥影响。。。这个说法有待考证.
module.exports = {
pages: {
index: {
entry: 'examples/main.js',
template: 'public/index.html',
filename: 'index.html'
}
},
}
复制代码
config.build.js
这块的难点就是在于打包组件时需要根据不同的组件设置各自的打包入口。getComponentEntries()
方法就是对入口的封装。
const fs = require('fs');
const path = require('path');
const join = path.join;
// 获取基于当前路径的目标文件
const resolve = dir => path.join(__dirname, '../', dir);
function getComponentEntries(path) {
let files = fs.readdirSync(resolve(path));
const componentEntries = files.reduce((fileObj, item) => {
// 文件路径
const itemPath = join(path, item);
// 在文件夹中
const isDir = fs.statSync(itemPath).isDirectory();
const [name, suffix] = item.split('.');
// 文件中的入口文件
if (isDir) {
fileObj[item] = resolve(join(itemPath, 'index.js'));
}
// 文件夹外的入口文件
else if (suffix === 'js') {
fileObj[name] = resolve(`${itemPath}`);
}
return fileObj;
}, {});
return componentEntries;
}
const buildConfig = {
// 输出文件目录
outputDir: resolve('lib'),
productionSourceMap: false,
// webpack配置
configureWebpack: {
// 入口文件
entry: getComponentEntries('packages'),
// 输出配置
output: {
filename: '[name]/index.js',// 文件名称
libraryTarget: 'umd',// 构建依赖类型
libraryExport: 'default',// 库中被导出的项
library: 'ywc-ui'// 引用时的依赖名
}
},
css: {
sourceMap: false,
extract: {
filename: '[name]/index.css'
}
},
chainWebpack: config => {
config.optimization.delete('splitChunks');
config.plugins.delete('copy');
config.plugins.delete('preload');
config.plugins.delete('prefetch');
config.plugins.delete('html');
config.plugins.delete('hmr');
config.entryPoints.delete('app');
}
};
module.exports = buildConfig;
复制代码
3. 发布时,非打包的代码如何忽略提交?
我们当然希望自己的包越小越好,钱包除外~!
增设.npmignore
文件,其实跟.gitignore
的功能一样,可以理解成是对它的补充。
# 忽略目录
examples/
packages/
public/
dist/
common/
build/
config/
# 忽略指定文件
vue.config.js
jsconfig.json
复制代码
4.组件发布之后,如何在项目中引入并使用。
- 不考虑按需引入
那就跟引入element-UI一样:
先安装(下面按需亦是如此)
npm install ywc-ui
复制代码
// main.js
import yui from 'ywc-ui'
Vue.use(yui)
复制代码
// 目标文件中直接引入组件
<YuiButton />
复制代码
- 按需引入组件
首先安装我们的组件库,然后安装babel-plugin-component
npm install babel-plugin-component -D
复制代码
项目中增设 babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
plugins: [
[
'import',
{
libraryName: 'ywc-ui',
style: (name) => {
return `${name}/index.css`;
},
camel2DashComponentName: false, // 是否需要驼峰转短线
camel2UnderlineComponentName: false // 是否需要驼峰转下划线
}
]
]
}
复制代码
// main.js
import { YuiButton } from "ywc-ui";
Vue.use(YuiButton)
复制代码
文章虽然比较简短,但是一个组件库demo基本功能都已实现,大佬的话就别杠我了(手动狗头)!
->github点击这里 组件库模板地址
如果对这方面感兴趣的小伙伴,可以联系我,我计划过一段时间会开始系统性地开发自己的组件库,希望有小伙伴可以加入我的开源计划
~缺人!!!