🔥🔥🔥 隆重推出 ESBuild,编译速度飞快!!!
目前项目热更新速度越来越慢,因此出现了这篇文章,这是一篇教程文章,当前设置是基于公司开发环境,此示例是之前测试和操作的。本文教程代码与实际项目代码或存在一定差异,如果合作伙伴也想为公司项目引入esbuild打包,可以留言。
由于公司的项目比较老旧,我主要谈的是开发环境下的工作经验。
🔥 创建一个基本的 CRA 项目
让我们从创建一个基本的 React 项目开始。
yarn create react-app my-app
预览文件夹
创建测试项目之后,让我们看看引入 esbuild 需要解决哪些问题?
- 我们需要一个本地服务器来显示打包后的文件。
- 还需要一个用于解析命令行参数的库,以便传递开发环境所需的变量。
- 每次启动项目时,还需要删除最后一个打包的文件。
- 此外,还需要解决端口号的问题。
- 解决svg 图标问题。
- 引入 esbuild 用于打包。
上述问题解决后,我们就可以实现这个演示了。
🔥 下载依赖包
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";
// Create the server.
const bs = browserSync.create();
// Deconstructing environment variables
const { dev } = commandLineArgs({ name: "dev", type: Boolean });
// Delete the package folder from the public-dev folder
del.sync("./public-dev/dist");
// Start esbuild to build the package
(async () => {
const buildResult = await esbuild
.build({
format: "esm", // Sets the output format of the generated JavaScript file.
target: "es2017", // Compile to convert version
entryPoints: ["./src/index.jsx"], // Packed Entrance
outdir: "./public-dev/dist", // Output Directory
chunkNames: "chunks/[name].[hash]", // Packed out file name
incremental: dev, // Because we are listening for file changes to repack, and we want the development environment to use esbuild, dev is true.
loader: {
// This option changes the way the given input file is interpreted.
".svg": "text",
".png": "dataurl",
},
bundle: true, // Bundling files means inlining any imported dependencies into the file itself.
splitting: true, // Code splitting is currently only available for esm output format.
plugins: [svgrPlugin()],
inject: ["./public-dev/react-shim.js"], // Import React into esbuild as a global variable
})
.catch((err) => {
console.error(chalk.red(err));
process.exit(1);
});
console.log(chalk.green("The build has finished! 📦\n"));
// Get the port number that can be used
const port = await getPort({
port: getPort.makeRange(4000, 4999),
});
console.log(
chalk.cyan(
`Launching the Shoelace dev server at http://localhost:${port}! 🥾\n`
)
);
// Server initialization
bs.init({
startPath: "/", // Initial path
port, // Port number
logLevel: "silent", // Log level
logFileChanges: true, // Log file changes
notify: true, // Small pop-up notifications in the browser
single: true, // Provide separate index.html
server: {
baseDir: "public-dev", // Base Folder
index: "index.html", // Set the server's entry file
},
files: "src/", // Listening to files under src
});
// Listening for changes under the src folder
bs.watch(["src/"]).on("change", async (filename) => {
console.log(`Source file changed - ${filename}`);
// Repackaging
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 是可以的!如果您感兴趣,不妨尝试一下!