DevUI是一支兼具设计视角和工程视角的团队,服务于华为云平台和华为内部数个中后台系统,服务于设计师和前端工程师。 官方网站:devui.design Ng组件库:ng-devui DevUIHelper插件:DevUIHelper-LSP
前言
随着前端生态的繁荣,工具库几乎是高效开发的必需品,lodash/dayjs/numberal等实用的工具库相信大家都用过。
我近期在开发Calendar Graph Github提交日历组件时,发现有很多需要处理颜色的场景,比如判断一个字符串是否是一个有效的颜色值、hex颜色值和rgb颜色值的互转等,但没有找到一个能很好满足我全部需求的开源库,所以决定自己造一个轮子。
这就是做ktools工具库的原因,本文将介绍如何使用Rollup这个轻量的下一代模块打包器打造自己的TypeScript工具库。
通过阅读本文,你将学到:
- 如何初始化一个Rollup工程项目
- 如何配置Rollup和TypeScript
- 如何编写脚本,构建并发布自己的工具库到npm仓库
1 创建并初始化Github项目
做一个开源库的第一步是创建一个Github(或Gitlab等)代码仓库,并进行简单的初始化,主要包括:
- 创建Git提交忽略配置 .gitignore
- 创建开源协议声明 LICENSE
- 初始化package.json
- 配置TypeScript tsconfig.json
- 配置Rollup rollup.config.js
1.1 Git提交忽略配置
为了防止node_modules
等自动生成的目录/文件提交到远程代码仓库,提交忽略是首先要考虑的事情,前期可以简单配置下即可。
先创建一个.gitignore文件
代码语言:javascript复制1 touch .gitignore
在新创建的.gitignore文件中增加以下内容:
代码语言:javascript复制1 # dependencies
2 /node_modules
3
4 # compiled output
5 /dist
详细的配置可以参考Github官方文档: https://docs.github.com/en/free-pro-team@latest/github/using-git/ignoring-files
1.2 创建开源协议声明 LICENSE
开源协议可以在创建Github仓库时选择,也可以创建仓库之后再加,一般选择MIT协议。
这里介绍一个创建仓库之后补加协议的小技巧。主要分成以下几个步骤:
- 在Github仓库增加一个文件
- 输入
LICENSE
(注意必须全部大写) - 选择协议
- 提交
Step 1: 在Github仓库增加一个文件
在代码仓库的目录结构右上方,有一个Add file
下拉框,选择其中的Create new file
选项,进入创建新文件的页面。
Step 2: 输入"LICENSE"
在文件名中输入全大些的LICENSE
,这时输入框右边会多出来一个按钮Choose a license template
。
Step 3: 选择协议
点击Choose a license template
按钮,进入选择协议模板的页面。
我们在左侧目录选择MIT License
,然后在右侧边栏输入年份和作者名字,可以看到中间的Copyright (c)
后面的年份和作者会相应变化,点击Review and submit
按钮,即可返回创建文件的页面,并自动用刚刚选择的协议内容填充到LICENSE文件中。
Step 4: 提交
点击创建文件页面下方的Commit new file
即可提交LICENSE文件到代码仓库
提交之后会自动跳转到LICENSE页面,效果如下:
1.3 初始化package.json
添加.gitignore
/LICENSE
这两个基本的文件之后,下一步就是初始化package.json
文件,这是管理依赖包及其版本的包配置文件,前端项目必备。
我们可以使用以下命令创建一个默认的package.json:
代码语言:javascript复制1 npm init -y
增加-y
参数是不想一直按Enter
创建好的package.json文件如下:
代码语言:javascript复制 1 {
2 "name": "ktools",
3 "version": "1.0.0",
4 "description": "",
5 "main": "index.js",
6 "scripts": {
7 "test": "echo "Error: no test specified" && exit 1"
8 },
9 "repository": {
10 "type": "git",
11 "url": "git https://github.com/kagol/ktools.git"
12 },
13 "keywords": [],
14 "author": "",
15 "license": "MIT"
16 }
我们可以简单地修改和完善下。
name
和version
分别是包名和版本号,均可后续发布时通过脚本动态修改,不用管。
description
描述可以加下:
1 "description": "前端工具库"
main
/scripts
这些后续在构建部署脚本的章节会细讲。
keywords
/author
可以加下:
1 "keywords": [
2 "toolkit",
3 "rollup",
4 "typescript"
5 ],
6 "author": "Kagol",
配置好package.json,后续安装依赖包时会自动更新该文件,可以非常方便地进行依赖管理。
1.4 配置TypeScript tsconfig.json
TypeScript这种强类型的语言,是对JavaScript很好的补充和增强,目前来看前景很好,必须用起来。
安装tsc
我们可以使用tsc命令行工具快速创建TypeScript默认配置文件。
先确认下是否安装tsc,输入命令:
代码语言:javascript复制1 tsc -v
出现以下命令说明未安装:
代码语言:javascript复制1 -bash: /usr/local/bin/tsc: No such file or directory
可以通过以下命令全局安装:
代码语言:javascript复制1 npm i -g typescript
成功安装之后,再查看下tsc版本:
代码语言:javascript复制1 $ tsc -v
2 Version 4.1.2
生成tsconfig.json配置文件
可以使用以下快速生成默认的tsconfig.json
配置:
1 tsc --init
生成的tsconfig.json
文件如下(已删除注释代码):
1 {
2 "compilerOptions": {
3 /* Visit https://aka.ms/tsconfig.json to read more about this file */
4
5 /* Basic Options */
6 "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
7 "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
8
9 /* Strict Type-Checking Options */
10 "strict": true, /* Enable all strict type-checking options. */
11
12 /* Module Resolution Options */
13 "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
14
15 /* Advanced Options */
16 "skipLibCheck": true, /* Skip type checking of declaration files. */
17 "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
18 }
19 }
默认的配置其实已经够用,我们不做修改,后续可以根据需要删减配置。
1.5 配置Rollup rollup.config.js
初始化工程的最后一步就是配置Rollup,先创建一个Rollup配置文件,没有Rollup CLI工具不支持初始化配置文件,只能手动创建:
代码语言:javascript复制1 touch rollup.config.js
然后在rollup.config.js
中增加以下内容:
1 import resolve from 'rollup-plugin-node-resolve';
2 import commonjs from 'rollup-plugin-commonjs';
3 import typescript from 'rollup-plugin-typescript';
4 import pkg from './package.json';
5
6 export default {
7 input: 'src/index.ts', // 打包入口
8 output: { // 打包出口
9 file: pkg.browser, // 最终打包出来的文件路径和文件名,这里是在package.json的browser: 'dist/index.js'字段中配置的
10 format: 'umd', // umd是兼容amd/cjs/iife的通用打包格式,适合浏览器
11 },
12 plugins: [ // 打包插件
13 resolve(), // 查找和打包node_modules中的第三方模块
14 commonjs(), // 将 CommonJS 转换成 ES2015 模块供 Rollup 处理
15 typescript() // 解析TypeScript
16 ]
17 };
在package.json
中配置browser
字段:
1 "browser": "dist/index.ts",
安装Rollup和TypeScript相关依赖:
代码语言:javascript复制1 npm i -D rollup typescript tslib rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-typescript
代码语言:javascript复制
注意tslib
这个依赖库也是必需的,因为rollup-plugin-typescript
插件依赖了该库。
Rollup配置文件每个配置项的具体含义可以参考:https://www.rollupjs.com/guide/big-list-of-options
Rollup可用插件列表可以参考:https://github.com/rollup/plugins
2 编写工具库源码
有了以上的初始工程,就可以正式开始写工具方法源码。
2.1 走通流程
先写一个demo,跑通编写源码
、构建打包
、引入使用
的流程。
编写源码
咱们的入口文件配置在了src/index.ts中,所以需要先创建该文件:
代码语言:javascript复制1 mkdir src
2 touch src/index.ts
然后在该文件中编写一些代码测试下打包是否正常:
代码语言:javascript复制1 console.log('hello ktools!');
构建打包
在命令行中输入以下命令对项目进行打包:
代码语言:javascript复制1 rollup -c
执行完之后会在dist目录生成打包文件index.js,内容如下:
代码语言:javascript复制1 (function (factory) {
2 typeof define === 'function' && define.amd ? define(factory) :
3 factory();
4 }((function () { 'use strict';
5
6 console.log('hello ktools!');
7
8 })));
引入使用
这时我们可以随便在一个Vue/React/Angular项目下引入这个空壳工具库,看下是否正常:
比如在 Vue CLI 工程的src/main.js中增加以下代码
代码语言:javascript复制 1 import Vue from 'vue';
2 import App from './App.vue';
3 import router from './router';
4 import store from './store';
5
6 import ktools from '../index'; // 新增加的代码,将在浏览器控制台输出"hello ktools!"
7
8 Vue.config.productionTip = false;
9
10 new Vue({
11 router,
12 store,
13 render: h => h(App),
14 }).$mount('#app');
或者在 Angular CLI 工程中的src/main.ts文件中增加:
代码语言:javascript复制 1 import { enableProdMode } from '@angular/core';
2 import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3
4 import { AppModule } from './app/app.module';
5 import { environment } from './environments/environment';
6
7 import ktools from '../index';
8 console.log('ktools:', ktools); // 必须加这个才能输出"hello ktools!",因为没有导出任何东西,所以打印出来的ktools是一个空对象
9
10 if (environment.production) {
11 enableProdMode();
12 }
13
14 platformBrowserDynamic().bootstrapModule(AppModule)
15 .catch(err => console.error(err));
2.2 编写工具方法
流程走通之后,就可以正式编写工具方法。
我们编写一个判断一个字符串是否是一个有效的hex十六进制颜色值的工具方法:isColor。
先创建src/is-color.ts文件:
代码语言:javascript复制1 touch src/is-color.ts
增加以下内容:
代码语言:javascript复制/**
* 判断字符串是否是十六进制的颜色值
* @param value
*/
const isColor = function(value: string): boolean {
return /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(value);
}
export default isColor;
然后在index.ts入口文件中增加引入is-color.ts文件的代码:
代码语言:javascript复制1 import isColor from './is-color';
2
3 export {
4 isColor,
5 };
重新执行rollup -c
进行构建,生成的dist/index.js如下:
1 (function (global, factory) {
2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ktools = {}));
5 }(this, (function (exports) { 'use strict';
6
7 /**
8 * 判断字符串是否是十六进制的颜色值
9 * @param value
10 */
11 var isColor = function (value) {
12 return /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(value);
13 };
14
15 exports.isColor = isColor;
16
17 Object.defineProperty(exports, '__esModule', { value: true });
18
19 })));
再到项目中引入:
代码语言:javascript复制1 import { isColor } from '../index';
2 console.log('isColor #c6e48b:', isColor('#c6e48b')); // isColor #c6e48b: true
3 console.log('isColor #c6e48:', isColor('#c6e48')); // isColor #c6e48: false
一切正常!
3 增加构建发布脚本
到这里其实我们的工具库ktools
已经完成了90%,还差最后一步,就是发布到npm仓库,可以手工发布。
3.1 手工发布
将package.json文件拷贝到dist目录,修改version为本次发布的版本号,比如0.0.1,然后进入该目录:
代码语言:javascript复制1 cd dist
执行以下命令即可将我们的ktools工具库发布到npm仓库:
代码语言:javascript复制1 npm publish
带着欢呼雀跃的心情等待发布成功,结果报错,以下是报错信息:
代码语言:javascript复制 1 $ npm publish
2 npm notice
3 npm notice ktools@0.0.1
4 npm notice === Tarball Contents ===
5 npm notice 315B index.html
6 npm notice 634B index.js
7 npm notice 691B package.json
8 npm notice === Tarball Details ===
9 npm notice name: ktools
10 npm notice version: 0.0.1
11 npm notice package size: 1.1 kB
12 npm notice unpacked size: 1.6 kB
13 npm notice shasum: 35c3501906443ff46be51c2747c07e73136bf85c
14 npm notice integrity: sha512-SZTM0msux0 Pt[...]IWmV6Gx5Tz41w==
15 npm notice total files: 3
16 npm notice
17 npm ERR! code E403
18 npm ERR! 403 403 Forbidden - PUT http://registry.npmjs.org/ktools - Package name too similar to existing packages; try renaming your package to '@kagol/ktools' and publishing with 'npm publish --access=public' instead
19 npm ERR! 403 In most cases, you or one of your dependencies are requesting
20 npm ERR! 403 a package version that is forbidden by your security policy.
21
22 npm ERR! A complete log of this run can be found in:
23 npm ERR! /Users/kagol/.npm/_logs/2020-12-05T05_42_31_632Z-debug.log
看提示似乎是包名重复[捂脸][苦涩],提示里还很友好地建议先重命名包名为@kagol/ktools
,然后再发布。
那我们就按照提示尝试下改个名字吧,加个scope:
代码语言:javascript复制1 "name": "ktools"
2
3 ->
4
5 "name": "@kagol/ktools",
改完名字重新发布,成功啦!
代码语言:javascript复制 1 $ npm publish
2 npm notice
3 npm notice @kagol/ktools@0.0.1
4 npm notice === Tarball Contents ===
5 npm notice 22.0kB index.js
6 npm notice 1.2kB package.json
7 npm notice 1.8kB README.md
8 npm notice === Tarball Details ===
9 npm notice name: @kagol/ktools
10 npm notice version: 0.0.1
11 npm notice package size: 6.9 kB
12 npm notice unpacked size: 25.0 kB
13 npm notice shasum: d85994aecc86160862cef4f0033e5bfdaa136072
14 npm notice integrity: sha512-UEDEJEsMSXcMg[...]yY4KsXp4mXIBA==
15 npm notice total files: 3
16 npm notice
17 @kagol/ktools@0.0.1
这时可以在项目中正式安装并引入使用。
先安装:
代码语言:javascript复制1 npm i @kagol/ktools
使用方式和之前的一样,只是需要把引入方式改了:
代码语言:javascript复制1 import { isColor } from '@kagol/ktools';
2 console.log('isColor #c6e48b:', isColor('#c6e48b')); // isColor #c6e48b: true
3 console.log('isColor #c6e48:', isColor('#c6e48')); // isColor #c6e48: false
3.2 通过脚本发布
每次发布还要将文件拷贝来拷贝去,又要修改包名,又要改版本号,很麻烦,可以编写脚本将这个过程自动化。
主要分以下步骤:
- 拷贝文件
- 修改文件
- 发布
Step 1: 拷贝文件
在package.json的scripts中增加拷贝文件的脚本:
代码语言:javascript复制1 "copy": "cp package.json README.md dist",
Step 2: 修改文件
新建scripts/publish.js文件,增加以下内容:
代码语言:javascript复制 1 const path = require('path');
2 const shelljs = require('shelljs');
3 const program = require('commander');
4
5 const targetFile = path.resolve(__dirname, '../dist/package.json');
6 const packagejson = require(targetFile);
7 const currentVersion = packagejson.version;
8 const versionArr = currentVersion.split('.');
9 const [mainVersion, subVersion, phaseVersion] = versionArr;
10
11 // 默认版本号
12 const defaultVersion = `${mainVersion}.${subVersion}.${ phaseVersion 1}`;
13
14 let newVersion = defaultVersion;
15
16 // 从命令行参数中取版本号
17 program
18 .option('-v, --versions <type>', 'Add release version number', defaultVersion);
19
20 program.parse(process.argv);
21
22 if (program.versions) {
23 newVersion = program.versions;
24 }
25
26 function publish() {
27 shelljs.sed('-i', '"name": "ktools"', '"name": "@kagol/ktools"', targetFile); // 修改包名
28 shelljs.sed('-i', `"version": "${currentVersion}"`, `"version": "${newVersion}"`, targetFile); // 修改版本号
29 shelljs.cd('dist');
30 shelljs.exec('npm publish'); // 发布
31 }
32
33 publish();
这里最核心的两步:
- 修改包名
- 获取正确的版本号并修改
其中修改文件使用shelljs库,获取版本号参数使用了TJ大神的commander工具。
需要提前安装这两个依赖库:
代码语言:javascript复制1 npm i -D shelljs commander
另外需要在package.json中增加构建的脚本命令:
代码语言:javascript复制1 "build": "rollup -c && npm run copy",
Step 3: 发布
发布的步骤比较简单,已经放在publish.js脚本文件中。
每次发布只需要依次运行以下命令即可:
代码语言:javascript复制1 npm run build
2 npm run publish -- -v 0.0.2
后续可以考虑将其集成到流水线,实现完全的自动化部署,这里可以参考我之前写的一片文章:大厂是如何用DevCloud流水线实现自动化部署Web应用的?
4 小结
本文详细地介绍了使用Rollup TypeScript打造一个开源工具库的流程和步骤,并介绍如何配置Rollup和TypeScript,如何编写部署脚本自动化发布工具库到npm仓库。希望大家喜欢,并欢迎给个Star鼓励,以下是ktools工具库的源码地址:
https://github.com/kagol/ktools
https://github.com/DevCloudFE/ng-devui