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

组件开发插件 #1550

Closed
3 of 4 tasks
clock157 opened this issue Nov 29, 2018 · 41 comments
Closed
3 of 4 tasks

组件开发插件 #1550

clock157 opened this issue Nov 29, 2018 · 41 comments

Comments

@clock157
Copy link
Contributor

clock157 commented Nov 29, 2018

背景

为了更方便的进行组件开发调试,并能很爽的写文档。在调研了流行的 storybook 和 docz 后,选型使用 docz,目前将计划开发 umi-plugin-doczumi-plugin-component,在此跟进与讨论。

项目地址

https://github.com/umijs/umi-plugin-library

进展

  • 细化方案
  • 第一版演示 2018-12-13
  • 内部第一版脚手架 2018-12-18
  • 对外脚手架 2018-12-31
@sorrycc
Copy link
Member

sorrycc commented Nov 29, 2018

umi-plugin-component 改成 umi-plugin-library 吧,通用的,不只是 component。

@sorrycc sorrycc mentioned this issue Nov 29, 2018
31 tasks
@yutingzhao1991
Copy link
Contributor

cc @zinkey

@afc163
Copy link
Contributor

afc163 commented Nov 29, 2018

就搞一个 umi-plugin-docz 就行,过度分层也没必要。

@yutingzhao1991
Copy link
Contributor

yutingzhao1991 commented Nov 29, 2018

那应该是 umi-plugin-library 这个插件,然后里面有 docz 这个的一个配置?

plugins: [[
  'umi-plugin-library',
  {
    docz: true,
  }
]]

@JIACHENG9
Copy link
Member

umi-plugin-library 具体做什么功能呢?

@yutingzhao1991
Copy link
Contributor

yutingzhao1991 commented Nov 29, 2018

umi-plugin-library 具体做什么功能呢?

如果不包含 doc 的话主要就是构建打包这块,库,组件和应用的打包方式不一样。比如说:

  • react 这些不应该打包进去。
  • 默认应该要转换为 es5,不能包含箭头函数这些。
  • 构建后的内容放到 lib 下面。

@JIACHENG9
Copy link
Member

docz 也包含了 build,那就是不用 docz 的 build?那 dev 是否包含呢?要是 umi-plugin-library 只包含 build 好像不是很好用,不如给个 umi-plugin-docz dev,build 都有

@sorrycc
Copy link
Member

sorrycc commented Nov 30, 2018

docz 只是文档,不会包含 library 的 build 的,library 的 build 得通过 rollup 来做。

@JIACHENG9
Copy link
Member

docz 不仅仅是文档,包含了 build 的

@clock157
Copy link
Contributor Author

clock157 commented Dec 4, 2018

这个 build 分为两种,一种是 doc site build ,另一种是 component 的 build,component 的 build 应该放在 library 中。
如果不分层,将docz 放在 umi-plugin-library中,那 library 同时可以 build doc 也可以 buid component。

@clock157
Copy link
Contributor Author

clock157 commented Dec 6, 2018

关于结构,我想分两个部分:

umi-plugin-docz

包含: docz 相关, doc 界面,doc的插件,对doc的增强,定制的东西比较多,比如支持 theme,相对 library 较独立。

使用方式:
umi doc [--dev] // 跑 doc server
umi doc --build // build
umi doc --deploy // 部署

umi-plugin-library

包含:打包, 可以打包任何东西,umi-tools build 能做吗?

使用方式:
umi library --build [ --input /src/component --output /lib ]

其他使用方式
umi dev --doc?
umi build --doc ?
umi build --library ?

优点:看起来umi命令没那么多。
缺点:侵入 umi代码。

你们的意见呢?

@sorrycc
Copy link
Member

sorrycc commented Dec 7, 2018

我的建议是这样,不侵入 umi 代码,

$ umi docz build
$ umi docz dev
$ umi docz deploy

$ umi library dev
$ umi library build

@afc163
Copy link
Contributor

afc163 commented Dec 7, 2018

就 umi library 好了,docz 只是 umi library 依赖的文档工具,不需要在命令行展现。

@clock157
Copy link
Contributor Author

clock157 commented Dec 7, 2018

就 umi library 好了,docz 只是 umi library 依赖的文档工具,不需要在命令行展现。

好,我就这样先搞一波。

@xiaohuoni
Copy link
Member

@clock157 是2012-12-13? 2018-12-13!

@okoala
Copy link
Contributor

okoala commented Dec 8, 2018

$ umi lib dev
$ umi lib build

看看能不能加个 lib 的 alias,毕竟最后也是放到 lib 目录

@yutingzhao1991
Copy link
Contributor

加了 #1585 一个 _modifyCommand 这个插件方法,可以实现命令行别名。

@sorrycc
Copy link
Member

sorrycc commented Dec 10, 2018

别名内置就好了,参考 umi gumi generate

@yutingzhao1991
Copy link
Contributor

umi library dev 需要调用 umi dev 吗?还是说完全独立的一套构建?

@sorrycc
Copy link
Member

sorrycc commented Dec 10, 2018

按我理解,library 要么用 test 调,要么用 docz 调吧。

@xiaoxiangmoe
Copy link
Contributor

xiaoxiangmoe commented Dec 11, 2018

umi 的 library 可以在一些纯打包 component 的项目中使用吗?比如 ant-design。

目前有一些类似的方案:

@yutingzhao1991
Copy link
Contributor

@xiaoxiangmoe 这个需求就是为了解决这种场景,使得 umi 能够支持组件或者库的开发。

@clock157
Copy link
Contributor Author

clock157 commented Dec 18, 2018

目前 library 实现了 dev 和 build,在这两个方向进行了一系列探索,反馈一下我的思路,大家有没有补充或问题:

dev

进度:可以正常调试,主题的还比较简陋。

  • 基于 docz,支持 mdx 编写组件文档。
  • 通过定制 docz-theme-antd,调研 docz 内部实现,发现可以很方便的进行定制。组件官网,文档说明,组件演示,典型页面,演示站,在同一套代码中即可实现。
  • 基于 webpack,使用 umi 运行时配置能比较好的兼容组件运行。

build

进度:可以打包组件,生成es5, es6 库文件,打的包已可以应用于项目。umd 还在调研

  • 调研了 antd material-ui bootstrap 等多个 ui 框架,普遍的做法是:用babel 编译一个 es5 的组件lib,编译一个 es6 的支持模块加载,最后再打包一个 umd 的包支持全家桶引用和浏览器使用。
  • 目前基于 babel 实现了 es5 和 es6 的库编译。支持css_modules,抽出了 less,并生产一个单独的样式文件。拿 ant-design-pro 打了一个产物已发布 testumilibrary-ant-design-pro 有兴趣可以看下,可以跑起来,样式正常。
  • umd 包准备试一下 rollup, 但是 umd 包需要将一些依赖打进去,这样才能兼容浏览,但 rollup 打依赖可能存在一大堆 named export 错需要解决,这方面经验稍后借鉴下 @xiaoxiangmoe 提到的 microbundle。除了 rollup ,还在犹豫是否使用 webpack 打包 umd ? 因为开发调试使用都是 webpack, 方案也比较成熟。大家的意见?rollup 的优势是 treeshaking, 现在 webpack 也支持,还有其他优点吗?

test

进度: 测试还未推进,build 搞好学习下 antd 目前应用的 jest + enzyme。如有兴趣的同学可以帮下我,最近业务太忙了= =;

@afc163
Copy link
Contributor

afc163 commented Dec 18, 2018

我建议是直接用 af-webpack,既然在 umi 体系内,能复用的东西用一套就好,rollup 比起 webpack 其实没有本质的优势,遇到自定义配置时还得学和写另一套配置方式。

@sorrycc
Copy link
Member

sorrycc commented Dec 18, 2018

rollup 的优势是 treeshaking, 现在 webpack 也支持,还有其他优点吗?

看下构建产物的区别呢?比如尺寸。

@afc163
Copy link
Contributor

afc163 commented Dec 19, 2018

语雀那边组件开发需求蛮强烈的,bigfish 上了之后可以从他们那里开始试水。

@sorrycc
Copy link
Member

sorrycc commented Dec 25, 2018

我的想法。

基本思路

  • 通过 umi-plugin-library 露出
    • 基于 rollup
  • doc 部分下沉到 umi-plugin-docz 里,然后在 umi-plugin-library 里调他,并透传参数

命令行

$ umi lib doc dev
$ umi lib doc build
$ umi lib doc publish
$ umi lib build
$ umi lib test
$ umi lib publish

注:

  • umi libumi library 的别名

配置方式

  • umi 通过插件使用,['umi-plugin-library', {}]
  • bigfish 通过 library 配置

配置项

  • entry: String | Object
    • 默认 src/index.(t|j)sx?
  • extraBabelPlugins: Array
    • 比如为 antd 配置 babel-plugin-import
  • umd: Object | false
    • 值为 false 时不生成
    • globals: Object
    • name: String
  • cjs: Object | false
    • 值为 false 时不生成
    • type: rollup | babel
      • 默认 rollup
    • dir: String
      • 默认 lib
    • proxy: Boolean
      • 默认 false
  • esm: Object | false
    • 值为 false 时不生成
    • type: rollup | babel
      • 默认 rollup
    • dir: String
      • 默认 es
  • doc
    • 透传给 umi-plugin-docz

脚手架 MVP

仅考虑 build 部分,实际脚手架需添加 doc 和 test 部分。

package.json

  • name: 'foo'
  • main: 'dist/foo.js
    • cjs
  • module: 'dist/foo.esm.js'
    • es modules
  • unpkg: 'dist/foo.umd.js'
  • sideEffects
    • 按需配置,可以是 false 或数组

src

  • index.js
    • import from Foo.js and Bar.js
  • index.css
  • Foo.js
  • Bar.js

dist (build 后输出)

  • foo.js
  • foo.esm.js
  • foo.umd.js
  • foo.umd.min.js
  • 以及相关 css 文件

@sorrycc
Copy link
Member

sorrycc commented Dec 25, 2018

调研笔记。

  • 问题
    • package.json 里的各个项是什么意思?
    • cjs, esm, umd, amd 是什么意思?他们是怎么来的?
    • es 2015 和 es6 是什么关系?
    • tree-shaking 怎么实现的?
    • 为什么有 .mjs?
    • 组件打包怎么处理补丁?@babel/plugin-transform-runtime 要不要加 polyfill?
  • 两个功能
    • doc 命令
      • 包括 doc devdoc build
      • 基于 docz 实现
      • 实现上可以再分层,通过 umi-plugin-docz 实现,这样项目要用 docz 也可以用
      • 然后 library 引 umi-plugin-docz 实现 doc 命令
    • build
      • 基于 rollup + babel
    • publish
      • changelog
      • commit
      • tag
      • push
  • 调研
    • htm
    • redux
      • 基于 rollup
      • 打出以下格式
        • lib/redux.js
          • commonjs (cjs)
          • external 依赖
          • 不压缩
        • es/redux.js
          • es module
          • external 依赖
          • 不压缩
        • es/redux.mjs
          • 为浏览器用的 es module
          • es module
          • 不 external 依赖
          • replace NODE_ENV 为 production
          • 压缩
        • dist/redux.js
          • umd,暴露为 Redux 全局变量
          • replace NODE_ENV 为 development
          • 不压缩
        • dist/redux.min.js
          • umd,暴露为 Redux 全局变量
          • replace NODE_ENV 为 production
          • 压缩
    • react-router
      • cjs/react-router.js
        • commonjs
        • external 依赖
        • 同步生成 min 文件
      • esm/react-router.js
        • es module
        • external 依赖
        • babel 配 runtimeHelpers: true,并且加 @babel/transform-runtieme + useESModules: true
      • umd/react-router.js
        • globals = react: React
        • 对外露出 ReactRouter
        • 调 commonjs 插件把 commonjs 转成 esm,让 node_modules 下的模块也能走 tree-shaking
    • reach-router
      • es
        • 把 src 下的文件打到 es 目录下
        • 基于 babel,env + modules: false,不做 modules 转化
      • cjs
        • 把 src 下的文件打到 ./ 根目录
        • 基于 babel, env + modules: 'commonjs'
      • umd
        • umd/reach-router.js
          • 有 min 版本
          • 基于 rollup
          • globals 掉 react 和 react-dom
    • redux-saga
    • immer
      • dist/immer.js
        • cjs
        • 不压缩
      • dist/immer.umd.js
        • umd
        • 压缩
      • dist/immer.module.js
        • es
        • 不压缩
    • mobx
      • 把 src 生成 .build.es5 和 .build.es6
      • 生成以下文件
        • 基于 rollup
        • lib/mobx.js, cjs
        • lib/mobx.module.js, esm
        • lib/mobx.es6.js, esm
      • 生成 umd 包 lib/mobx.umd.js
        • 基于 browserify
      • 基于 envify 生成 lib/mobx.prod.js
      • 基于 uglifyjs 生成
        • lib/mobx.min.js
        • lib/mobx.umd.min.js
  • 几种格式
    • es 5 module system
      • cjs (common js)
        • require 和 module.exports
        • 同步加载
        • 适合 server 端
      • amd
        • Asynchronous Module Definition
        • seajs, requirejs
        • define + require
        • 异步加载
        • 适合 browser 端
    • es 6 modules
      • 来自 es6 / es2015
      • 同时解决 cjs 和 amd 的需要
      • export (default) 和 import
      • 浏览器里怎么用?
        • import()
        • require.ensure()
        • System.import()
        • type="module"
    • umd
  • 产出格式
    • cjs
      • 给谁用?
        • node 端
        • 组件是不是不用产出 cjs 产物?
          • 不是,比如要支持 ssr
      • 怎么产生?倾向后者。
        • babel 直接转,比如把 src 转成 cjs 或 lib,多文件,然后 package.json 里配 lib
        • rollup 转,单文件,比如生成 dist/[name].js
          • 可以区分 development 和 production
          • 可以有 proxy 层,自动引入 dev 或 prod 版本
      • 注意点
        • external dependencies + peerDependencies
    • esm
      • 给谁用?
        • webpack(浏览器端)
        • 浏览器直接用
          • script type="module"
        • node 端?
      • 为什么用?
        • 新版方案,解决 commonjs 和 amd 的方案
        • tree shaking,因为是静态的产出
      • 怎么产生?
        • babel 转,比如把 src 转成 es,多文件,然后 package.json 里配 es
        • rollup 转,单文件,比如生成 dist/[name].esm.js
          • esm 已经可以做 tree-shaking,所以不需要产生多个文件,即可实现按需
          • 单文件在 webpack 使用时更快,因为少了文件系统 io
      • 注意点
        • external dependencies + peerDependencies
        • 根据库的实际情况考虑是否配 sideEffect: false 或者 sideEffect: [文件1, 文件2]
    • umd
      • 给谁用?
        • 浏览器直接引
      • 怎么产生
        • rollup
          • 单文件,比如生成 dist/[name].umd.js
          • 同时生成 min 文件,比如 dist/[name].umd.min.js
          • 然后在 package.json 里配 unpkg 或 umd:main 指向他
        • webpack
          • 感觉会慢且大
        • browserify
          • 过时
      • 注意点
        • 只 external peerDependencies,不 external dependencies
          • 比如我们通常要 external react, react-dom, antd, dva 等
          • rollup 里通过 globals 实现
  • 方案
    • 基于 rollup
      • 相比 webpack
        • 构建速度快
        • 产物小
        • tree-shaking 优势
          • 通过 commonjs 插件,把 node_modules 下的依赖也转成 esm,使之支持 tree-shaking
      • 专注于组件构建,社区成熟
    • 关于配置
      • 配置方式
        • umi 通过插件使用,['umi-plugin-library', {}]
        • bigfish 通过 library 配置
      • 配置项
        • entry: src/index.js
        • extraBabelPlugins
          • 比如为 antd 配置 babel-plugin-import
        • umd
          • globals(别名:externals)
            • 比如 react:React,'react-dom':ReactDOM
        • cjs
          • type: rollup | babel
          • dir: lib
          • proxy: true | false
        • esm
          • type: rollup | babel
          • dir: es
        • doc
          • 透传给 umi-plugin-docz 用
    • 脚手架 MVP
      • 注:不包含 doc 的部分
      • package.json
        • name: foo
        • main: dist/foo.js
          • cjs
        • module: dist/foo.esm.js
        • unpkg: dist/foo.umd.js
      • src
        • Foo.js
        • Bar.js
        • index.js
          • import from Foo.js and Bar.js
        • index.css
      • 输出
        • dist/
          • foo.js
          • foo.esm.js
          • foo.umd.js
          • foo.umd.min.js
          • 一一对应的 css 文件
    • 使用场景
      • react 组件
      • 非 react 组件
      • 独立库
      • 集成在项目中使用
        • 可指定 entry,比如 components/index.js
        • 可指定输出路径,并在此路径包含 package.json
          • name
          • dependencies
          • 等等
      • lerna 项目
    • 包含功能
  • package.json 里的项
    • main
      • 指向 cjs
    • module
      • 指向 esm
    • unpkg
      • 指向 umd
    • umd:main
      • 同 unpkg,用一个就好了
    • typings
    • 这些项在 webpack 里的应用
  • tree shaking
    • 去死代码
    • 依赖 es module 的 Static module structure
      • import 和 export 都是静态的
      • 相比之下,commonjs 的 require 和 exports 是动态的
    • 概念和名词由 rollup 引入
    • sideEffects
      • 可以是 false,也可以是数组
      • 在 100% 的 ESM 世界里是不需要的
  • 脑暴
    • react 包的处理方式
    • mjs
    • 怎么用?
  • 词汇
    • JavaScript
    • ECMAScript
    • ES3
      • 1999
    • ES5
      • 第 5 版 ECMAScript,于 2009 年标准化
    • ES6 / ES2015
      • 第 6 版
    • ES2016
      • 第 7 版
  • JavaScript 来源
    • 1995
      • LiveScript,作为 Netscape Navigator 的一部分
      • 一年半后,更名为 JavaScript
    • 1996
      • Netscape 向 ECMA International 提交标准化 JavaScript
      • 即 ECMAScript
    • 1999
      • ECMAScript 3
    • 2009
      • ECMAScript 5
    • 2015
      • ECMAScript 6
    • 2016
      • ECMAScript 7

参考

@clock157
Copy link
Contributor Author

超赞!虽然我也调研过好些库,但是没有通过这样的形式进行整理和输出,知识成了个人的一次性消费,今后也要这样带着问题去调研和整理。😁

@xiaohuoni
Copy link
Member

学习了,就是专业啊。不愧是我偶像

@xiaoxiangmoe
Copy link
Contributor

xiaoxiangmoe commented Dec 25, 2018

我还有很多疑问🤔️:

  1. 比如entry: String | Objectumd: Object | false,很多地方用了 Array 和 Object,而这里面具体是 Array<String>,还是 Array<{foo:string,bar?:number,baz:number|string}> ,作为文档的阅读者,我并不清楚这些,建议用更严格的 TypeScript 类型签名指定
  2. build,基于 rollup + babel,那么是通过 babel 提供 TypeScript 的支持,还是 rollup-plugin-typescript2 提供 TypeScript 支持,比如 rollup-plugin-typescript2 的一些配置,比如 transformers,babel 是否有对应的解决方案?
  3. publish 是在 ci 上 push 到某个分支执行,还是得用户手动执行,是否要测试和 lerna 的 publish 的兼容性,因为 lerna 以及它的插件也提供了 changelog/commit/tag/push 等功能
  4. 纯网页端的库是否要提供 cjs?(是否有无浏览器运行的测试库依赖 cjs? ssr 可以不依赖 cjs 吗?)
  5. <package>.module 字段和 moment 里的<package>."jsnext:main"字段有什么关系?<package>.typings<package>.types有什么区别?
  6. es module 是否要提供压缩版本的,给浏览器端的 type='module'使用?比如 foo.esm.min.js
  7. 是否要提供 css 的 tree shaking?我们因为库很庞大时候,css 代码可能会很多,有 TypeScript 的 transformer 做了类似的事情:https://github.com/Brooooooklyn/ts-import-plugin
  8. 由于是提供库,我们是否要提供 css 的 class 名的规则自定义?毕竟不是直接最下游的用户,可以无脑 uglify 加 hash
  9. 哪些包应该打包进 umd,哪些应该作为依赖?我用 umd 会不会出现上游的 A 和 B 都依赖 moment,于是我加载了两个 moment?
  10. 可指定 entry,entry 是否要像 micro bundle 里一样使用 source 字段?这会影响到下游的 source package 的使用吗?比如 [RFC] Support source field in package.json to enable babel on symlinked modules parcel-bundler/parcel#1101

@sorrycc
Copy link
Member

sorrycc commented Dec 25, 2018

@xiaoxiangmoe 好问题,我找时间整理下。

@sorrycc
Copy link
Member

sorrycc commented Dec 27, 2018

  1. 比如entry: String | Objectumd: Object | false,很多地方用了 Array 和 Object,而这里面具体是 Array<String>,还是 Array<{foo:string,bar?:number,baz:number|string}> ,作为文档的阅读者,我并不清楚这些,建议用更严格的 TypeScript 类型签名指定

好,等我先熟悉下 Typescript。

  1. build,基于 rollup + babel,那么是通过 babel 提供 TypeScript 的支持,还是 rollup-plugin-typescript2 提供 TypeScript 支持,比如 rollup-plugin-typescript2 的一些配置,比如 transformers,babel 是否有对应的解决方案?

我倾向于 typescript 的方案全部统一到 babel 里做,这样可以顺便让 webpack 和 rollup 里保持一致,没必要有多种方案。cra 也是用的 babel 处理 typescript。

  1. publish 是在 ci 上 push 到某个分支执行,还是得用户手动执行,是否要测试和 lerna 的 publish 的兼容性,因为 lerna 以及它的插件也提供了 changelog/commit/tag/push 等功能

publish 不是核心功能,只做简单的,比如 changelog 生成、交互式升版本、打 tag、push 等。不做和 lerna 的整合,用 lerna 的场景直接用 lerna-changelog + lerna publish 就行了。

  1. 纯网页端的库是否要提供 cjs?(是否有无浏览器运行的测试库依赖 cjs? ssr 可以不依赖 cjs 吗?)

个人认为 cjs 是给 node 环境用的,因为 webpack/rollup 都走 esm 了,但不排除一些老的打包工具(比如 systemjs.js,webpack 1 等等)不支持 esm,还在使用 cjs。

理论上,给浏览器用的库且无 ssr 需求是可以不生成 cjs 格式,不过我觉得还是都提供吧,万一以后有 ssr 需求了呢?

  1. <package>.module 字段和 moment 里的<package>."jsnext:main"字段有什么关系?<package>.typings<package>.types有什么区别?

jsnext:main 是技术发展的中间产物吧,现在应该不太用了。比如 webpack 默认的 resovle 字段是:browser -> module -> main,所以写了通常也没有用。

我的理解是:

  • main: es5
  • module: es5 + esm
  • jsnext:main: es next,包括 esm,通常是指向 src/index.js

参考:jsforum/jsforum#5

  1. es module 是否要提供压缩版本的,给浏览器端的 type='module'使用?比如 foo.esm.min.js

我觉得可以提供,但默认先不开,然后输出名是 foo.mjsfoo.min.mjs。另外,这种使用方式短时间内我觉得流行不起来,在我调研的库里只有 redux 里有输出这种格式。

  1. 是否要提供 css 的 tree shaking?我们因为库很庞大时候,css 代码可能会很多,有 TypeScript 的 transformer 做了类似的事情:https://github.com/Brooooooklyn/ts-import-plugin

可以自行配置,但不内置的工具里。

  1. 由于是提供库,我们是否要提供 css 的 class 名的规则自定义?毕竟不是直接最下游的用户,可以无脑 uglify 加 hash

处理 css 命名冲突的方案有很多,应用自己选就好了,工具层不做限制。

  • css 前缀
  • css modules
  • bem
  • css in js
  1. 哪些包应该打包进 umd,哪些应该作为依赖?我用 umd 会不会出现上游的 A 和 B 都依赖 moment,于是我加载了两个 moment?

这也应该是工具使用者决定的,moment、react、react-dom 我觉得通常都不应该打到 umd 包里。

  1. 可指定 entry,entry 是否要像 micro bundle 里一样使用 source 字段?这会影响到下游的 source package 的使用吗?比如 [RFC] Support source field in package.json to enable babel on symlinked modules parcel-bundler/parcel#1101

配置不在 package.json 里,而是作为插件的配置项。source 不支持,我觉得用不到。

@xiaoxiangmoe
Copy link
Contributor

xiaoxiangmoe commented Dec 27, 2018

我倾向于 typescript 的方案全部统一到 babel 里做,这样可以顺便让 webpack 和 rollup 里保持一致,没必要有多种方案。cra 也是用的 babel 处理 typescript。

cra 使用 babel 处理 TypeScript,但是禁止了 CustomTransformers 的使用,而我们未来可能会基于 TypeScript 的 CustomTransformers 做很多工作,比如非 js 文件的类型签名在编译期的生成和检查等(比如 css-module 的类型签名,现在我们只能基于 language service plugin 来做基于编辑器的编辑阶段的检查,而不会影响到编译期)。

Babel 的 AST 和 TypeScript 的 AST 差别挺大的,不方便做这些事情。我觉得我们应该推进 cra 使用 ts-loader 来支持 CustomTransformers。

publish 不是核心功能,只做简单的,比如 changelog 生成、交互式升版本、打 tag、push 等。

也就是「我们每次的 publish 是人手动介入的,在 cli 里交互式地 publish」的意思吗?

@sorrycc
Copy link
Member

sorrycc commented Dec 27, 2018

内部分享版。

《如何打包组件?》

Why,组件为什么要打包?

  • 组件是一层抽象,他需要输出,给项目用
  • 源码并不能直接用
    • es6
    • es modules
    • ...

What

src -> dist,做输出,给项目用

输出什么?

  • 来源于需求,有人用才会有输出
  • amd
  • cjs
  • esm
    • 浏览器版
    • node 版
  • umd

模块历史

通过 package.json 看各种格式

  • main
    • 指向 cjs
  • module
    • 指向 esm
  • unpkg
    • 指向 umd
  • umd:main
    • 同 unpkg,用一个就好了
  • typings
  • 这些项在 webpack 里的应用
  • sideEffects
    • 可以是 false,也可以是数组
    • 拿来做 tree-shaking
    • 在 100% 的 ESM 世界里是不需要的

名词解释,ES6, ES2015, EMCAScript, JavaScript, ES Next ...

  • JavaScript 来源
    • 1995
      • LiveScript,作为 Netscape Navigator 的一部分
      • 一年半后,更名为 JavaScript
    • 1996
      • Netscape 向 ECMA International 提交标准化 JavaScript
      • 即 ECMAScript
    • 1999
      • ECMAScript 3
    • 2009
      • ECMAScript 5
    • 2015
      • ECMAScript 6
    • 2016
      • ECMAScript 7
  • ES Next
    • = babel ?

How

  • 从需求到实现(从怎么用到怎么实现)

cjs

  • 怎么用?
    • node 端
    • 组件是不是不用产出 cjs 产物?
      • 不是,比如要支持 ssr
  • 怎么产生?倾向后者。
    • babel 直接转,比如把 src 转成 cjs 或 lib,多文件,然后 package.json 里配 lib
    • rollup 转,单文件,比如生成 dist/[name].js
      • 可以区分 development 和 production
      • 可以有 proxy 层,自动引入 dev 或 prod 版本
  • 注意点
    • external dependencies + peerDependencies

esm

  • 怎么用?
    • webpack(浏览器端)
    • 浏览器直接用
      • script type="module"
    • node 端?
  • 为什么用?
    • 新版方案,解决 commonjs 和 amd 的方案
    • tree shaking,因为是静态的产出
  • 怎么产生?
    • babel 转,比如把 src 转成 es,多文件,然后 package.json 里配 es
    • rollup 转,单文件,比如生成 dist/[name].esm.js
      • esm 已经可以做 tree-shaking,所以不需要产生多个文件,即可实现按需
      • 单文件在 webpack 使用时更快,因为少了文件系统 io
  • 注意点
    • external dependencies + peerDependencies
    • 根据库的实际情况考虑是否配 sideEffect: false 或者 sideEffect: [文件1, 文件2]

umd

  • 怎么用?
    • 浏览器直接引
  • 怎么产生
    • rollup
      • 单文件,比如生成 dist/[name].umd.js
      • 同时生成 min 文件,比如 dist/[name].umd.min.js
      • 然后在 package.json 里配 unpkg 或 umd:main 指向他
    • webpack
      • 感觉会慢且大
    • browserify
      • 过时
  • 注意点
    • 只 external peerDependencies,不 external dependencies
      • 比如我们通常要 external react, react-dom, antd, dva 等
      • rollup 里通过 globals 实现

社区的库是怎么用的?

  • htm
  • redux
    • 基于 rollup
    • 打出以下格式
      • lib/redux.js
        • commonjs (cjs)
        • external 依赖
        • 不压缩
      • es/redux.js
        • es module
        • external 依赖
        • 不压缩
      • es/redux.mjs
        • 为浏览器用的 es module
        • es module
        • 不 external 依赖
        • replace NODE_ENV 为 production
        • 压缩
      • dist/redux.js
        • umd,暴露为 Redux 全局变量
        • replace NODE_ENV 为 development
        • 不压缩
      • dist/redux.min.js
        • umd,暴露为 Redux 全局变量
        • replace NODE_ENV 为 production
        • 压缩
  • react-router
    • cjs/react-router.js
      • commonjs
      • external 依赖
      • 同步生成 min 文件
    • esm/react-router.js
      • es module
      • external 依赖
      • babel 配 runtimeHelpers: true,并且加 @babel/transform-runtieme + useESModules: true
    • umd/react-router.js
      • globals = react: React
      • 对外露出 ReactRouter
      • 调 commonjs 插件把 commonjs 转成 esm,让 node_modules 下的模块也能走 tree-shaking
  • reach-router
    • es
      • 把 src 下的文件打到 es 目录下
      • 基于 babel,env + modules: false,不做 modules 转化
    • cjs
      • 把 src 下的文件打到 ./ 根目录
      • 基于 babel, env + modules: 'commonjs'
    • umd
      • umd/reach-router.js
        • 有 min 版本
        • 基于 rollup
        • globals 掉 react 和 react-dom
  • redux-saga
  • immer
    • dist/immer.js
      • cjs
      • 不压缩
    • dist/immer.umd.js
      • umd
      • 压缩
    • dist/immer.module.js
      • es
      • 不压缩
  • mobx
    • 把 src 生成 .build.es5 和 .build.es6
    • 生成以下文件
      • 基于 rollup
      • lib/mobx.js, cjs
      • lib/mobx.module.js, esm
      • lib/mobx.es6.js, esm
    • 生成 umd 包 lib/mobx.umd.js
      • 基于 browserify
    • 基于 envify 生成 lib/mobx.prod.js
    • 基于 uglifyjs 生成
      • lib/mobx.min.js
      • lib/mobx.umd.min.js
  • react
    • 也是基于 rollup,但太复杂,没时间看。。

方案

#1550 (comment)

@clock157
Copy link
Contributor Author

2018 年最后一刻,提交了一版。剩下的 2019优化下 😂

https://github.com/umijs/umi-plugin-library/pull/new/refactor/use_monorepo_manage_project

@clock157
Copy link
Contributor Author

clock157 commented Jan 1, 2019

@sorrycc
Copy link
Member

sorrycc commented Jan 11, 2019

已可用,后续改进在 https://github.com/umijs/umi-plugin-library/issues 跟进。

@sorrycc sorrycc closed this as completed Jan 11, 2019
@ql434
Copy link
Contributor

ql434 commented Apr 9, 2019

mark

@johanazhu
Copy link

开发的组件变多之后,性能上很卡,很吃内存

@dengnan123
Copy link

继续学习。

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

No branches or pull requests