一个非常快的js打包工具
yarn add esbuild
npm install esbuild
bundler 默认输出浏览器的代码,所以不需要额外的配置就可以上手.对于开发构建,您可能希望使用 --sourcemap 启用源映射,而对于生产构建,您可能希望使用 --minify 启用缩小。您可能还想为您支持的浏览器配置目标环境。所有这些可能看起来像这样:
require('esbuild').buildSync({
entryPoints: ['app.jsx'],
bundle: true,
minify: true,
sourcemap: true,
target: ['chrome58', 'firefox57', 'safari11', 'edge16'],
outfile: 'out.js',
})
有时候一个你想使用的包可能会导入另一个只有node才有的包,比如内置的路径包。发生这种情况时,您可以使用 package.json 文件中的浏览器字段,将包替换为浏览器友好的替代方案,如下所示:
{
"browser": {
"path": "path-browserify"
}
}
您要使用的某些 npm 包可能不是设计为在浏览器中运行的。有时您可以使用 esbuild 的配置选项来解决某些问题并成功地捆绑包。未定义的全局变量可以在简单情况下用 define功能替换,或者在更复杂情况下用inject功能替换。
尽管在使用 node 时不需要 bundler,但有时在 node 中运行之前使用 esbuild 处理代码仍然是有益的。Bundling 可以自动剥离 TypeScript 类型,将 ECMAScript 模块语法转换为 CommonJS,并将新的 JavaScript 语法转换为特定版本节点的旧语法。并且在发布之前捆绑包可能是有益的,这样下载量就更小,加载时从文件系统读取的时间也更少。
如果您正在捆绑将在 node 中运行的代码,您应该通过将 --platform=node 传递给 esbuild 来配置平台设置。这同时将一些不同的设置更改为节点友好的默认值。例如,所有内置于节点的包(如 fs)都会自动标记为外部包,因此 esbuild 不会尝试捆绑它们。此设置还会禁用 package.json 中浏览器字段的解释。
如果您的代码使用在您的 node 版本中不起作用的较新 JavaScript 语法,您将需要配置 node 的目标版本:
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
platform: 'node',
target: ['node10.4'],
outfile: 'out.js',
})
有时,您要使用的包包含由于某种原因无法捆绑的代码。这方面的一个示例是带有本机扩展(如 fsevents)的包。或者,您可能出于其他原因希望从捆绑包中排除一个包。这可以通过将包标记为外部来完成:
require('esbuild').buildSync({
entryPoints: ['app.jsx'],
bundle: true,
platform: 'node',
external: ['fsevents'],
outfile: 'out.js',
})
esbuild 的 API 中有两个主要的 API 调用:transform 和 build。了解您应该使用哪一个很重要,因为它们的工作方式不同。
形式 --foo 用于启用布尔标志,例如 --minify; 形式 --foo=bar 用于具有单个值且仅指定一次的标志,例如 --platform=;并且形式 --foo:bar 用于具有多个值并且可以多次重新指定的标志,例如 --external:
Transform API调用对单个字符串进行操作,不需要访问文件系统。非常适合在没有文件系统的环境中使用或作为另一个工具链的一部分
require('esbuild').transformSync('let x: number = 1', {
loader: 'ts',
})
{
code: 'let x = 1;\n',
map: '',
warnings: []
}
Build API调用对文件系统中的一个或多个文件进行操作。这使得文件可以相互引用,并被编译在一起。下面是个简单例子:
require('fs').writeFileSync('in.ts', 'let x: number = 1')
require('esbuild').buildSync({
entryPoints: ['in.ts'],
outfile: 'out.js',
})
捆绑文件意味着将任何导入的依赖项内联到文件本身中.此过程是递归的,因此依赖项(等等)的依赖项也将被内联。默认情况下,esbuild 不会捆绑输入文件。必须像这样显式启用捆绑
require('esbuild').buildSync({
entryPoints: ['in.js'],
bundle: true,
outfile: 'out.js',
})
不可分析的bunble : 与 esbuild 捆绑仅适用于静态定义的导入(即当导入路径是字符串文字时)。在运行时定义的导入(即依赖于运行时代码评估的导入)不会被捆绑,因为捆绑是一个编译时操作.
解决此问题的方法是将包含此问题代码的包标记为外部包,使其不包含在包中。然后,您需要确保外部包的副本在运行时可用于您的捆绑代码。
一些打包器(例如 Webpack)尝试通过将所有可能可访问的文件包含在包中然后在运行时模拟文件系统来支持这一点.但是,运行时文件系统仿真超出了范围,不会在 esbuild 中实现。如果您确实需要捆绑执行此操作的代码,则可能需要使用另一个捆绑器而不是 esbuild。
此功能提供了一种用常量表达式替换全局标识符的方法。它可以是一种在构建之间更改某些代码行为而不更改代码本身的方法:
let js = 'DEBUG && require("hooks")'
require('esbuild').transformSync(js, {
define: { DEBUG: 'true' },
})
替换表达式必须是 JSON 对象(空值、布尔值、数字、字符串、数组或对象)或单个标识符。数组和对象以外的替换表达式是内联替换的,这意味着它们可以参与常量折叠。数组和对象替换表达式存储在一个变量中,然后使用标识符引用而不是内联替换,这避免了替换值的重复副本,但意味着这些值不参与常量折叠。
如果您想用字符串文本替换某些内容,请记住传递给 esbuild 的替换值本身必须包含引号。省略引号意味着替换值是一个标识符
引号在不同操作系统中有不同的作用 用命令行去写命令会存在兼容性问题,一般用js文件执行esbuild去消除这些兼容问题
这是一个文件数组,每个文件都用作捆绑算法的输入。它们被称为“入口点”,因为每个入口点都是被评估的初始脚本,然后加载它所代表的代码的所有其他方面。不是使用
require('esbuild').buildSync({
entryPoints: ['home.ts', 'settings.ts'],
bundle: true,
write: true,
outdir: 'out',
})
这将生成两个输出文件,out/home.js 和 out/settings.js,分别对应两个入口点 home.ts 和 settings.ts
此外,您还可以使用替代入口点语法为每个单独的入口点指定完全自定义的输出路径:
require('esbuild').buildSync({
entryPoints: {
out1: 'home.js',
out2: 'settings.js',
},
bundle: true,
write: true,
outdir: 'out',
})
这将生成两个输出文件,out/out1.js 和 out/out2.js 分别对应两个入口点 home.ts 和 settings.ts
您可以将文件或包标记为外部以将其从构建中排除
这有多种用途。首先,它可用于从您的包中修剪不必要的代码,以便您知道永远不会执行的代码路径。例如,一个包可能包含只在 node 中运行的代码,但你只能在浏览器中使用该包。它还可用于在运行时从无法捆绑的包中导入 node 中的代码。例如, fsevents 包包含一个本机扩展,而 esbuild 不支持该扩展。将某些内容标记为外部内容如下所示:
require('fs').writeFileSync('app.js', 'require("fsevents")')
require('esbuild').buildSync({
entryPoints: ['app.js'],
outfile: 'out.js',
bundle: true,
platform: 'node',
external: ['fsevents'],
})
您还可以在外部路径中使用 * 通配符将匹配该模式的所有文件标记为外部文件。
这将设置生成的 JavaScript 文件的输出格式。 目前可以配置三个可能的值:iife、cjs 和 esm。 如果未指定输出格式,esbuild 会在启用 bundling(如下所述)的情况下为您选择一种输出格式,或者如果禁用 bundling则不进行任何格式转换。
let js = 'alert("test")'
let out = require('esbuild').transformSync(js, {
format: 'iife',
})
process.stdout.write(out.code)
let js = 'export default "test"'
let out = require('esbuild').transformSync(js, {
format: 'cjs',
})
process.stdout.write(out.code)
let js = 'module.exports = "test"'
let out = require('esbuild').transformSync(js, {
format: 'esm',
})
process.stdout.write(out.code)
esm 格式既可以在浏览器中使用,也可以在node中使用,但是您必须将其作为模块显式加载。如果您从另一个模块导入它,这会自动发生。
在浏览器中,您可以使用 加载模块。
在 node 中,您可以使用 node --experimental-modules file.mjs 加载模块。请注意,节点需要 .mjs 扩展名,除非您在 package.json 文件中配置了 “type”: “module”。您可以使用 esbuild 中的 out 扩展名设置来自定义 esbuild 生成的文件的输出扩展名。
此选项允许您使用来自另一个文件的导入自动替换全局变量。这可能是一个有用的工具,可以将您无法控制的代码适应新环境。例如,假设您有一个名为 process-shim.js 的文件,它导出一个名为 process 的变量:
// process-shim.js
export let process = {
cwd: () => ''
}
// entry.js
console.log(process.cwd())
require('esbuild').buildSync({
entryPoints: ['entry.js'],
bundle: true,
inject: ['./process-shim.js'],
outfile: 'out.js',
})
// out.js
let process = {cwd: () => ""};
console.log(process.cwd());
define vs inject
// process-shim.js
export function dummy_process_cwd() {
return ''
}
// entry.js
console.log(process.cwd())
require('esbuild').buildSync({
entryPoints: ['entry.js'],
bundle: true,
inject: ['./process-shim.js'],
outfile: 'out.js',
})
// out.js
let process = {cwd: () => ""};
console.log(process.cwd());
JSX 的自动导入:您可以使用注入功能自动提供 JSX 表达式的实现。比如你可以自动导入react包来提供React.createElement等功能。
此选项更改给定输入文件的解释方式。例如,js 加载器将文件解释为 JavaScript,而 css 加载器将文件解释为 CSS。有关所有内置加载器的完整列表,请参阅内容类型页面。
为给定的文件类型配置加载器允许您使用导入语句或 require 调用加载该文件类型。例如,将 .png 文件扩展名配置为使用数据 URL 加载程序意味着导入 .png 文件会为您提供一个包含该图像内容的数据 URL:
import url from './example.png'
let image = new Image
image.src = url
document.body.appendChild(image)
import svg from './example.svg'
let doc = new DOMParser().parseFromString(svg, 'application/xml')
let node = document.importNode(doc.documentElement, true)
document.body.appendChild(node)
上面的代码可以像这样使用构建 API 调用进行捆绑
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
loader: {
'.png': 'dataurl',
'.svg': 'text',
},
outfile: 'out.js',
})
如果您将构建 API 与来自 stdin 的输入一起使用,则此选项的指定方式不同,因为 stdin 没有文件扩展名。使用构建 API 为 stdin 配置加载器如下所示
require('esbuild').buildSync({
stdin: {
contents: 'import pkg = require("./pkg")',
loader: 'ts',
resolveDir: __dirname,
},
bundle: true,
outfile: 'out.js',
})
转换 API 调用只需要一个加载器,因为它不涉及与文件系统的交互,因此不处理文件扩展名。为转换 API 配置加载器(在本例中为 ts 加载器)如下所示:
let ts = 'let x: number = 1'
require('esbuild').transformSync(ts, {
loader: 'ts',
})
{
code: 'let x = 1;\n',
map: '',
warnings: []
}
Minify
启用后,生成的代码将被缩小而不是漂亮的打印。压缩代码通常等同于非压缩代码,但更小,这意味着它下载速度更快但更难调试。通常你会在生产中缩小代码而不是在开发中。
在 esbuild 中启用缩小如下所示:
var js = 'fn = obj => { return obj.x }'
require('esbuild').transformSync(js, {
minify: true,
})
{
code: 'fn=n=>n.x;\n',
map: '',
warnings: []
}
此选项组合执行三个独立的操作:删除空格,将语法重写为更紧凑,并将局部变量重命名为更短。通常你想要做所有这些事情,但如果需要,也可以单独启用这些选项:
var js = 'fn = obj => { return obj.x }'
require('esbuild').transformSync(js, {
minifyWhitespace: true,
})
{
code: 'fn=obj=>{return obj.x};\n',
map: '',
warnings: []
}
require('esbuild').transformSync(js, {
minifyIdentifiers: true,
})
{
code: 'fn = (n) => {\n return n.x;\n};\n',
map: '',
warnings: []
}
require('esbuild').transformSync(js, {
minifySyntax: true,
})
{
code: 'fn = (obj) => obj.x;\n',
map: '',
warnings: []
}
这些相同的概念也适用于 CSS,而不仅仅是 JavaScript:
var css = 'div { color: yellow }'
require('esbuild').transformSync(css, {
loader: 'css',
minify: true,
})
{
code: 'div{color:#ff0}\n',
map: '',
warnings: []
}
esbuild 中的 JavaScript 缩小算法通常生成的输出非常接近行业标准 JavaScript 缩小工具的缩小输出大小。该基准测试对不同缩小器之间的输出大小进行了示例比较。虽然 esbuild 不是所有情况下的最佳 JavaScript 缩小器(并且不会尝试成为),但它努力在大多数代码的专用缩小工具大小的百分之几内生成缩小的输出,当然,这样做比其他工具快得多。
注意事项:
// Direct eval (will disable minification for the whole file)
let result = eval(something)
您可能应该像这样编写代码,以便可以缩小代码:
// Indirect eval (has no effect on the surrounding code)
let result = (0, eval)(something)
此处提供了有关直接评估的后果和可用替代方案的更多信息。
esbuild 中的缩小算法尚未进行高级代码优化。特别是,以下代码优化对于 JavaScript 代码是可能的,但不是由 esbuild 完成的(不是详尽的列表)
此选项设置构建操作的输出目录。例如,此命令将生成一个名为out的目录:
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
outdir: 'out',
})
如果输出目录尚不存在,则会生成输出目录,但如果已包含某些文件,则不会清除该目录。任何生成的文件都会以静默方式覆盖同名的现有文件。如果您希望输出目录仅包含来自当前 esbuild 运行的文件,您应该在运行 esbuild 之前自己清除输出目录。
如果您的构建在不同的目录中包含多个入口点,则目录结构将从所有输入入口点路径中最低的公共祖先目录开始复制到输出目录中。例如,如果有两个入口点 src/home/index.ts 和 src/about/index.ts,则输出目录将包含 home/index.js 和 about/index.js。如果要自定义此行为,则应更改 outbase 目录。
此选项设置构建操作的输出文件名。这仅适用于有单个入口点的情况。如果有多个入口点,则必须改用 outdir 选项来指定输出目录。使用 outfile 看起来像这样:
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
outfile: 'out.js',
})
默认情况下,esbuild 的 bundler 被配置为生成用于浏览器的代码。如果您的捆绑代码打算在 node 中运行,您应该将平台设置为 node:
require('esbuild').buildSync({
entryPoints: ['app.js'],
bundle: true,
platform: 'node',
outfile: 'out.js',
})
当平台设置为浏览器时(默认值):
在开发过程中,进行更改时经常在文本编辑器和浏览器之间来回切换。在浏览器中重新加载代码之前手动重新运行 esbuild 很不方便。有几种方法可以自动执行此操作:
require('esbuild').serve({
servedir: 'www',
}, {
entryPoints: ['src/app.js'],
outdir: 'www/js',
bundle: true,
}).then(server => {
// Call "stop" on the web server to stop serving
server.stop()
})
在上面的例子中,你的 www/index.html 页面可以像这样引用 src/app.js 中的编译代码:
<script src="js/app.js"></script>
当您这样做时,每个 HTTP 请求都会导致 esbuild 重建您的代码并为您提供最新版本。因此,每次您重新加载页面时,js/app.js 将始终是最新的。请注意,尽管生成的代码似乎在 outdir 目录中,但它实际上从未使用 serve API 写入文件系统。相反,生成的代码阴影的路径(即优先于)servedir 和生成的文件中的其他路径直接从内存中提供。
这样做的好处是您可以在开发和生产中使用完全相同的 HTML 页面。在开发中,您可以使用 --servedir= 运行 esbuild,esbuild 将直接提供生成的输出文件。对于生产,您可以省略该标志,esbuild 会将生成的文件写入文件系统。在这两种情况下,您应该在开发和生产中使用完全相同的代码在浏览器中获得完全相同的结果。
默认情况下,端口会自动选择为第一个等于或大于 8000 的开放端口。端口号从 API 调用返回(或打印到 CLI 的终端),因此您可以知道要访问哪个 URL。端口号从 API 调用返回(或打印到 CLI 的终端),因此您可以知道要访问哪个 URL。如有必要,可以将端口设置为特定的内容(下面将进一步描述)。
require('esbuild').serve({
port: 8000,
}, {
entryPoints: ['src/app.js'],
bundle: true,
outfile: 'out.js',
}).then(server => {
// Call "stop" on the web server to stop serving
server.stop()
})
上面示例中的 API 调用将在 http://localhost:8000/out.js 提供 src/app.js 的编译内容.就像第一种方法一样,每个 HTTP 请求都会导致 esbuild 重建您的代码并为您提供最新版本,因此 out.js 将始终是最新的。然后,您的 HTML 文件(由另一个端口上的另一个 Web 服务器提供服务)可以像这样从您的 HTML 引用编译后的文件:
<script src="http://localhost:8000/out.js"></script>
在未启用 Web 服务器的情况下使用普通构建命令时,Web 服务器的 URL 结构与输出目录的 URL 结构完全相同。例如,如果输出目录通常包含一个名为 ./pages/about.js 的文件,则 Web 服务器将具有相应的 /pages/about.js 路径。
如果您想浏览 Web 服务器以查看哪些 URL 可用,您可以通过访问目录名而不是文件名来使用内置目录列表.例如,如果您在端口 8000 上运行 esbuild 的 Web 服务器,则可以在浏览器中访问 http://localhost:8000/ 以查看 Web 服务器的根目录。从那里您可以单击链接以浏览 Web 服务器上的不同文件和目录。
请注意,服务 API 是与构建 API 不同的 API 调用。这是因为启动一个长时间运行的 Web 服务器是不同的,足以保证不同的参数和返回值。服务 API 调用的第一个参数是带有服务特定选项的选项对象:
interface ServeOptions {
port?: number;
host?: string;
servedir?: string;
onRequest?: (args: ServeOnRequestArgs) => void;
}
interface ServeOnRequestArgs {
remoteAddress: string;
method: string;
path: string;
status: number;
timeInMS: number;
}
interface ServeResult {
port: number;
host: string;
wait: Promise<void>;
stop: () => void;
}
无法连接到 esbuild 的本地服务器来自定义服务器本身的行为。相反,应该通过在 esbuild 前面放置一个代理来自定义行为。这是一个简单的代理服务器示例,可帮助您入门。它添加了一个自定义的 404 页面,而不是 esbuild 的默认 404 页面:
const esbuild = require('esbuild');
const http = require('http');
// Start esbuild's server on a random local port
esbuild.serve({
servedir: __dirname,
}, {
// ... your build options go here ...
}).then(result => {
// The result tells us where esbuild's local server is
const {host, port} = result
// Then start a proxy server on port 3000
http.createServer((req, res) => {
const options = {
hostname: host,
port: port,
path: req.url,
method: req.method,
headers: req.headers,
}
// Forward each incoming request to esbuild
const proxyReq = http.request(options, proxyRes => {
// If esbuild returns "not found", send a custom 404 page
if (proxyRes.statusCode === 404) {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>A custom 404 page</h1>');
return;
}
// Otherwise, forward the response from esbuild to the client
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res, { end: true });
});
// Forward the body of the request to esbuild
req.pipe(proxyReq, { end: true });
}).listen(3000);
});
此代码在随机本地端口上启动 esbuild 的服务器,然后在端口 3000 上启动代理服务器。在开发过程中,您将在浏览器中加载 http://localhost:3000,它与代理通信。此示例演示在 esbuild 处理请求后修改响应,但您也可以在 esbuild 处理请求之前修改或替换请求。
你可以用这样的代理做很多事情
源映射可以更轻松地调试您的代码。它们对将生成的输出文件中的行/列偏移转换回相应原始输入文件中的行/列偏移所需的信息进行编码。如果您生成的代码与原始代码完全不同(例如,您的原始代码是 TypeScript 或您启用了缩小),这将非常有用。如果您更喜欢在浏览器的开发工具中查看单个文件而不是一个大的捆绑文件,这也很有用。
请注意,JavaScript 和 CSS 都支持源地图输出,并且相同的选项适用于两者。下面讨论 .js 文件的所有内容也同样适用于 .css 文件。
源映射生成有四种不同的模式:
require('esbuild').buildSync({
entryPoints: ['app.ts'],
sourcemap: true,
outfile: 'out.js',
})
require('esbuild').buildSync({
entryPoints: ['app.ts'],
sourcemap: 'external',
outfile: 'out.js',
})
require('esbuild').buildSync({
entryPoints: ['app.ts'],
sourcemap: 'inline',
outfile: 'out.js',
})
require('esbuild').buildSync({
entryPoints: ['app.ts'],
sourcemap: 'both',
outfile: 'out.js',
})
构建 API 支持上面列出的所有四种源映射模式,但转换 API 不支持链接模式。这是因为从转换 API 返回的输出没有关联的文件名。如果您希望转换 API 的输出具有源映射注释,您可以自己附加一个。另外,transform API 的 CLI 形式只支持 inline 模式,因为输出是写到 stdout 的,所以生成多个输出文件是不可能的。
在浏览器中,只要启用了源映射设置,浏览器的开发人员工具就会自动获取源映射。请注意,浏览器仅使用源映射在记录到控制台时更改堆栈跟踪的显示。堆栈跟踪本身不会被修改,因此在您的代码中检查 error.stack 仍然会提供包含已编译代码的未映射堆栈跟踪。以下是在浏览器的开发人员工具中启用此设置的方法:
Chrome:⚙ → 启用 JavaScript 源映射 Safari: ⚙ → Sources → Enable source maps 火狐:···→ 启用源地图
在 node 中,从 v12.12.0 版本开始原生支持源映射。默认情况下禁用此功能,但可以使用标志启用。与浏览器不同,实际的堆栈跟踪也在 node 中修改,因此检查代码中的 error.stack 将提供包含原始源代码的映射堆栈跟踪.以下是在节点中启用此设置的方法(–enable-source-maps 标志必须位于脚本文件名之前)node --enable-source-maps app.js
代码拆分仍在进行中。它目前仅适用于 esm 输出格式。跨代码拆分块的导入语句也存在一个已知的排序问题。您可以关注跟踪问题以获取有关此功能的更新。
这启用了“代码拆分”,它有两个目的:
require('esbuild').buildSync({
entryPoints: ['home.ts', 'about.ts'],
bundle: true,
splitting: true,
outdir: 'out',
format: 'esm',
})
他为生成的 JavaScript 和/或 CSS 代码设置目标环境。例如,您可以将 esbuild 配置为不生成 Chrome 版本 58 无法处理的任何更新的 JavaScript 或 CSS。目标可以设置为 JavaScript 语言版本,例如 es2020,也可以设置为单个引擎的版本列表(当前为 chrome、firefox、safari、edge 或 node)。默认目标是 esnext,这意味着默认情况下,esbuild 将假定支持所有最新的 JavaScript 和 CSS 功能。
这是一个使用 esbuild 中所有可用目标环境名称的示例。请注意,您不需要指定所有这些;您可以只指定您的项目关心的目标环境的子集。如果您愿意,您还可以更精确地了解版本号(例如 node12.19.0 而不仅仅是 node12):
require('esbuild').buildSync({
entryPoints: ['app.js'],
target: [
'es2020',
'chrome58',
'firefox57',
'safari11',
'edge16',
'node12',
],
outfile: 'out.
您可以参考 JavaScript 加载器,详细了解哪些语言版本引入了哪些语法特性。请记住,虽然 es2020 等 JavaScript 语言版本是按年份标识的,但这是规范获得批准的年份。它与所有主要浏览器实现该规范的年份无关,该规范通常早于或晚于该年。
请注意,如果您使用 esbuild 尚不支持转换为当前语言目标的语法功能,则 esbuild 将在使用不受支持的语法时生成错误。例如,当以 es5 语言版本为目标时,经常会出现这种情况,因为 esbuild 仅支持将大多数较新的 JavaScript 语法特性转换为 es6.
在构建 API 上启用监视模式会告诉 esbuild 侦听文件系统上的更改,并在可能使构建无效的文件更改时重新构建。使用它看起来像这样:
require('esbuild').build({
entryPoints: ['app.js'],
outfile: 'out.js',
bundle: true,
watch: true,
}).then(result => {
console.log('watching...')
})
如果您使用的是 JavaScript 或 Go API,您可以选择提供一个回调,每当增量构建完成时都会调用该回调。这可用于在构建完成后执行某些操作(例如,在浏览器中重新加载您的应用程序):
require('esbuild').build({
entryPoints: ['app.js'],
outfile: 'out.js',
bundle: true,
watch: {
onRebuild(error, result) {
if (error) console.error('watch build failed:', error)
else console.log('watch build succeeded:', result)
},
},
}).then(result => {
console.log('watching...')
})
如果您想在将来的某个时刻停止监视模式,您可以对结果对象调用“停止”以终止文件监视程序: JS 去
require('esbuild').build({
entryPoints: ['app.js'],
outfile: 'out.js',
bundle: true,
watch: true,
}).then(result => {
console.log('watching...')
setTimeout(() => {
result.stop()
console.log('stopped watching')
}, 10 * 1000)
})
esbuild 中的监视模式是使用轮询而不是特定于操作系统的文件系统 API 实现的,以实现可移植性。轮询系统被设计为使用相对较少的 CPU,而不是一次扫描整个目录树的更传统的轮询系统。文件系统仍会定期扫描,但每次扫描仅检查文件的随机子集,这意味着文件更改将在更改后不久被发现,但不一定立即生效。
使用当前的启发式方法,大型项目应该每 2 秒左右完全扫描一次,因此在最坏的情况下,可能需要长达 2 秒才能注意到更改。但是,在注意到更改后,更改的路径会出现在最近更改的路径的简短列表中,在每次扫描时都会检查这些路径,因此应该几乎立即注意到对最近更改的文件的进一步更改。
请注意,如果您不想使用基于轮询的方法,仍然可以使用 esbuild 的增量构建 API 和您选择的文件观察器库自己实现观察模式。
构建 API 调用可以直接写入文件系统,也可以返回本应作为内存缓冲区写入的文件。默认情况下,CLI 和 JavaScript API 会写入文件系统,而 Go API 不会。要使用内存缓冲区:
let result = require('esbuild').buildSync({
entryPoints: ['app.js'],
sourcemap: 'external',
write: false,
outdir: 'out',
})
for (let out of result.outputFiles) {
console.log(out.path, out.contents)
}