🔥项目引入ESBuild,编译直接快上天!!

5,362 阅读5分钟

目前手中的项目热更新是越来越慢,所以才有了本片文章的出现,这是一篇教程文章,目前这套已经上来公司的开发环境,这个示例是之前为了测试而做的实验。本片教程的代码和真正引入项目中的代码还是有一定的差异,如果小伙伴们也想为公司的项目引入esbuild打包,可以留言评论。

由于公司的项目是个老项目,所以我主要解决了在开发环境的工作体验。

创建基础的CRA项目

首先我们先来创建一个基础的react项目。

yarn create react-app my-app

预览文件夹

2021-10-16 15.17.42.gif

在创建完毕测试项目之后我们来看看要引入esbuild要解决那些问题?

  1. 我们需要一个本地的服务器,将打包的文件展示出来。
  2. 还需要一个解析命令行参数的库,传递开发环境的变量。
  3. 还需每一次启动项目删除上一次打包的文件
  4. 还需要解决端口号的问题。
  5. 解决svg的icon
  6. 引入esbuild进行打包。

解决了上面的问题,我们就可以实现这个demo了。

下载依赖包

yarn add browser-sync --dev

这个包的主要作用就是创建服务器,将打包的文件渲染出来,并且监听指定文件中的文件变更,让esbuild重新打包。

yarn add chalk --dev

这个包主要的作用就是美化终端的字符样式。

yarn add command-line-args --dev

这是一个主要用于解析命令行参数的库,我们主要用它确认是否是开发环境。

yarn add del --dev

我们主要使用这个包进行对打包文件或文件夹的删除操作。

yarn add get-port@5.1.1 --dev

我们使用这个库主要用来获取当前TCP可用的端口号。我没有安装最新版,因为最新版对Node.js有要求,我的node版本是 v12.18.3,而它的预期node版本为:“^12.20.0 || ^14.13.1 || >=16.0.0”。

我们复制public文件夹,重命名为public-dev, 这个文件夹中的index.html为我们程序的入口。

yarn add --dev esbuild-plugin-svgr

esbuild的插件,增加了对*.svg文件导入作为 React 组件的支持。

yarn add esbuild --dev

最后就是安装esbuild。

修改 package.json

    "scripts": {
        ...
+++     "dev": "node devBuild.js --dev"
      },
      ...
+++ "type": "module"

创建 devBuild.js

更改完毕package.json文件,接下来在根文件夹下创建 devBuild.js。

import browserSync from "browser-sync";
import chalk from "chalk";
import commandLineArgs from "command-line-args";
import del from "del";
import esbuild from "esbuild";
import getPort from "get-port";
import svgrPlugin from "esbuild-plugin-svgr";
// 创建服务器。
const bs = browserSync.create();
// 解构环境变量
const { dev } = commandLineArgs({ name: "dev", type: Boolean });
// 删除文件夹 public-dev 中的打包文件夹
del.sync("./public-dev/dist");

// 开始 esbuild 打包
(async () => {
  const buildResult = await esbuild
    .build({
      format: "esm", // 设置生成的 JavaScript 文件的输出格式。
      target: "es2017", // 编译转化版本
      entryPoints: ["./src/index.jsx"], // 打包入口
      outdir: "./public-dev/dist", // 输出目录
      chunkNames: "chunks/[name].[hash]", // 打包出来的文件名
      incremental: dev, // 因为我们监听文件的改变重新打包,而且我们要开发环境使用esbuild 所以 dev 为 true
      loader: {
        // 此选项更改给定输入文件的解释方式。
        ".svg": "text",
        ".png": "dataurl",
      },
      bundle: true, // 捆绑文件意味着将任何导入的依赖项内联到文件本身中。
      splitting: true, // 代码拆分目前仅适用于esm输出格式。
      plugins: [svgrPlugin()],
      inject: ["./public-dev/react-shim.js"], // 将 React 作为全局变量导入esbuild
    })
    .catch((err) => {
      console.error(chalk.red(err));
      process.exit(1);
    });
  console.log(chalk.green("The build has finished! 📦\n"));
  // 获取可以使用的端口号
  const port = await getPort({
    port: getPort.makeRange(4000, 4999),
  });

  console.log(
    chalk.cyan(
      `Launching the Shoelace dev server at http://localhost:${port}! 🥾\n`
    )
  );
  // 服务器初始化
  bs.init({
    startPath: "/", // 初始路径
    port, // 端口号
    logLevel: "silent", // 日志级别
    logFileChanges: true, // 日志文件更改
    notify: true, // 浏览器中的小弹出通知
    single: true, // 提供单独的 index.html
    server: {
      baseDir: "public-dev", // 基础文件夹
      index: "index.html", // 设置服务器的入口文件
    },
    files: "src/", // 监听 src 下的文件
  });

  // 监听 src 文件夹下的更改
  bs.watch(["src/"]).on("change", async (filename) => {
    console.log(`Source file changed - ${filename}`);
    // 重新打包
    buildResult.rebuild();
  });
})();

index.html

因为我不想直接在public文件下面改东西,所以我直接复制了public文件夹重命名为public-dev。为什么这么做呢?主要是不想和webpack打包的文件有交集。所以干脆直接复制一个文件夹。

在index.html 文件中 我们要引入打包好的 css和 js。这里在引入js时要注意,一定要使用ESM的方式引入。否则就会报错!!!

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="theme-color" content="#000000" />
  <meta name="description" content="Web site created using create-react-app" />
  <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
++  <link rel="stylesheet" type="text/css" href="./dist/index.css" />
  <title>React App</title>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>
++  <script type="module">
++    import './dist/index.js'
++  </script>
</body>

</html>

将组件的后缀名改为.jsx

react-shim.js

创建这个文件的主要作用就是将React作为全局变量导入esbuild中,这样就可以不需要在每个组件中引入react了。

import * as React from "react";
export { React };

修改 App.jsx

这里主要是需改了 svg 的使用方法。因为要符合 esbuild-plugin-svgr 这个插件的用法。

还有一个至关重要的就是,要将所有组件的后缀名有之前的js改为jsx。

++ import Logo from "./logo.svg";
import "./App.css";

function App() {
  return (
    <div className="App">
      <header className="App-header">
++        <Logo className="App-logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

至此,在CRA中引入esbuild就Ok了! 如果感兴趣就快去试试吧!

预览 demo

2021-10-16 18.29.06.gif

往期精彩