该教程主要是仿照
pro-components
和ant-design
, 所以感谢dumi
,ant-design
和pro-components
,让前端组件更加丰富, 感谢开源社区。
以前本想用storybook搭建一个组件库,后来通过公司的一位前辈了解到,通过dumi搭建更加方便,因此学习一下。
通过本篇文章,可以大概了解到的内容有
- dumi创建组件库
- lerna管理多个包
- prettier和eslint配置代码风格
- git hooks和commitlin配置提交规范
dumi创建组件库
- 创建一个k-component的目录并用vscode打开
mkdir k-component
cd k-component
vscode .
复制代码
- 用dumi脚手架创建组件库项目
npx @umijs/create-dumi-lib --site
复制代码
- 下载依赖并运行
npm install
npm run start
复制代码
运行的结果如下图所示
为了让界面和pro-components一样好看一点,可以把pro-components的.dumi/theme目录复制到自己的项目中,
然后重新运行,出现以下错误信息
按照提示下载依赖
npm install --save @ant-design/pro-layout @ant-design/pro-skeleton antd moment react-helmet-async react-lazyload
复制代码
重新运行npm run start
, 出现下图所示
用lerna管理组件库
lerna按照官方的解释
Lerna是一个管理工具,用于管理包含多个软件包(package)的JavaScript项目
下面是一些使用步骤
- 下载lerna
npm install --global lerna
复制代码
- 在项目根目录中初始化lerna
lerna init
复制代码
使用lerna初始化之后,会在项目的根目录中多出一个lerna.json
文件和packages
目录
- 在packages目录中创建子包
# 创建一个button组件
lerna create @keith/button packages/button --yes
# 创建一个tag组件
lerna create @keith/tag packages/tag --yes
复制代码
- 创建包之后,需要通过
lerna link
把当前lerna存储中相互依赖的lerna包符号链接在一起;然后在tsconfig.json
文件中新加一个paths
, 然后把刚才的组件目录添加进去,否则在组件写demo的时候,不能自动识别到引用的组件
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"types": ["jest"],
"strict": true,
"skipLibCheck": true,
"declaration": true,
// 把组件目录添加到该处
"paths": {
"@keith/button":["./packages/button/src/index.tsx"],
"@keith/tag":["./packages/tag/src/index.tsx"]
}
}
}
复制代码
运行完lerna link
后如果不能生效,需要重启vscode
- 修改组件包中的
package.json
, 例如button组件下的package.json
{
"name": "@keith/button",
"version": "0.0.0",
"keywords": [],
"license": "MIT",
"main": "lib/index.js",
"module": "es/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"es",
"dist"
],
"peerDependencies": {
"antd": "4.x",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
}
}
复制代码
- 在
.fatherrc.ts
文件中,添加button
和tag
import { readdirSync } from 'fs';
import { join } from 'path';
// utils must build before core
// runtime must build before renderer-react
// components dependencies order: form -> table -> list
const headPkgs: string[] = ['button', 'tag']; // 添加button和tag
const tailPkgs = readdirSync(join(__dirname, 'packages')).filter(
(pkg) => pkg.charAt(0) !== '.' && !headPkgs.includes(pkg),
);
const type = process.env.BUILD_TYPE;
let config = {};
if (type === 'lib') {
config = {
cjs: { type: 'babel', lazy: true },
esm: false,
runtimeHelpers: true,
pkgs: [...headPkgs, ...tailPkgs],
extraBabelPlugins: [
['babel-plugin-import', { libraryName: 'antd', libraryDirectory: 'es', style: true }, 'antd'],
],
};
}
if (type === 'es') {
config = {
cjs: false,
esm: {
type: 'babel',
},
runtimeHelpers: true,
pkgs: [...headPkgs, ...tailPkgs],
extraBabelPlugins: [
[require('./scripts/replaceLib')],
['babel-plugin-import', { libraryName: 'antd', libraryDirectory: 'es', style: true }, 'antd'],
],
};
}
export default config;
复制代码
father
是一个构建工具,可以支持cjs
、esm
和umd
打包,具体看查看father
- 在
package.json
中添加workspaces
// ...
// 添加workspaces
"workspaces": [
"packages/*"
],
"scripts": {
"start": "dumi dev",
"docs:build": "dumi build",
"docs:deploy": "gh-pages -d docs-dist",
"build": "father-build",
"deploy": "npm run docs:build && npm run docs:deploy",
"prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
"test": "umi-test",
"test:coverage": "umi-test --coverage",
"prepublishOnly": "npm run build"
},
// ...
复制代码
- 去除多余的目录,比如组件目录下的
lib
、_test_
和根目录下的src
然后重新npm run start
, 最后的效果如下图所示
组件库文档中的导航配置,具体可以看基础使用 - dumi (umijs.org)
常用的lerna命令
lerna init // 初始化lerna配置
lerna create // 创建lerna包
lerna link // 链接lerna包
lerna add // 安装单个依赖
lerna bootstrap // 安装全局依赖并链接到所有子包
lerna clean // 清除node_modules
lerna list // 列出子包
复制代码
具体可以看lerna
下面记录代码规范和提交规范的内容。。。
prettier和eslint配置代码风格
首先先在vscode中下载prettier
和eslint
,
用dumi脚手架创建的项目中已经有
prettier
的配置文件了
// .prettierrc.js
module.exports = require('@umijs/fabric').prettier;
// 通过引用路径可以找到@umijs/fabric下的prettier配置,配置如下
"use strict";
/** @format */
module.exports = {
singleQuote: true, // 单引号
trailingComma: 'all', // 对象{}的最后一个属性是否加,
printWidth: 100, // 每行超过100个字符换行
proseWrap: 'never', // 不强制换行
endOfLine: 'lf', // 以lf为换行符,常见的还有cr,cflf
overrides: [
{
files: '.prettierrc',
options: {
parser: 'json',
},
},
{
files: 'document.ejs',
options: {
parser: 'html',
},
},
],
};
复制代码
常见的prettier配置还有
"semi": false, // 是否有分号
"bracketSpacing": true, // 在对象中{a: 1},是否答应空格如果是{ a: 1 }
"arrowParens": "always" // 设置箭头函数中的参数是否包裹()
复制代码
然后打开vscode中的文件>>首选项>>设置
打开之后,在项目的工作目录中会出现一个.vscode/settings.json
的文件,配置如下
{
"editor.formatOnSave": true, // 自动保存的时候格式化代码
"search.exclude": { // 排除下面的文件
"**/node_modules": true,
"dist": true,
"yarn.lock": true,
},
}
复制代码
按ctrl + s
的时候就会自动格式化代码
prettier
解决了代码的风格统一的问题,对于代码质量的问题需要用到eslint
, 在该项目的根目录中新建.eslintrc.js
和.eslintignore
文件,因为该项目中已安装了umi, 可以像配置prettier
那样,直接用umi中的eslint配置
// .eslintrc.js
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
};
// umijs下的eslint
module.exports = {
extends: ['prettier', 'plugin:react/recommended'],
parser: '@babel/eslint-parser',
plugins: ['react', 'jest', 'unicorn', 'react-hooks'],
env: {
browser: true,
node: true,
es6: true,
mocha: true,
jest: true,
jasmine: true,
},
rules: {
strict: ['error', 'never'],
'react/display-name': 0,
'react/jsx-props-no-spreading': 0,
'react/state-in-constructor': 0,
'react/static-property-placement': 0,
// Too restrictive: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md
'react/destructuring-assignment': 'off',
'react/jsx-filename-extension': 'off',
'react/no-array-index-key': 'warn',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'react/require-default-props': 0,
'react/jsx-fragments': 0,
'react/jsx-wrap-multilines': 0,
'react/prop-types': 0,
'react/forbid-prop-types': 0,
'react/sort-comp': 0,
'react/react-in-jsx-scope': 0,
'react/jsx-one-expression-per-line': 0,
'generator-star-spacing': 0,
'function-paren-newline': 0,
'sort-imports': 0,
'class-methods-use-this': 0,
'no-confusing-arrow': 0,
'linebreak-style': 0,
// Too restrictive, writing ugly code to defend against a very unlikely scenario: https://eslint.org/docs/rules/no-prototype-builtins
'no-prototype-builtins': 'off',
'unicorn/prevent-abbreviations': 'off',
// Conflict with prettier
'arrow-body-style': 0,
'arrow-parens': 0,
'object-curly-newline': 0,
'implicit-arrow-linebreak': 0,
'operator-linebreak': 0,
'no-param-reassign': 2,
'space-before-function-paren': 0,
'react/self-closing-comp': 1,
'react/jsx-key': 1,
},
settings: {
// support import modules from TypeScript files in JavaScript files
'import/resolver': {
node: {
extensions: isTsProject ? ['.js', '.jsx', '.ts', '.tsx', '.d.ts'] : ['.js', '.jsx'],
},
},
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.d.ts'],
},
'import/extensions': ['.js', '.mjs', '.jsx', '.ts', '.tsx', '.d.ts'],
'import/external-module-folders': ['node_modules', 'node_modules/@types'],
polyfills: ['fetch', 'Promise', 'URL', 'object-assign'],
},
overrides: isTsProject
? [
{
files: ['**/*.{ts,tsx}'],
parser: '@typescript-eslint/parser',
rules: tsEslintConfig_1.default,
extends: ['prettier', 'plugin:@typescript-eslint/recommended'],
},
]
: [],
parserOptions: parserOptions,
};
复制代码
eslint中的配置太多了,具体可以查看的官方文档ESLint 配置好了之后,如果编写的代码不符合eslint中定义的规则,则会出现提示
git hooks和commitlin配置提交规范
git hooks类似于vue中的钩子函数一样,常用的有pre-commit
和commit-msg
, 这两个都是在git commit之前执行
。除了这两个之外,还有其它的git hooks,详情可以看git hooks官网
因为dumi项目中自带yorkie
来配置git hooks
, 所以就不用husky
去配置。
- 安装依赖
npm install @umijs/yorkie -D
复制代码
- 在项目的根目录的package.json配置
{
// ...
"gitHooks": {
"pre-commit": "lint-staged",
"commit-msg": "fabric verify-commit" //这里commitlint配置文件是在 "./node_modules/@umijs/fabric/dist/verifyCommit.js"
},
"lint-staged": {
"packages/**/*.{js,ts,jsx,tsx, md, json}": [
"eslint --fix",
"prettier --write",
"git add ."
]
},
// ...
}
复制代码
- 代码提交
- 使用git commit的时候,会触发eslint和prettier, 如果代码中有不符合eslint规则的,则提交不成功
- 修改eslint中的报错,然后重新提交。如果
git commit
不符合规范,则提交不成功,例如使用git commit -m "xxx"
用yorkie
配置的过程中有一个坑,因为查看package.json文件中,发现已有yorkie
和@umijs/fabric
的依赖,但是使用git commit
的时候却没有触发git hooks
。搜索了一下,最后在github上发现ant-design-pro
项目中的package.json
中有一个@umi/yorkie
的依赖,试着下载一下,发现真的可以了。
本来还想写jest单元测试、gitlab-ci跑lint和test、lerna发包到npmjs.com,下次再写吧。。。
参考链接
dumi - 为组件开发场景而生的文档工具
pro-components
lerna
prettier中文文档
esint中文文档