Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

渣渣灰手摸手带你开发一个组件库 #1

Open
clock157 opened this issue Feb 8, 2019 · 11 comments
Open

渣渣灰手摸手带你开发一个组件库 #1

clock157 opened this issue Feb 8, 2019 · 11 comments

Comments

@clock157
Copy link
Owner

clock157 commented Feb 8, 2019

大家好, 我是渣渣灰~
本文的目标是带你开发一个组件库,并走通开发、测试、文档、打包还有发布流程。

准备环境

如果你想快速开始,也可以直接使用我们的脚手架

涉及工具:umi-library

初始化项目

# 创建目录
$ mkdir umi-library-demo && cd umi-library-demo

# 初始化
$ yarn init -y

# 安装依赖
$ yarn add umi-library --save-dev

添加配置文件 .umirc.library.js

export default {
  entry: 'src/index.js',
  esm: 'rollup',
  cjs: 'rollup'
}

package.json 添加 script:

+ "scripts": {
+    "doc:dev": "umi-lib doc dev"
+ },

这时, 你已经可以通过以下命令跑起来:

$ yarn run doc:dev

浏览器访问 http://127.0.0.1:8001/,即可看到我们的组件开发环境。

开发组件

规划目录结构, 入口为 src/index.jsFoo为我们的第一个组件

.
├── .umirc.library.js		# 配置
├── package.json
└── src
    ├── Foo					# 组件
    │   └── index.js
    └── index.js			# 入口

Foo 组件代码如下:

// src/Foo/index.js
import * as React from 'react';

export default function(props) {
  return (
    <button
      style={{
        fontSize: props.size === 'large' ? 40 : 20,
      }}
    >
      { props.children }
    </button>
  );
}

接下来跑一下我们的组件,在 src/Foo 目录下创建 index.mdx,基于 mdx,你可以使用 markdownjsx 语法来组织文档。

---
name: Foo
route: /
---

import { Playground } from 'docz';
import Foo from './';

# Foo Component

## Normal Foo

<Foo>Hi</Foo>

## Large Foo with playground

<Playground>
    <Foo size="large">Hi</Foo>
</Playground>

再看下我们的开发环境,可以看到组件效果
屏幕快照 2019-02-06 23.26.51

组件测试

为了保证组件质量,我们需要引入组件测试,测试方案可以直接使用 umi-test

$ yarn add umi-test --save-dev

src/Foo 目录新建测试文件 index.test.js

import { shallow } from 'enzyme';
import Foo from './index.js';

describe('<Foo />', () => {
    it('render Foo', () => {
        const wrapper = shallow(<Foo size="large">hello, umi</Foo>);
        expect(wrapper.prop('style').fontSize).toEqual(40);
        expect(wrapper.children().text()).toEqual('hello, umi');
    });
});

然后在 package.jsonscripts 添加测试命令

  "scripts": {
    "doc:dev": "umi-lib doc dev",
+   "test": "umi-test"
  },

执行测试命令

$ yarn run test

执行结果,测试通过!

 PASS  src/Foo/index.test.js
  <Foo />
    ✓ render Foo (39ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.701s
Ran all test suites.
✨  Done in 15.82s.

组件打包

组件开发测试完成后,需要打包成不同的产物以适应不同的场景。默认使用 rollup 打包生成三个格式的包:

  • cjs: CommonJs,能被 Node 和 打包工具如 webpack 使用。
  • esm: ES Module,支持静态分析可以 tree shaking。
  • umd: Universal Module Definition 通用包,既能像 cjs 一样被使用,也可以发布到 cdn,通过 script 的方式被浏览器使用。

修改 package.json

-  "main": "index.js",
+  "main": "dist/index.js",
+  "module": "dist/index.esm.js",
   "scripts": {
    "doc:dev": "umi-lib doc dev",
+   "dev": "umi-lib build --watch",
+   "build": "umi-lib build",
    "test": "umi-test"
  },

使用命令

# 监控文件变化并打包
$ yarn run dev

# 打包
$ yarn run build

打包结果

$ yarn run build
yarn run v1.13.0
$ umi-lib build

ℹ  info      Clean dist directory
ℹ  info      Build cjs with rollup
ℹ  info      Build esm with rollup
✨  Done in 2.75s.

验证产物

为了验证我们的产物是否可用,我们可以基于 umi 创建一个小 demo 使用一下,,在项目下创建目录 example,目录结构:

example/
└── pages
    └── demo-foo
        └── index.js

我们创建了 demo-foo 这个页面, 并使用 Foo 组件,其 index.js 代码:

import { Foo } from '../../../dist';

export default function() {
    return (
        <Foo size="large">hello, world</Foo>
    );
}

我们跑一下

$ cd example
$ umi dev

# 如果没有 umi 这个命令, 请安装
$ yarn global add umi

启动好以后,console 会提示访问地址,打开后访问页面 /demo-foo,就可以看到效果:
组件效果

发布组件

组件开发好,发布到 npm registry 就可以被大家使用,也可以发布到私有 registry 内部使用。如果没有 npm 账号需要先注册,然后登陆 yarn login

修改 package.json,添加发布 script,发布前执行测试用例,并且包里只含 dist 目录:

+ "files": ["dist"],
  "scripts": {
+   "pub": "yarn run test && yarn publish",
    "test": "umi-test"
  },

执行命令

$ yarn run pub

发布成功后,你就可以在 npm 看到 umi-library-demo

对于其他用户,就可以使用以下命令来安装使用这个包。

# 使用 yarn
$ yarn add umi-library-demo --save

#使用 npm
$ npm install umi-library-demo --save

发布文档

在我们的组件开发完毕,文档相应写完后我们需要打包和部署文档,以便使用者查阅。

首先修改 package.json,添加 script:

  "scripts": {
    "doc:dev": "umi-lib doc dev",
+   "doc:build": "umi-lib doc build",
+   "doc:deploy": "umi-lib doc deploy",
  },

umi-library 默认将文档部署到 github.io, url 规则是 https://{yourname}.github.io/{your-repo},我们需要修改 .umirc.library.js 配置一下文档静态资源的前缀base

export default {
  entry: 'src/index.js',
  esm: 'rollup',
  cjs: 'rollup',
+ doc: {
+   base: '/umi-library-demo'
+ }
}

接下来执行命令:

# 打包文档
$ yarn run doc:build

# 部署文档, 速度取决于网速
$ yarn run doc:deploy

部署成功后,以这个项目为例, 文档地址为:

https://clock157.github.io/umi-library-demo/

结语

示例完整代码

至此, 发布一个组件库的流程::搭建、开发、测试、打包、验证、发布、文档整个流程就走通了,在实际的开发过程中,你可能会遇到更多的问题,或者你对这篇教程有不理解的地方,都可以反馈我们。

钉钉群

这是手摸手系列第一篇, 本系列旨在为前端开发者服务, 探索前端开发的最佳实践. 后面会陆续出更多的教程, 欢迎留言提出你宝贵的建议和想了解的点.

@clock157 clock157 changed the title 渣渣辉手摸手带你开发一个组件库 渣渣灰手摸手带你开发一个组件库 Feb 10, 2019
@yutingzhao1991
Copy link

yarn create umi --library 这样初始化更快吧。

@clock157
Copy link
Owner Author

yarn create umi --library 这样初始化更快吧。

用脚手架是要快一些,但那只是一个工具。这篇帖子偏向是教程,是想抛出一些点:让用户了解开发一个组件库的全貌,大概知道每一步完成的职责,应该注意什么。这是一个开头,稍后会对一些技术点,比如打包优化再进行深入。

@clock157
Copy link
Owner Author

clock157 commented Mar 7, 2019

update: 2019-03-07, 使用umi-library重构,更加小巧更加优雅。

@jyzwf
Copy link

jyzwf commented Mar 8, 2019

您好,请问下,我在组件中使用了装饰器,并且运行 yarn run doc:dev 命令,但是还是提示我不支持装饰器,
image

image

谢谢😀

@clock157
Copy link
Owner Author

clock157 commented Mar 8, 2019

@jyzwf 稍后会有 pr 将一些常用 babel 插件集成。

@jyzwf
Copy link

jyzwf commented Mar 8, 2019

@jyzwf 稍后会有 pr 将一些常用 babel 插件集成。

好的,,谢谢了🤓

@haozhuanye
Copy link

Module parse failed: Unexpected token (473:30)
You may need an appropriate loader to handle this file type.
| async function loadFromImports(path) {
| // tslint:disable-next-line

const { imports } = await import('~imports');

| const { default: Component$$1, getInitialData } = await importspath;
| const ExportedComponent = props => (createElement(AsyncComponent, Object.assign({}, props, { as: Component$$1 || 'div', getInitialData: getInitialData })));

我在本地npm run doc:dev启动的时候,报这个错,大神能帮忙看一下么,我直接用yarn create umi --library启动项目也报这个错

@clock157
Copy link
Owner Author

clock157 commented Mar 14, 2019

你安装依赖是怎么安装的? 使用 yarn install
umijs/umi#2072

@fohui
Copy link

fohui commented Jun 11, 2019

您好,在组件打包那里遇到了问题:
执行yarn run build之后提示是这样的:

$ umi-lib build
ℹ  info      Clean dist directory
ℹ  info      Build cjs with rollup
'createElement' is not exported by 'node_modules/react/index.js'
ℹ  info      Build esm with rollup
'createElement' is not exported by 'node_modules/react/index.js'
✨  Done in 3.54s.

rollup打包的结果也是有问题:没有获取到React.createElement方法

'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./cjs/react.production.min.js');
} else {
  module.exports = require('./cjs/react.development.js');
}

function index (props) {
  return undefined("button", {
    style: {
      fontSize: props.size === 'large' ? 40 : 20
    }
  }, props.children);
}

exports.Foo = index;

然后我改了.umirc.library.js配置为:

esm: 'babel',
cjs: 'babel'

打包结果是正确、可执行的,但是多出了es和lib两个目录。

我的问题是:
1.rollup的配置有问题是什么情况,改怎么解决呀?
2.怎么做配置,把babel的打包结果输出到指定文件,file属性失效了?
3.umi-library项目404了

@clock157
Copy link
Owner Author

@fohui 你好,umi-library 现在已升级为 https://github.com/umijs/father

@ammagician
Copy link

@clock157 你好,请问怎么在antdesignpro的工程项目里,指定将某些文件打包为一个组件? 也就是说有一个功能点很好,然后希望把这个功能点的相关代码打包成一个包含js,css文件的插件,其他项目直接引用就可以看到该功能点。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants