目前手中的项目热更新是越来越慢,所以才有了本片文章的出现,这是一篇教程文章,目前这套已经上来公司的开发环境,这个示例是之前为了测试而做的实验。本片教程的代码和真正引入项目中的代码还是有一定的差异,如果小伙伴们也想为公司的项目引入esbuild打包,可以留言评论。
由于公司的项目是个老项目,所以我主要解决了在开发环境的工作体验。
创建基础的CRA项目
首先我们先来创建一个基础的react项目。
yarn create react-app my-app
预览文件夹
在创建完毕测试项目之后我们来看看要引入esbuild要解决那些问题?
- 我们需要一个本地的服务器,将打包的文件展示出来。
- 还需要一个解析命令行参数的库,传递开发环境的变量。
- 还需每一次启动项目删除上一次打包的文件。
- 还需要解决端口号的问题。
- 解决svg的icon
- 引入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了! 如果感兴趣就快去试试吧!