通过storybook实现组件库

# 环境及基本配置

# 初始化

create-react-app  yourProjectName --template typescript
1

然后进入项目目录

cd yourProjectName 
1

之后使用storybook的cli进行安装

npx -p @storybook/cli sb init --type react_scripts
1

默认用yarn安装,如果yarn不行,可以换npm

npx -p @storybook/cli sb init --type react_scripts --use-npm
1

如果还不行就切中国源

npm config set registry=https://registry.npm.taobao.org
1

打开根目录下的.storybook文件夹,其中main.js的配置:

module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app"
  ]
}
1
2
3
4
5
6
7
8
9
10
11

默认提供了addon-links插件、addon-essentials插件和preset-create-react-app插件。

actions插件有点像jest的fn一样,用来在触发事件时显示在action面板上,避免人为打开控制台查看输出了啥。

actions插件有点像jest的fn一样,用来在触发事件时显示在action面板上,避免人为打开控制台查看输出了啥。

actions插件文档地址 https://github.com/storybookjs/storybook/tree/master/addons/actions

links插件用来在各个故事书中进行跳转,相当于a标签一样,是个很常用的插件。

links插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/links

除了这几个,还有些比较常用而且好用的插件:

viewport插件,用来自由调整视口大小。

插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/viewport

knob插件,用来调整输入范例。

插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/knobs

docs插件,用来制作文档。

插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/docs

a11y插件,用来自动检测组件是否支持视障人士等规范的。

插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/a11y

source插件,故事书上的源码映射。

插件文档地址https://github.com/storybookjs/storybook/tree/master/addons/storysource

addon-essentials 里预设了以下插件

Actions
Backgrounds
Controls
Docs
Viewport
Toolbars
1
2
3
4
5
6

# 安装相关依赖

我们把其它插件装上

npm i @storybook/addon-a11y @storybook/addon-knobs @storybook/addon-storysource -D
1

将cra产生的多余文件删除,保留setupTest.ts和react-app-env.d.ts。一个用来测试用的,一个用来编译用的。

npm install -D @storybook/addon-a11y
npm install -D @storybook/addon-docs
npm install -D @storybook/addon-knobs
npm install -D @storybook/addon-storysource
npm install -D @storybook/addon-viewport
npm install -D styled-components @types/styled-components
1
2
3
4
5
6

重新使用npm run storybook打开,可以发现页面多了很多工具,有了这些工具,就能使我们开发一个更完备的组件。

# 全局样式与插件

全局样式一般是用来抹平浏览器默认差异的。

以前的做法是使用reset.css,现在普遍做法是使用normalize.css,antd的全局样式也是normalize.css上改的。

在components下新建shared文件夹,用来存放通用样式。

新建global.tsx ,我们使用styled-component作为GlobalStyle变量加进来。由于normalize注释里面有些反引号,为防止最后编译有问题,去掉所有注释。

src\components\shared\global.tsx

对于全局插件,storybook在编译时会先去.storybook文件夹下执行preview文件。

我们将全局样式与全局插件添加至这里:

# TOKEN制作

token是原子化的关键,有了styled-component,便于我们将所有样式token化。

# 颜色

对于颜色,通常情况是设置其中性色与主题色。除了这些颜色,可能还有边框颜色等等。 将颜色统一做成一个token并导出,后续使用时即可保证颜色风格的统一。

# 排版

排版除了字体大小,还有字重,字体类型。等等,根据需求自行设置

# 间距与圆角

间距也是个特别常用的属性,依据个人对其进行设置

# StoryOf&CSF&MDX

写故事一般有3种写法,一种是用StoryOf的API,一种是CSF,Component Story Format。一种是MDX,这里不讲第一种写法,本次训练营使用CSF+MDX形式组合制作

默认情况下,每个导出代表一个故事。一个stories文件里只能有一个默认导出。

当安装了docs插件后,storybook便也可以支持MDX写法。

MDX是MD格式的变体,旨在用类似md和jsx的语法写文档。

storybook的MDX工作模式是通过MDX来映射成对应的CSF写法。所以其实2者最后写出来都是一个玩意。

mdx需要有个meta标签,对应着CSF写法的默认导出。 title中有分隔符存在,可以对标题与storyName进行分隔。

# styled-components

styled-components制作组件的方法跟传统用css或者预处理器制作的模式有点不太一样。

传统做法是建立样式文件写对应类名,js中控制改变类名即可。

styled-components可以理解成就是写行内样式,其实是js插个动态类把样式弄来。先将各种属性以及对应传参写出来,产生对应样式,再把这个组件渲染出来即可。

对于每个组件,可以一个组件对应一个文件夹,以及其story文件和test文件。复杂组件可能需要建立多个文件,这里为了方便,将button组件直接写到button下的index里。

# polished

为了在styled-components里像scss等预处理器一样写常用函数,还需要安装下polished这个库。

网站官网https://polished.js.org/docs/

$ npm install --save polished
1

-S安装它,它自带声明,不需要安装@types

# PROPS TABLE

在编写story之前,我们需要对props table进行设置,props table是docs插件借助dockgen产生的,前面编写好Button组件后,自动会出来一堆属性,这些属性有很多是不用展示的,不需要全部列举出来。所以我们需要对属性进行过滤。

修改docgen插件配置:

.storybook\main.js

{
	loader: require.resolve("react-docgen-typescript-loader"),
	options: {
		shouldExtractLiteralValuesFromEnum: true,
		propFilter: (prop) => {
			if (prop.parent) {
				return !prop.parent.fileName.includes(
					"node_modules"
				);
			}
			return true;
		},
	},
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如果你的propFilter不起作用,请更换为2.1.1重新安装。

"@storybook/preset-create-react-app": "^2.1.1"
1

并显式安装react-docgen-typescript-loader。

npm i react-docgen-typescript-loader -D
1

此时,propTable已经可以正常显示。

# 结合KNOB

Storybook强大地方就在于各种神奇插件,knob就是个非常好用的插件。

使用knob,我们可以在canvas里对组件进行互动,告别只能看设置好的示例。测试人员或者UI都可以借助平台对其进行调校,直到做出满意的组件。

打开storybook,canvas里可以进行各种调校即成功。

# 组件

# 目录顺序

preview里可以设置目录顺序:

import { addParameters, configure } from "@storybook/react";
const loaderFn = () => {
	return [
		require("../src/stories/Welcome.stories.mdx"),
		require("../src/stories/color.stories.mdx"),
		....
	];
};
configure(loaderFn, module);
1
2
3
4
5
6
7
8
9

# Button组件

# 需求分析

首先需要分析下button的需求。

首要需求就是颜色,昨天已经对颜色制作了token,组件只要根据传参来显示对应颜色即可。同时,颜色除了背景颜色,还有文字颜色,边框颜色。

然后是大小,我们需要进行传参,然后改变button的大小,可能还需要处理里面文字大小。

此外,点击跳转也是个常用功能,如果传递href的话,需要渲染a标签而不是button标签。

loading状态, 这个需要处理很多细节方面。

disabled状态,这也是很常用的功能,需要单独设置disabled状态和样式。

# 定义类型

首先,先定义button的表现形式,这里使用几种类型,主题色,主题反白色,二级主题色,二级主题反白色,默认轮廓,轮廓主题色,轮廓二级主题色,三级主题色。

# 按功能进行编写

一般来说,编写测试用例是按照代码覆盖率来的,可以先试着对主要功能进行编写,再根据代码覆盖率进行完善。

先给组件加上 data-testid="button"

# 编写测试

已经完成了button组件以及其story,story通常是视觉检测,一般来说,代码检测的工作也不能省,如果后期对组件进行维护,这个组件被多个别的组件所依赖,没有代码测试就很容易让某些组件的功能失效。导致左边补个bug,又边又多个bug出来。

# JEST

由于我们使用CRA进行安装,内部自带了JEST测试框架,我们使用JEST编写测试用例。

官网地址https://jestjs.io/

testing-library地址:https://testing-library.com/docs/react-testing-library/api

首先先建个button.test.tsx,放入__test__文件夹下

# 快照测试

除了前面的测试方法,jest还提供快照测试。

如果你想的话,除了对test文件执行快照,还可以对story进行快照,以此来测试story文件中的变动。

story的快照需要用到storyShots插件,官网地址:https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core

story的快照这里不进行展开,对普通测试文件的快照可以直接调用:

expect(wrapper).toMatchSnapshot();
1

# 代码覆盖率

jest框架已经自带了代码覆盖率工具,不需要额外去安装nyc istanbul之类的工具了。

在package.json里添加scripts:

"coverage": "react-scripts test --coverage --watchAll=false",
1

npm run coverage 即可看见代码覆盖率。

其中button.stores.tsx、global.tsx,以及snapshot覆盖率是0。

story文件我们不需要测它,snap文件不需要包含进覆盖率,通过package.json配置jest字段将其排除。

"jest": {
	"collectCoverageFrom": [
		"!src/**/*.stories.tsx",
		"src/**/*.tsx",
		"!src/**/*.snap"
	]
}
1
2
3
4
5
6
7

同时编写globalStyle的测试,styles一般不修改,直接给个快照完事。

如果想看更详细内容,对coverage文件夹浏览即可。

npx http-server ./coverage
1

# icon组件

使用plop新建icon组件

# 轮播图组件

轮播图的按钮部分可以复用下昨天写的radio。

轮播图主要还是做出来,功能可以不用特别全。

最起码的功能就是自动播放和翻页了。

轮播制作原理使用图片拼接转移。就是在翻页时把需要的图片拼起来然后进行移动即可。

# 上传组件

# 搭建后台

为了方便测试,简单用express做个后台:

项目外找个文件夹init -y

cnpm i typescript express  @types/express multer @types/multer ts-node-dev  cors @types/cors  -S
npx tsconfig.json
1
2

然后选择node。

修改package.json

  "scripts": {
    "build": "tsc",
    "start": "ts-node-dev --respawn src/index.ts"
  },
1
2
3
4

然后src下建index.ts

import express, { Request, Response, NextFunction } from "express";
import cors from "cors";
import path from "path";
import multer from "multer";

const PORT = 51111;

const storage = multer.diskStorage({
	destination: path.join(__dirname, "public", "uploads"),
	filename(_req: Request, file: Express.Multer.File, cb) {
		cb(null, Date.now() + path.extname(file.originalname));
	},
});

const upload = multer({ storage });
const app = express();
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.get("/", (_req, res, _next) => {
	res.json({ success: true, data: "xx" });
});

app.post(
	"/user/uploadAvatar",
	upload.single("avatar"),
	(req: Request, res: Response, _next: NextFunction) => {
		let domain = "localhost";
		let avatar = `http://${domain}:${PORT}/uploads/${req.file.filename}`;
		res.send({ success: true, data: avatar });
	}
);

(async function () {
	app.listen(PORT, () => {
		console.log(`running on http://localhost:${PORT}`);
	});
})();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

然后启动它。

使用工具比如insominia上传个文件试试。

post 地址:http://localhost:51111/user/uploadAvatar/

格式选择multipart form

字段传avatar 然后value就是选个file。

发送后会返回:

{
  "success": true,
  "data": "http://localhost:51111/uploads/1596019074057.dll"
}
1
2
3
4

然后看看src文件夹里是不是多了刚刚上传的文件。都ok说明完成了。

# 分页与表格组件

# keep-alive组件

# 原理

先要分清2层概念,一个是fiber树上的显示,一个是真实dom的展示。

由于fiber树不强检测是否跟真实dom匹配,利用这个特性,可以控制组件的渲染状态。

keepalive组件可以拿到要渲染的虚拟dom,将其转移至alivescope组件,alivescope就是前面说的父组件,keepalive就是前面说的子组件。

父组件拿到子组件传来的虚拟dom进行渲染,这样,在其fiber树上就会表示这个组件已经被其渲染了。

关键点来了,渲染了后,父组件就可以获取这个组件dom,再把dom传给子组件,子组件获取dom后,插入自己已渲染的dom里。

这样就会导致,父组件渲染了dom,并且有这个dom的fiber,享受父组件的生命周期,但是渲染却是按照子组件渲染的逻辑走(就跟key错误误删一个道理),当子组件卸载时,fiber会commit掉子组件的dom,当然子组件fiber没有记录父组件有个dom跑子组件下了,结果这个dom就一起跟着被干掉了。

实际fiber树上仍然有这个dom,因为这个dom在父组件。

当子组件重新显示时,子组件dom加载完毕后,会调用父组件方法,重新获取父组件目前已经渲染的dom,有人可能奇怪,这个dom不是已经被干掉了?实际dom会缓存在fiber里,前面删掉的那个只是其中一个引用。

这样子组件又把父组件传来的dom给渲染出来了,而且是未卸载的状态。

# 使用PLOP

我们还需要写下一个组件,但是很多东西实际上是重复的代码。所以需要PLOP来帮助我们完成这个工作。

官网地址:https://plopjs.com/documentation/

安装完毕后建立plopfile.js

module.exports = function(plop) {
	// controller generator
	plop.addHelper("headCaps", function(p) {
		p = p.trim();
		return p.slice(0, 1).toUpperCase() + p.slice(1);
	});
	plop.setGenerator("component", {
		description: "create component",
		prompts: [
			{
				type: "input",
				name: "name",
				message: "component name please",
			},
		],
		actions: [
			{
				type: "add",
				path: "src/components/{{name}}/index.tsx",
				templateFile: "plop-template/componentIndex.hbs",
			},
			{
				type: "add",
				path: "src/components/{{name}}/__test__/{{name}}.test.tsx",
				templateFile: "plop-template/componentTest.hbs",
			},
			{
				type: "add",
				path: "src/components/{{name}}/{{name}}.stories.tsx",
				templateFile: "plop-template/componentStories.hbs",
			},
		],
	});
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

新建plop-template制作hbs文件模板:

npm i -g plop// 全局安装
npm i --save-dev plop // 本地安装
1
2

# 使用NP

np是一个标准化发布工具,避免手动更改version发布手动打tag以及手动写changelog等流程,发布前还会进行检测git是否有未提交代码。

官网地址https://www.npmjs.com/package/np

我们进行安装np,使用-D安装或者全局安装,提交所有代码。

np本身是不支持githubpackage包的发布的,所以我们还需要修改其源码,找到np下的source\prerequisite-tasks.js

将第32行verify user is authenticated到第54行给注释掉。这样就可以支持githubpackage包的发布了。

喜欢折腾的可以试试用patch-package或者别名搞一下

npm i -g microbundle np

# 使用MICROBUNDLE

前面我们已经走了一次打包发布流程了,但这个包并不完善,一般情况除了esmodule,还要打包别的模块的

microbundle是国外比较火的零配置打包工具,它旨在只使用package.json配置完成复杂的打包需求

官网:https://github.com/developit/microbundle

首先-D安装它。

microbundle推荐ts配置里module和target为esnext。我们进行更改下:tsconfig.json

"target": "ESNext",
"module": "ESNext"
1
2

然后在package.json里修改build指令

"build": "microbundle build  --tsconfig tsconfig.build.json --jsx React.createElement"
1

然后运行它,dist文件里就已经生成打包好的文件了。

默认打包生成4种格式modern,esm,cjs,umd,这玩意有个bug,就是esm和cjs名字一样,会导致覆盖。所以需要分开打包,打包完成后,使用cjs打包进行覆盖。

修改指令:

 "build-cjs": "microbundle build --tsconfig tsconfig.build.json --jsx React.createElement  --compress=false --format cjs", 
 "build-all": "microbundle build --tsconfig tsconfig.build.json --jsx React.createElement  --compress=false", "build": "npm run build-all & npm run build-cjs", 
1
2

运行build重新打包,可以发现模块就齐了。

然后需要在package.json配置模块:

  "types": "dist/index.d.ts",
   // "module": "dist/index.js",
  "main": "dist/rat-ui.js",
  "module": "dist/rat-ui.modern.js",
1
2
3
4

# 测试包

我们换一个文件夹cra新开个项目,安装刚刚发布的包。

使用以下demo:

import React from "react";
import { Button, Icon } from "@samyzh/rat-ui";
import { GlobalStyle, color } from "@samyzh/rat-ui";
color.primary = "blue";

function App() {
	return (
		<div className="App">
			<GlobalStyle></GlobalStyle>
			<Button appearance="primary">2222</Button>
			<Icon icon="admin"></Icon>
		</div>
	);
}

export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以如果启动后能看见蓝色的button就说明成功了。

生产环境测试:

使用npm run build进行打包。

使用npx http-server ./build查看输出文件,如果也是同样效果证明没有问题。

# GitHub相关库操作

# GitHub Package 发包

  • 对于需要发布的包,有几个前置知识是需要知道的。
  • 对于dependencies,只要有用户下载你这个包,dependencies里面的包都会进行安装。
  • 对于devDependencies,用户下载你这个包不会安装这些包。
  • 对于peerDependencies,用户下载你这个包后如果用户没安装会进行报警,如果用户已有这个包但版本与你的不匹配会报警。用户下载你这个包不会自动安装peerDependencies。

修改依赖

有了上面知识,我们需要对package.json进行修改。

所有的声明文件时不需要被用户安装的。

react,以及styled-components是需要放入peerDependencies的。

dependecies只保留polished

	"dependencies": {
		"polished": "^3.6.5"
	},
	"peerDependencies": {
		"react": ">=16.8.0",
		"react-dom": ">=16.8.0",
		"styled-components": "^5.1.1"
	  },
1
2
3
4
5
6
7
8

# 1.前期配置

目前,这个包还不能用,因为没有编译输出,我们肯定不能用react-scripts来输出。需要自行制作编译。

由于使用ts,所以我们需要做个tsconfig.build.json作为输出的配置文件。

{
    "compilerOptions": {
        "outDir": "dist",
        "target": "es5",
        "module": "esnext",
        "declaration": true,
        "jsx": "react",
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "resolveJsonModule": true
    },
    "include": ["src"],
    "exclude": ["src/**/*.stories.tsx", "src/**/*.test.tsx"]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

修改script配置:

"build": "tsc -p tsconfig.build.json"
1

之后可以生成dist目录

将dist 添加进gitignore不写入。

package.json对发包目录进行配置:

"files": [
    "dist"
],
1
2
3

对私有进行修改:

"private": false,
1

github package目前只支持作用域包,所以我们需要先进行改名,改成作用域+包名。

githubPackage的包不会显示在npm页面上,虽然都是使用npm进行安装。所以很多开源项目一般不发github package。

# 2.修改 package.json

  • name为 @用户名/原包名
  • 把仓库上传到github,并把地址贴到repository里,仓库的名字和包名是一样的
  • registry为 https://npm.pkg.github.com/用户名
"name": "@samyzh/rat-ui",
"repository":"https://github.com/samyzh/rat-ui",
"publishConfig": {
    "registry": "https://npm.pkg.github.com/samyzh"
},
1
2
3
4
5

会让你输入密码,这个密码是githubtoken,注意,是githubtoken ,是githubtoken。重要的事说3遍,因为这个设计有点反人类,它是粘贴并且看不见粘贴上没有。githubtoken在github的setting里面生成。

# 3.登录npm

npm login --registry=https://npm.pkg.github.com --scope=@samyzh
username 为你的github用户名
password 为刚才第一步生成的token
1
2
3

# 4. 发包

npm run build
npm publish
1
2

# 5.在github上搜索包名

# 6.安装组件测试

npm i -S @samyzh/rat-ui

import React from 'react'
// import Button from "@samyzh/rat-ui/dist/components/button";
// import { GlobalStyle } from "@samyzh/rat-ui/dist/components/shared/global";
import { Button, Icon } from '@samyzh/rat-ui'
import { GlobalStyle } from '@samyzh/rat-ui'

function App() {
  return (
    <div className="App">
      <GlobalStyle></GlobalStyle>
      <Button appearance="primary">2222</Button>
      <Icon icon="admin"></Icon>
    </div>
  )
}
export default App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# GitHub Actions 持续集成

# 1.生成token

# 访问token页面

img

# 创建token,给权限

img

# 把token拷贝出来

img

# 2.修改命令

在package.json中增加修改build-storybook命令

  "scripts": {
    "start": "react-scripts start",
    "build": "tsc -p tsconfig.build.json",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006 -s public",
+    "build-storybook": "build-storybook --no-dll --quiet",
    "coverage": "react-scripts test --coverage --watchAll=false",
    "coverall": "npm run coverage  && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
  },
1
2
3
4
5
6
7
8
9
10

# 3.添加ACCESS_TOKEN

writesccesstoken

# 4.添加Actions

  • 打开项目的[actions(https://github.com/zhufengnodejs/zhufengreactui/actions)页面
  • 根据向导添加脚本,会自动写到.github\workflows\blank.yml目录中

setupworkflow

name: Build and Deploy
on: [push]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 🛎️
        uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
        with:
          persist-credentials: false

      - name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
        run: |
          npm install
          npm run build-storybook

      - name: Deploy 🚀
        uses: JamesIves/github-pages-deploy-action@releases/v3
        with:
          GITHUB_TOKEN: ${{secrets.ACCESS_TOKEN}}
          BRANCH: gh-pages # The branch the action should deploy to.
          FOLDER: storybook-static # The folder the action should deploy. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 5.拉取Action代码

  • 在本地用git pull 把服务器端生成的blank.yml代码拉取本地

# 6.合并后推送

buildsuccess

# COVERALLS代码覆盖率

前面我们已经可以通过npm run coverage生成代码覆盖率,这样还要敲个命令麻烦,可以通过coveralls来告诉我们。

# 1.coveralls注册

img

点击detail到详情页拷贝出来token

img

# 2.添加COVERALLS_REPO_TOKEN

img

# 3.安装coveralls

yarn add coveralls
1

# 4.添加命令

  "scripts": {
    "start": "react-scripts start",
    "build": "tsc -p tsconfig.build.json",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "storybook": "start-storybook -p 6006 -s public",
    "build-storybook": "build-storybook --no-dll --quiet",
    "coverage": "react-scripts test --coverage --watchAll=false",
+    "coverall": "npm run coverage  && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
  },
1
2
3
4
5
6
7
8
9
10

# 5.修改githubActions

.github\workflows\你的名字.yml

+  - name: Coveralls
+        env:
+          COVERALLS_SERVICE_NAME: 'GitHub CI'
+          COVERALLS_GIT_BRANCH: master
+          COVERALLS_REPO_TOKEN : ${{secrets.COVERALLS_REPO_TOKEN}}
+        run: |
+          npm run coverall
1
2
3
4
5
6
7
  • # 6.添加badges

    • 把这一段拷贝到自己的README.mdimg

    # 7.提交并自动触发构建

    img

  • https://coveralls.io/github/zhufengnodejs/zhufengreactui?branch=master)

# 测试发布后的组件

npx create-react-app my-app

create-react-app yourProjectName --template typescript

我们可以新建个cra项目,安装刚才发的包进行测试。

由于styledComponent是peerDependency所以记得还要安装下styledComponent。

import React from "react";
import Button from "@samyzh/rat-ui/dist/components/button";
import { GlobalStyle } from "@samyzh/rat-ui/dist/components/shared/global";

function App() {
	return (
		<div className="App">
			<GlobalStyle></GlobalStyle>
			<Button appearance="primary">2222</Button>
		</div>
	);
}

export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

npm run start 可以看见,全局样式和按钮已经正确的显示出来了。

# TreeShaking&SideEffects

这种导入方式略微有点麻烦,可以制作个index.tsx将导出全部统一起来管理。这样的话就不得不说一下tree-shaking了。

使用es语法可以静态分析模块从而进行拆包,比如我们要做的index.tsx将所有导出集中到一个文件上,如果没有拆包,那么我们引入这个文件上的任意一个文件,都会把整个库里所有文件打包进来。而如果要拆包,需要配置sideEffects,因为sideEffects默认为true,代表我这个包的文件全部有副作用,别给我乱tree-shaking。对于我们这种无css文件组成的组件库,只要没有写什么乱七八糟的骚操作,直接配置为false即可,代表我的包你随便拆吧,都是单独的模块。

制作index.tsx

export * from "./components/button";
export * from "./components/shared/global";
export * from "./components/shared/styles";
export * from "./components/shared/animation";
1
2
3
4

对package.json进行设置:

"module": "dist/index.js",
"types": "dist/index.d.ts",
1
2

让ts可以识别入口。

以及sideeffects:

"sideEffects": false,
1

调整版本号再发布一次。

npm i -S @samyzh/rat-ui
npm i -S styled-components
1
2

进行验证:

import React from "react";
import { Button } from "@samyzh/rat-ui";
import { GlobalStyle } from "@samyzh/rat-ui";
function App() {
	return (
		<div className="App">
			<GlobalStyle></GlobalStyle>
			<Button appearance="primary">2222</Button>
		</div>
	);
}
export default App;
1
2
3
4
5
6
7
8
9
10
11
12

npm run start 看见按钮就成功了。

上次更新: 2022/04/15, 05:41:29
×