react发布一个组件库 系列篇(一)

前言

经常使用别人写好的组件库,然后安装引入使用即可。比如:

npm install beautiful-table
import BeautifulTable from 'beautiful-table'

function App() {
  return (
    <div className="App">
      <BeautifulTable/>
    </div>
  );
}

export default App;

这对于我们开发这来说,非常的舒服对吧!
那么你有考虑这些组件是如何编写的吗?
接下来,我将从头到尾的,写一个demo组件库,并且发版到npm平台上!

这个组件我们起名字 哈喽组件, 即 hello-componet简写下 hello-cmp。
然后我们再新建一个react简单项目 起名为myApp,在这个项目使用组件库hello-cmp。

思考:可否将源代码直接发包

有了这个想法很好,这就是编写组件库的第一步!
这是最简单的方式,不用任何编译工具进行转换,直接将源码发布到npm上。

├── index.jsx                 组件核心
├── package.json
// index.jsx
export default (props)=>{
    return <div>你好啊,{props.msg}</div>
}
// package.json
{
  "name": "hello-cmp",
  "version": "0.0.1-beta.2",
  "description": "",
  "main": "index.jsx",
  "keywords": [],
  "author": "",
  "license": "ISC"
}

接下来我们尝试在一个现有的react项目中安装并使用下这个包

// src/app.js
import HelloCmp from 'hello-cmp'

function App() {
  return (
    <div className="App">
      <HelloCmp msg="张三"/>
    </div>
  );
}

export default App;

xx,尴尬的事情发生了,页面以及启动控制台底部都输出了相同的错误

Compiled with problems:X

ERROR in ./node_modules/hello-cmp/index.jsx 2:11

Module parse failed: Unexpected token (2:11)
File was processed with these loaders:
 * ./node_modules/source-map-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
| export default (props)=>{
>     return <div>你好啊,{props.msg}</div>
| }

这是因为默认情况下,项目(里的编译工具如babel、esbuild等)均忽略node_modules里的代码处理
而react脚手架创建的项目中 将jsx等文件的解析器用的就是是babel,所以在babel-loader没有处理jsx转换为js的情况下,交给下一个loader即source-map-loader处理。
可loader链里的source-map-loader只能处理js文件,遇到了没有经过babel-loader处理的hello-cmp组件库里的jsx元素交给它处理的时候 自然就崩溃了。

知道原因,自然就好处理了,我们修改当前react项目myApp的webpack配置里的babel-loader,将其不要忽略包hello-cmp的编译即可。

npm run eject之后,修改webpack配置文件如下:修改rules字段,让只编译src扩充到也编译你的包,即可。

eject后查看webpack.config.js 也可以发现react脚手架创建的项目中 将jsx等文件的解析器用的loader是babel-loader,而babel-loader默认即忽略node_modules

// webpack.config.js
{
    test: /\.(js|mjs|jsx|ts|tsx)$/,  
    // 原来这有这个 include: paths.appSrc,
    // 其中paths.YourCmp即在path中定义的你组件包的路径 resolveApp('node_modules/YourCmp')
    include: [paths.appSrc,paths.YourCmp], 
    ...
}

再次启动,自动打开浏览器,访问页面,开心的一幕出现了

你好啊,张三

结论

1、虽然 npm 中的 package 没有明确规范需要编译成 es5/es3的语法,但是目前事实就是绝大部分公开的 package 都是编译到这个规范的,所以已经是一个事实标准了,如果你的包代码是低版本的js 你当然可以直接发版源码。

2、但是如果是你用到了jsx、ts、vue或用到了esnext最新版本等(非js语言的),别人下载引入你的包 自然也无法开箱即用了。
a、使用者下载安装你的包后,仍然还需要去安装对用的编译器去编译你的代码之后才可以使用。
b、而且很多编译工具默认都会忽略node_modules下的代码,也意味着你还要去设置它(某编译器的)include。
与其麻烦每个使用者一顿猛如虎的操作,还不如库作者直接处理好供我们使用。

3、我司内部的 package 为了方便调试和学习,都是直接暴露源码的,那就需要手动修改编译工具配置 include 相应的包了,大家也可能会遇到这种情况,那发布源码也是请情有可原

其它

如果你的代码里如果只有js+esm,直接发包就可以了,这个不用编译再发包也是可以的。
因为你开发的插件或组件库, 最终还要引入到一个项目中的。
这个项目多半是脚手架创建的 或者至少支持webpack的。
而你组件库或插件里的 esm最终会被当前项目的webpack处理(webpack就是干这个的),webpack并不会忽略node_modules。

比如:以下代码可以直接发包源码,在项目使用就行(放在2020年之前不行,仍然需要通过babel打包,那个时候esm上不被认可,大家还是通过babel将其转换成cjs)

├── index.js 
├── calculator.js
├── package.json
// index.js
import {add} from './calculator'
export default add(1,2)
// calculator.js
export function add(x,y){
    return x+y;
}
posted @ 2022-08-19 15:24  丁少华  阅读(292)  评论(0)    收藏  举报