开发模式
预览 demo
在开发一个 ui 组件库时, 肯定需要一边预览 demo, 一边修改代码.
常见的解决方案是像开发一般项目一样使用 webpack-dev-server 预览组件, 比如通过 vue-cli 初始化项目, 或者自己配置脚本.
文艺一点儿地可能会用到 parcel 来简化 demo 的开发配置 (比如 https://github.com/museui/muse-ui ).
展示文档
作为一个 ui 组件库, 也肯定要有自己的组件展示文档.
一般业界常见方案是自己开发展示文档...
但这样会带来一个组件库和文档如何同步的问题.
为何不用 vuepress?
由于 vuepress 支持在 Markdown 中插入组件 https://vuepress.vuejs.org/zh/guide/using-vue.html , 所以我们其实可以很自然地边写文档边开发组件.
从开发步骤上来说, 甚至可以先写文档说明, 再具体地编写代码实现组件功能. 这样一来文档即是预览 demo, 与组件开发可以同步更新.
p.s. React 的组件文档可以试试这俩库:
- https://github.com/pedronauck/docz
- https://github.com/janryWang/doc-scripts
类型声明
在开发和使用过程中如果对于一些对象, 方法的参数能够智能提示, 岂不美哉?
如何实现呢?
其实就是在相应文件夹中添加组件相关的类型声明 (*.d.ts), 并通过 src/index.d.ts 导出.
- {
- "typings": "src/index.d.ts",
- }
一开始将声明文件都放在 types/ 文件夹下, 但在实践中觉得还是放在当前文件夹下比较好. 一方面有利于维护, 另一方面是读取源码时也有类型提示.
如何打包
打包工具
和打包库一样, 选了 rollup.
单文件组件
在开发中用不用 *.vue 这样的单文件组件来开发呢?
https://github.com/museui/muse-ui 完全不写 <template> 只使用 render 函数.
https://github.com/iview/iview , https://github.com/ElemeFE/element , https://github.com/youzan/vant 使用 .vue 文件, 但样式单独写.
https://github.com/vueComponent/ant-design-vue 使用 .jsx 文件, 样式也单独写.
https://github.com/airyland/vux 使用带 <style> 的 .vue 文件, 但在使用时必须用 https://github.com/airyland/vux-loader .
https://github.com/didi/cube-ui 使用带 <style> 的 .vue 文件, 但有一些配置.
讲道理, 完全不写 <template> 有点儿麻烦, 所以添加了 https://github.com/vuejs/rollup-plugin-vue 插件用于打包 .vue 文件.
但碰到一个问题: 如何打包 <style> 中的样式?
首先尝试不写 <style>, 直接在 JS 里 import SCSS 文件. 没问题, 但是写组件时不直观, 同一组件的代码也分散在了两个地方
接着尝试配置 https://github.com/vuejs/rollup-plugin-vue , 碰到一个 source-map 报错的问题. 我提了个 .
加载方式
区分场景
为了区分不同的场景使用不同的 JS, 所以一共打包了三份 JS(commonJs,es module,umd), 以及一份压缩后的 CSS(dist/tua-ui.CSS).
- {
- "main": "dist/TuaUI.cjs.js",
- "module": "dist/TuaUI.es.js",
- "browser": "dist/TuaUI.umd.js",
- }
完整加载
大部分 ui 库都支持完整加载, 和把大象装冰箱一样简单 (但 https://github.com/airyland/vux 只支持按需加载):
引入 JS
引入 CSS
安装插件
- import TuaUI from '@tencent/tua-ui'
- import '@tencent/tua-ui/dist/tua-ui.css'
- Vue.use(TuaUI)
因缺思厅的是 cube-ui 把基础样式也写成 Vue 插件, 导致按需引入的时候还要单独引入 Style,emmmmmmmmm...
- import {
- /* eslint-disable no-unused-vars */
- Style, // <-- 不写这行按需引入时就没基础样式
- Button
- } from 'cube-ui'
按需加载
ui 库若是只能完整加载, 显然会打包多余代码.
所以各种库一般都支持按需加载组件, 大概分以下几种.
https://github.com/museui/muse-ui , https://github.com/iview/iview , https://github.com/vueComponent/ant-design-vue , https://github.com/youzan/vant 通过 https://github.com/ant-design/babel-plugin-import 插件实现.
https://github.com/ElemeFE/element 通过 (fork 自 https://github.com/ant-design/babel-plugin-import ) 插件实现.
https://github.com/airyland/vux 通过自己的 https://github.com/airyland/vux-loader 实现.
https://github.com/didi/cube-ui 通过配置 webpack 实现.
tree-shaking
webpack 其实在打包的时候是支持 https://webpack.docschina.org/guides/tree-shaking/ 的, 那么我们能不能直接引用源码实现按需加载呢?
注意源码必须满足 es 模块规范 (import,export).
- import {
- TuaToast
- } from '@tencent/tua-ui/src/'
- Vue.use(TuaToast)
尝试打包, 发现 tree-shaking 并没有起作用, 还是打包了所有代码.
sideEffects
其实问题出在没有在 ui 库的 package.JSON 中声明 sideEffects 属性.
在一个纯粹的 ESM 模块世界中, 识别出哪些文件有副作用很简单. 然而, 我们的项目无法达到这种纯度, 所以, 此时有必要向 webpack 的 compiler 提供提示哪些代码是 "纯粹部分". -- 《webpack 文档》
注意: 样式部分是有副作用的! 即不应该被 tree-shaking!
若是直接声明 sideEffects 为 false, 那么打包时将不包括样式! 所以应该向下面这样配置:
- {
- "sideEffects": [ "*.sass", "*.scss", "*.css" ],
- }
vuepress 组件样式
用 vuepress 写文档的时候, 一般会在 docs/.vuepress/components/ 下写一些全局组件.
开发时没啥问题, 但是发现一个坑: 打包文档时发现组件里的样式 <style> 全丢了.
猜一猜原因是什么?
这口锅就出在上一节的 sideEffects, 详情看这个 https://github.com/vuejs/vuepress/issues/718 . 解决方案就是在 sideEffects 里加一条 "*.vue" 即可.
测试数据
下面咱们打包一下安装了 ui 库的项目, 看看按需加载的效果怎么样.
- Origin
- dist/JS/chunk-vendors.71ea9e72.JS ----- 114.04 kb
- TuaToast
- dist/JS/chunk-vendors.beb8cff5.JS ----- 115.03 kb
- dist/CSS/chunk-vendors.97c93b2d.CSS ----- 0.79 kb
- TuaIcon
- dist/JS/chunk-vendors.25d8bdbd.JS ----- 115.00 kb
- dist/CSS/chunk-vendors.eab6517c.CSS ----- 6.46 kb
- TuaUI
- dist/JS/chunk-vendors.6e0e6390.JS ----- 117.39 kb
- dist/CSS/chunk-vendors.7388ba27.CSS ----- 8.04 kb
总结一下就是:
原始项目的 JS 打包出来为 114.o4kb
只添加 TuaToast 后 JS 增加了 0.99kb,CSS 增加了 0.79kb
只添加 TuaIcon 后 JS 增加了 0.96kb,CSS 增加了 6.46kb
添加完整 TuaUI 后 JS 增加了 3.35kb,CSS 增加了 8.04kb
可以看出按需加载还是有效果的~
以上 to be continued...
参考资料
vuepress 在 Markdown 中 使用 Vue https://vuepress.vuejs.org/zh/guide/using-vue.html
- https://github.com/museui/muse-ui
- https://github.com/iview/iview
- https://github.com/ElemeFE/element
- https://github.com/vueComponent/ant-design-vue
- https://github.com/ant-design/babel-plugin-import
- https://github.com/airyland/vux
- https://github.com/youzan/vant
- https://github.com/airyland/vux-loader
- https://github.com/didi/cube-ui
cube-ui 的后编译和普通编译
- https://webpack.docschina.org/guides/tree-shaking/
- https://github.com/vuejs/rollup-plugin-vue
source-map 报错的问题
vuepress sideEffects issue https://github.com/vuejs/vuepress/issues/718
来源: https://juejin.im/post/5c334eb56fb9a049d9755f49