使用 esbuild 来打包一个 React 库

395 篇文章 34 订阅

前言
esbuild 的大名相信大家也有耳闻,它是一个非常快的 Javascript 打包工具,用 GO 语言编写,是 figma 的 cto Evan Wallace 著作的,一个 30 min 的 webpack 项目用 esbuild 可以分钟级运行。本文将记录使用 esbuild 来打包一个 React 库。

需求
这里我打算开发一个 react-checkbox 为例

<input type="checkbox" checked={true}/>
<input type="checkbox" checked={false}/>
复制代码

因为 checkbox 只有两种值:选中(checked)或未选中(unchecked),在视觉上 checkbox 有三种状态:checked、unchecked、indeterminate(不确定的),在实现全选效果时,你可能会用到 indeterminate 属性, 对于indeterminate 这个状态无法在HTML中设置checkbox的状态为indeterminate。因为HTML中没有indeterminate这个属性,你可以通过 Javascript 脚本来设置

const checkbox = document.getElementById("checkbox");
checkbox.indeterminate = true;
复制代码

效果如下:

在这里插入图片描述

所以我们的需求是需要给 checkbox 增加一个 indeterminate 属性

项目初始化
首先我们来创建一个文件夹并且初始化 npm.

mkdir react-checkbox && cd react-checkbox && npm init --yes
复制代码

我们使用 typescript,当然也要安装 react 和 react-dom

npm i esbuild typescript @types/react @types/react-dom --save-dev
复制代码

然后我们在根目录下创建文件 ./tsconfig.json

{
  "compilerOptions": {
    "outDir": "./lib",
    "target": "es6",
    "module": "commonjs",
    "noImplicitAny": true,
    "strictNullChecks": true,
    "declaration": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "jsx": "react-jsx",
    "typeRoots": ["node_modules/@types"]
  },
  "include": ["./src/**/*.tsx", "./src/**/*.ts", "example/index.tsx"],
  "exclude": ["node_modules"]
}

复制代码

代码实现
接下来我们创建 src/checkbox.tsx,下面是实现代码

import { ReactElement, CSSProperties, ChangeEvent } from "react";

export interface CheckboxProps {
  checked?: boolean;
  indeterminate?: boolean;
  className?: string;
  style?: CSSProperties;
  disabled?: boolean;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}

const Checkbox = ({
  checked = false,
  indeterminate = false,
  className = "",
  style = {},
  disabled = false,
  onChange,
}: CheckboxProps): ReactElement => {
  return (
    <input
      type="checkbox"
      className={className}
      style={style}
      ref={(input) => {
        if (input) {
          input.checked = checked;
          input.indeterminate = indeterminate as boolean;
          input.disabled = disabled as boolean;
        }
      }}
      onChange={(e) => {
        if (onChange) {
          onChange(e);
        }
      }}
    />
  );
};

export default Checkbox;

复制代码

很简单,直接使用 ref 设置 dom 属性就可以了。

代码打包
接着我们在项目根目录下建立./esbuild.js文件

写入打包配置

const esbuild = require('esbuild');

esbuild
    .build({
        entryPoints: ['src/checkbox.tsx'],
        outdir: 'lib',
        bundle: true,
        sourcemap: true,
        minify: true,
        splitting: true,
        format: 'esm',
        target: ['esnext']
    })
    .catch(() => process.exit(1));
复制代码

entryPoints 和 ourdir 指定需要将哪些文件输入和打包输出目录

bundle 代表是否递归引用打包文件。

sourcemap 代表是否生成 sourcemap 源映射文件

minify 代表是否压缩代码

splitting 代表

多入口的是否提取公共代码
是否将 import() 异步文件单独打包
target 定义了我们想要输出的 javascript 类型

format 是设置生成的 javascript 文件的输出格式, 有3个值可选,cjs、esm、iife

iife 格式代表“立即调用函数表达式”,可以在浏览器中运行。
cjs 格式代表“CommonJS”,在 node 中运行。
esm 格式代表“ECMAScript 模块”,既可以在浏览器中使用,也可以在 node 中使用
然后使用node ./esbuild.js 就可以打包成功了,但是一个typescript项目最终要提供d.ts出来给外部用,但是esbuild最终 build 出来的内容中并没有d.ts,因此我们要单独运行tsc,稍微修改一下上面的代码。

我们在 package.json 中加入如下代码

"scripts": {
    "ts-types": " tsc --emitDeclarationOnly --outDir lib",
    "build": "rm -rf lib && node ./esbuild.js && npm run ts-types"
 },
复制代码

还是使用 tsc 的 emitDeclarationOnly 来生成 d.ts

然后我们在package.json 中指定入口文件

"main": "lib/checkbox.js",
"module": "lib/checkbox.js",
"types": "lib/checkbox.d.ts",
"files": [
    "lib"
 ]
复制代码

至此打包完成,如果需要发包,我们要还需要添加测试。

本地预览
当然我们的项目需要预览,建立一个 example/index.tsx 文件

import React, { ReactElement } from "react";
import { render } from "react-dom";

import Checkbox from "../src/checkbox";

function App(): ReactElement {
  return (
    <div>
      <Checkbox></Checkbox>
      <Checkbox checked={true}></Checkbox>
      <Checkbox indeterminate={true}></Checkbox>
    </div>
  );
}

render(<App />, document.querySelector("#root"));

复制代码

这个文件作为预览 js 的打包入口;

然后建立一个./example/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>checkbox</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="./bandle.js"></script>
  </body>
</html>
复制代码

这个html 就引用了 bandle.js,接下来,我们需要打包出一个 bandle.js

建立一个./example/esbuild.js 文件,代码如下:

const esbuild = require("esbuild");
const path = require("path");

esbuild
  .build({
    entryPoints: [path.resolve(__dirname, "./index.tsx")],
    outfile: path.resolve(__dirname, "./bandle.js"),
    bundle: true,
    minify: true,
    target: ["esnext"],
    watch: {
      onRebuild(error, result) {
        if (error) console.error("watch build failed:", error);
        else console.log("watch build succeeded:", result);
      },
    },
    format: "esm",
  })
  .then((result) => {
    console.log("watching...");
  });
复制代码

这个 esbuild.js 是打包预览文件的配置,这里开启了监听模式,这样修改 js 就会自动打包了。

然后在 package.json 的 scripts 中添加 :

"start": " node ./example/esbuild.js"
复制代码

接着修改 js 就会自动打包了,我们一起来看下效果,唯一的缺点是没有热更新,我们需要手动刷新。

在这里插入图片描述

小结
本文结合 react 对 esbuid 这个打包工具进行了简单使用;

esbuid 的缺点

es5 支持不是很好,不支持将 es6 转 es5。
esbuild 没有提供 AST 的操作能力 (如 babel-plugin-import)
esbuild 的优点

esbuild 除了打包速度飞快,对于ts、css 文件的处理也是非常友好,不需要设置各种 loader,配置简单。如果你的项目不需要兼容 es5、完全可以将一些 Monorepo 的 js 库迁移到 esbuild。

最后
如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star: https://gitee.com/ZhongBangKeJi不胜感激 !

PHP学习手册:https://doc.crmeb.com
技术交流论坛:https://q.crmeb.com

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值