UI组件库的搭建与发布

背景


  一直以来,前端所做的事情是重复枯燥的,确切的来说并没有什么太大的技术含量(仅从我这个初级前端角度来说)。特别是现在前端工程化所带来的各项工具的发展,前端开发越来越像积木搭建师。找到合适的模块,按照UI图进行拼装,然后在此基础上修修补补。具体表现之一就是UI组件库的使用,饿了么UI库很强大,经常被拿来「开箱即用」。这样的确是提高了开发效率,但是居安思危来看,前端工程师存在的意义也大大降低了。
  知其然,更要知其所以然。这句话是老话了,但是大多数人都做不到,包括我在内。正好公司这次项目大改动,需要抽出一些公用的组件,趁此机会,我的思路是搭建一个公用的UI组件库,并将其发布在NPM上面。这样子,不同的项目就能分别引入npm包,做到组件的通用性。
  按照这个思路,网上找了不少文章,发现有着和我同样想法的人真不少。基本都写出了一个demo,但是缺点也有。那就是大部分都是个人实践,并不是工作需要,所以一些细节方面并不严谨。这也是可以理解的,毕竟不是工作上的任务,所以会随意点。综合这些前辈的实践,我开始尝试写出一个UI组件库。

了解NPM


  在此之前,我对于npm的理解就是一个node包管理工具,每次运行新项目都要首先npm install安装好相关依赖,然后npm run dev运行。至于还有yarn也只知道皮毛,类似于npm的包管理工具,据说使用起来比npm好用。除此之外,对于npm的了解就没有了。
  现在了解到了更多,第一次登陆了npm的官网。

UI组件库的搭建与发布_第1张图片
NPM官网

  这个官网的搜索框可以搜索npm现存的所有package,如果你发布了自己的npm包,也可以直接搜索出来。当你想要发布自己的npm包时,你首先需要注册一个账号,可以拿常用的邮箱进行注册,这里要注意的是注册账号的 验证邮件可能被邮箱当做垃圾邮件
i

搭建UI组件库


  1. 初始化项目
      因为公司前端项目是基于Vue的,所以构建的UI组件库也是准备基于Vue,所以要使用vue-cli来初始化项目。这里出了一个问题,那就是安装vue-cli。因为我电脑并没有安装vue-cli,所以直接npm install -g @vue/cli时,安装的是最新的4.0版本。4.0版本的vue-cli命令和项目结构和3.0版本很多不一样,所以之前找到的文章都没有参考性了。所以前期为了学习,就卸载了4.0版本的vue-cli,安装了3.5.0版本的vue-cli。

// 全局安装 vue-cli 工具
npm install -g @vue/[email protected]
npm install -g @vue/cli-init
// 初始化项目
vue create touchealth-ui
然后看自己喜好选择一些配置,几下回车之后一个清爽的初始项目就有了。

  1. 修改目录结构
      为了开发时对组件进行预览,将src改为example用来写开发样例,测试组件效果,然后在根目录下新建一个 packages 文件夹,这是用来放组件的。修改后的目录结构:
UI组件库的搭建与发布_第2张图片
目录结构

  这样的目录结构是模仿饿了么UI的目录结构的,可以先阅读一下饿了么UI的源码,学习一些经验。

  1. 添加配置文件
      小改了一下目录之后,你会惊奇的发现项目运行不了了。没关系,这很正常,毕竟 src 都不见了,路径啥的肯定得报错。所以现在我们来解决这个问题。 在根目录下新建一个 vue.config.js 文件(新项目是没有这个文件的),并写入以下内容:
const path = require('path')
module.exports = {
  // 修改 pages 入口
  pages: {
    index: {
      entry: 'examples/main.js', // 入口
      template: 'public/index.html', // 模板
      filename: 'index.html' // 输出文件
    }
  },
  // 扩展 webpack 配置
  chainWebpack: config => {
    // @ 默认指向 src 目录,这里要改成 examples
    // 另外也可以新增一个 ~ 指向 packages
    config.resolve.alias
      .set('@', path.resolve('examples'))
      .set('~', path.resolve('packages'))

    // 把 packages 和 examples 加入编译,因为新增的文件默认是不被 webpack 处理的
    config.module
      .rule('js')
      .include.add(/packages/).end()
      .include.add(/examples/).end()
      .use('babel')
      .loader('babel-loader')
      .tap(options => {
        // 修改它的选项...
        return options
      })
  }
}

  这个时候运行npm run serve命令就可以预览效果了,会看到经典的 Welcome to Your Vue.js App。

  1. 安装sass插件
      sass是css预处理插件,提高了写css的效率,所以我们首先安装一下sass插件。

npm install node-sass sass-loader --save-dev

那么如何在页面中使用呢?


5、安装postcss相关插件,将px转为vw,适配移动端
  本UI库是用于移动端的,所以当然需要考虑到移动端的样式适配,我使用的是px->转vw的方案。因为这样在写css时,可以直接写px,而不需要进行换算到rem。但是vw方案会有一个bug,当你使用图片时,可能会出现部分手机浏览器中图片消失的问题。解决方法也很简单,在全局加入下面的css代码

img {
    content: normal !important;
  }

下面我们继续进行相关插件的安装:

  • postcss-url
  • postcss-import
  • postcss-cssnext
  • postcss-aspect-ratio-mini
  • postcss-px-to-viewport-opt
  • postcss-viewport-units
  • postcss-write-svg
  • cssnano

npm i postcss-aspect-ratio-mini postcss-px-to-viewport-opt postcss-write-svg postcss-cssnext postcss-viewport-units cssnano postcss-url postcss-import --S
安装成功之后,在项目根目录下的package.json文件中,可以看到新安装的依赖包:

"dependencies": {
    "core-js": "^3.4.4",
    "cssnano": "^4.1.10",
    "postcss-aspect-ratio-mini": "^1.0.1",
    "postcss-cssnext": "^3.1.0",
    "postcss-import": "^12.0.1",
    "postcss-px-to-viewport-opt": "0.0.4",
    "postcss-url": "^8.0.0",
    "postcss-viewport-units": "^0.1.6",
    "postcss-write-svg": "^3.0.1",
    "vue": "^2.6.10"
  },

接下来在根目录新建postcss.config.js文件,对新安装的PostCSS插件进行配置:

module.exports = {
  "plugins": {
    "postcss-import": {},
    "postcss-url": {},
    "postcss-aspect-ratio-mini": {},
    // to edit target browsers: use "browserslist" field in package.json
    "postcss-write-svg": {
      uft8: false
    },
    "postcss-cssnext": {},
    "postcss-px-to-viewport-opt": {
      viewportWidth: 750,                      // 设计稿宽度
      // viewportHeight: 1230,                 // 设计稿高度,可以不指定
      unitPrecision: 3,                        // px to vw无法整除时,保留几位小数
      viewportUnit: 'vw',                      // 转换成vw单位
      selectorBlackList: ['.ignore', '.hairlines','.vux-number-selector-plus','.vux-number-selector-sub'], // 不转换的类名
      minPixelValue: 1,                        // 小于1px不转换
      mediaQuery: false,                       // 允许媒体查询中转换
      exclude: /(\/|\\)(node_modules)(\/|\\)/,
      keepComment: 'no'
    },
    "postcss-viewport-units": {},
    "cssnano": {
      preset: "advanced",
      autoprefixer: false,                     // 和cssnext同样具有autoprefixer,保留一个
      "postcss-zindex": false,
      reduceIdents: false ,                    // 解决了 animation-name 被重写的 bug  https://github.com/cssnano/cssnano/issues/247
    }
  }
}

特别声明:由于cssnextcssnano都具有autoprefixer,事实上只需要一个,所以把默认的autoprefixer删除掉,然后把cssnano中的autoprefixer设置为false
由于配置文件修改了,所以重新跑一下npm run dev。项目就可以正常看到了。

编写组件


1、开发组件
  在新建的packages文件夹中新建index.js,这个会在后面的全局引入中用到,接着新建一个Test文件夹用来存放test组件,其中Test里的index.js是为后面按需加载准备的(暂时忽略)。文件目录如下:

UI组件库的搭建与发布_第3张图片
文件结构

packages文件夹下面的index.js文件代码如下:

import ToShare from './share'
import ToCoupon from './coupon'
import ToQa from './qa'
import LeftSlide from './leftSlide'
import CountDown from "./countDown"
import UserComment from "./comment"

// 所有组件列表
const components = [
  ToShare,
  ToCoupon,
  ToQa,
  LeftSlide,
  CountDown,
  UserComment
]

// 定义 install 方法,接收 Vue 作为参数
const install = function(Vue) {
  // 判断是否安装,安装过就不继续往下执行
  if (install.installed) return;
  install.installed = true;
  // 遍历注册所有组件
  components.map(component => Vue.component(component.name, component));
  // 下面这个写法也可以
  // components.map(component => Vue.use(component))
};

// 检测到 Vue 才执行,毕竟我们是基于 Vue 的
if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue);
}

export default {
  install,
  // 所有组件,必须具有 install,才能使用 Vue.use()
  ...components
};

这个文件所起的作用就是引入编写的各个小组件,统一注册对外暴露使用。

2、预览组件
  我们在开发自定义的组件的时候,难免会遇到一些问题,所以一个完整的本地调试是很有必要的。否则发布到npm上再改来改去,造成了很多无效的版本的浪费。前面已经说了我们将最开始的src文件夹重命名为example,这个文件夹里就是本地调试组件的代码。

UI组件库的搭建与发布_第4张图片
examples文件夹

这里的代码就是我们一般的Vue文件里面的 src源码文件夹,只需要将我们开发的组件当成是本地组件,引入使用即可。
  首先在main.js文件中引入组件,并注册组件:
UI组件库的搭建与发布_第5张图片
引入本地组件库

然后就正常使用组件。

3、打包组件
  组件发布到npm上之前,需要进行打包。在 vue-cli3 中我们通过以下命令可以将一个单独的入口打包成一个库:

// target: 默认为构建应用,改为 lib 即可启用构建库模式
// name: 输出文件名
// dest: 输出目录,默认为 dist,这里我们改为 lib
// entry: 入口文件路径
vue-cli-service build --target lib --name lib [entry]

要注意的是在库模式中,打包出来的库中是不包含 Vue 的。 然后我们修改一下 package.json 文件,就像下面这样:

image.png

接着执行 npm run lib 就能生成库啦,看看左侧的目录是不是多了个 lib 文件夹,那个就是我们要发布的东西。
补充下,lib 目录下面的 js 之所以有好几种,是因为有两种规范(common 和 umd)、是否压缩(min)和映射(map)的区别,暂且知道有这么回事就行,不用深究。

4、发布组件
万事俱备,只欠发布。

  • 万事俱备,只欠发布。
  • 修改一下 package.json 文件:
{ 
  "name": "xr-ui",
  "version": "0.3.0",
  "description": "基于 vue-cli3 的 UI 组件库",
  "main": "lib/xr-ui.umd.min.js",  // 这是 lib 目录下的其中一个
  "keywords": "xr-ui",
  "private": false,
  "license": "MIT"
}

  • 在根目录下新建一个 .npmignore 文件,内容和 .gitignore 差不多:
# 这是复制 .gitignore 里面的
.DS_Store
node_modules
/dist

# local env files
.env.local
.env.*.local

# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

# 以下是新增的
# 要忽略目录和指定文件
examples/
packages/
public/
vue.config.js
babel.config.js
*.map
*.html

最后执行 npm login 登入 npm 账号,再执行 npm publish 发布即可,就这么简单的两步就可以,过一会在 npm 上就能搜到了。当然前提是你有个 npm 账号,没有的话去注册一个吧,很 easy 的,然后还要搜下你的 npm 包名是否有人用,有的话就换一个。

5、更新组件

参考文章


  1. Element-UI 技术揭秘(2)- 组件库的整体设计
  2. 基于 vue-cli3 打造属于自己的 UI 库
  3. 如何在Vue项目中使用vw实现移动端适配
  4. 记基于Vue.js的UI插件开发并发布到NPM

你可能感兴趣的:(UI组件库的搭建与发布)