使用dumi搭建React 组件库并发布包

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用dumi搭建React 组件库并发布包相关的知识,希望对你有一定的参考价值。

参考技术A 前情:原先在github找个别人写好的组件库研究搭建的webpack配置,结果很多问题,经过一天的修修改改才能install、build及link。研究了一天后了解到dumi,为组件开发场景而生的文档工具。具体的搭建可以查看下文的链接,就不献丑了。
dumi 文档: https://d.umijs.org/zh-CN

首先使用npm run build完成构建打包
再在组件库目录下执行:npm link
最后在本地的其他项目下执行:npm link [组件库的packagejs的name]

场景描述:现有项目 my-app 及 组件库 dumi-ui(package文件里的name:dumi-ui)

注意:设置了淘宝镜像会影响登录,如果登录不成功可以试一下

dumi组件库打包总结

最近在做页面抽成组件然后发布,期间也是遇到了很多问题和坑,现在顺便分享一下。

dumi官网

dumi为组件开发场景而生的文档工具,这里注重分享打包的过程,

father

dumi使用father打包,father文档

1 使用rollup打包的时候报错。

father提供了几种打包的方式,umd, cjs, esm。
也支持使用rollup或者babel来打包成cjs/esm。
一开始选择的是rollup来打包。
出现的问题:

  • rollup只支持esmodule,不支持commonjs,如果你的组件库引用了类似于lodash的库,lodash是commonjs的,就会报错。这时候可以配置extraExternals。
  • 比如我的组件库使用了lodash.debounce和lodash的throttle方法,
export default 
  cjs:  type: 'rollup' ,
  esm: 
    type: 'rollup',
   
  ,
 cssModules: true,
	extraExternals: [
    'lodash.debounce',
    'lodash.throttle',
  ],

  • extraExternals表示为rollup模式配置额外的external。这样debounce的代码不会被打包进index.js,而是换成了
var debounce = require('lodash.debounce');
var throttle = require('lodash.throttle');

直接require。

2 peerDependencies和dependencies

一文搞懂peerDependencies
假设denpendencies是这样的

  dependencies: 
  "ahooks": "^2.10.12",
    "antd": "^4.19.3",
    "crypto-js": "^4.1.1",
    "react": "^16.12.0",
    

这时候外部引用的时候,不管版本是否一致,都会打包两份react,两份antd。
而使用了peerDependencies之后

peerDependencies: 
 "ahooks": "^2.10.12",
    "antd": ">=4.19.3",
    "crypto-js": "^4.1.1",
    "react": ">=16.12.0",
,
dependencies: 
 "ahooks": "^2.10.12",
    "antd": ">=4.19.3",
    "crypto-js": "^4.1.1",
    "react": ">=16.12.0",
    

比如当外部的react版本是17的,就满足条件,那么组件库不会多打包一份react代码,而是直接使用外部引用项目的react。

  • 这里i还有一个注意的点,配置了peerDependencies之后,不能配置webpack的resolve.modules去指定第三方库的位置

3 组件库配置antd样式前缀问题

因为是从页面抽离成组件,所以一开始是有配置antd样式前缀的,但是打包成组件库之后便无法使用样式前缀了。

  • 原因:组件库依赖的antd,并不会在打包的时候直接将代码打包到输出产物。
  • 简单理解就是,antd的代码,是在外部引用组件库的时候,比较antd版本的区别,
  • 如果符合,那么组件库使用的antd就是项目的antd。而项目的antd我们无法控制他使用跟组件库一样的样式前缀。
  • 如果不符合,那么组件库会多打包出一份antd的代码,而这个antd同样是没有webpack来帮我们修改样式文件的前缀的。
  • 上面两种情况就会导致组件库手动修改的antd前缀修改,如自己定义的.ant-xxx的.ant会被修改前缀,但是引用的css/less文件的前缀还是.ant

使用babel打包代码

  • 使用rollup打包后的代码,全部都输出到一个文件,这也是rollup的特色。
  • 但是组件库的方式不适合使用rollup打包,不利于按需引入。
  • 引入一个组件,会导致全部都被引入,打包体积大大增加。比如一个组件依赖了一些大一点的库,但是我引入了其他的一个组件,也会导致没引入的组件和他依赖的库都被打包了。
  • 使用rollup打包后的体积:

test就是引入组件的页面,vendors~test…是组件库依赖的第三方文件,其中就包括没有引用的组件的依赖也被打包了。

改造,使用babel打包代码。参考antd的代码结构。
 cjs:  type: 'babel', lazy: true ,
  esm: 
    type: 'babel',
    //importLibToEs: true,
  ,

cjs打包后的代码在lib,esm打包后的代码在es。
package.json配置

"main": "lib/index.js",
 "module": "es/index.js",

main字段,会在外部项目引入组件库的时候,当打包的时候就会找到lib/index.js文件,就是cjs的方式。
module字段,会在外部项目引入组件库的时候,当本地启动的时候,就会找到es/index.js文件。

使用了babel之后,打包后的代码结构如

不会将所有代码打包到一个文件去了。
为了配合babel-plugin-imports插件实现按需引入,我们的文件命名和目录结构选择跟antd类似的即可。

babel打包遇到路径别名问题。

babel形式的打包,如果遇到了’@/xx’,他不会解析@,这时候就需要另一个插件来帮忙了。

babel-plugin-module-resolver

 extraBabelPlugins: [
    [
      'import',
      
        libraryName: 'antd',
        //libraryDirectory: 'es',
        style: true,
      ,
    ],
   [
       require.resolve('babel-plugin-module-resolver'),
      
        root: ['./'],
        alias: 
         '@': './es',
         ,
      ,
     ],
  ],

他会将@转换成es的相对路径,但是对于cjs来说,文件夹是lib,所以这样配也有问题,暂时没有找到好的解决办法,所以将只能将别名一一改掉,如果只需要打包一种形式的,就可以使用该插件,如只打包esm。

改进后效果:

跟上面的例子一样,正常引入一个组件。然后在.babelrc.js文件中配置bable-plugin-imports,npm上有他的很多配置。

他可以帮助我们转化代码实现按需引入,比如上面的import button,到打包后就转成require(‘antd/lib/button’)。
这时候我们配置

module.exports = 
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    [
      "import",
      
        "libraryName": "antd",
        "style": true
      
    ],
    // 配置我们的组件库按需引入
    [
      "import",
      
        "libraryName": "xxxx",
        "libraryDirectory": "lib",
        //"camel2DashComponentName": false,
        // "customName": (name, file) => 
        //   name = name[0].toLowerCase() + name.slice(1)
        //   return `xxxx/$name`;
        // 
      ,
      "xxxx"
    ]
  ]


然后,正常打包,
再对比使用rollup打包的组件库

左边是rollup,右边是babel打包加按需加载的效果。

可以看到,test是引用了组件的页面,

  • 在rollup下,所有的包括组件库依赖的第三方依赖也会被打包进来。
  • 在babel打包+babel-plugin-import插件的帮助下,只打包进了引用的组件。

如果没有使用babel-plugin-import

打包后的代码也是全量引入。

以上是关于使用dumi搭建React 组件库并发布包的主要内容,如果未能解决你的问题,请参考以下文章

dumi组件库打包总结

组件库文档工具 dumi 的介绍与对比及踩坑小结

组件库文档工具 dumi 的介绍与对比及踩坑小结

组件库文档工具 dumi 的介绍与对比及踩坑小结

React 组件库框架搭建

可能是最详细的React组件库搭建总结