背景
一直以来,前端所做的事情是重复枯燥的,确切的来说并没有什么太大的技术含量(仅从我这个初级前端角度来说)。特别是现在前端工程化所带来的各项工具的发展,前端开发越来越像积木搭建师。找到合适的模块,按照UI图进行拼装,然后在此基础上修修补补。具体表现之一就是UI组件库的使用,饿了么UI库很强大,经常被拿来「开箱即用」。这样的确是提高了开发效率,但是居安思危来看,前端工程师存在的意义也大大降低了。
知其然,更要知其所以然。这句话是老话了,但是大多数人都做不到,包括我在内。正好公司这次项目大改动,需要抽出一些公用的组件,趁此机会,我的思路是搭建一个公用的UI组件库,并将其发布在NPM上面。这样子,不同的项目就能分别引入npm包,做到组件的通用性。
按照这个思路,网上找了不少文章,发现有着和我同样想法的人真不少。基本都写出了一个demo,但是缺点也有。那就是大部分都是个人实践,并不是工作需要,所以一些细节方面并不严谨。这也是可以理解的,毕竟不是工作上的任务,所以会随意点。综合这些前辈的实践,我开始尝试写出一个UI组件库。
了解NPM
在此之前,我对于npm的理解就是一个node包管理工具,每次运行新项目都要首先npm install
安装好相关依赖,然后npm run dev
运行。至于还有yarn
也只知道皮毛,类似于npm的包管理工具,据说使用起来比npm好用。除此之外,对于npm的了解就没有了。
现在了解到了更多,第一次登陆了npm的官网。
这个官网的搜索框可以搜索npm现存的所有package,如果你发布了自己的npm包,也可以直接搜索出来。当你想要发布自己的npm包时,你首先需要注册一个账号,可以拿常用的邮箱进行注册,这里要注意的是注册账号的 验证邮件可能被邮箱当做垃圾邮件。
i
搭建UI组件库
- 初始化项目
因为公司前端项目是基于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
然后看自己喜好选择一些配置,几下回车之后一个清爽的初始项目就有了。
- 修改目录结构
为了开发时对组件进行预览,将src
改为example
用来写开发样例,测试组件效果,然后在根目录下新建一个 packages 文件夹,这是用来放组件的。修改后的目录结构:
这样的目录结构是模仿饿了么UI的目录结构的,可以先阅读一下饿了么UI的源码,学习一些经验。
- 添加配置文件
小改了一下目录之后,你会惊奇的发现项目运行不了了。没关系,这很正常,毕竟 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。
- 安装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
}
}
}
特别声明:由于cssnext
和cssnano
都具有autoprefixer
,事实上只需要一个,所以把默认的autoprefixer
删除掉,然后把cssnano
中的autoprefixer
设置为false
。
由于配置文件修改了,所以重新跑一下npm run dev。项目就可以正常看到了。
编写组件
1、开发组件
在新建的packages
文件夹中新建index.js
,这个会在后面的全局引入中用到,接着新建一个Test
文件夹用来存放test
组件,其中Test里的index.js是为后面按需加载准备的(暂时忽略)。文件目录如下:
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
,这个文件夹里就是本地调试组件的代码。
这里的代码就是我们一般的Vue文件里面的
src
源码文件夹,只需要将我们开发的组件当成是本地组件,引入使用即可。
首先在main.js文件中引入组件,并注册组件:
然后就正常使用组件。
3、打包组件
组件发布到npm上之前,需要进行打包。在 vue-cli3 中我们通过以下命令可以将一个单独的入口打包成一个库:
// target: 默认为构建应用,改为 lib 即可启用构建库模式
// name: 输出文件名
// dest: 输出目录,默认为 dist,这里我们改为 lib
// entry: 入口文件路径
vue-cli-service build --target lib --name lib [entry]
要注意的是在库模式中,打包出来的库中是不包含 Vue 的。 然后我们修改一下 package.json 文件,就像下面这样:
接着执行
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、更新组件
参考文章
- Element-UI 技术揭秘(2)- 组件库的整体设计
- 基于 vue-cli3 打造属于自己的 UI 库
- 如何在Vue项目中使用vw实现移动端适配
- 记基于Vue.js的UI插件开发并发布到NPM