浅尝 | 从 0 到 1 Vue 组件库封装

1,765 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

写在前面

对于目前框架为王的时代,前端可能很大一部分时间,都是在开发相关的页面组件,而有句话说得好,没有哪个前端不想拥有一个属于自己的,为自己量身定制的组件库,那么本文就为大家整理一下:

如何从 0 到 1 搭建一个属于自己的组件库

开发环境

本文将基于 vue-cli4.5 脚手架搭建项目基础框架

// 全局安装vue脚手架
npm install -g @vue/cli
// 创建项目
vue create 项目名称

修改项目结构

由于使用脚手架创建的项目结构,主要是面向业务开发,因此我们需要根据我们自己的需求,进行一下适当的调整

抽离 components 目录,用于放置我们之后开发的组件库的源码

将 src 改为 example ,用于存放测试组件的代码

3.png

创建组件目录

在 components 中创建 css 文件夹用于存放组件相关的 css 样式

在 components 中创建 lib 文件夹用于存放组件相关的源码(vue、js等)

4.png

添加组件相关文件

5.png

在每个组件中新建一个 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;

添加组件样式

7.png

在 /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'
      }
    ]
  }
}
打包踩坑

9.png

这里出现的问题是 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"

10.png

最后一步,运行命令完成 js 打包

npm run build:js

11.png

打包样式

打包样式需要用到另外一个构建工具 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

12.png

优化打包命令

由于 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

13.png

最后最后,见证奇迹的时候到了~~

运行 npm pubilsh 完成 npm 包发布

14.png

总结

搭建组件库本身并没有什么技术难点,最主要是打包流程以及对于组件库目录结构的把握,对于相对复杂的组件库来说,一个清晰、层级分明的目录非常重要,这不仅能够使之后组件开发过程更加标准、可控,也能够使组件对组件使用者更加灵活、友好!

往期好文推荐

面试官:说说从输入 URL 到页面显示到底经历了什么,体现一下你的知识广度

面试官:作为前端,服务器相关了解多少?

面试官:HTTPS 采用的是对称加密还是非对称加密?具体说说其加密过程

面试官:说说 Cookie 和 Token 的区别?

面试官:网络安全了解多少,简单说说?(一)

面试官:网络安全了解多少,简单说说?(二)

面试官:网络安全了解多少,简单说说?(三)

面试官:网络安全了解多少,简单说说?(四)

面试官:网络安全了解多少,简单说说?(五)

面试官:网络安全了解多少,简单说说?(六)

面试官:网络安全了解多少,简单说说?(七)

面试官:网络安全了解多少,简单说说?(八)

浅尝 | 从 0 到 1 Vue 组件库封装

面试官:这么简单的正则表达式都不会?

Webpack 打包类库踩坑

面试官:你就只会 npm run build 吗?(Webpack 配置 Vue+Ts)

面试官:连VuePress都没搭过还说开发过组件库?(VuePress 搭建)

面试官: 连 Vue 视图更新都不会写?(Vue视图更新原理【一】)

面试官: 能不能手写 Vue 响应式?(Vue2 响应式原理【完整版】)

面试官:能不能手写 Vue3 响应式(Vue3 原理解析之响应系统的实现)

JS 优雅之道(JS 代码优化小 Tip)

面试官:你真的会用 SVG 吗? (SVG 应用实战)

面试官:说一下这个Loading动画实现思路 (CSS3 实现 Loading 动画)

JS 扫盲题 ( 面试题梳理系列 (一))

面试官:你确定你说的防抖不是节流吗?( 面试题梳理系列 (二))

面试官:除了 HTTP,你还用过什么通信协议?(Websocket 在数字孪生中的应用)

面试官:你真的理解 Event Loop 吗?( JS 事件循环 )

面试官:v-for 中 key 为什么不能用 index,从原理层面聊聊?

面试官:vue-router 的 hash 与 history 哪个模式会刷新页面?

面试官:说说你平时用过的自适应方案(数字孪生可视化自适应方案)

面试官:说一下如何优化过渡动画(数字孪生可视化过渡动画)

写在最后

博主接下来将持续更新好文,欢迎关注博主哟!!
如果文章对您有帮助麻烦亲点赞、收藏 + 关注和博主一起成长哟!!❤️❤️❤️