本文已参与「新人创作礼」活动,一起开启掘金创作之路
写在前面
对于目前框架为王的时代,前端可能很大一部分时间,都是在开发相关的页面组件,而有句话说得好,没有哪个前端不想拥有一个属于自己的,为自己量身定制的组件库,那么本文就为大家整理一下:
如何从 0 到 1 搭建一个属于自己的组件库
开发环境
本文将基于 vue-cli4.5 脚手架搭建项目基础框架
// 全局安装vue脚手架
npm install -g @vue/cli
// 创建项目
vue create 项目名称
修改项目结构
由于使用脚手架创建的项目结构,主要是面向业务开发,因此我们需要根据我们自己的需求,进行一下适当的调整
抽离 components 目录,用于放置我们之后开发的组件库的源码
将 src 改为 example ,用于存放测试组件的代码
创建组件目录
在 components 中创建 css 文件夹用于存放组件相关的 css 样式
在 components 中创建 lib 文件夹用于存放组件相关的源码(vue、js等)
添加组件相关文件
在每个组件中新建一个 src 文件夹用于存放组件源码,src 中写入测试源码 main.vue
<template>
<div class="demo">Demo</div>
</template>
<script>
export default {
name: 'Demo'
}
</script>
在每个组件的根目录创建一个 index.js 文件,用于导出该组件,代码如下:
// 引入组件
import Demo from './src/main.vue'
// 为组件添加 install 方法,在vue中调用 Vue.use(组件)
// 将自动调用组件的 install 方法注册组件
Demo.install = function(Vue){
Vue.component(Demo.name, Demo)
}
export default Demo
最后在 lib 根目录创建 index.js 用于批量导出所有组件,代码如下:
// 引入组件
import Demo from './demo'
import Demo2 from './demo2'
const components = {
Demo,
Demo2
}
// 添加 install 方法,在vue中调用 Vue.use(组件)
// 将自动调用 install 方法注册所有组件
const install = function(Vue){
if(install.installed) return;
Object.keys(components).forEach(key =>{
Vue.component(components[key].name,components[key])
})
}
// 导出所有组件
const API = {
install
}
export default API;
添加组件样式
在 /components/css 中分别为每个组件创建 .scss 文件并写入样式
.demo {
background: cadetblue;
}
在 /components/css 中创建 index.scss 文件,用于导出所有样式
// 引入所有组件的样式
@import './demo.scss';
@import './demo2.scss';
打包组件库
打包 vue、js
安装 webpack-cli
npm install webpack-cli
在项目根目录创建用于打包组件库的配置文件并写入配置
Tips: 当打包失败时,可通过直接运行webpack.js 文件检测插件引入是否正常
// 引入 glob 用于匹配路径
const glob = require('glob')
// 引入 path 用于生成绝对路径
const path = require('path')
// 引入 VueLoaderPlugin 用于解析vue文件
const { VueLoaderPlugin } = require('vue-loader')
// 生成所有组件对应目录组成的数组
const list = {}
async function makeList(dirPath, list){
// path/*/name 表示匹配在path子文件夹中所有name文件
// path/**/name 表示匹配在path/中以及
// 子目录的所有name文件(递归匹配所有目录)
const files = glob.sync(`${dirPath}/**/index.js`)
for(let file of files){
const component = file.split(/[/.]/)[2]
list[component] = `./${file}`
}
}
makeList('components/lib',list)
module.exports = {
// webpack 打包类型
mode: 'development',
// 入口文件为所有组件目录组成的数组
entry: list,
// libraryTarget 为 umd 则表示打包的组件库为通用组件库
output: {
filename: '[name].umd.js',
path: path.resolve(__dirname, 'dist'),
library: 'yimwu',
libraryTarget: 'umd'
},
plugins: [
new VueLoaderPlugin()
],
module: {
rules: [
{
// 匹配所有vue文件并使用vue-loader进行解析
test: /\.vue$/,
loader: 'vue-loader'
}
]
}
}
打包踩坑
这里出现的问题是 vue-loader 版本太高,无法和 Vue2 匹配,更换低版本的vue-loader 即可解决
npm uninstall vue-loader
npm install vue-loader@15
在package.json 中添加 script 打包脚本命令
"build:js": "webpack --config ./webpack.component.config.js"
最后一步,运行命令完成 js 打包
npm run build:js
打包样式
打包样式需要用到另外一个构建工具 gulp,首先安装gulp以及相关插件
npm install gulp gulp-sass gulp-minify-css
在根目录创建 gulp 配置文件 gulpfile.js 并写入配置
const gulp = require('gulp');
// sass -> css
const sass = require('gulp-sass')(require('node-sass'))
// 压缩 css
const minifyCSS = require('gulp-minify-css')
gulp.task('sass', async function(){
return gulp.src('components/css/**/*.scss')
.pipe(sass())
.pipe(minifyCSS())
.pipe(gulp.dest('dist/css'))
})
在package.json 中添加 script 打包脚本命令
"build:css": "npx gulp sass"
最后一步,运行打包命令,完成 css 打包
npm run build:css
优化打包命令
由于 js 和 css 是分开打包的,所以可以通过 package.json 中sciprt的配置,将 js 与 css 打包整合
"build": "npm run build:js && npm run build:css"
至此,所有组件打包相关的工作就结束了,组件库已经可以正常使用了
NPM 包发布
完成了打包工作后,最后一步就是将组件发布到 npm 上
编写 README.md 文件
在 README.md 中写入组件的安装、引用以及使用的相关说明
配置 package.json 文件
- 在 package 中添加以下 npm 相关的配置
- main 表示组件库的入口
- files 表示需要发布到 npm 上的目录
- 由于 npm 包为公开组件库,因此需要删除原来存在的 private 属性
"name": "test",
"version": "0.1.1",
"description": "测试组件库",
"main": "dist/index.umd.js",
"keywords": [
"yimwu-ui",
"vue",
"ui"
],
"author": "yimwu",
"files": [
"dist",
"components"
],
注册 npm 账号并通过命令行登录账号
npm login
最后最后,见证奇迹的时候到了~~
运行 npm pubilsh 完成 npm 包发布
总结
搭建组件库本身并没有什么技术难点,最主要是打包流程以及对于组件库目录结构的把握,对于相对复杂的组件库来说,一个清晰、层级分明的目录非常重要,这不仅能够使之后组件开发过程更加标准、可控,也能够使组件对组件使用者更加灵活、友好!
往期好文推荐
面试官:说说从输入 URL 到页面显示到底经历了什么,体现一下你的知识广度
面试官:HTTPS 采用的是对称加密还是非对称加密?具体说说其加密过程
面试官:你就只会 npm run build 吗?(Webpack 配置 Vue+Ts)
面试官:连VuePress都没搭过还说开发过组件库?(VuePress 搭建)
面试官: 连 Vue 视图更新都不会写?(Vue视图更新原理【一】)
面试官: 能不能手写 Vue 响应式?(Vue2 响应式原理【完整版】)
面试官:能不能手写 Vue3 响应式(Vue3 原理解析之响应系统的实现)
面试官:说一下这个Loading动画实现思路 (CSS3 实现 Loading 动画)
面试官:你确定你说的防抖不是节流吗?( 面试题梳理系列 (二))
面试官:除了 HTTP,你还用过什么通信协议?(Websocket 在数字孪生中的应用)
面试官:你真的理解 Event Loop 吗?( JS 事件循环 )
面试官:v-for 中 key 为什么不能用 index,从原理层面聊聊?
面试官:vue-router 的 hash 与 history 哪个模式会刷新页面?
面试官:说说你平时用过的自适应方案(数字孪生可视化自适应方案)
写在最后
博主接下来将持续更新好文,欢迎关注博主哟!!
如果文章对您有帮助麻烦亲点赞、收藏 + 关注和博主一起成长哟!!❤️❤️❤️