CoolFace
Datasetpublic

enigmare/v2-crawler

sourceHugging Faceupdated 28d agoView on Hugging Face
1likes904downloads
esbuild_github_io.jsonl9 linesDownload Raw Back to documentation
1{"id":"doc-esbuild_bundle_size_analyzer-8f1a973e","source":"documentation","title":"esbuild - Bundle Size Analyzer","url":"https://esbuild.github.io/analyze/","text":"esbuild Bundle Size Analyzer This page provides a way to visualize the contents of your esbuild bundle. Add the metafile option to your esbuild command, then import it using the button your metafile... Or you can load an example to play around with the visualization.\n\nTreemap Chart Sunburst Chart Flame Chart\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.370Z","totalSectionsIncluded":2,"totalCodeBlocksIncluded":0,"totalLines":5,"estimatedTokens":81}}2{"id":"doc-esbuild_an_extremely_fast_bundler_for_the_web-a05afa3e","source":"documentation","title":"esbuild - An extremely fast bundler for the web","url":"https://esbuild.github.io/","text":"esbuildAn extremely fast bundler for the webesbuild0.39sparcel 214.91srollup 4 + terser34.10swebpack 541.21s0s10s20s30s40sAbove: the time to do a production bundle of 10 copies of the three.js library from scratch using default settings, including minification and source maps. More info here.Our current build tools for the web are 10-100x slower than they could be. The main goal of the esbuild bundler project is to bring about a new era of build tool performance, and create an easy-to-use modern bundler along the way.Major speed without needing a cacheJavaScript, CSS, TypeScript, and JSX built-inA straightforward API for CLI, JS, and GoBundles ESM and CommonJS modulesBundles CSS including CSS modulesTree shaking, minification, and source mapsLocal server, watch mode, and pluginsCheck out the getting started instructions if you want to give esbuild a try.\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.370Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":0,"totalLines":3,"estimatedTokens":220}}3{"id":"doc-esbuild_getting_started-b553e415","source":"documentation","title":"esbuild - Getting Started","url":"https://esbuild.github.io/getting-started/","text":"Getting Started#Install esbuildFirst, download and install the esbuild command locally. A prebuilt native executable can be installed using npm (which is automatically installed when you install the node JavaScript runtime):npm install --save-exact --save-dev esbuildThis should have installed esbuild in your local node_modules folder. You can run the esbuild executable to verify that everything is working Windows ./node_modules/.bin/esbuild --version .\\node_modules\\.bin\\esbuild --version The recommended way to install esbuild is to install the native executable using npm. But if you don't want to do that, there are also some other ways to install. You can also read more about additional npm flags if you're passing additional flags to npm, as they may affect how esbuild gets installed.#Your first bundleThis is a quick real-world example of what esbuild is capable of and how to use it. First, install the react and react-dom install react react-domThen create a file called app.jsx containing the following * as React from 'react' import * as Server from 'react-dom/server' let Greet = () => <h1>Hello, world!</h1> console.log(Server.renderToString(<Greet />))Finally, tell esbuild to bundle the Windows ./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js .\\node_modules\\.bin\\esbuild app.jsx --bundle --outfile=out.js This should have created a file called out.js containing your code and the React library bundled together. The code is completely self-contained and no longer depends on your node_modules directory. If you run the code using node out.js, you should see something like this:<h1 data-reactroot=\"\">Hello, world!</h1>Notice that esbuild also converted JSX syntax to JavaScript without any configuration other than the Notice that this uses the esbuild command directly without a relative path. This works because everything in the scripts section is run with the esbuild command already in the path (as long as you have installed the package).The build script can be invoked like run buildHowever, using the command-line interface can become unwieldy if you need to pass many options to esbuild. For more sophisticated uses you will likely want to write a build script in JavaScript using esbuild's JavaScript API. That might look something like this (note that this code must be saved in a file with the ) The build function runs the esbuild executable in a child process and returns a promise that resolves when the build is complete. There is also a buildSync API that is not asynchronous, but the asynchronous API is better for build scripts because plugins only work with the asynchronous API. You can read more about the configuration options for the build API in the API documentation.#Bundling for the browserThe bundler outputs code for the browser by default, so no additional configuration is necessary to get started. For development builds you probably want to enable source maps with --sourcemap, and for production builds you probably want to enable minification with --minify. You probably also want to configure the target environment for the browsers you support so that JavaScript syntax which is too new will be transformed into older JavaScript syntax. All of that might looks something like JS Go esbuild app.jsx --bundle --minify --sourcemap --target=chrome58,firefox57,safari11,edge16 import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.jsx'], , , , target: ['chrome58', 'firefox57', 'safari11', 'edge16'], outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, , , , , Engines: []api.Engine{ {api.EngineChrome, \"58\"}, {api.EngineFirefox, \"57\"}, {api.EngineSafari, \"11\"}, {api.EngineEdge, \"16\"}, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } Some npm packages you want to use may not be designed to be run in the browser. Sometimes you can use esbuild's configuration options to work around certain issues and successfully bundle the package anyway. Undefined globals can be replaced with either the define feature in simple cases or the inject feature in more complex cases.#Bundling for nodeEven though a bundler is not necessary when using node, sometimes it can still be beneficial to process your code with esbuild before running it in node. Bundling can automatically strip TypeScript types, convert ECMAScript module syntax to CommonJS, and transform newer JavaScript syntax into older syntax for a specific version of node. And it may be beneficial to bundle your package before publishing it so that it's a smaller download and so it spends less time reading from the file system when being loaded.If you are bundling code that will be run in node, you should configure the platform setting by passing --platform=node to esbuild. This simultaneously changes a few different settings to node-friendly default values. For example, all packages that are built-in to node such as fs are automatically marked as external so esbuild doesn't try to bundle them. This setting also disables the interpretation of the browser field in package.json.If your code uses newer JavaScript syntax that doesn't work in your version of node, you will want to configure the target version of JS Go esbuild app.js --bundle --platform=node --target=node10.4 import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , platform: 'node', target: ['node10.4'], outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , Engines: []api.Engine{ {api.EngineNode, \"10.4\"}, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } You also may not want to bundle your dependencies with esbuild. There are many node-specific features that esbuild doesn't support while bundling such as __dirname, import.meta.url, fs.readFileSync, and *.node native binary modules. You can exclude all of your dependencies from the bundle by setting packages to JS Go esbuild app.jsx --bundle --platform=node --packages=external require('esbuild').buildSync({ entryPoints: ['app.jsx'], , platform: 'node', packages: 'external', outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, , , , , }) if len(result.Errors) > 0 { os.Exit(1) } } If you do this, your dependencies must still be present on the file system at run-time since they are no longer included in the bundle.#Simultaneous platformsYou cannot install esbuild on one OS, copy the node_modules directory to another OS without reinstalling, and then run esbuild on that other OS. This won't work because esbuild is written with native code and needs to install a platform-specific binary executable. Normally this isn't an issue because you typically check your package.json file into version control, not your node_modules directory, and then everyone runs npm install on their local machine after cloning the repository.However, people sometimes get into this situation by installing esbuild on Windows or macOS and copying their node_modules directory into a Docker image that runs Linux, or by copying their node_modules directory between Windows and WSL environments. The way to get this to work depends on your package /pnpm: If you are installing with npm or pnpm, you can try not copying the node_modules directory when you copy the files over, and running npm ci or npm install on the destination platform after the copy. Or you could consider using Yarn instead which has built-in support for installing a package on multiple platforms simultaneously. you are installing with Yarn, you can try listing both this platform and the other platform in your .yarnrc.yml file using the supportedArchitectures feature. Keep in mind that this means multiple copies of esbuild will be present on the file system. You can also get into this situation on a macOS computer with an ARM processor if you install esbuild using the ARM version of npm but then try to run esbuild with the x86-64 version of node running inside of Rosetta. In that case, an easy fix is to run your code using the ARM version of node instead, which can be downloaded ://nodejs.org/en/download/.Another alternative is to use the esbuild-wasm package instead, which works the same way on all platforms. But it comes with a heavy performance cost and can sometimes be 10x slower than the esbuild package, so you may also not want to do that.#Using Yarn Plug'n'PlayYarn's Plug'n'Play package installation strategy is supported natively by esbuild. To use it, make sure you are running esbuild such that the current working directory contains Yarn's generated package manifest JavaScript file (either .pnp.cjs or .pnp.js). If a Yarn Plug'n'Play package manifest is detected, esbuild will automatically resolve package imports to paths inside the .zip files in Yarn's package cache, and will automatically extract these files on the fly during bundling.Because esbuild is written in Go, support for Yarn Plug'n'Play has been completely re-implemented in Go instead of relying on Yarn's JavaScript API. This allows Yarn Plug'n'Play package resolution to integrate well with esbuild's fully parallelized bundling pipeline for maximum speed. Note that Yarn's command-line interface adds a lot of unavoidable performance overhead to every command. For maximum esbuild performance, you may want to consider running esbuild without using Yarn's CLI (i.e. not using yarn esbuild). This can result in esbuild running 10x faster.#Additional npm flagsThere are two npm flags that can potentially interfere with how the esbuild package is and --no-optional. This is because the esbuild package uses an install script and because the esbuild package depends on a separate optional package for each platform-specific binary executable.The optimal way to install esbuild is to not use either of these flags. The installation flow for esbuild is designed to still partially work when one of these flags is present, but it cannot work at all when both of these flags are present.In more install esbuild This is the default installation flow. The esbuild binary for the current platform should be automatically selected and installed from esbuild's optional dependencies by npm. The install script then runs which a) checks that the esbuild binary is the correct version (which is sometimes not the case due to package manager bugs) and b) optimizes the esbuild command in node_modules/.bin to be the esbuild executable itself instead of a JavaScript shim file that runs the actual esbuild executable. npm install esbuild --ignore-scripts This means esbuild's install script doesn't run. However, the esbuild binary for the current platform should still be automatically selected and installed from esbuild's optional dependencies by npm. The esbuild command in node_modules/.bin remains pointed to the JavaScript shim file that runs the actual esbuild executable. This means that running esbuild using for example ./node_modules/.bin/esbuild will experience some unnecessary performance overhead as an extra node process will be launched to invoke esbuild. Uses of the esbuild API (so not the esbuild CLI) do not have degraded performance as that use case already requires a node process to be launched (for the caller of the JavaScript API). The performance overhead of launching the extra node process is not nothing but also not that big. So this is not the end of the world. npm install esbuild --no-optional This means npm doesn't install the optional package with the esbuild binary for the current platform, as it has been instructed not to install any optional packages. The install script then runs and notices the missing esbuild binary and attempts to download it manually from the npm registry. This is less robust than the default installation flow because many people have complex npm configuration that esbuild's install script can't necessarily replicate. For example, this may fail if the network path to the internet involves a proxy, or a custom npm registry is in use. But this install flow has been added because it works for some people who do this. If this fails for you, the solution is to not do this. npm install esbuild --ignore-scripts --no-optional In this scenario, the installed esbuild package is broken because nothing downloads the actual esbuild binary. I consider this to be a user error. The solution is to not do this. #Other ways to installThe recommended way to install esbuild is to install the native executable using npm. But you can also install esbuild in these ways:#Download a buildIf you have a Unix system, you can use the following command to download the esbuild binary executable for your current platform (it will be downloaded to the current working directory):curl -fsSL https://esbuild.github.io/dl/v0.28.2 | shYou can also use latest instead of the version number to download the most recent version of -fsSL https://esbuild.github.io/dl/latest | shIf you don't want to evaluate a shell script from the internet to download esbuild, you can also manually download the package from npm yourself instead (which is all the above shell script is doing). Although the precompiled native executables are hosted using npm, you don't actually need npm installed to download them. The npm package registry is a normal HTTP server and packages are normal gzipped tar files.Here is an example of downloading a binary executable -O https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz tar xzf ./darwin-x64-0.28.2.tgz ./package/bin/esbuild [options] [entry points] ... The native executable in the @esbuild/darwin-x64 package is for the macOS operating system and the 64-bit Intel architecture. As of writing, this is the full list of native executable packages for the platforms esbuild name OS Architecture Download @esbuild/aix-ppc64 aix ppc64 @esbuild/android-arm3 android arm @esbuild/android-arm64 android arm64 @esbuild/android-x643 android x64 @esbuild/darwin-arm64 darwin arm64 @esbuild/darwin-x64 darwin x64 @esbuild/freebsd-arm64 freebsd arm64 @esbuild/freebsd-x64 freebsd x64 @esbuild/linux-arm linux arm @esbuild/linux-arm64 linux arm64 @esbuild/linux-ia32 linux ia32 @esbuild/linux-loong64 linux loong642 @esbuild/linux-mips64el linux mips64el2 @esbuild/linux-ppc64 linux ppc64 @esbuild/linux-riscv64 linux riscv642 @esbuild/linux-s390x linux s390x @esbuild/linux-x64 linux x64 @esbuild/netbsd-arm64 netbsd1 arm64 @esbuild/netbsd-x64 netbsd1 x64 @esbuild/openbsd-arm64 openbsd arm64 @esbuild/openbsd-x64 openbsd x64 @esbuild/openharmony-arm643 openharmony arm64 @esbuild/sunos-x64 sunos x64 @esbuild/win32-arm64 win32 arm64 @esbuild/win32-ia32 win32 ia32 @esbuild/win32-x64 win32 x64 Why this is not approach only works on Unix systems that can run shell scripts, so it will require WSL on Windows. An additional drawback is that you cannot use plugins with the native version of esbuild.If you choose to write your own code to download esbuild directly from npm, then you are relying on internal implementation details of esbuild's native executable installer. These details may change at some point, in which case this approach will no longer work for new esbuild versions. This is only a minor drawback though since the approach should still work forever for existing esbuild versions (packages published to npm are immutable). 1 This operating system is not on node's list of supported platforms 2 This architecture is not on node's list of supported architectures 3 This configuration is not supported by Go, so WebAssembly is used instead of a native executable #Install the WASM versionIn addition to the esbuild npm package, there is also an esbuild-wasm package that functions similarly but that uses WebAssembly instead of native code. Installing it will also install an executable called install --save-exact esbuild-wasmWhy this is not WebAssembly version is much, much slower than the native version. In many cases it is an order of magnitude (i.e. 10x) slower. This is for various reasons including a) node re-compiles the WebAssembly code from scratch on every run, b) Go's WebAssembly compilation approach is single-threaded, and c) node has WebAssembly bugs that can delay the exiting of the process by many seconds. The WebAssembly version also excludes some features such as the local file server. You should only use the WebAssembly package like this if there is no other option, such as when you want to use esbuild on an unsupported platform. The WebAssembly package is primarily intended to only be used in the browser.#Build from sourceTo build esbuild from the Go ://go.dev/dl/Download the source code for clone --depth 1 --branch v0.28.2 https://github.com/evanw/esbuild.git cd esbuild Build the esbuild executable (it will be esbuild.exe on Windows): go build ./cmd/esbuildIf you want to build for other platforms, you can just prefix the build command with the platform information. For example, you can build the 32-bit Linux version using this =linux GOARCH=386 go build ./cmd/esbuildWhy this is not native version can only be used via the command-line interface, which can be unergonomic for complex use cases and which does not support plugins. You will need to write JavaScript or Go code and use esbuild's API to use plugins.\n\nExample:\n```text\nnpm install --save-exact --save-dev esbuild\n```\n\nExample:\n```text\n./node_modules/.bin/esbuild --version\n```\n\nExample:\n```text\n.\\node_modules\\.bin\\esbuild --version\n```\n\nExample:\n```text\nnpm install react react-dom\n```\n\nExample:\n```text\nimport * as React from 'react'\nimport * as Server from 'react-dom/server'\n\nlet Greet = () => <h1>Hello, world!</h1>\nconsole.log(Server.renderToString(<Greet />))\n```\n\nExample:\n```text\n./node_modules/.bin/esbuild app.jsx --bundle --outfile=out.js\n```\n\nExample:\n```text\n.\\node_modules\\.bin\\esbuild app.jsx --bundle --outfile=out.js\n```\n\nExample:\n```text\n<h1 data-reactroot=\"\">Hello, world!</h1>\n```\n\nExample:\n```text\n{\n  \"scripts\": {\n    \"build\": \"esbuild app.jsx --bundle --outfile=out.js\"\n  }\n}\n```\n\nExample:\n```text\nnpm run build\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.jsx'],\n  bundle: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\nesbuild app.jsx --bundle --minify --sourcemap --target=chrome58,firefox57,safari11,edge16\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.jsx'],\n  bundle: true,\n  minify: true,\n  sourcemap: true,\n  target: ['chrome58', 'firefox57', 'safari11', 'edge16'],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"app.jsx\"},\n    Bundle:            true,\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n    Engines: []api.Engine{\n      {api.EngineChrome, \"58\"},\n      {api.EngineFirefox, \"57\"},\n      {api.EngineSafari, \"11\"},\n      {api.EngineEdge, \"16\"},\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --platform=node --target=node10.4\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  platform: 'node',\n  target: ['node10.4'],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Platform:    api.PlatformNode,\n    Engines: []api.Engine{\n      {api.EngineNode, \"10.4\"},\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.jsx --bundle --platform=node --packages=external\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.jsx'],\n  bundle: true,\n  platform: 'node',\n  packages: 'external',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.jsx\"},\n    Bundle:      true,\n    Platform:    api.PlatformNode,\n    Packages:    api.PackagesExternal,\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nnpm install esbuild\n```\n\nExample:\n```text\nnpm install esbuild --ignore-scripts\n```\n\nExample:\n```text\nnpm install esbuild --no-optional\n```\n\nExample:\n```text\nnpm install esbuild --ignore-scripts --no-optional\n```\n\nExample:\n```text\ncurl -fsSL https://esbuild.github.io/dl/v0.28.2 | sh\n```\n\nExample:\n```text\ncurl -fsSL https://esbuild.github.io/dl/latest | sh\n```\n\nExample:\n```text\ncurl -O https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz\ntar xzf ./darwin-x64-0.28.2.tgz\n./package/bin/esbuild\nUsage:\n  esbuild [options] [entry points]\n\n...\n```\n\nExample:\n```text\nnpm install --save-exact esbuild-wasm\n```\n\nExample:\n```text\ngit clone --depth 1 --branch v0.28.2 https://github.com/evanw/esbuild.git\ncd esbuild\n```\n\nExample:\n```text\ngo build ./cmd/esbuild\n```\n\nExample:\n```text\nGOOS=linux GOARCH=386 go build ./cmd/esbuild\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.372Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":31,"totalLines":262,"estimatedTokens":5365}}4{"id":"doc-esbuild_faq-189d76f5","source":"documentation","title":"esbuild - FAQ","url":"https://esbuild.github.io/faq/","text":"FAQThis is a collection of common questions about esbuild. You can also ask questions on the GitHub issue tracker. Why is esbuild fast? Benchmark details Upcoming roadmap Production readiness Anti-virus software Not a sandbox Outdated version of Go Minified newlines Avoiding name collisions Strict mode Top-level var function doesNotUseStrictMode() { return this; } console.log( usesStrictMode(), doesNotUseStrictMode(), )The strict mode feature is complicated and error-prone for many does not compose well because there is no way to turn it off for a nested scope. For example, it's unclear what the above code will print. The first function will definitely return undefined because this is always defaults to undefined when calling a strict mode function. But the second function may either return undefined or the global object depending on whether or not the scope surrounding this code snippet is in strict mode. Strict mode can be affected by your choice of JavaScript module format. CommonJS modules (files that reference module and/or exports) are only in strict mode if they start with a \"use strict\"; directive. However, ECMAScript modules (files that use the import and export keywords) are always in strict mode regardless of whether or not the \"use strict\"; directive is present. The TypeScript compiler automatically inserts a \"use strict\"; directive for you if you enable the strict or alwaysStrict options in your tsconfig.json file. This isn't necessarily obvious because the strict option is typically associated with type checking, not changing run-time behavior. Because esbuild emulates these TypeScript settings, esbuild will also insert \"use strict\"; in these cases. When esbuild bundles multiple modules into a single file, some of the modules that shouldn't be run in strict mode may end up being run in strict mode anyway. This can happen when the output format is an ECMAScript module (implicit strict mode) or when the entry point is in strict mode (either with an explicit directive or implicit strict mode from tsconfig.json). This is because bundling places the dependencies in nested scopes and because JavaScript doesn't have a way to turn strict mode back off in a nested scope.There isn't really a general solution to these problems because of how the strict mode feature was designed. Hopefully this information can help you diagnose and work around any compatibility problems that come up.#Top-level varPeople are sometimes surprised that esbuild sometimes rewrites top-level let, const, and class declarations as var declarations instead. This is done for a few correctness Bundling sometimes needs to lazily-initialize a module. For example, this happens when you call require() or import() using the path of a module within the bundle. Doing this involves separating the declaration and initialization of top-level symbols by moving the initialization into a closure. So for example class statements are rewritten as an assignment of a class expression to a variable. Keeping the declarations out of the lazy-initialization closure is important for performance, since it means other modules can reference them directly instead by name instead of indirectly via a slower property access. Another case where this is needed is when transforming top-level using declarations. This involves wrapping the entire module body in a try block, which also involves separating the declaration and initialization of top-level symbols. Top-level symbols may need to be exported, which means they cannot be declared within the try block. In both of these cases esbuild will fail with a build error if the source code contains a mutation of a const symbol, so it's not possible for esbuild's rewriting of top-level const into var to result in the mutation of a constant. Due to esbuild's current architecture, the part of esbuild that does this transformation (the parser) cannot know whether the current module will end up being lazily initialized or not. The information for this decision may only be discovered later on in the build, or may even change in future incremental builds that reuse the same AST (per-file ASTs are transformed once during parsing and then cached and reused across incremental builds). So this transformation is always done when bundling is active. For performance Multiple JavaScript VMs have had and continue to have performance issues with TDZ (i.e. \"temporal dead zone\") checks. These checks validate that a let, or const, or class symbol isn't used before it's initialized. Here are two issues with well-known : https://bugs.chromium.org/p/v8/issues/detail?id=13723 (10% slowdown) ://bugs.webkit.org/show_bug.cgi?id=199866 (1,000% slowdown!) JavaScriptCore had a severe performance issue as their TDZ implementation had time complexity that was quadratic in the number of variables needing TDZ checks in the same scope (with the top-level scope typically being the worst offender). V8 has ongoing issues with TDZ checks being present throughout the code their JIT generates even when they have already been checked earlier in the same function or when the function in question has already been run (so the checks have already happened). In JavaScript, let, const, and class declarations all introduce TDZ checks while var declarations do not. Since bundling typically merges many modules into a single very large top-level scope, the performance impact of these TDZ checks can be pretty severe. Converting top-level let, const, and class declarations into var helps automatically make your code faster. Note that esbuild doesn't preserve top-level TDZ side effects because modules may need to be lazily initialized (as described above), which means separating declaration from initialization. TDZ checks for top-level symbols could hypothetically still be supported by generating extra code that checks before each use of a top-level symbol and throws if it hasn't been initialized yet (effectively manually implementing what a real JavaScript VM would do). However, this seems like an excessive overhead for both code size and run time, and does not seem like something that a production-oriented bundler should do.\n\nExample:\n```text\nvar text=\"a\\nb\\nc\\n\";\n```\n\nExample:\n```text\nvar text=`a\nb\nc\n`;\n```\n\nExample:\n```text\nfunction usesStrictMode() {\n  \"use strict\";\n  return this;\n}\n\nfunction doesNotUseStrictMode() {\n  return this;\n}\n\nconsole.log(\n  usesStrictMode(),\n  doesNotUseStrictMode(),\n)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.376Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":3,"totalLines":33,"estimatedTokens":1618}}5{"id":"doc-esbuild_gradient_transformation_tests-c28050bf","source":"documentation","title":"esbuild - Gradient Transformation Tests","url":"https://esbuild.github.io/gradient-tests/","text":"# Gradient Transformation Tests\n\nThis page is a visual test of esbuild's transformation of modern CSS gradient syntax for older browsers. Each test case compares the browser's native rendering of the modern syntax to esbuild's transformation (which uses the legacy syntax instead). This makes it easy to visually verify that esbuild's transformation is correct as well as to visually inspect a given browser's rendering of these gradient syntax features.\n\n## 1. Red to green in P3\n\ngradient( color(display-p3 1 0 0), color(display-p3 0 0.6 0))\n\nnative esbuild native esbuild\n\nshould happen in the oklab color space.\n\n## 2. Rainbow using shorter hue\n\ngradient( in hwb shorter hue, hsl(180deg 100% 75%) 10%, hsl(240deg 100% 75%) 90%)\n\nnative esbuild native esbuild\n\n## 3. Rainbow using longer hue\n\ngradient( in hsl longer hue, hsl(180deg 100% 75%) 10%, hsl(240deg 100% 75%) 90%)\n\nnative esbuild native esbuild\n\n## 4. Rainbow using increasing hue\n\ngradient( in lch increasing hue, hsl(240deg 100% 75%) 10%, hsl(180deg 100% 75%) 90%)\n\nnative esbuild native esbuild\n\n## 5. Rainbow using decreasing hue\n\ngradient( in oklch decreasing hue, hsl(180deg 100% 75%) 10%, hsl(240deg 100% 75%) 90%)\n\nnative esbuild native esbuild\n\n## 6. Transition hint / midpoint\n\ngradient(#f00, #ff0, 75%, #0ff, #00f)\n\nnative esbuild native esbuild\n\ngradient should be \"pulled\" to one side.\n\n## 7. Premultiplied alpha\n\ngradient(#f00f, 10%, #00f1, 90%, #0f0f)\n\nnative esbuild native esbuild\n\ntransparent area should not have much blue color.\n\n## 8. Mixed units\n\ngradient( color(display-p3 0.4 0 1) 30px, color(display-p3 1 0.75 0.4) 60%)\n\nnative esbuild native esbuild\n\nunits can be supported by emitting calc() expressions.\n\nExample:\n```text\ngradient(\n  color(display-p3 1 0 0),\n  color(display-p3 0 0.6 0))\n```\n\nExample:\n```text\ngradient(\n  in hwb shorter hue,\n  hsl(180deg 100% 75%) 10%,\n  hsl(240deg 100% 75%) 90%)\n```\n\nExample:\n```text\ngradient(\n  in hsl longer hue,\n  hsl(180deg 100% 75%) 10%,\n  hsl(240deg 100% 75%) 90%)\n```\n\nExample:\n```text\ngradient(\n  in lch increasing hue,\n  hsl(240deg 100% 75%) 10%,\n  hsl(180deg 100% 75%) 90%)\n```\n\nExample:\n```text\ngradient(\n  in oklch decreasing hue,\n  hsl(180deg 100% 75%) 10%,\n  hsl(240deg 100% 75%) 90%)\n```\n\nExample:\n```text\ngradient(#f00, #ff0, 75%, #0ff, #00f)\n```\n\nExample:\n```text\ngradient(#f00f, 10%, #00f1, 90%, #0f0f)\n```\n\nExample:\n```text\ngradient(\n  color(display-p3 0.4 0 1) 30px,\n  color(display-p3 1 0.75 0.4) 60%)\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.377Z","totalSectionsIncluded":30,"totalCodeBlocksIncluded":8,"totalLines":117,"estimatedTokens":617}}6{"id":"doc-esbuild_content_types-d60742b3","source":"documentation","title":"esbuild - Content Types","url":"https://esbuild.github.io/content-types/","text":"Content TypesAll of the built-in content types are listed below. Each content type has an associated \"loader\" which tells esbuild how to interpret the file contents. Some file extensions already have a loader configured for them by default, although the defaults can be overridden.#JavaScriptLoader: jsThis loader is enabled by default for Asynchronous iteration es2018 for await (let x of y) {} Async generators es2018 async function* foo() {} Spread properties es2018 let x = {...y} Rest properties es2018 let {...x} = y Optional catch binding es2019 try {} catch {} BigInt es2020 123n Optional chaining es2020 a?.b Nullish coalescing es2020 a ?? b import.meta es2020 import.meta Logical assignment operators es2021 a ??= b Class instance fields es2022 class { x } Static class fields es2022 class { static x } Private instance methods es2022 class { } Private instance fields es2022 class { Private static fields es2022 class { static Import assertions esnext import \"x\" assert {}1 Import attributes esnext import \"x\" with {} Auto-accessors esnext class { accessor x } using declarations esnext using x = y Decorators esnext @foo class Bar {} 1 Import assertions never made it into the JavaScript specification. They are deprecated in favor of import attributes and are actively being removed from JavaScript runtimes. These syntax features are currently always passed through transform Unsupported when --target is below Example RegExp dotAll flag es2018 /./s1 RegExp lookbehind assertions es2018 /(?<=x)y/1 RegExp named capture groups es2018 /(?<foo>\\d+)/1 RegExp unicode property escapes es2018 /\\p{ASCII}/u1 Top-level await es2022 await import(x) Arbitrary module namespace identifiers es2022 export {foo as 'f o o'} RegExp match indices es2022 /x(.+)y/d1 Hashbang grammar es2023 #!/usr/bin/env node RegExp set notation es2024 /[\\w--\\d]/v1 Deferred imports esnext import.defer('x') Source phase imports esnext import.source('x') 1 Unsupported regular expression literals are transformed into a new RegExp() constructor call so you can bring your own polyfill library to get them to work anyway. See also the list of finished ECMAScript proposals and the list of active ECMAScript proposals. Note that while transforming code containing top-level await is supported, bundling code containing top-level await is only supported when the output format is set to esm.#JavaScript caveatsYou should keep the following things in mind when using JavaScript with esbuild:#ES5 is not supported wellTransforming ES6+ syntax to ES5 is not supported yet. However, if you're using esbuild to transform ES5 code, you should still set the target to es5. This prevents esbuild from introducing ES6 syntax into your ES5 code. For example, without this flag the object literal {x: x} will become {x} and the string \"a\\nb\" will become a multi-line template literal when minifying. Both of these substitutions are done because the resulting code is shorter, but the substitutions will not be performed if the target is es5.#Private member performanceThe private member transform (for the import './something-that-needs-foo'There are some broken implementations of ECMAScript modules out there (e.g. the TypeScript compiler) that don't follow the JavaScript specification in this regard. Code compiled with these tools may \"work\" since the import is replaced with an inline call to require(), which ignores the hoisting requirement. But such code will not work with real ECMAScript module implementations such as node, a browser, or esbuild, so writing code like this is non-portable and is not recommended.The way to do this correctly is to move the global state modification into its own import. That way it will be run before the other './assign-to-foo-on-window' import './something-that-needs-foo'#Avoid direct eval when bundlingAlthough the expression eval(x) looks like a normal function call, it actually takes on special behavior in JavaScript. Using eval in this way means that the evaluated code stored in x can reference any variable in any containing scope by name. For example, the code let y = 123; return eval('y') will return 123.This is called \"direct eval\" and is problematic when bundling your code for many bundlers contain an optimization called \"scope hoisting\" that merges all bundled files into a single file and renames variables to avoid name collisions. However, this means code evaluated by direct eval can read and write variables in any file in the bundle! This is a correctness issue because the evaluated code may try to access a global variable but may accidentally access a private variable with the same name from another file instead. It can potentially even be a security issue if a private variable in another file has sensitive data. The evaluated code may not work correctly when it references variables imported using an import statement. Imported variables are live bindings to variables in another file. They are not copies of those variables. So when esbuild bundles your code, your imports are replaced with a direct reference to the variable in the imported file. But that variable may have a different name, in which case the code evaluated by direct eval will be unable to reference it by the expected name. Using direct eval forces esbuild to deoptimize all of the code in all of the scopes containing calls to direct eval. For correctness, it must assume that the evaluated code might need to access any of the other code in the file reachable from that eval call. This means none of that code will be eliminated as dead code and none of that code will be minified. Because the code evaluated by the direct eval could need to reference any reachable variable by name, esbuild is prevented from renaming all of the variables reachable by the evaluated code. This means it can't rename variables to avoid name collisions with other variables in the bundle. So the direct eval causes esbuild to wrap the file in a CommonJS closure, which avoids name collisions by introducing a new scope instead. However, this makes the generated code bigger and slower because exported variables use run-time dynamic binding instead of compile-time static binding. Luckily it is usually easy to avoid using direct eval. There are two commonly-used alternatives that avoid all of the drawbacks mentioned above:(0, eval)('x') This is known as \"indirect eval\" because eval is not being called directly, and so does not trigger the grammatical special case for direct eval in the JavaScript VM. You can call indirect eval using any syntax at all except for an expression of the exact form eval('x'). For example, var eval2 = eval; eval2('x') and [eval][0]('x') and window.eval('x') are all indirect eval calls. When you use indirect eval, the code is evaluated in the global scope instead of in the inline scope of the caller. new Function('x') This constructs a new function object at run-time. It is as if you wrote function() { x } in the global scope except that x can be an arbitrary string of code. This form is sometimes convenient because you can add arguments to the function, and use those arguments to expose variables to the evaluated code. For example, (new Function('env', 'x'))(someEnv) is as if you wrote (function(env) { x })(someEnv). This is often a sufficient alternative for direct eval when the evaluated code needs to access local variables because you can pass the local variables in as arguments. export function bar() { console.log('bar') }The reason for this is that esbuild automatically rewrites code most code that uses module namespace objects to code that imports things directly instead. That means the example code above will be converted to this instead, which removes the this context for the function { foo } from './foo.js' foo()This transformation dramatically improves tree shaking (a.k.a. dead code elimination) because it makes it possible for esbuild to understand which exported symbols are unused. It has the drawback that this changes the behavior of code that uses this to access the module's exports, but this isn't an issue because no one should ever write bizarre code like this in the first place. If you need to access an exported function from the same file, just call it directly (i.e. bar() instead of this.bar() in the example above).#The default export can be error-prone The ES module format (i.e. ESM) have a special export called default that sometimes behaves differently than all other export names. When code in the ESM format that has a default export is converted to the CommonJS format, and then that CommonJS code is imported into another module in ESM format, there are two different interpretations of what should happen that are both widely-used (the Babel way and the Node way). This is very unfortunate because it causes endless compatibility headaches, especially since JavaScript libraries are often authored in ESM and published as CommonJS.When esbuild bundles code that does this, it has to decide which interpretation to use, and there's no perfect answer. The heuristics that esbuild uses are the same heuristics that Webpack uses (see below for details). Since Webpack is the most widely-used bundler, this means that esbuild is being the most compatible that it can be with the existing ecosystem regarding this compatibility problem. So the good news is that if you can get code with this problem to work with esbuild, it should also work with Webpack.Here's an example that demonstrates the problem:// index.js import foo from './somelib.js' console.log(foo)// somelib.js Object.defineProperty(exports, \"__esModule\", { }); exports[\"default\"] = 'foo';And here are the two interpretations, both of which are Babel interpretation If the Babel interpretation is used, this code will print foo. Their rationale is that somelib.js was converted from ESM into CommonJS (as you can tell by the __esModule marker) and the original code looked something like this: // somelib.js export default 'foo' If somelib.js hadn't been converted from ESM into CommonJS, then this code would print foo, so it should still print foo regardless of the module format. This is accomplished by detecting when a CommonJS module used to be an ES module via the __esModule marker (which all module conversion tools set including Babel, TypeScript, Webpack, and esbuild) and setting the default import to exports.default if the __esModule marker is present. This behavior is important because it's necessary to run cross-compiled ESM correctly in a CommonJS environment, and for a long time that was the only way to run ESM code in Node before Node eventually added native ESM support. The Node interpretation If the Node interpretation is used, this code will print { default: 'foo' }. Their rationale is that CommonJS code uses dynamic exports while ESM code uses static exports, so the fully general approach to importing CommonJS into ESM is to expose the CommonJS exports object itself somehow. For example, CommonJS code can do exports[Math.random()] = 'foo' which has no equivalent in ESM syntax. The default export is used for this because that's actually what it was originally designed for by the people who came up with the ES module specification. This interpretation is entirely reasonable for normal CommonJS modules. It only causes compatibility problems for CommonJS modules that used to be ES modules (i.e. when __esModule is present) in which case the behavior diverges from the Babel interpretation. If you are a library writing new code, you should strongly consider avoiding the default export entirely. It has unfortunately been tainted with compatibility problems and using it will likely cause problems for your users at some point.If you are a library default, esbuild will use the Babel interpretation. If you want esbuild to use the Node interpretation instead, you need to either put your code in a file ending in Type declarations type Foo = number Function declarations function foo(): void; Ambient declarations declare module 'foo' {} Type-only imports import type {Type} from 'foo' Type-only exports export type {Type} from 'foo' Type-only import specifiers import {type Type} from 'foo' Type-only export specifiers export {type Type} from 'foo' TypeScript-only syntax extensions are supported, and are always converted to JavaScript (a non-exhaustive list): Syntax feature Example Notes Namespaces namespace Foo {} Enums enum Foo { A, B } Const enums const enum Foo { A, B } Generic type parameters <T>(a: T): T => a Must write <T,>(... with the tsx loader JSX with types <Element<T>/> Type casts a as B and <B>a Type imports import {Type} from 'foo' Handled by removing all unused imports Type exports export {Type} from 'foo' Handled by ignoring missing exports in TypeScript files Experimental decorators @sealed class Foo {} Requires experimentalDecorators, does not support emitDecoratorMetadata Instantiation expressions Array<number> TypeScript 4.7+ extends on infer infer A extends B TypeScript 4.7+ Variance annotations type A<out B> = () => B TypeScript 4.7+ The satisfies operator a satisfies T TypeScript 4.9+ const type parameters class Foo<const T> {} TypeScript 5.0+ from './types' (you need to use export type {T} from './types' instead).#Imports follow ECMAScript module behaviorFor historical reasons, the TypeScript compiler compiles ESM (ECMAScript module) syntax to CommonJS syntax by default. For example, import * as foo from 'foo' is compiled to const foo = require('foo'). Presumably this happened because ECMAScript modules were still a proposal when TypeScript adopted the syntax. However, this is legacy behavior that doesn't match how this syntax behaves on real platforms such as node. For example, the require function can return any JavaScript value including a string but the import * as syntax always results in an object and cannot be a string.To avoid problems due to this legacy feature, you should enable the esModuleInterop TypeScript configuration option if you use TypeScript with esbuild. Enabling it disables this legacy behavior and makes TypeScript's type system compatible with ESM. This option is not enabled by default because it would be a breaking change for existing TypeScript projects, but Microsoft highly recommends applying it both to new and existing projects (and then updating your code) for better compatibility with the rest of the ecosystem.Specifically this means that importing a non-object value from a CommonJS module with ESM import syntax must be done using a default import instead of using import * as. So if a CommonJS module exports a function via module.exports = fn, you need to use import fn from 'path' instead of import * as fn from 'path'.#Features that need a type system are not supportedTypeScript types are treated as comments and are ignored by esbuild, so TypeScript is treated as \"type-checked JavaScript.\" The interpretation of the type annotations is up to the TypeScript type checker, which you should be running in addition to esbuild if you're using TypeScript. This is the same compilation strategy that Babel's TypeScript implementation uses. However, it means that some TypeScript compilation features which require type interpretation to work do not work with esbuild.Specifically: The emitDecoratorMetadata TypeScript configuration option is not supported. This feature passes a JavaScript representation of the corresponding TypeScript type to the attached decorator function. Since esbuild does not replicate TypeScript's type system, it does not have enough information to implement this feature. The declaration TypeScript configuration option (i.e. generation of with the tsx loader. This is intentional, and matches the behavior of the official TypeScript compiler. That space in the tsx grammar is reserved for JSX elements.#JSXLoader: jsx or tsxJSX is an XML-like syntax extension for JavaScript that was created for React. It's intended to be converted into normal JavaScript by your build tool. Each XML element becomes a normal JavaScript function call. For example, the following JSX Button from './button' let button = <Button>Click me</Button> render(button)Will be converted to the following JavaScript Button from \"./button\"; let button = React.createElement(Button, null, \"Click me\"); render(button);This loader is enabled by default for ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".js\": api.LoaderJSX, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, , Outfile: \"out.js\", }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, JSXFactory: \"h\", JSXFragment: \"Fragment\", , }) if len(result.Errors) > 0 { os.Exit(1) } } Alternatively, if you are using TypeScript, you can just configure JSX for TypeScript by adding this to your tsconfig.json file and esbuild should pick it up automatically without needing to be configured:{ \"compilerOptions\": { \"jsxFactory\": \"h\", \"jsxFragmentFactory\": \"Fragment\" } }You will also have to add import {h, Fragment} from 'preact' in files containing JSX syntax unless you use auto-importing as described above.#JSONLoader: jsonThis loader is enabled by default for from './package.json' console.log(version)#Import AttributeThe json loader can also be accessed without needing to change esbuild's configuration by adding with { type: 'json' } after the import statement. That looks like object from './example.data' with { type: 'json' } console.log(object)This is from the JavaScript JSON modules proposal. Support for this syntax has also been added to many other JavaScript tools so code written this way will be more portable across tools.#CSSLoader: css (also global-css and local-css for CSS modules)The css loader is enabled by default for ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.css\"}, , Outfile: \"out.css\", , }) if len(result.Errors) > 0 { os.Exit(1) } } You can @import other CSS files and reference image and font files with url() and esbuild will bundle everything together. Note that you will have to configure a loader for image and font files, since esbuild doesn't have any pre-configured. Usually this is either the data URL loader or the external file loader.These syntax features are conditionally transformed for older browsers depending on the configured language transform Example Nested declarations a { &:hover { } } Modern RGB/HSL syntax 1 This is demonstrated visually by esbuild's gradient transformation tests. Note that by default, esbuild's output will take advantage of modern CSS features. For example, will become color: ) => <div className=\"button\">{text}</div>The bundled JavaScript generated by esbuild will not automatically import the generated CSS into your HTML page for you. Instead, you should import the generated CSS into your HTML page yourself along with the generated JavaScript. This means the browser can download the CSS and JavaScript files in parallel, which is the most efficient way to do it. That looks like this:<html> <head> <link href=\"app.css\" rel=\"stylesheet\"> <script src=\"app.js\"></script> </head> </html>If the generated output names are not straightforward (for example if you have added [hash] to the entry names setting and the output file names have content hashes) then you will likely want to look up the generated output names in the metafile. To do this, first find the JS file by looking for the output with the matching entryPoint property. This file goes in the <script> tag. The associated CSS file can then be found using the cssBundle property. This file goes in the <link> tag.#CSS modulesCSS modules is a CSS preprocessor technique to avoid unintentional CSS name collisions. CSS class names are normally global, but CSS modules provides a way to make CSS class names local to the file they appear in instead. If two separate CSS files use the same local class name from './app.module.css' const div = document.createElement('div') div.className = outerShell document.body.appendChild(div)/* app.module.css */ When you bundle this with esbuild app.js --bundle --outdir=out you'll get this (notice how the local CSS name outerShell has been renamed):// out/app.js (() => { // app.module.css var outerShell = \"app_outerShell\"; // app.js var div = document.createElement(\"div\"); div.className = outerShell; document.body.appendChild(div); })();/* out/app.css */ This feature only makes sense to use when bundling is enabled both because your code needs to import the renamed local names so that it can use them, and because esbuild needs to be able to process all CSS files containing local names in a single bundling operation so that it can successfully rename conflicting local names to avoid collisions.The names that esbuild generates for local CSS names are an implementation detail and are not intended to be hard-coded anywhere. The only way you should be referencing the local CSS names in your JS or HTML is with an import statement in JS that is bundled with esbuild, as demonstrated above. For example, when minification is enabled, esbuild will use a different name generation algorithm which generates names that are as short as possible (analogous to how esbuild minifies local identifiers in JS).#Using global namesThe local-css loader makes all CSS names in the file local by default. However, sometimes you want to mix local and global names in the same file. There are several ways to do can wrap class names (...) make them global (...) to make them local.You can to make names default to being global to make names default to being local.You can use the global-css loader to still have local CSS features enabled but have names default to being global.Here are some examples:/* * This is a local name with the \"local-css\" loader * and a global name with the \"global-css\" loader */ /* This is a local name with both loaders */ :local(.button) { } /* This is a global name with both loaders */ :global(.button) { } /* \"foo\" is global and \"bar\" is local */ :global /* \"foo\" is global and \"bar\" is local */ :global { .foo { :local { } } }#The composes directiveThe CSS modules specification also describes a composes directive. It allows class selectors with local names to reference other class selectors. This can be used to split out common sets of properties to avoid duplicating them. And with the from keyword, it can also be used to reference class selectors with local names in other files. Here's an example:// app.js import { submit } from './style.css' const div = document.createElement('div') div.className = submit document.body.appendChild(div)/* style.css */ /* anim.css */ Bundling this with esbuild app.js --bundle --outdir=dist =local-css will give you something like this:(() => { // style.css var submit = \"anim_pulse style_button style_submit\"; // app.js var div = document.createElement(\"div\"); div.className = submit; document.body.appendChild(div); })();/* anim.css */ /* style.css */ Notice how using composes causes the string imported into JavaScript to become a space-separated list of all of the local names that were composed together. This is intended to be passed to the className property on a DOM element. Also notice how using composes with from allows you to (indirectly) reference local names in other CSS files.Note that the order in which composed CSS classes from separate files appear in the bundled output file is deliberately undefined by design (see the specification for details). You are not supposed to declare the same CSS property in two separate class selectors and then compose them together. You are only supposed to compose CSS class selectors that declare non-overlapping CSS properties.#CSS caveatsYou should keep the following things in mind when using CSS with esbuild:#Limited CSS verificationCSS has a general syntax specification that all CSS processors use and then many specifications that define what specific CSS rules mean. While esbuild understands general CSS syntax and can understand some CSS rules (enough to bundle CSS file together and to minify CSS reasonably well), esbuild does not contain complete knowledge of CSS. This means esbuild takes a \"garbage in, garbage out\" philosophy toward CSS. If you want to verify that your compiled CSS is free of typos, you should be using a CSS linter in addition to esbuild.#@import order matches the browser The @import rule in CSS behaves differently than the import keyword in JavaScript. In JavaScript, an import means roughly \"make sure the imported file is evaluated before this file is evaluated\" but in CSS, @import means roughly \"re-evaluate the imported file again here\" instead. For example, consider the following @import \"foreground.css\";@import \"background.css\";foreground.css@import \"reset.css\";body { }background.css@import \"reset.css\";body { }reset.cssbody { }Using your intuition from JavaScript, you might think that this code first resets the body to black text on a white background, and then overrides that to white text on a black background. This is not what happens. Instead, the body will be entirely black (both the foreground and the background). This is because @import is supposed to behave as if the import rule was replaced by the imported file (sort of like /* foreground.css */ body { } /* reset.css */ body { } /* background.css */ body { }which ultimately reduces down to { }This behavior is unfortunate, but esbuild behaves this way because that's how CSS is specified, and that's how CSS works in browsers. This is important to know about because some other commonly-used CSS processing tools such as postcss-import incorrectly resolve CSS imports in JavaScript order instead of in CSS order. If you are porting CSS code written for those tools to esbuild (or even just switching over to running your CSS code natively in the browser), you may have appearance changes if your code depends on the incorrect import order.#TextLoader: textThis loader is enabled by default for after the import statement. That looks like string from './example.data' with { type: 'text' } console.log(string)This is from the JavaScript import text proposal. Support for this syntax has also been added to many other JavaScript tools so code written this way will be more portable across tools.#BinaryLoader: binaryThis loader will load the file as a binary buffer at build time and embed it into the bundle using Base64 encoding. The original bytes of the file are decoded from Base64 at run time and exported as a Uint8Array using the default export. Using it looks like uint8array from './example.data' console.log(uint8array)If you need an ArrayBuffer instead, you can just access uint8array.buffer. Note that this loader is not enabled by default. You will need to configure it for the appropriate file extension like JS Go esbuild app.js --bundle =binary require('esbuild').buildSync({ entryPoints: ['app.js'], , loader: { '.data': 'binary' }, outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".data\": api.LoaderBinary, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } after the import statement. That looks like uint8array from './example.data' with { type: 'bytes' } console.log(uint8array)This uses the name bytes instead of binary because it's from the JavaScript import bytes proposal, and that uses the name bytes. Support for this syntax has also been added to many other JavaScript tools so code written this way will be more portable across tools.#Base64Loader: base64This loader will load the file as a binary buffer at build time and embed it into the bundle as a string using Base64 encoding. This string is exported using the default export. Using it looks like base64string from './example.data' console.log(base64string)Note that this loader is not enabled by default. You will need to configure it for the appropriate file extension like JS Go esbuild app.js --bundle =base64 require('esbuild').buildSync({ entryPoints: ['app.js'], , loader: { '.data': 'base64' }, outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".data\": api.LoaderBase64, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } If you intend to turn this into a Uint8Array or an ArrayBuffer, you should use the binary loader instead. It uses an optimized Base64-to-binary converter that is faster than the usual atob conversion process.#Data loader will load the file as a binary buffer at build time and embed it into the bundle as a Base64-encoded data URL. This string is exported using the default export. Using it looks like url from './example.png' let image = new Image image.src = url document.body.appendChild(image)The data URL includes a best guess at the MIME type based on the file extension and/or the file contents, and will look something like this for binary :image/png;base64,iVBORw0KGgo=...or like this for textual :image/svg+xml,<svg></svg>%0ANote that this loader is not enabled by default. You will need to configure it for the appropriate file extension like JS Go esbuild app.js --bundle =dataurl require('esbuild').buildSync({ entryPoints: ['app.js'], , loader: { '.png': 'dataurl' }, outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".png\": api.LoaderDataURL, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".png\": api.LoaderFile, }, Outdir: \"out\", , }) if len(result.Errors) > 0 { os.Exit(1) } } By default the exported string is just the file name. If you would like to prepend a base path to the exported string, this can be done with the public path API option.#The copy loader will copy the file to the output directory and rewrite the import path to point to the copied file. This means the import will still exist in the final bundle and the final bundle will still reference the file instead of including the file inside the bundle. This might be useful if you are running additional bundling tools on esbuild's output, if you want to omit a rarely-used data file from the bundle for faster startup performance, or if you want to rely on specific behavior of your runtime that's triggered by an import. For json from './example.json' assert { type: 'json' } console.log(json)If you bundle the above code with the following JS Go esbuild app.js --bundle =copy --outdir=out --format=esm require('esbuild').buildSync({ entryPoints: ['app.js'], , loader: { '.json': 'copy' }, outdir: 'out', format: 'esm', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".json\": api.LoaderCopy, }, Outdir: \"out\", , , }) if len(result.Errors) > 0 { os.Exit(1) } } the resulting out/app.js file might look something like this:// app.js import json from \"./example-PVCBWCM4.json\" assert { type: \"json\" }; console.log(json);Notice how the import path has been rewritten to point to the copied file out/example-PVCBWCM4.json (a content hash has been added due to the default value of the asset names setting), and how the import assertion for JSON has been kept so the runtime will be able to load the JSON file.#Empty loader tells esbuild to pretend that a file is empty. It can be a helpful way to remove content from your bundle in certain situations. For example, you can configure ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".css\": api.LoaderEmpty, }, }) if len(result.Errors) > 0 { os.Exit(1) } } This loader also lets you remove imported assets from CSS files. For example, you can configure .png files to load with empty so that references to .png files in CSS code such as url(image.png) are replaced with url().\n\nExample:\n```text\nwindow.foo = {}\nimport './something-that-needs-foo'\n```\n\nExample:\n```text\nimport './assign-to-foo-on-window'\nimport './something-that-needs-foo'\n```\n\nExample:\n```text\nlet pow = (a, b) => a ** b;\nlet pow2 = (0, eval)(pow.toString());\nconsole.log(pow2(2, 3));\n```\n\nExample:\n```text\nlet __pow = Math.pow;\nlet pow = (a, b) => __pow(a, b);\nlet pow2 = (0, eval)(pow.toString());\nconsole.log(pow2(2, 3));\n```\n\nExample:\n```text\nimport * as ns from './foo.js'\nns.foo()\n```\n\nExample:\n```text\n// foo.js\nexport function foo() {\n  this.bar()\n}\nexport function bar() {\n  console.log('bar')\n}\n```\n\nExample:\n```text\nimport { foo } from './foo.js'\nfoo()\n```\n\nExample:\n```text\n// index.js\nimport foo from './somelib.js'\nconsole.log(foo)\n```\n\nExample:\n```text\n// somelib.js\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports[\"default\"] = 'foo';\n```\n\nExample:\n```text\n// somelib.js\nexport default 'foo'\n```\n\nExample:\n```text\nimport Button from './button'\nlet button = <Button>Click me</Button>\nrender(button)\n```\n\nExample:\n```text\nimport Button from \"./button\";\nlet button = React.createElement(Button, null, \"Click me\");\nrender(button);\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.js=jsx\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.js': 'jsx' },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".js\": api.LoaderJSX,\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport * as React from 'react'\nrender(<div/>)\n```\n\nExample:\n```text\nesbuild app.jsx --jsx=automatic\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.jsx'],\n  jsx: 'automatic',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.jsx\"},\n    JSX:         api.JSXAutomatic,\n    Outfile:     \"out.js\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.jsx --jsx-factory=h --jsx-fragment=Fragment\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.jsx'],\n  jsxFactory: 'h',\n  jsxFragment: 'Fragment',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.jsx\"},\n    JSXFactory:  \"h\",\n    JSXFragment: \"Fragment\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"compilerOptions\": {\n    \"jsxFactory\": \"h\",\n    \"jsxFragmentFactory\": \"Fragment\"\n  }\n}\n```\n\nExample:\n```text\nimport object from './example.json'\nconsole.log(object)\n```\n\nExample:\n```text\nimport { version } from './package.json'\nconsole.log(version)\n```\n\nExample:\n```text\nimport object from './example.data' with { type: 'json' }\nconsole.log(object)\n```\n\nExample:\n```text\nesbuild --bundle app.css --outfile=out.css\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.css'],\n  bundle: true,\n  outfile: 'out.css',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.css\"},\n    Bundle:      true,\n    Outfile:     \"out.css\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport './button.css'\n\nexport let Button = ({ text }) =>\n  <div className=\"button\">{text}</div>\n```\n\nExample:\n```text\n<html>\n  <head>\n    <link href=\"app.css\" rel=\"stylesheet\">\n    <script src=\"app.js\"></script>\n  </head>\n</html>\n```\n\nExample:\n```text\n// app.js\nimport { outerShell } from './app.module.css'\nconst div = document.createElement('div')\ndiv.className = outerShell\ndocument.body.appendChild(div)\n```\n\nExample:\n```text\n/* app.module.css */\n.outerShell {\n  position: absolute;\n  inset: 0;\n}\n```\n\nExample:\n```text\n// out/app.js\n(() => {\n  // app.module.css\n  var outerShell = \"app_outerShell\";\n\n  // app.js\n  var div = document.createElement(\"div\");\n  div.className = outerShell;\n  document.body.appendChild(div);\n})();\n```\n\nExample:\n```text\n/* out/app.css */\n.app_outerShell {\n  position: absolute;\n  inset: 0;\n}\n```\n\nExample:\n```text\n/*\n * This is a local name with the \"local-css\" loader\n * and a global name with the \"global-css\" loader\n */\n.button {\n}\n\n/* This is a local name with both loaders */\n:local(.button) {\n}\n\n/* This is a global name with both loaders */\n:global(.button) {\n}\n\n/* \"foo\" is global and \"bar\" is local */\n:global .foo :local .bar {\n}\n\n/* \"foo\" is global and \"bar\" is local */\n:global {\n  .foo {\n    :local {\n      .bar {}\n    }\n  }\n}\n```\n\nExample:\n```text\n// app.js\nimport { submit } from './style.css'\nconst div = document.createElement('div')\ndiv.className = submit\ndocument.body.appendChild(div)\n```\n\nExample:\n```text\n/* style.css */\n.button {\n  composes: pulse from \"anim.css\";\n  display: inline-block;\n}\n.submit {\n  composes: button;\n  font-weight: bold;\n}\n```\n\nExample:\n```text\n/* anim.css */\n@keyframes pulse {\n  from, to { opacity: 1 }\n  50% { opacity: 0.5 }\n}\n.pulse {\n  animation: 2s ease-in-out infinite pulse;\n}\n```\n\nExample:\n```text\n(() => {\n  // style.css\n  var submit = \"anim_pulse style_button style_submit\";\n\n  // app.js\n  var div = document.createElement(\"div\");\n  div.className = submit;\n  document.body.appendChild(div);\n})();\n```\n\nExample:\n```text\n/* anim.css */\n@keyframes anim_pulse {\n  from, to {\n    opacity: 1;\n  }\n  50% {\n    opacity: 0.5;\n  }\n}\n.anim_pulse {\n  animation: 2s ease-in-out infinite anim_pulse;\n}\n\n/* style.css */\n.style_button {\n  display: inline-block;\n}\n.style_submit {\n  font-weight: bold;\n}\n```\n\nExample:\n```text\n@import \"foreground.css\";@import \"background.css\";\n```\n\nExample:\n```text\n@import \"reset.css\";body {  color: white;}\n```\n\nExample:\n```text\n@import \"reset.css\";body {  background: black;}\n```\n\nExample:\n```text\nbody {  color: black;  background: white;}\n```\n\nExample:\n```text\n/* reset.css */\nbody {\n  color: black;\n  background: white;\n}\n\n/* foreground.css */\nbody {\n  color: white;\n}\n\n/* reset.css */\nbody {\n  color: black;\n  background: white;\n}\n\n/* background.css */\nbody {\n  background: black;\n}\n```\n\nExample:\n```text\nbody {\n  color: black;\n  background: black;\n}\n```\n\nExample:\n```text\nimport string from './example.txt'\nconsole.log(string)\n```\n\nExample:\n```text\nimport string from './example.data' with { type: 'text' }\nconsole.log(string)\n```\n\nExample:\n```text\nimport uint8array from './example.data'\nconsole.log(uint8array)\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.data=binary\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.data': 'binary' },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".data\": api.LoaderBinary,\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport uint8array from './example.data' with { type: 'bytes' }\nconsole.log(uint8array)\n```\n\nExample:\n```text\nimport base64string from './example.data'\nconsole.log(base64string)\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.data=base64\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.data': 'base64' },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".data\": api.LoaderBase64,\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport url from './example.png'\nlet image = new Image\nimage.src = url\ndocument.body.appendChild(image)\n```\n\nExample:\n```text\ndata:image/png;base64,iVBORw0KGgo=\n```\n\nExample:\n```text\ndata:image/svg+xml,<svg></svg>%0A\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.png=dataurl\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.png': 'dataurl' },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderDataURL,\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.png=file --outdir=out\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.png': 'file' },\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderFile,\n    },\n    Outdir: \"out\",\n    Write:  true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport json from './example.json' assert { type: 'json' }\nconsole.log(json)\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.json=copy --outdir=out --format=esm\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.json': 'copy' },\n  outdir: 'out',\n  format: 'esm',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".json\": api.LoaderCopy,\n    },\n    Outdir: \"out\",\n    Write:  true,\n    Format: api.FormatESModule,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n// app.js\nimport json from \"./example-PVCBWCM4.json\" assert { type: \"json\" };\nconsole.log(json);\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.css=empty\n```\n\nExample:\n```javascript\nrequire('esbuild').buildSync({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.css': 'empty' },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".css\": api.LoaderEmpty,\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.381Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":75,"totalLines":771,"estimatedTokens":10947}}7{"id":"doc-esbuild_plugins-f4f468d7","source":"documentation","title":"esbuild - Plugins","url":"https://esbuild.github.io/plugins/","text":"PluginsThe plugin API allows you to inject code into various parts of the build process. Unlike the rest of the API, it's not available from the command line. You must write either JavaScript or Go code to use the plugin API. Plugins can also only be used with the build API, not with the transform API.#Finding pluginsThere are two ways to find esbuild plugins. One way is to check the (uncurated) central list of existing esbuild plugins. Another way is to search for the esbuild-plugin keyword on the npm registry.If you want to share your esbuild plugin, you \"keywords\": [\"esbuild-plugin\"] to your plugin's package.json file before you publish it.Publish it to npm so others can install it.Add it to the list of existing esbuild plugins so others can find it.#Using pluginsAn esbuild plugin is an object with a name and a setup function. They are passed in an array to the build API call. The setup function is run once for each build API call.Here's a simple plugin example that allows you to import the current environment variables at build Go import * as esbuild from 'esbuild' let envPlugin = { name: 'env', setup(build) { // Intercept import paths called \"env\" so esbuild doesn't attempt // to map them to a file system location. Tag them with the \"env-ns\" // namespace to reserve them for this plugin. build.onResolve({ filter: /^env$/ }, args => ({ , namespace: 'env-ns', })) // Load paths tagged with the \"env-ns\" namespace and behave as if // they point to a JSON file containing the environment variables. build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({ (process.env), loader: 'json', })) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [envPlugin], }) package main import \"encoding/json\" import \"os\" import \"strings\" import \"github.com/evanw/esbuild/pkg/api\" var envPlugin = api.Plugin{ Name: \"env\", (build api.PluginBuild) { // Intercept import paths called \"env\" so esbuild doesn't attempt // to map them to a file system location. Tag them with the \"env-ns\" // namespace to reserve them for this plugin. build.OnResolve(api.OnResolveOptions{Filter: `^env$`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { return api.OnResolveResult{ , Namespace: \"env-ns\", }, nil }) // Load paths tagged with the \"env-ns\" namespace and behave as if // they point to a JSON file containing the environment variables. build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"env-ns\"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { mappings := make(map[string]string) for _, item := range os.Environ() { if equals := strings.IndexByte(item, '='); equals != -1 { mappings[item[:equals]] = item[equals+1:] } } bytes, err := json.Marshal(mappings) if err != nil { return api.OnLoadResult{}, err } contents := string(bytes) return api.OnLoadResult{ Contents: &contents, , }, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{envPlugin}, , }) if len(result.Errors) > 0 { os.Exit(1) } } You would use it like { PATH } from 'env' console.log(`PATH is ${PATH}`)#ConceptsWriting a plugin for esbuild works a little differently than writing a plugin for other bundlers. The concepts below are important to understand before developing your plugin:#NamespacesEvery module has an associated namespace. By default esbuild operates in the file namespace, which corresponds to files on the file system. But esbuild can also handle \"virtual\" modules that don't have a corresponding location on the file system. One case when this happens is when a module is provided using stdin.Plugins can be used to create virtual modules. Virtual modules usually use a namespace other than file to distinguish them from file system modules. Usually the namespace is specific to the plugin that created them. For example, the sample HTTP plugin below uses the http-url namespace for downloaded files.#FiltersEvery callback must provide a regular expression as a filter. This is used by esbuild to skip calling the callback when the path doesn't match its filter, which is done for performance. Calling from esbuild's highly-parallel internals into single-threaded JavaScript code is expensive and should be avoided whenever possible for maximum speed.You should try to use the filter regular expression instead of using JavaScript code for filtering whenever you can. This is faster because the regular expression is evaluated inside of esbuild without calling out to JavaScript at all. For example, the sample HTTP plugin below uses a filter of ^https?:// to ensure that the performance overhead of running the plugin is only incurred for paths that start with http:// or https://.The allowed regular expression syntax is the syntax supported by Go's regular expression engine. This is slightly different than JavaScript. Specifically, look-ahead, look-behind, and backreferences are not supported. Go's regular expression engine is designed to avoid the catastrophic exponential-time worst case performance issues that can affect JavaScript regular expressions.Note that namespaces can also be used for filtering. Callbacks must provide a filter regular expression but can optionally also provide a namespace to further restrict what paths are matched. This can be useful for \"remembering\" where a virtual module came from. Keep in mind that namespaces are matched using an exact string equality test instead of a regular expression, so unlike module paths they are not intended for storing arbitrary data.#On-resolve callbacksA callback added using onResolve will be run on each import path in each module that esbuild builds. The callback can customize how esbuild does path resolution. For example, it can intercept import paths and redirect them somewhere else. It can also mark paths as external. Here is an Go import * as esbuild from 'esbuild' import path from 'node:path' let exampleOnResolvePlugin = { name: 'example', setup(build) { // Redirect all paths starting with \"images/\" to \"./public/images/\" build.onResolve({ filter: /^images\\// }, args => { return { (args.resolveDir, 'public', args.path) } }) // Mark all paths starting with \"http://\" or \"https://\" as external build.onResolve({ filter: /^https?:\\/\\// }, args => { return { , } }) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [exampleOnResolvePlugin], loader: { '.png': 'binary' }, }) package main import \"os\" import \"path/filepath\" import \"github.com/evanw/esbuild/pkg/api\" var exampleOnResolvePlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { // Redirect all paths starting with \"images/\" to \"./public/images/\" build.OnResolve(api.OnResolveOptions{Filter: `^images/`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { return api.OnResolveResult{ (args.ResolveDir, \"public\", args.Path), }, nil }) // Mark all paths starting with \"http://\" or \"https://\" as external build.OnResolve(api.OnResolveOptions{Filter: `^https?://`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { return api.OnResolveResult{ , , }, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{exampleOnResolvePlugin}, , [string]api.Loader{ \".png\": api.LoaderBinary, }, }) if len(result.Errors) > 0 { os.Exit(1) } } The callback can return without providing a path to pass on responsibility for path resolution to the next callback. For a given import path, all onResolve callbacks from all plugins will be run in the order they were registered until one takes responsibility for path resolution. If no callback returns a path, esbuild will run its default path resolution logic.Keep in mind that many callbacks may be running concurrently. In JavaScript, if your callback does expensive work that can run on another thread such as fs.existsSync(), you should make the callback async and use await (in this case with fs.promises.exists()) to allow other code to run in the meantime. In Go, each callback may be run on a separate goroutine. Make sure you have appropriate synchronization in place if your plugin uses any shared data structures.#On-resolve optionsThe onResolve API is meant to be called within the setup function and registers a callback to be triggered in certain situations. It takes a few Go interface OnResolveOptions { namespace?: string; } type OnResolveOptions struct { Filter string Namespace string } filter Every callback must provide a filter, which is a regular expression. The registered callback will be skipped when the path doesn't match this filter. You can read more about filters here. namespace This is optional. If provided, the callback is only run on paths within modules in the provided namespace. You can read more about namespaces here. type ResolveKind = | 'entry-point' | 'import-statement' | 'require-call' | 'dynamic-import' | 'require-resolve' | 'import-rule' | 'composes-from' | 'url-token' type OnResolveArgs struct { Path string Importer string Namespace string ResolveDir string Kind ResolveKind PluginData interface{} With map[string]string } const ( ResolveEntryPoint ResolveKind ResolveJSImportStatement ResolveKind ResolveJSRequireCall ResolveKind ResolveJSDynamicImport ResolveKind ResolveJSRequireResolve ResolveKind ResolveCSSImportRule ResolveKind ResolveCSSComposesFrom ResolveKind ResolveCSSURLToken ResolveKind ) path This is the verbatim unresolved path from the underlying module's source code. It can take any form. While esbuild's default behavior is to interpret import paths as either a relative path or a package name, plugins can be used to introduce new path forms. For example, the sample HTTP plugin below gives special meaning to paths starting with http://. importer This is the path of the module containing this import to be resolved. Note that this path is only guaranteed to be a file system path if the namespace is file. If you want to resolve a path relative to the directory containing the importer module, you should use resolveDir instead since that also works for virtual modules. namespace This is the namespace of the module containing this import to be resolved, as set by the on-load callback that loaded this file. This defaults to the file namespace for modules loaded with esbuild's default behavior. You can read more about namespaces here. resolveDir This is the file system directory to use when resolving an import path to a real path on the file system. For modules in the file namespace, this value defaults to the directory part of the module path. For virtual modules this value defaults to empty but on-load callbacks can optionally give virtual modules a resolve directory too. If that happens, it will be provided to resolve callbacks for unresolved paths in that file. kind This says how the path to be resolved is being imported. For example, 'entry-point' means the path was provided to the API as an entry point path, 'import-statement' means the path is from a JavaScript import or export statement, and 'import-rule' means the path is from a CSS @import rule. pluginData This property is passed from the previous plugin, as set by the on-load callback that loaded this file. with This contains a map of the import attributes that were present on the import statement used to import this module. For example, a module imported using with { type: 'json' } will provide a with value of { type: 'json' } to plugins. You can use this to resolve to a different path depending on the import attributes. in Go). Here are the optional properties that can be Go interface OnResolveResult { errors?: Message[]; external?: boolean; namespace?: string; path?: string; pluginData?: any; pluginName?: string; sideEffects?: boolean; suffix?: string; warnings?: Message[]; watchDirs?: string[]; watchFiles?: string[]; } interface Message { | null; // The original error from a JavaScript plugin, if applicable } interface Location { // 1-based // 0-based, in bytes // in bytes } type OnResolveResult struct { Errors []Message External bool Namespace string Path string PluginData interface{} PluginName string SideEffects SideEffects Suffix string Warnings []Message WatchDirs []string WatchFiles []string } type Message struct { Text string Location *Location Detail interface{} // The original error from a Go plugin, if applicable } type Location struct { File string Namespace string Line int // 1-based Column int // 0-based, in bytes Length int // in bytes LineText string } path Set this to a non-empty string to resolve the import to a specific path. If this is set, no more on-resolve callbacks will be run for this import path in this module. If this is not set, esbuild will continue to run on-resolve callbacks that were registered after the current one. Then, if the path still isn't resolved, esbuild will default to resolving the path relative to the resolve directory of the current module. external Set this to true to mark the module as external, which means it will not be included in the bundle and will instead be imported at run-time. namespace This is the namespace associated with the resolved path. If left empty, it will default to the file namespace for non-external paths. Paths in the file namespace must be an absolute path for the current file system (so starting with a forward slash on Unix and with a drive letter on Windows). If you want to resolve to a path that isn't a file system path, you should set the namespace to something other than file or an empty string. This tells esbuild to not treat the path as pointing to something on the file system. errors and warnings These properties let you pass any log messages generated during path resolution to esbuild where they will be displayed in the terminal according to the current log level and end up in the final build result. For example, if you are calling a library and that library can return errors and/or warnings, you will want to forward them using these properties. If you only have a single error to return, you don't have to pass it via errors. You can simply throw the error in JavaScript or return the error object as the second return value in Go. watchFiles and watchDirs These properties let you return additional file system paths for esbuild's watch mode to scan. By default esbuild will only scan the path provided to onLoad plugins, and only if the namespace is file. If your plugin needs to react to additional changes in the file system, it needs to use one of these properties. A rebuild will be triggered if any file in the watchFiles array has been changed since the last build. Change detection is somewhat complicated and may check the file contents and/or the file's metadata. A rebuild will also be triggered if the list of directory entries for any directory in the watchDirs array has been changed since the last build. Note that this does not check anything about the contents of any file in these directories, and it also does not check any subdirectories. Think of this as checking the output of the Unix ls command. For robustness, you should include all file system paths that were used during the evaluation of the plugin. For example, if your plugin does something equivalent to require.resolve(), you'll need to include the paths of all \"does this file exist\" checks, not just the final path. Otherwise a new file could be created that causes the build to become outdated, but esbuild doesn't detect it because that path wasn't listed. pluginName This property lets you replace this plugin's name with another name for this path resolution operation. It's useful for proxying another plugin through this plugin. For example, it lets you have a single plugin that forwards to a child process containing multiple plugins. You probably won't need to use this. pluginData This property will be passed to the next plugin that runs in the plugin chain. If you return it from an onLoad plugin, it will be passed to the onResolve plugins for any imports in that file, and if you return it from an onResolve plugin, an arbitrary one will be passed to the onLoad plugin when it loads the file (it's arbitrary since the relationship is many-to-one). This is useful to pass data between different plugins without them having to coordinate directly. sideEffects Setting this property to false tells esbuild that imports of this module can be removed if the imported names are unused. This behaves as if \"sideEffects\": false was specified the corresponding package.json file. For example, import { x } from \"y\" may be completely removed if x is unused and y has been marked as You can read more about what sideEffects means in Webpack's documentation about the feature. suffix Returning a value here lets you pass along an optional URL query or hash to append to the path that is not included in the path itself. Storing this separately is beneficial in cases when the path is processed by something that is not aware of the suffix, either by esbuild itself or by another plugin. For example, an on-resolve plugin might return a suffix of ?#iefix for a .eot file in a build with a different on-load plugin for paths ending in .eot. Keeping the suffix separate means the suffix is still associated with the path but the .eot plugin will still match the file without needing to know anything about suffixes. If you do set a suffix, it must begin with either ? or # because it's intended to be a URL query or hash. This feature has certain obscure uses such as hacking around bugs in IE8's CSS parser and may not be that useful otherwise. If you do use it, keep in mind that each unique namespace, path, and suffix combination is considered by esbuild to be a unique module identifier so by returning a different suffix for the same path, you are telling esbuild to create another copy of the module. #On-load callbacksA callback added using onLoad will be run for each unique path/namespace pair that has not been marked as external. Its job is to return the contents of the module and to tell esbuild how to interpret it. Here's an example plugin that converts .txt files into an array of Go import * as esbuild from 'esbuild' import fs from 'node:fs' let exampleOnLoadPlugin = { name: 'example', setup(build) { // Load \".txt\" files and return an array of words build.onLoad({ filter: /\\.txt$/ }, async (args) => { let text = await fs.promises.readFile(args.path, 'utf8') return { (text.split(/\\s+/)), loader: 'json', } }) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [exampleOnLoadPlugin], }) package main import \"encoding/json\" import \"io/ioutil\" import \"os\" import \"strings\" import \"github.com/evanw/esbuild/pkg/api\" var exampleOnLoadPlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { // Load \".txt\" files and return an array of words build.OnLoad(api.OnLoadOptions{Filter: `\\.txt$`}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { text, err := ioutil.ReadFile(args.Path) if err != nil { return api.OnLoadResult{}, err } bytes, err := json.Marshal(strings.Fields(string(text))) if err != nil { return api.OnLoadResult{}, err } contents := string(bytes) return api.OnLoadResult{ Contents: &contents, , }, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{exampleOnLoadPlugin}, , }) if len(result.Errors) > 0 { os.Exit(1) } } The callback can return without providing the contents of the module. In that case the responsibility for loading the module is passed to the next registered callback. For a given module, all onLoad callbacks from all plugins will be run in the order they were registered until one takes responsibility for loading the module. If no callback returns contents for the module, esbuild will run its default module loading logic.Keep in mind that many callbacks may be running concurrently. In JavaScript, if your callback does expensive work that can run on another thread such as fs.readFileSync(), you should make the callback async and use await (in this case with fs.promises.readFile()) to allow other code to run in the meantime. In Go, each callback may be run on a separate goroutine. Make sure you have appropriate synchronization in place if your plugin uses any shared data structures.#On-load optionsThe onLoad API is meant to be called within the setup function and registers a callback to be triggered in certain situations. It takes a few Go interface OnLoadOptions { namespace?: string; } type OnLoadOptions struct { Filter string Namespace string } filter Every callback must provide a filter, which is a regular expression. The registered callback will be skipped when the path doesn't match this filter. You can read more about filters here. namespace This is optional. If provided, the callback is only run on paths within modules in the provided namespace. You can read more about namespaces here. type OnLoadArgs struct { Path string Namespace string Suffix string PluginData interface{} With map[string]string } path This is the fully-resolved path to the module. It should be considered a file system path if the namespace is file, but otherwise the path can take any form. For example, the sample HTTP plugin below gives special meaning to paths starting with http://. namespace This is the namespace that the module path is in, as set by the on-resolve callback that resolved this file. It defaults to the file namespace for modules loaded with esbuild's default behavior. You can read more about namespaces here. suffix This is the URL query and/or hash at the end of the file path, if there is one. It's either filled in by esbuild's native path resolution behavior or returned by the on-resolve callback that resolved this file. This is stored separately from the path so that most plugins can just deal with the path and ignore the suffix. The on-load behavior that's built into esbuild just ignores the suffix and loads the file from its path alone. For context, IE8's CSS parser has a bug where it considers certain URLs to extend to the last ) instead of the first ). So the CSS code url('Foo.eot') format('eot') is incorrectly considered to have a URL of Foo.eot') format('eot. To avoid this, people typically add something like ?#iefix so that IE8 sees the URL as Foo.eot?#iefix') format('eot. Then the path part of the URL is Foo.eot and the query part is ?#iefix') format('eot, which means IE8 can find the file Foo.eot by discarding the query. The suffix feature was added to esbuild to handle CSS files containing these hacks. A URL of Foo.eot?#iefix should be considered external if all files matching *.eot have been marked as external, but the ?#iefix suffix should still be present in the final output file. pluginData This property is passed from the previous plugin, as set by the on-resolve callback that runs in the plugin chain. with This contains a map of the import attributes that were present on the import statement used to import this module. For example, a module imported using with { type: 'json' } will provide a with value of { type: 'json' } to plugins. A given module is loaded separately for each unique combination of import attributes, so these attributes are guaranteed to have been provided by all import statements used to import this module. That means they can be used by the plugin to alter the content of this module. in Go). Here are the optional properties that can be Go interface OnLoadResult { contents?: string | Uint8Array; errors?: Message[]; loader?: Loader; pluginData?: any; pluginName?: string; resolveDir?: string; warnings?: Message[]; watchDirs?: string[]; watchFiles?: string[]; } interface Message { | null; // The original error from a JavaScript plugin, if applicable } interface Location { // 1-based // 0-based, in bytes // in bytes } type OnLoadResult struct { Contents *string Errors []Message Loader Loader PluginData interface{} PluginName string ResolveDir string Warnings []Message WatchDirs []string WatchFiles []string } type Message struct { Text string Location *Location Detail interface{} // The original error from a Go plugin, if applicable } type Location struct { File string Namespace string Line int // 1-based Column int // 0-based, in bytes Length int // in bytes LineText string } contents Set this to a string to specify the contents of the module. If this is set, no more on-load callbacks will be run for this resolved path. If this is not set, esbuild will continue to run on-load callbacks that were registered after the current one. Then, if the contents are still not set, esbuild will default to loading the contents from the file system if the resolved path is in the file namespace. loader This tells esbuild how to interpret the contents. For example, the js loader interprets the contents as JavaScript and the css loader interprets the contents as CSS. The loader defaults to js if it's not specified. See the content types page for a complete list of all built-in loaders. resolveDir This is the file system directory to use when resolving an import path in this module to a real path on the file system. For modules in the file namespace, this value defaults to the directory part of the module path. Otherwise this value defaults to empty unless the plugin provides one. If the plugin doesn't provide one, esbuild's default behavior won't resolve any imports in this module. This directory will be passed to any on-resolve callbacks that run on unresolved import paths in this module. errors and warnings These properties let you pass any log messages generated during path resolution to esbuild where they will be displayed in the terminal according to the current log level and end up in the final build result. For example, if you are calling a library and that library can return errors and/or warnings, you will want to forward them using these properties. If you only have a single error to return, you don't have to pass it via errors. You can simply throw the error in JavaScript or return the error object as the second return value in Go. watchFiles and watchDirs These properties let you return additional file system paths for esbuild's watch mode to scan. By default esbuild will only scan the path provided to onLoad plugins, and only if the namespace is file. If your plugin needs to react to additional changes in the file system, it needs to use one of these properties. A rebuild will be triggered if any file in the watchFiles array has been changed since the last build. Change detection is somewhat complicated and may check the file contents and/or the file's metadata. A rebuild will also be triggered if the list of directory entries for any directory in the watchDirs array has been changed since the last build. Note that this does not check anything about the contents of any file in these directories, and it also does not check any subdirectories. Think of this as checking the output of the Unix ls command. For robustness, you should include all file system paths that were used during the evaluation of the plugin. For example, if your plugin does something equivalent to require.resolve(), you'll need to include the paths of all \"does this file exist\" checks, not just the final path. Otherwise a new file could be created that causes the build to become outdated, but esbuild doesn't detect it because that path wasn't listed. pluginName This property lets you replace this plugin's name with another name for this module load operation. It's useful for proxying another plugin through this plugin. For example, it lets you have a single plugin that forwards to a child process containing multiple plugins. You probably won't need to use this. pluginData This property will be passed to the next plugin that runs in the plugin chain. If you return it from an onLoad plugin, it will be passed to the onResolve plugins for any imports in that file, and if you return it from an onResolve plugin, an arbitrary one will be passed to the onLoad plugin when it loads the file (it's arbitrary since the relationship is many-to-one). This is useful to pass data between different plugins without them having to coordinate directly. #Caching your pluginSince esbuild is so fast, it's often the case that plugin evaluation is the main bottleneck when building with esbuild. Caching of plugin evaluation is left up to each plugin instead of being a part of esbuild itself because cache invalidation is plugin-specific. If you are writing a slow plugin that needs a cache to be fast, you will have to write the cache logic yourself.A cache is essentially a map that memoizes the transform function that represents your plugin. The keys of the map usually contain the inputs to your transform function and the values of the map usually contain the outputs of your transform function. In addition, the map usually has some form of least-recently-used cache eviction policy to avoid continually growing larger in size over time.The cache can either be stored in memory (beneficial for use with esbuild's rebuild API), on disk (beneficial for caching across separate build script invocations), or even on a server (beneficial for really slow transforms that can be shared between different developer machines). Where to store the cache is case-specific and depends on your plugin.Here is a simple caching example. Say we want to cache the function slowTransform() that takes as input the contents of a file in the *.example format and transforms it to JavaScript. An in-memory cache that avoids redundant calls to this function when used with esbuild's rebuild API) might look something like fs from 'node:fs' let examplePlugin = { name: 'example', setup(build) { let cache = new Map build.onLoad({ filter: /\\.example$/ }, async (args) => { let input = await fs.promises.readFile(args.path, 'utf8') let key = args.path let value = cache.get(key) if (!value || value.input !== input) { let contents = slowTransform(input) value = { input, output: { contents } } cache.set(key, value) } return value.output }) } }Some important caveats about the caching code is no cache eviction policy present in the code above. Memory usage will continue to grow if more and more keys are added to the cache map. To combat this limitation somewhat, the input value is stored in the cache value instead of in the cache key. This means that changing the contents of a file will not leak memory because the key only includes the file path, not the file contents. Changing the file contents only overwrites the previous cache entry. This is probably fine for common usage where someone repeatedly edits the same file in between incremental rebuilds and only occasionally adds or renames files. But the cache will continue to grow in size if each build contains new unique path names (e.g. perhaps an auto-generated temporary file path containing the current time). A more advanced version might use a least-recently-used eviction policy. Cache invalidation only works if slowTransform() is a pure function (meaning that the output of the function only depends on the inputs to the function) and if all of the inputs to the function are somehow captured in the lookup to the cache map. For example if the transform function automatically reads the contents of some other files and the output depends on the contents of those files too, then the cache would fail to be invalidated when those files are changed because they are not included in the cache key. This part is easy to mess up so it's worth going through a specific example. Consider a plugin that implements a compile-to-CSS language. If that plugin implements @import rules itself by parsing imported files and either bundles them or makes any exported variable declarations available to the importing code, your plugin will not be correct if it only checks that the importing file's contents haven't changed because a change to the imported file could also invalidate the cache. You may be thinking that you could just add the contents of the imported file to the cache key to fix this problem. However, even that may be incorrect. Say for example this plugin uses require.resolve() to resolve the import path to an absolute file path. This is a common approach because it uses node's built-in path resolution that can resolve to a path inside a package. This function usually does many checks for files in different locations before returning the resolved path. For example, importing the path pkg/file from the file src/entry.css might check the following locations (yes, node's package resolution algorithm is very inefficient): src/node_modules/pkg/file src/node_modules/pkg/file.css src/node_modules/pkg/file/package.json src/node_modules/pkg/file/main src/node_modules/pkg/file/main.css src/node_modules/pkg/file/main/index.css src/node_modules/pkg/file/index.css node_modules/pkg/file node_modules/pkg/file.css node_modules/pkg/file/package.json node_modules/pkg/file/main node_modules/pkg/file/main.css node_modules/pkg/file/main/index.css node_modules/pkg/file/index.css Say the import pkg/file was ultimately resolved to the absolute path node_modules/pkg/file/index.css. Even if you cache the contents of both the importing file and the imported file and verify that the contents of both files are still the same before reusing the cache entry, the cache entry could still be stale if one of the other files that require.resolve() checks for has either been created or deleted since the cache entry was added. Caching this correctly essentially involves always re-running all such path resolutions even when none of the input files have been changed and verifying that none of the path resolutions have changed either. These cache keys are only correct for an in-memory cache. It would be incorrect to implement a file system cache using the same cache keys. While an in-memory cache is guaranteed to always run the same code for every build because the code is also stored in memory, a file system cache could potentially be accessed by two separate builds that each contain different code. Specifically the code for the slowTransform() function may have been changed in between builds. This can happen in various cases. The package containing the function slowTransform() may have been updated, or one of its transitive dependencies may have been updated even if you have pinned the package's version due to how npm handles semver, or someone may have mutated the package contents on the file system in the meantime, or the transform function may be calling a node API and different builds could be running on different node versions. If you want to store your cache on the file system, you should guard against changes to the code for the transform function by storing some representation of the code for the transform function in the cache key. This is usually some form of hash that contains the contents of all relevant files in all relevant packages as well as potentially other details such as which node version you are currently running on. Getting all of this to be correct is non-trivial. #On-start callbacksRegister an on-start callback to be notified when a new build starts. This triggers for all builds, not just the initial build, so it's especially useful for rebuilds, watch mode, and serve mode. Here's how to add an on-start Go let examplePlugin = { name: 'example', setup(build) { build.onStart(() => { console.log('build started') }) }, } package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" var examplePlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { build.OnStart(func() (api.OnStartResult, error) { fmt.Fprintf(os.Stderr, \"build started\\n\") return api.OnStartResult{}, nil }) }, } func main() { } You should not use an on-start callback for initialization since it can be run multiple times. If you want to initialize something, just put your plugin initialization code directly inside the setup function instead.The on-start callback can be async and can return a promise. All on-start callbacks from all plugins are run concurrently, and then the build waits for all on-start callbacks to finish before proceeding. On-start callbacks can optionally return errors and/or warnings to be included with the build.Note that on-start callbacks do not have the ability to mutate the build options. The initial build options can only be modified within the setup function and are consumed once setup returns. All builds after the first one reuse the same initial options so the initial options are never re-consumed, and modifications to build.initialOptions that are done within the start callback are ignored.#On-end callbacksRegister an on-end callback to be notified when a new build ends. This triggers for all builds, not just the initial build, so it's especially useful for rebuilds, watch mode, and serve mode. Here's how to add an on-end Go let examplePlugin = { name: 'example', setup(build) { build.onEnd(result => { console.log(`build ended with ${result.errors.length} errors`) }) }, } package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" var examplePlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { build.OnEnd(func(result *api.BuildResult) (api.OnEndResult, error) { fmt.Fprintf(os.Stderr, \"build ended with %d errors\\n\", len(result.Errors)) return api.OnEndResult{}, nil }) }, } func main() { } All on-end callbacks are run in serial and each callback is given access to the final build result. It can modify the build result before returning and can delay the end of the build by returning a promise. If you want to be able to inspect the build graph, you should enable the metafile setting on the initial options and the build graph will be returned as the metafile property on the build result object.#On-dispose callbacksRegister an on-dispose callback to perform cleanup when the plugin is no longer used. It will be called after every build() call regardless of whether the build failed or not, as well as after the first dispose() call on a given build context. Here's how to add an on-dispose Go let examplePlugin = { name: 'example', setup(build) { build.onDispose(() => { console.log('This plugin is no longer used') }) }, } package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" var examplePlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { build.OnDispose(func() { fmt.Println(\"This plugin is no longer used\") }) }, } func main() { } #Accessing build optionsPlugins can access the initial build options from within the setup method. This lets you inspect how the build is configured as well as modify the build options before the build starts. Here is an Go let examplePlugin = { name: 'auto-node-env', setup(build) { const options = build.initialOptions options.define = options.define || {} options.define['process.env.NODE_ENV'] = options.minify ? '\"production\"' : '\"development\"' }, } package main import \"github.com/evanw/esbuild/pkg/api\" var examplePlugin = api.Plugin{ Name: \"auto-node-env\", (build api.PluginBuild) { options := build.InitialOptions if options.Define == nil { options.Define = map[string]string{} } if options.MinifyWhitespace && options.MinifyIdentifiers && options.MinifySyntax { options.Define[`process.env.NODE_ENV`] = `\"production\"` } else { options.Define[`process.env.NODE_ENV`] = `\"development\"` } }, } func main() { } Note that modifications to the build options after the build starts do not affect the build. In particular, rebuilds, watch mode, and serve mode do not update their build options if plugins mutate the build options object after the first build has started.#Resolving pathsWhen a plugin returns a result from an on-resolve callback, the result completely replaces esbuild's built-in path resolution. This gives the plugin complete control over how path resolution works, but it means that the plugin may have to reimplement some of the behavior that esbuild already has built-in if it wants to have similar behavior. For example, a plugin may want to search for a package in the user's node_modules directory, which is something esbuild already implements.Instead of reimplementing esbuild's built-in behavior, plugins have the option of running esbuild's path resolution manually and inspecting the result. This lets you adjust the inputs and/or the outputs of esbuild's path resolution. Here's an Go import * as esbuild from 'esbuild' let examplePlugin = { name: 'example', setup(build) { build.onResolve({ filter: /^example$/ }, async () => { const result = await build.resolve('./foo', { kind: 'import-statement', resolveDir: './bar', }) if (result.errors.length > 0) { return { } } return { , } }) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [examplePlugin], }) package main import \"os\" import \"github.com/evanw/esbuild/pkg/api\" var examplePlugin = api.Plugin{ Name: \"example\", (build api.PluginBuild) { build.OnResolve(api.OnResolveOptions{Filter: `^example$`}, func(api.OnResolveArgs) (api.OnResolveResult, error) { result := build.Resolve(\"./foo\", api.ResolveOptions{ , ResolveDir: \"./bar\", }) if len(result.Errors) > 0 { return api.OnResolveResult{Errors: result.Errors}, nil } return api.OnResolveResult{Path: result.Path, }, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{examplePlugin}, , }) if len(result.Errors) > 0 { os.Exit(1) } } This plugin intercepts imports to the path example, tells esbuild to resolve the import ./foo in the directory ./bar, forces whatever path esbuild returns to be considered external, and maps the import for example to that external path.Here are some additional things to know about this you don't pass the optional resolveDir parameter, esbuild will still run onResolve plugin callbacks but will not attempt any path resolution itself. All of esbuild's path resolution logic depends on the resolveDir parameter including looking for packages in node_modules directories (since it needs to know where those node_modules directories might be). If you want to resolve a file name in a specific directory, make sure the input path starts with ./. Otherwise the input path will be treated as a package path instead of a relative path. This behavior is identical to esbuild's normal path resolution logic. If path resolution fails, the errors property on the returned object will be a non-empty array containing the error information. This function does not always throw an error when it fails. You need to check for errors after calling it. The behavior of this function depends on the build configuration. That's why it's a property of the build object instead of being a top-level API call. This also means you can't call it until all plugin setup functions have finished since these give plugins the opportunity to adjust the build configuration before it's frozen at the start of the build. So the resolve function is going to be most useful inside your onResolve and/or onLoad callbacks. There is currently no attempt made to detect infinite path resolution loops. Calling resolve from within onResolve with the same parameters is almost certainly a bad idea. type ResolveKind = | 'entry-point' | 'import-statement' | 'require-call' | 'dynamic-import' | 'require-resolve' | 'import-rule' | 'url-token' type ResolveOptions struct { Kind ResolveKind Importer string Namespace string ResolveDir string PluginData interface{} With map[string]string } const ( ResolveEntryPoint ResolveKind ResolveJSImportStatement ResolveKind ResolveJSRequireCall ResolveKind ResolveJSDynamicImport ResolveKind ResolveJSRequireResolve ResolveKind ResolveCSSImportRule ResolveKind ResolveCSSURLToken ResolveKind ) kind This tells esbuild how the path was imported, which can affect path resolution. For example, node's path resolution rules say that paths imported using 'require-call' should respect conditional package imports in the \"require\" section in package.json while paths imported using 'import-statement' should respect conditional package imports in the \"import\" section instead. importer If set, this is interpreted as the path of the module containing this import to be resolved. This affects plugins with onResolve callbacks that check the importer value. namespace If set, this is interpreted as the namespace of the module containing this import to be resolved. This affects plugins with onResolve callbacks that check the namespace value. You can read more about namespaces here. resolveDir This is the file system directory to use when resolving an import path to a real path on the file system. This must be set for esbuild's built-in path resolution to be able to find a given file, even for non-relative package paths (since esbuild needs to know where the node_modules directory is). pluginData This property can be used to pass custom data to whatever on-resolve callbacks match this import path. The meaning of this data is left entirely up to you. with This is the import attributes assocated with the import statement for this path. For example, a with value of { type: 'json' } would be appropriate for a module imported using with { type: 'json' } attributes on the import statement. This information isn't used by esbuild but may be used by on-resolve callbacks. interface Message { | null; // The original error from a JavaScript plugin, if applicable } interface Location { // 1-based // 0-based, in bytes // in bytes } type ResolveResult struct { Errors []Message External bool Namespace string Path string PluginData interface{} SideEffects bool Suffix string Warnings []Message } type Message struct { Text string Location *Location Detail interface{} // The original error from a Go plugin, if applicable } type Location struct { File string Namespace string Line int // 1-based Column int // 0-based, in bytes Length int // in bytes LineText string } path This is the result of path resolution, or an empty string if path resolution failed. external This will be true if the path was marked as external, which means it will not be included in the bundle and will instead be imported at run-time. namespace This is the namespace associated with the resolved path. You can read more about namespaces here. errors and warnings These properties hold any log messages generated during path resolution, either by any plugins that responded to this path resolution operation or by esbuild itself. These log messages are not automatically included in the log, so they will be completely invisible if you discard them. If you want them to be included in the log, you'll need to return them from either onResolve or onLoad. pluginData If a plugin responded to this path resolution operation and returned pluginData from its onResolve callback, that data will end up here. This is useful to pass data between different plugins without them having to coordinate directly. sideEffects This property will be true unless the module is somehow annotated as having no side effects, in which case it will be false. This will be false for packages that have \"sideEffects\": false in the corresponding package.json file, and also if a plugin responds to this path resolution operation and returns You can read more about what sideEffects means in Webpack's documentation about the feature. suffix This can contain an optional URL query or hash if there was one at the end of the path to be resolved and if removing it was required for the path to resolve successfully. from 'https://unpkg.com/lodash-es@4.17.15/lodash.js' console.log(zip([1, 2], ['a', 'b']))This can be accomplished with the following plugin. Note that for real usage the downloads should be cached, but caching has been omitted from this example for Go import * as esbuild from 'esbuild' import https from 'node:https' import http from 'node:http' let httpPlugin = { name: 'http', setup(build) { // Intercept import paths starting with \"http:\" and \"https:\" so // esbuild doesn't attempt to map them to a file system location. // Tag them with the \"http-url\" namespace to associate them with // this plugin. build.onResolve({ filter: /^https?:\\/\\// }, args => ({ , namespace: 'http-url', })) // We also want to intercept all import paths inside downloaded // files and resolve them against the original URL. All of these // files will be in the \"http-url\" namespace. Make sure to keep // the newly resolved URL in the \"http-url\" namespace so imports // inside it will also be resolved as URLs recursively. build.onResolve({ filter: /.*/, namespace: 'http-url' }, args => ({ URL(args.path, args.importer).toString(), namespace: 'http-url', })) // When a URL is loaded, we want to actually download the content // from the internet. This has just enough logic to be able to // handle the example import from unpkg.com but in reality this // would probably need to be more complex. build.onLoad({ filter: /.*/, namespace: 'http-url' }, async (args) => { let contents = await new Promise((resolve, reject) => { function fetch(url) { console.log(`Downloading: ${url}`) let lib = url.startsWith('https') ? let req = lib.get(url, res => { if ([301, 302, 307].includes(res.statusCode)) { fetch(new URL(res.headers.location, url).toString()) req.abort() } else if (res.statusCode === 200) { let chunks = [] res.on('data', chunk => chunks.push(chunk)) res.on('end', () => resolve(Buffer.concat(chunks))) } else { reject(new Error(`GET ${url} ${res.statusCode}`)) } }).on('error', reject) } fetch(args.path) }) return { contents } }) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [httpPlugin], }) package main import \"io/ioutil\" import \"net/http\" import \"net/url\" import \"os\" import \"github.com/evanw/esbuild/pkg/api\" var httpPlugin = api.Plugin{ Name: \"http\", (build api.PluginBuild) { // Intercept import paths starting with \"http:\" and \"https:\" so // esbuild doesn't attempt to map them to a file system location. // Tag them with the \"http-url\" namespace to associate them with // this plugin. build.OnResolve(api.OnResolveOptions{Filter: `^https?://`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { return api.OnResolveResult{ , Namespace: \"http-url\", }, nil }) // We also want to intercept all import paths inside downloaded // files and resolve them against the original URL. All of these // files will be in the \"http-url\" namespace. Make sure to keep // the newly resolved URL in the \"http-url\" namespace so imports // inside it will also be resolved as URLs recursively. build.OnResolve(api.OnResolveOptions{Filter: \".*\", Namespace: \"http-url\"}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { base, err := url.Parse(args.Importer) if err != nil { return api.OnResolveResult{}, err } relative, err := url.Parse(args.Path) if err != nil { return api.OnResolveResult{}, err } return api.OnResolveResult{ (relative).String(), Namespace: \"http-url\", }, nil }) // When a URL is loaded, we want to actually download the content // from the internet. This has just enough logic to be able to // handle the example import from unpkg.com but in reality this // would probably need to be more complex. build.OnLoad(api.OnLoadOptions{Filter: \".*\", Namespace: \"http-url\"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { res, err := http.Get(args.Path) if err != nil { return api.OnLoadResult{}, err } defer res.Body.Close() bytes, err := ioutil.ReadAll(res.Body) if err != nil { return api.OnLoadResult{}, err } contents := string(bytes) return api.OnLoadResult{Contents: &contents}, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{httpPlugin}, , }) if len(result.Errors) > 0 { os.Exit(1) } } The plugin first uses a resolver to move http:// and https:// URLs to the http-url namespace. Setting the namespace tells esbuild to not treat these paths as file system paths. Then, a loader for the http-url namespace downloads the module and returns the contents to esbuild. From there, another resolver for import paths inside modules in the http-url namespace picks up relative paths and translates them into full URLs by resolving them against the importing module's URL. That then feeds back into the loader allowing downloaded modules to download additional modules recursively.#WebAssembly pluginThis example with binary data, creating virtual modules using import statements, re-using the same path with different namespaces.This plugin allows you to import )When you import a .wasm file, this plugin generates a virtual JavaScript module in the wasm-stub namespace with a single function that loads the WebAssembly module exported as the default export. That stub module looks something like wasm from '/path/to/example.wasm' export default (imports) => WebAssembly.instantiate(wasm, imports).then( result => result.instance.exports)Then that stub module imports the WebAssembly file itself as another module in the wasm-binary namespace using esbuild's built-in binary loader. This means importing a .wasm file actually generates two virtual modules. Here's the code for the Go import * as esbuild from 'esbuild' import path from 'node:path' import fs from 'node:fs' let wasmPlugin = { name: 'wasm', setup(build) { // Resolve \".wasm\" files to a path with a namespace build.onResolve({ filter: /\\.wasm$/ }, args => { // If this is the import inside the stub module, import the // binary itself. Put the path in the \"wasm-binary\" namespace // to tell our binary load callback to load the binary file. if (args.namespace === 'wasm-stub') { return { , namespace: 'wasm-binary', } } // Otherwise, generate the JavaScript stub module for this // \".wasm\" file. Put it in the \"wasm-stub\" namespace to tell // our stub load callback to fill it with JavaScript. // // Resolve relative paths to absolute paths here since this // resolve callback is given \"resolveDir\", the directory to // resolve imports against. if (args.resolveDir === '') { return // Ignore unresolvable paths } return { (args.path) ? args.path : path.join(args.resolveDir, args.path), namespace: 'wasm-stub', } }) // Virtual modules in the \"wasm-stub\" namespace are filled with // the JavaScript code for compiling the WebAssembly binary. The // binary itself is imported from a second virtual module. build.onLoad({ filter: /.*/, namespace: 'wasm-stub' }, async (args) => ({ contents: `import wasm from ${JSON.stringify(args.path)} export default (imports) => WebAssembly.instantiate(wasm, imports).then( result => result.instance.exports)`, })) // Virtual modules in the \"wasm-binary\" namespace contain the // actual bytes of the WebAssembly file. This uses esbuild's // built-in \"binary\" loader instead of manually embedding the // binary data inside JavaScript code ourselves. build.onLoad({ filter: /.*/, namespace: 'wasm-binary' }, async (args) => ({ fs.promises.readFile(args.path), loader: 'binary', })) }, } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [wasmPlugin], }) package main import \"encoding/json\" import \"io/ioutil\" import \"os\" import \"path/filepath\" import \"github.com/evanw/esbuild/pkg/api\" var wasmPlugin = api.Plugin{ Name: \"wasm\", (build api.PluginBuild) { // Resolve \".wasm\" files to a path with a namespace build.OnResolve(api.OnResolveOptions{Filter: `\\.wasm$`}, func(args api.OnResolveArgs) (api.OnResolveResult, error) { // If this is the import inside the stub module, import the // binary itself. Put the path in the \"wasm-binary\" namespace // to tell our binary load callback to load the binary file. if args.Namespace == \"wasm-stub\" { return api.OnResolveResult{ , Namespace: \"wasm-binary\", }, nil } // Otherwise, generate the JavaScript stub module for this // \".wasm\" file. Put it in the \"wasm-stub\" namespace to tell // our stub load callback to fill it with JavaScript. // // Resolve relative paths to absolute paths here since this // resolve callback is given \"resolveDir\", the directory to // resolve imports against. if args.ResolveDir == \"\" { return api.OnResolveResult{}, nil // Ignore unresolvable paths } if !filepath.IsAbs(args.Path) { args.Path = filepath.Join(args.ResolveDir, args.Path) } return api.OnResolveResult{ , Namespace: \"wasm-stub\", }, nil }) // Virtual modules in the \"wasm-stub\" namespace are filled with // the JavaScript code for compiling the WebAssembly binary. The // binary itself is imported from a second virtual module. build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"wasm-stub\"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { bytes, err := json.Marshal(args.Path) if err != nil { return api.OnLoadResult{}, err } contents := `import wasm from ` + string(bytes) + ` export default (imports) => WebAssembly.instantiate(wasm, imports).then( result => result.instance.exports)` return api.OnLoadResult{Contents: &contents}, nil }) // Virtual modules in the \"wasm-binary\" namespace contain the // actual bytes of the WebAssembly file. This uses esbuild's // built-in \"binary\" loader instead of manually embedding the // binary data inside JavaScript code ourselves. build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"wasm-binary\"}, func(args api.OnLoadArgs) (api.OnLoadResult, error) { bytes, err := ioutil.ReadFile(args.Path) if err != nil { return api.OnLoadResult{}, err } contents := string(bytes) return api.OnLoadResult{ Contents: &contents, , }, nil }) }, } func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", Plugins: []api.Plugin{wasmPlugin}, , }) if len(result.Errors) > 0 { os.Exit(1) } } The plugin works in multiple steps. First, a resolve callback captures > <input type=\"number\" ={b}> <p>{a} + {b} = {a + b}</p>Compiling this code with the Svelte compiler generates a JavaScript module that depends on the svelte/internal package and that exports the component as a a single class using the default export. This means .svelte files can be compiled independently, which makes Svelte a good fit for an esbuild plugin. This plugin is triggered by importing a .svelte file like Button from './button.svelte'Here's the code for the plugin (there is no Go version of this plugin because the Svelte compiler is written in JavaScript):import * as esbuild from 'esbuild' import * as svelte from 'svelte/compiler' import path from 'node:path' import fs from 'node:fs' let sveltePlugin = { name: 'svelte', setup(build) { build.onLoad({ filter: /\\.svelte$/ }, async (args) => { // This converts a message in Svelte's format to esbuild's format let convertMessage = ({ message, start, end }) => { let location if (start && end) { let lineText = source.split(/\\r\\n|\\r|\\n/g)[start.line - 1] let lineEnd = start.line === end.line ? end.column : lineText.length location = { , , , - start.column, lineText, } } return { , location } } // Load the file from the file system let source = await fs.promises.readFile(args.path, 'utf8') let filename = path.relative(process.cwd(), args.path) // Convert Svelte syntax to JavaScript try { let { js, warnings } = svelte.compile(source, { filename }) let contents = js.code + `//# sourceMappingURL=` + js.map.toUrl() return { contents, (convertMessage) } } catch (e) { return { errors: [convertMessage(e)] } } }) } } await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', plugins: [sveltePlugin], }) This plugin only needs a load callback, not a resolve callback, because it's simple enough that it just needs to transform the loaded code into JavaScript without worrying about where the code comes from.It appends a //# sourceMappingURL= comment to the generated JavaScript to tell esbuild how to map the generated JavaScript back to the original source code. If source maps are enabled during the build, esbuild will use this to ensure that the generated positions in the final source map are mapped all the way back to the original Svelte file instead of to the intermediate JavaScript code.#Plugin API limitationsThis API does not intend to cover all use cases. It's not possible to hook into every part of the bundling process. For example, it's not currently possible to modify the AST directly. This restriction exists to preserve the excellent performance characteristics of esbuild as well as to avoid exposing too much API surface which would be a maintenance burden and would prevent improvements that involve changing the AST.One way to think about esbuild is as a \"linker\" for the web. Just like a linker for native code, esbuild's job is to take a set of files, resolve and bind references between them, and generate a single file containing all of the code linked together. A plugin's job is to generate the individual files that end up being linked.Plugins in esbuild work best when they are relatively scoped and only customize a small aspect of the build. For example, a plugin for a special configuration file in a custom format (e.g. YAML) is very appropriate. The more plugins you use, the slower your build will get, especially if your plugin is written in JavaScript. If a plugin applies to every file in your build, then your build will likely be very slow. If caching is applicable, it must be done by the plugin itself.\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet envPlugin = {\n  name: 'env',\n  setup(build) {\n    // Intercept import paths called \"env\" so esbuild doesn't attempt\n    // to map them to a file system location. Tag them with the \"env-ns\"\n    // namespace to reserve them for this plugin.\n    build.onResolve({ filter: /^env$/ }, args => ({\n      path: args.path,\n      namespace: 'env-ns',\n    }))\n\n    // Load paths tagged with the \"env-ns\" namespace and behave as if\n    // they point to a JSON file containing the environment variables.\n    build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () => ({\n      contents: JSON.stringify(process.env),\n      loader: 'json',\n    }))\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [envPlugin],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"encoding/json\"\nimport \"os\"\nimport \"strings\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar envPlugin = api.Plugin{\n  Name: \"env\",\n  Setup: func(build api.PluginBuild) {\n    // Intercept import paths called \"env\" so esbuild doesn't attempt\n    // to map them to a file system location. Tag them with the \"env-ns\"\n    // namespace to reserve them for this plugin.\n    build.OnResolve(api.OnResolveOptions{Filter: `^env$`},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        return api.OnResolveResult{\n          Path:      args.Path,\n          Namespace: \"env-ns\",\n        }, nil\n      })\n\n    // Load paths tagged with the \"env-ns\" namespace and behave as if\n    // they point to a JSON file containing the environment variables.\n    build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"env-ns\"},\n      func(args api.OnLoadArgs) (api.OnLoadResult, error) {\n        mappings := make(map[string]string)\n        for _, item := range os.Environ() {\n          if equals := strings.IndexByte(item, '='); equals != -1 {\n            mappings[item[:equals]] = item[equals+1:]\n          }\n        }\n        bytes, err := json.Marshal(mappings)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        contents := string(bytes)\n        return api.OnLoadResult{\n          Contents: &contents,\n          Loader:   api.LoaderJSON,\n        }, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{envPlugin},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport { PATH } from 'env'\nconsole.log(`PATH is ${PATH}`)\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport path from 'node:path'\n\nlet exampleOnResolvePlugin = {\n  name: 'example',\n  setup(build) {\n    // Redirect all paths starting with \"images/\" to \"./public/images/\"\n    build.onResolve({ filter: /^images\\// }, args => {\n      return { path: path.join(args.resolveDir, 'public', args.path) }\n    })\n\n    // Mark all paths starting with \"http://\" or \"https://\" as external\n    build.onResolve({ filter: /^https?:\\/\\// }, args => {\n      return { path: args.path, external: true }\n    })\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [exampleOnResolvePlugin],\n  loader: { '.png': 'binary' },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"os\"\nimport \"path/filepath\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar exampleOnResolvePlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    // Redirect all paths starting with \"images/\" to \"./public/images/\"\n    build.OnResolve(api.OnResolveOptions{Filter: `^images/`},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        return api.OnResolveResult{\n          Path: filepath.Join(args.ResolveDir, \"public\", args.Path),\n        }, nil\n      })\n\n    // Mark all paths starting with \"http://\" or \"https://\" as external\n    build.OnResolve(api.OnResolveOptions{Filter: `^https?://`},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        return api.OnResolveResult{\n          Path:     args.Path,\n          External: true,\n        }, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{exampleOnResolvePlugin},\n    Write:       true,\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderBinary,\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\ninterface OnResolveOptions {\n  filter: RegExp;\n  namespace?: string;\n}\n```\n\nExample:\n```text\ntype OnResolveOptions struct {\n  Filter    string\n  Namespace string\n}\n```\n\nExample:\n```javascript\ninterface OnResolveArgs {\n  path: string;\n  importer: string;\n  namespace: string;\n  resolveDir: string;\n  kind: ResolveKind;\n  pluginData: any;\n  with: Record<string, string>;\n}\n\ntype ResolveKind =\n  | 'entry-point'\n  | 'import-statement'\n  | 'require-call'\n  | 'dynamic-import'\n  | 'require-resolve'\n  | 'import-rule'\n  | 'composes-from'\n  | 'url-token'\n```\n\nExample:\n```text\ntype OnResolveArgs struct {\n  Path       string\n  Importer   string\n  Namespace  string\n  ResolveDir string\n  Kind       ResolveKind\n  PluginData interface{}\n  With       map[string]string\n}\n\nconst (\n  ResolveEntryPoint        ResolveKind\n  ResolveJSImportStatement ResolveKind\n  ResolveJSRequireCall     ResolveKind\n  ResolveJSDynamicImport   ResolveKind\n  ResolveJSRequireResolve  ResolveKind\n  ResolveCSSImportRule     ResolveKind\n  ResolveCSSComposesFrom   ResolveKind\n  ResolveCSSURLToken       ResolveKind\n)\n```\n\nExample:\n```javascript\ninterface OnResolveResult {\n  errors?: Message[];\n  external?: boolean;\n  namespace?: string;\n  path?: string;\n  pluginData?: any;\n  pluginName?: string;\n  sideEffects?: boolean;\n  suffix?: string;\n  warnings?: Message[];\n  watchDirs?: string[];\n  watchFiles?: string[];\n}\n\ninterface Message {\n  text: string;\n  location: Location | null;\n  detail: any; // The original error from a JavaScript plugin, if applicable\n}\n\ninterface Location {\n  file: string;\n  namespace: string;\n  line: number; // 1-based\n  column: number; // 0-based, in bytes\n  length: number; // in bytes\n  lineText: string;\n}\n```\n\nExample:\n```text\ntype OnResolveResult struct {\n  Errors      []Message\n  External    bool\n  Namespace   string\n  Path        string\n  PluginData  interface{}\n  PluginName  string\n  SideEffects SideEffects\n  Suffix      string\n  Warnings    []Message\n  WatchDirs   []string\n  WatchFiles  []string\n}\n\ntype Message struct {\n  Text     string\n  Location *Location\n  Detail   interface{} // The original error from a Go plugin, if applicable\n}\n\ntype Location struct {\n  File      string\n  Namespace string\n  Line      int // 1-based\n  Column    int // 0-based, in bytes\n  Length    int // in bytes\n  LineText  string\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport fs from 'node:fs'\n\nlet exampleOnLoadPlugin = {\n  name: 'example',\n  setup(build) {\n    // Load \".txt\" files and return an array of words\n    build.onLoad({ filter: /\\.txt$/ }, async (args) => {\n      let text = await fs.promises.readFile(args.path, 'utf8')\n      return {\n        contents: JSON.stringify(text.split(/\\s+/)),\n        loader: 'json',\n      }\n    })\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [exampleOnLoadPlugin],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"encoding/json\"\nimport \"io/ioutil\"\nimport \"os\"\nimport \"strings\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar exampleOnLoadPlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    // Load \".txt\" files and return an array of words\n    build.OnLoad(api.OnLoadOptions{Filter: `\\.txt$`},\n      func(args api.OnLoadArgs) (api.OnLoadResult, error) {\n        text, err := ioutil.ReadFile(args.Path)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        bytes, err := json.Marshal(strings.Fields(string(text)))\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        contents := string(bytes)\n        return api.OnLoadResult{\n          Contents: &contents,\n          Loader:   api.LoaderJSON,\n        }, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{exampleOnLoadPlugin},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\ninterface OnLoadOptions {\n  filter: RegExp;\n  namespace?: string;\n}\n```\n\nExample:\n```text\ntype OnLoadOptions struct {\n  Filter    string\n  Namespace string\n}\n```\n\nExample:\n```javascript\ninterface OnLoadArgs {\n  path: string;\n  namespace: string;\n  suffix: string;\n  pluginData: any;\n  with: Record<string, string>;\n}\n```\n\nExample:\n```text\ntype OnLoadArgs struct {\n  Path       string\n  Namespace  string\n  Suffix     string\n  PluginData interface{}\n  With       map[string]string\n}\n```\n\nExample:\n```javascript\ninterface OnLoadResult {\n  contents?: string | Uint8Array;\n  errors?: Message[];\n  loader?: Loader;\n  pluginData?: any;\n  pluginName?: string;\n  resolveDir?: string;\n  warnings?: Message[];\n  watchDirs?: string[];\n  watchFiles?: string[];\n}\n\ninterface Message {\n  text: string;\n  location: Location | null;\n  detail: any; // The original error from a JavaScript plugin, if applicable\n}\n\ninterface Location {\n  file: string;\n  namespace: string;\n  line: number; // 1-based\n  column: number; // 0-based, in bytes\n  length: number; // in bytes\n  lineText: string;\n}\n```\n\nExample:\n```text\ntype OnLoadResult struct {\n  Contents   *string\n  Errors     []Message\n  Loader     Loader\n  PluginData interface{}\n  PluginName string\n  ResolveDir string\n  Warnings   []Message\n  WatchDirs  []string\n  WatchFiles []string\n}\n\ntype Message struct {\n  Text     string\n  Location *Location\n  Detail   interface{} // The original error from a Go plugin, if applicable\n}\n\ntype Location struct {\n  File      string\n  Namespace string\n  Line      int // 1-based\n  Column    int // 0-based, in bytes\n  Length    int // in bytes\n  LineText  string\n}\n```\n\nExample:\n```text\nimport fs from 'node:fs'\n\nlet examplePlugin = {\n  name: 'example',\n  setup(build) {\n    let cache = new Map\n\n    build.onLoad({ filter: /\\.example$/ }, async (args) => {\n      let input = await fs.promises.readFile(args.path, 'utf8')\n      let key = args.path\n      let value = cache.get(key)\n\n      if (!value || value.input !== input) {\n        let contents = slowTransform(input)\n        value = { input, output: { contents } }\n        cache.set(key, value)\n      }\n\n      return value.output\n    })\n  }\n}\n```\n\nExample:\n```text\nsrc/node_modules/pkg/file\nsrc/node_modules/pkg/file.css\nsrc/node_modules/pkg/file/package.json\nsrc/node_modules/pkg/file/main\nsrc/node_modules/pkg/file/main.css\nsrc/node_modules/pkg/file/main/index.css\nsrc/node_modules/pkg/file/index.css\nnode_modules/pkg/file\nnode_modules/pkg/file.css\nnode_modules/pkg/file/package.json\nnode_modules/pkg/file/main\nnode_modules/pkg/file/main.css\nnode_modules/pkg/file/main/index.css\nnode_modules/pkg/file/index.css\n```\n\nExample:\n```javascript\nlet examplePlugin = {\n  name: 'example',\n  setup(build) {\n    build.onStart(() => {\n      console.log('build started')\n    })\n  },\n}\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nvar examplePlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    build.OnStart(func() (api.OnStartResult, error) {\n      fmt.Fprintf(os.Stderr, \"build started\\n\")\n      return api.OnStartResult{}, nil\n    })\n  },\n}\n\nfunc main() {\n}\n```\n\nExample:\n```javascript\nlet examplePlugin = {\n  name: 'example',\n  setup(build) {\n    build.onEnd(result => {\n      console.log(`build ended with ${result.errors.length} errors`)\n    })\n  },\n}\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nvar examplePlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    build.OnEnd(func(result *api.BuildResult) (api.OnEndResult, error) {\n      fmt.Fprintf(os.Stderr, \"build ended with %d errors\\n\", len(result.Errors))\n      return api.OnEndResult{}, nil\n    })\n  },\n}\n\nfunc main() {\n}\n```\n\nExample:\n```javascript\nlet examplePlugin = {\n  name: 'example',\n  setup(build) {\n    build.onDispose(() => {\n      console.log('This plugin is no longer used')\n    })\n  },\n}\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar examplePlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    build.OnDispose(func() {\n      fmt.Println(\"This plugin is no longer used\")\n    })\n  },\n}\n\nfunc main() {\n}\n```\n\nExample:\n```javascript\nlet examplePlugin = {\n  name: 'auto-node-env',\n  setup(build) {\n    const options = build.initialOptions\n    options.define = options.define || {}\n    options.define['process.env.NODE_ENV'] =\n      options.minify ? '\"production\"' : '\"development\"'\n  },\n}\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar examplePlugin = api.Plugin{\n  Name: \"auto-node-env\",\n  Setup: func(build api.PluginBuild) {\n    options := build.InitialOptions\n    if options.Define == nil {\n      options.Define = map[string]string{}\n    }\n    if options.MinifyWhitespace && options.MinifyIdentifiers && options.MinifySyntax {\n      options.Define[`process.env.NODE_ENV`] = `\"production\"`\n    } else {\n      options.Define[`process.env.NODE_ENV`] = `\"development\"`\n    }\n  },\n}\n\nfunc main() {\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet examplePlugin = {\n  name: 'example',\n  setup(build) {\n    build.onResolve({ filter: /^example$/ }, async () => {\n      const result = await build.resolve('./foo', {\n        kind: 'import-statement',\n        resolveDir: './bar',\n      })\n      if (result.errors.length > 0) {\n        return { errors: result.errors }\n      }\n      return { path: result.path, external: true }\n    })\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [examplePlugin],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"os\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar examplePlugin = api.Plugin{\n  Name: \"example\",\n  Setup: func(build api.PluginBuild) {\n    build.OnResolve(api.OnResolveOptions{Filter: `^example$`},\n      func(api.OnResolveArgs) (api.OnResolveResult, error) {\n        result := build.Resolve(\"./foo\", api.ResolveOptions{\n          Kind:       api.ResolveJSImportStatement,\n          ResolveDir: \"./bar\",\n        })\n        if len(result.Errors) > 0 {\n          return api.OnResolveResult{Errors: result.Errors}, nil\n        }\n        return api.OnResolveResult{Path: result.Path, External: true}, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{examplePlugin},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\ninterface ResolveOptions {\n  kind: ResolveKind;\n  importer?: string;\n  namespace?: string;\n  resolveDir?: string;\n  pluginData?: any;\n  with?: Record<string, string>;\n}\n\ntype ResolveKind =\n  | 'entry-point'\n  | 'import-statement'\n  | 'require-call'\n  | 'dynamic-import'\n  | 'require-resolve'\n  | 'import-rule'\n  | 'url-token'\n```\n\nExample:\n```text\ntype ResolveOptions struct {\n  Kind       ResolveKind\n  Importer   string\n  Namespace  string\n  ResolveDir string\n  PluginData interface{}\n  With       map[string]string\n}\n\nconst (\n  ResolveEntryPoint        ResolveKind\n  ResolveJSImportStatement ResolveKind\n  ResolveJSRequireCall     ResolveKind\n  ResolveJSDynamicImport   ResolveKind\n  ResolveJSRequireResolve  ResolveKind\n  ResolveCSSImportRule     ResolveKind\n  ResolveCSSURLToken       ResolveKind\n)\n```\n\nExample:\n```javascript\nexport interface ResolveResult {\n  errors: Message[];\n  external: boolean;\n  namespace: string;\n  path: string;\n  pluginData: any;\n  sideEffects: boolean;\n  suffix: string;\n  warnings: Message[];\n}\n\ninterface Message {\n  text: string;\n  location: Location | null;\n  detail: any; // The original error from a JavaScript plugin, if applicable\n}\n\ninterface Location {\n  file: string;\n  namespace: string;\n  line: number; // 1-based\n  column: number; // 0-based, in bytes\n  length: number; // in bytes\n  lineText: string;\n}\n```\n\nExample:\n```text\ntype ResolveResult struct {\n  Errors      []Message\n  External    bool\n  Namespace   string\n  Path        string\n  PluginData  interface{}\n  SideEffects bool\n  Suffix      string\n  Warnings    []Message\n}\n\ntype Message struct {\n  Text     string\n  Location *Location\n  Detail   interface{} // The original error from a Go plugin, if applicable\n}\n\ntype Location struct {\n  File      string\n  Namespace string\n  Line      int // 1-based\n  Column    int // 0-based, in bytes\n  Length    int // in bytes\n  LineText  string\n}\n```\n\nExample:\n```text\nimport { zip } from 'https://unpkg.com/lodash-es@4.17.15/lodash.js'\nconsole.log(zip([1, 2], ['a', 'b']))\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport https from 'node:https'\nimport http from 'node:http'\n\nlet httpPlugin = {\n  name: 'http',\n  setup(build) {\n    // Intercept import paths starting with \"http:\" and \"https:\" so\n    // esbuild doesn't attempt to map them to a file system location.\n    // Tag them with the \"http-url\" namespace to associate them with\n    // this plugin.\n    build.onResolve({ filter: /^https?:\\/\\// }, args => ({\n      path: args.path,\n      namespace: 'http-url',\n    }))\n\n    // We also want to intercept all import paths inside downloaded\n    // files and resolve them against the original URL. All of these\n    // files will be in the \"http-url\" namespace. Make sure to keep\n    // the newly resolved URL in the \"http-url\" namespace so imports\n    // inside it will also be resolved as URLs recursively.\n    build.onResolve({ filter: /.*/, namespace: 'http-url' }, args => ({\n      path: new URL(args.path, args.importer).toString(),\n      namespace: 'http-url',\n    }))\n\n    // When a URL is loaded, we want to actually download the content\n    // from the internet. This has just enough logic to be able to\n    // handle the example import from unpkg.com but in reality this\n    // would probably need to be more complex.\n    build.onLoad({ filter: /.*/, namespace: 'http-url' }, async (args) => {\n      let contents = await new Promise((resolve, reject) => {\n        function fetch(url) {\n          console.log(`Downloading: ${url}`)\n          let lib = url.startsWith('https') ? https : http\n          let req = lib.get(url, res => {\n            if ([301, 302, 307].includes(res.statusCode)) {\n              fetch(new URL(res.headers.location, url).toString())\n              req.abort()\n            } else if (res.statusCode === 200) {\n              let chunks = []\n              res.on('data', chunk => chunks.push(chunk))\n              res.on('end', () => resolve(Buffer.concat(chunks)))\n            } else {\n              reject(new Error(`GET ${url} failed: status ${res.statusCode}`))\n            }\n          }).on('error', reject)\n        }\n        fetch(args.path)\n      })\n      return { contents }\n    })\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [httpPlugin],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"io/ioutil\"\nimport \"net/http\"\nimport \"net/url\"\nimport \"os\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar httpPlugin = api.Plugin{\n  Name: \"http\",\n  Setup: func(build api.PluginBuild) {\n    // Intercept import paths starting with \"http:\" and \"https:\" so\n    // esbuild doesn't attempt to map them to a file system location.\n    // Tag them with the \"http-url\" namespace to associate them with\n    // this plugin.\n    build.OnResolve(api.OnResolveOptions{Filter: `^https?://`},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        return api.OnResolveResult{\n          Path:      args.Path,\n          Namespace: \"http-url\",\n        }, nil\n      })\n\n    // We also want to intercept all import paths inside downloaded\n    // files and resolve them against the original URL. All of these\n    // files will be in the \"http-url\" namespace. Make sure to keep\n    // the newly resolved URL in the \"http-url\" namespace so imports\n    // inside it will also be resolved as URLs recursively.\n    build.OnResolve(api.OnResolveOptions{Filter: \".*\", Namespace: \"http-url\"},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        base, err := url.Parse(args.Importer)\n        if err != nil {\n          return api.OnResolveResult{}, err\n        }\n        relative, err := url.Parse(args.Path)\n        if err != nil {\n          return api.OnResolveResult{}, err\n        }\n        return api.OnResolveResult{\n          Path:      base.ResolveReference(relative).String(),\n          Namespace: \"http-url\",\n        }, nil\n      })\n\n    // When a URL is loaded, we want to actually download the content\n    // from the internet. This has just enough logic to be able to\n    // handle the example import from unpkg.com but in reality this\n    // would probably need to be more complex.\n    build.OnLoad(api.OnLoadOptions{Filter: \".*\", Namespace: \"http-url\"},\n      func(args api.OnLoadArgs) (api.OnLoadResult, error) {\n        res, err := http.Get(args.Path)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        defer res.Body.Close()\n        bytes, err := ioutil.ReadAll(res.Body)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        contents := string(bytes)\n        return api.OnLoadResult{Contents: &contents}, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{httpPlugin},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport load from './example.wasm'\nload(imports).then(exports => { ... })\n```\n\nExample:\n```text\nimport wasm from '/path/to/example.wasm'\nexport default (imports) =>\n  WebAssembly.instantiate(wasm, imports).then(\n    result => result.instance.exports)\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport path from 'node:path'\nimport fs from 'node:fs'\n\nlet wasmPlugin = {\n  name: 'wasm',\n  setup(build) {\n    // Resolve \".wasm\" files to a path with a namespace\n    build.onResolve({ filter: /\\.wasm$/ }, args => {\n      // If this is the import inside the stub module, import the\n      // binary itself. Put the path in the \"wasm-binary\" namespace\n      // to tell our binary load callback to load the binary file.\n      if (args.namespace === 'wasm-stub') {\n        return {\n          path: args.path,\n          namespace: 'wasm-binary',\n        }\n      }\n\n      // Otherwise, generate the JavaScript stub module for this\n      // \".wasm\" file. Put it in the \"wasm-stub\" namespace to tell\n      // our stub load callback to fill it with JavaScript.\n      //\n      // Resolve relative paths to absolute paths here since this\n      // resolve callback is given \"resolveDir\", the directory to\n      // resolve imports against.\n      if (args.resolveDir === '') {\n        return // Ignore unresolvable paths\n      }\n      return {\n        path: path.isAbsolute(args.path) ? args.path : path.join(args.resolveDir, args.path),\n        namespace: 'wasm-stub',\n      }\n    })\n\n    // Virtual modules in the \"wasm-stub\" namespace are filled with\n    // the JavaScript code for compiling the WebAssembly binary. The\n    // binary itself is imported from a second virtual module.\n    build.onLoad({ filter: /.*/, namespace: 'wasm-stub' }, async (args) => ({\n      contents: `import wasm from ${JSON.stringify(args.path)}\n        export default (imports) =>\n          WebAssembly.instantiate(wasm, imports).then(\n            result => result.instance.exports)`,\n    }))\n\n    // Virtual modules in the \"wasm-binary\" namespace contain the\n    // actual bytes of the WebAssembly file. This uses esbuild's\n    // built-in \"binary\" loader instead of manually embedding the\n    // binary data inside JavaScript code ourselves.\n    build.onLoad({ filter: /.*/, namespace: 'wasm-binary' }, async (args) => ({\n      contents: await fs.promises.readFile(args.path),\n      loader: 'binary',\n    }))\n  },\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [wasmPlugin],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"encoding/json\"\nimport \"io/ioutil\"\nimport \"os\"\nimport \"path/filepath\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nvar wasmPlugin = api.Plugin{\n  Name: \"wasm\",\n  Setup: func(build api.PluginBuild) {\n    // Resolve \".wasm\" files to a path with a namespace\n    build.OnResolve(api.OnResolveOptions{Filter: `\\.wasm$`},\n      func(args api.OnResolveArgs) (api.OnResolveResult, error) {\n        // If this is the import inside the stub module, import the\n        // binary itself. Put the path in the \"wasm-binary\" namespace\n        // to tell our binary load callback to load the binary file.\n        if args.Namespace == \"wasm-stub\" {\n          return api.OnResolveResult{\n            Path:      args.Path,\n            Namespace: \"wasm-binary\",\n          }, nil\n        }\n\n        // Otherwise, generate the JavaScript stub module for this\n        // \".wasm\" file. Put it in the \"wasm-stub\" namespace to tell\n        // our stub load callback to fill it with JavaScript.\n        //\n        // Resolve relative paths to absolute paths here since this\n        // resolve callback is given \"resolveDir\", the directory to\n        // resolve imports against.\n        if args.ResolveDir == \"\" {\n          return api.OnResolveResult{}, nil // Ignore unresolvable paths\n        }\n        if !filepath.IsAbs(args.Path) {\n          args.Path = filepath.Join(args.ResolveDir, args.Path)\n        }\n        return api.OnResolveResult{\n          Path:      args.Path,\n          Namespace: \"wasm-stub\",\n        }, nil\n      })\n\n    // Virtual modules in the \"wasm-stub\" namespace are filled with\n    // the JavaScript code for compiling the WebAssembly binary. The\n    // binary itself is imported from a second virtual module.\n    build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"wasm-stub\"},\n      func(args api.OnLoadArgs) (api.OnLoadResult, error) {\n        bytes, err := json.Marshal(args.Path)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        contents := `import wasm from ` + string(bytes) + `\n          export default (imports) =>\n            WebAssembly.instantiate(wasm, imports).then(\n              result => result.instance.exports)`\n        return api.OnLoadResult{Contents: &contents}, nil\n      })\n\n    // Virtual modules in the \"wasm-binary\" namespace contain the\n    // actual bytes of the WebAssembly file. This uses esbuild's\n    // built-in \"binary\" loader instead of manually embedding the\n    // binary data inside JavaScript code ourselves.\n    build.OnLoad(api.OnLoadOptions{Filter: `.*`, Namespace: \"wasm-binary\"},\n      func(args api.OnLoadArgs) (api.OnLoadResult, error) {\n        bytes, err := ioutil.ReadFile(args.Path)\n        if err != nil {\n          return api.OnLoadResult{}, err\n        }\n        contents := string(bytes)\n        return api.OnLoadResult{\n          Contents: &contents,\n          Loader:   api.LoaderBinary,\n        }, nil\n      })\n  },\n}\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Plugins:     []api.Plugin{wasmPlugin},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n<script>\n  let a = 1;\n  let b = 2;\n</script>\n<input type=\"number\" bind:value={a}>\n<input type=\"number\" bind:value={b}>\n<p>{a} + {b} = {a + b}</p>\n```\n\nExample:\n```text\nimport Button from './button.svelte'\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport * as svelte from 'svelte/compiler'\nimport path from 'node:path'\nimport fs from 'node:fs'\n\nlet sveltePlugin = {\n  name: 'svelte',\n  setup(build) {\n    build.onLoad({ filter: /\\.svelte$/ }, async (args) => {\n      // This converts a message in Svelte's format to esbuild's format\n      let convertMessage = ({ message, start, end }) => {\n        let location\n        if (start && end) {\n          let lineText = source.split(/\\r\\n|\\r|\\n/g)[start.line - 1]\n          let lineEnd = start.line === end.line ? end.column : lineText.length\n          location = {\n            file: filename,\n            line: start.line,\n            column: start.column,\n            length: lineEnd - start.column,\n            lineText,\n          }\n        }\n        return { text: message, location }\n      }\n\n      // Load the file from the file system\n      let source = await fs.promises.readFile(args.path, 'utf8')\n      let filename = path.relative(process.cwd(), args.path)\n\n      // Convert Svelte syntax to JavaScript\n      try {\n        let { js, warnings } = svelte.compile(source, { filename })\n        let contents = js.code + `//# sourceMappingURL=` + js.map.toUrl()\n        return { contents, warnings: warnings.map(convertMessage) }\n      } catch (e) {\n        return { errors: [convertMessage(e)] }\n      }\n    })\n  }\n}\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n  plugins: [sveltePlugin],\n})\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.393Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":45,"totalLines":1225,"estimatedTokens":22724}}8{"id":"doc-esbuild_api-a9d2a66a","source":"documentation","title":"esbuild - API","url":"https://esbuild.github.io/api/","text":"APIThe API can be accessed in one of three the command line, in JavaScript, and in Go. The concepts and parameters are largely identical between the three languages so they will be presented together here instead of having separate documentation for each language. You can switch between languages using the CLI, JS, and Go tabs in the top-right corner of each code example. Some specifics for each : If you are using the command-line API, it may be helpful to know that the flags come in one of three , --foo=bar, or The form --foo is used for enabling boolean flags such as --minify, the form --foo=bar is used for flags that have a single value and are only specified once such as --platform=, and the form is used for flags that have multiple values and can be re-specified multiple times such as Also keep in mind that using a CLI (in general, not specific to esbuild) means that your current shell interprets the command's arguments before the command you are running sees them. For example, even though the echo command just writes out what it reads in, echo \"foo\" can print foo instead of \"foo\", and echo *.json can print package.json instead of *.json (the specific behavior depends on which shell you use). If you want to avoid the problems that shell-specific behavior can cause, then you should use esbuild's JavaScript or Go APIs instead of esbuild's CLI. you are using JavaScript be sure to check out the JS-specific details and browser sections below. You may also find the TypeScript type definitions for esbuild helpful as a reference. you are using Go, you may find the automatically generated Go documentation for esbuild helpful as a reference. There is separate documentation for both of the public Go /api and pkg/cli. ) console.log(result) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"dist\", }) if len(result.Errors) != 0 { os.Exit(1) } } Advanced use of the build API involves setting up a long-running build context. This context is an explicit object in JS and Go but is implicit with the CLI. All builds done with a given context share the same build options, and subsequent builds are done incrementally (i.e. they reuse some work from previous builds to improve performance). This is useful for development because esbuild can rebuild your app in the background for you while you work.There are three different incremental build mode tells esbuild to watch the file system and automatically rebuild for you whenever you edit and save a file that could invalidate the build. Here's an JS Go esbuild app.ts --bundle --outdir=dist --watch [watch] build finished, watching for changes... let ctx = await esbuild.context({ entryPoints: ['app.ts'], , outdir: 'dist', }) await ctx.watch() ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"dist\", }) err2 := ctx.Watch(api.WatchOptions{}) Serve mode starts a local development server that serves the results of the latest build. Incoming requests automatically start new builds so your web app is always up to date when you reload the page in the browser. Here's an JS Go esbuild app.ts --bundle --outdir=dist --serve > ://127.0.0.1:8000/ > ://192.168.0.1:8000/ 127.0.0.1:61302 - \"GET /\" 200 [1ms] let ctx = await esbuild.context({ entryPoints: ['app.ts'], , outdir: 'dist', }) let { hosts, port } = await ctx.serve() ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"dist\", }) server, err2 := ctx.Serve(api.ServeOptions{}) Rebuild mode lets you manually invoke a build. This is useful when integrating esbuild with other tools (e.g. using a custom file watcher or development server instead of esbuild's built-in ones). Here's an JS Go # The CLI does not have an API for \"rebuild\" let ctx = await esbuild.context({ entryPoints: ['app.ts'], , outdir: 'dist', }) for (let i = 0; i < 5; i++) { let result = await ctx.rebuild() } ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"dist\", }) for i := 0; i < 5; i++ { result := ctx.Rebuild() } These three incremental build APIs can be combined. To enable live reloading (automatically reloading the page when you edit and save a file) you'll need to enable watch and serve together on the same context.When you are done with a context object, you can call dispose() on the context to wait for existing builds to finish, stop watch and/or serve mode, and free up resources.The build and context APIs both take the following reloadPlatformRebuildServeTsconfigTsconfig pointsLoaderStdinOutput nameLegal commentsLine limitSplittingOutput overwriteAsset namesChunk namesEntry namesOut extensionOutbaseOutdirOutfilePublic pathWritePath fieldsNode pathsPackagesPreserve symlinksResolve extensionsWorking devJSX factoryJSX fragmentJSX import sourceJSX side labelsIgnore annotationsInjectKeep namesMangle propsMinifyPureTree shakingSource rootSourcefileSourcemapSources contentBuild :ColorFormat messagesLog levelLog limitLog overrideLog style#TransformThis is a limited special-case of build that transforms a string of code representing an in-memory file in an isolated environment that's completely disconnected from any other files. Common uses include minifying code and transforming TypeScript into JavaScript. Here's an JS Go echo 'let = 1' | esbuild --loader=ts let x = 1; import * as esbuild from 'esbuild' let ts = 'let = 1' let result = await esbuild.transform(ts, { loader: 'ts', }) console.log(result) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { ts := \"let = 1\" result := api.Transform(ts, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } Taking a string instead of a file as input is more ergonomic for certain use cases. File system isolation has certain advantages (e.g. works in the browser, not affected by nearby package.json files) and certain disadvantages (e.g. can't be used with bundling or plugins). If your use case doesn't fit the transform API then you should use the more general build API instead.The transform API takes the following nameLegal commentsLine devJSX factoryJSX fragmentJSX import sourceJSX side labelsIgnore annotationsKeep namesMangle propsMinifyPureTree shakingSource rootSourcefileSourcemapSources messagesLog levelLog limitLog overrideLog style#JS-specific detailsThe JS API for esbuild comes in both asynchronous and synchronous flavors. The asynchronous API is recommended because it works in all environments and it's faster and more powerful. The synchronous API only works in node and can only do certain things, but it's sometimes necessary in certain node-specific situations. In detail:#Async APIAsynchronous API calls return their results using a promise. Note that you'll likely have to use the ) let result1 = await esbuild.transform(code, options) let result2 = esbuild.build(options)If you're already running this code from a worker and don't want initialize to create another worker, you can pass to it. Then it will create a WebAssembly module in the same thread as the thread that calls initialize.You can also use esbuild's API as a script tag in a HTML file without needing to use a bundler by loading the lib/browser.min.js file with a <script> tag. In this case the API creates a global called esbuild that holds the API object:<script src=\"./node_modules/esbuild-wasm/lib/browser.min.js\"></script> <script> esbuild.initialize({ wasmURL: './node_modules/esbuild-wasm/esbuild.wasm', }).then(() => { ... }) </script>If you want to use this API with ECMAScript modules, you should import the esm/browser.min.js file instead:<script type=\"module\"> import * as esbuild from './node_modules/esbuild-wasm/esm/browser.min.js' await esbuild.initialize({ wasmURL: './node_modules/esbuild-wasm/esbuild.wasm', }) ... </script>#General options#BundleSupported bundle a file means to inline any imported dependencies into the file itself. This process is recursive so dependencies of dependencies (and so on) will also be inlined. By default esbuild will not bundle the input files. Bundling must be explicitly enabled like JS Go esbuild in.js --bundle import * as esbuild from 'esbuild' console.log(await esbuild.build({ entryPoints: ['in.js'], , outfile: 'out.js', })) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"in.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } Refer to the getting started guide for an example of bundling with real-world code.Note that bundling is different than file concatenation. Passing esbuild multiple input files with bundling enabled will create multiple separate bundles instead of joining the input files together. To join a set of files together with esbuild, import them all into a single entry point file and bundle just that one file with esbuild.#Non-analyzable importsImport paths are currently only bundled if they are a string literal or a glob pattern. Other forms of import paths are not bundled, and are instead preserved verbatim in the generated output. This is because bundling is a compile-time operation and esbuild doesn't support all forms of run-time path resolution. Here are some examples:// Analyzable imports (will be bundled by esbuild) import 'pkg'; import('pkg'); require('pkg'); import(`./locale-${foo}.json`); require(`./locale-${foo}.json`); // Non-analyzable imports (will not be bundled by esbuild) import(`pkg/${foo}`); require(`pkg/${foo}`); ['pkg'].map(require);The way to work around non-analyzable imports is to mark the package containing this problematic code as external so that it's not included in the bundle. You will then need to ensure that a copy of the external package is available to your bundled code at run-time.Some bundlers such as Webpack try to support all forms of run-time path resolution by including all potentially-reachable files in the bundle and then emulating a file system at run-time. However, run-time file system emulation is out of scope and will not be implemented in esbuild. If you really need to bundle code that does this, you will likely need to use another bundler instead of esbuild.#Glob-style importsImport paths that are evaluated at run-time can now be bundled in certain limited situations. The import path expression must be a form of string concatenation and must start with either ./ or ../. Each non-string expression in the string concatenation chain becomes a wildcard in a glob pattern. Some examples:// These two forms are equivalent const json1 = require('./data/' + kind + '.json') const json2 = require(`./data/${kind}.json`)When you do this, esbuild will search the file system for all files that match the pattern and include all of them in the bundle along with a map that maps the matching import path to the bundled module. The import expression will be replaced with a lookup into that map. An error will be thrown at run-time if the import path is not present in the map. The generated code will look something like this (unimportant parts were omitted for brevity):// data/bar.json var require_bar = ...; // data/foo.json var require_foo = ...; // require(\"./data/**/*.json\") in example.js var globRequire_data_json = __glob({ \"./data/bar.json\": () => require_bar(), \"./data/foo.json\": () => require_foo() }); // example.js var json1 = globRequire_data_json(\"./data/\" + kind + \".json\"); var json2 = globRequire_data_json(`./data/${kind}.json`);This feature works with require(...) and import(...) because these can all accept run-time expressions. It does not work with import and export statements because these cannot accept run-time expressions. If you want to prevent esbuild from trying to bundle these imports, you should move the string concatenation expression outside of the require(...) or import(...). For example:// This will be bundled const json1 = require('./data/' + kind + '.json') // This will not be bundled const path = './data/' + kind + '.json' const json2 = require(path)Note that using this feature means esbuild will potentially do a lot of file system I/O to find all possible files that might match the pattern. This is by design, and is not a bug. If this is a concern, there are two ways to reduce the amount of file system I/O that esbuild simplest approach is to put all files that you want to import for a given run-time import expression in a subdirectory and then include the subdirectory in the pattern. This limits esbuild to searching inside that subdirectory since esbuild doesn't consider .. path elements during pattern-matching. Another approach is to prevent esbuild from searching into any subdirectory at all. The pattern matching algorithm that esbuild uses only allows a wildcard to match something containing a / path separator if that wildcard has a / before it in the pattern. So for example './data/' + x + '.json' will match x with anything in any subdirectory while './data-' + x + '.json' will only match x with anything in the top-level directory (but not in any subdirectory). ) // Whenever we get some data over stdin process.stdin.on('data', async () => { try { // Cancel the already-running build await ctx.cancel() // Then start a new build console.log('build:', await ctx.rebuild()) } catch (err) { console.error(err) } }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"www\", , }) if err != nil { os.Exit(1) } // Whenever we get some data over stdin buf := make([]byte, 100) for { if n, err := os.Stdin.Read(buf); err != nil || n == 0 { break } go func() { // Cancel the already-running build ctx.Cancel() // Then start a new build result := ctx.Rebuild() fmt.Fprintf(os.Stderr, \"build: %v\\n\", result) }() } } Make sure to wait until the cancel operation is done before starting a new build (i.e. await the returned promise when using JavaScript), otherwise the next rebuild will give you the just-canceled build that still hasn't ended yet. Note that plugin on-end callbacks will still be run regardless of whether or not the build was canceled.#Live reloadSupported reload is an approach to development where you have your browser open and visible at the same time as your code editor. When you edit and save your source code, the browser automatically reloads and the reloaded version of the app contains your changes. This means you can iterate faster because you don't have to manually switch to your browser, reload, and then switch back to your code editor after every change. It's very helpful when changing CSS, for example.There is no esbuild API for live reloading directly. Instead, you can construct live reloading by combining watch mode (to automatically start a build when you edit and save a file) and serve mode (to serve the latest build, but block until it's done) plus a small bit of client-side JavaScript code that you add to your app only during development.The first step is to enable watch and serve JS Go esbuild app.ts --bundle --outdir=www --watch --servedir=www import * as esbuild from 'esbuild' let ctx = await esbuild.context({ entryPoints: ['app.ts'], , outdir: 'www', }) await ctx.watch() let { hosts, port } = await ctx.serve({ servedir: 'www', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outdir: \"www\", }) if err != nil { os.Exit(1) } err2 := ctx.Watch(api.WatchOptions{}) if err2 != nil { os.Exit(1) } result, err3 := ctx.Serve(api.ServeOptions{ Servedir: \"www\", }) if err3 != nil { os.Exit(1) } } The second step is to add some code to your JavaScript that subscribes to the /esbuild server-sent event source. When you get the change event, you can reload the page to get the latest version of the app. You can do this in a single line of EventSource('/esbuild').addEventListener('change', () => location.reload())That's it! If you load your app in the browser, the page should now automatically reload when you edit and save a file (assuming there are no build errors).This should only be included during development, and should not be included in production. One way to remove this code in production is to guard it with an if statement such as if (!window.IS_PRODUCTION) and then use define to set window.IS_PRODUCTION to true in production.#Live reload caveatsImplementing live reloading like this has a few known events only trigger when esbuild's output changes. They do not trigger when files unrelated to the build being watched are changed. If your HTML file references other files that esbuild doesn't know about and those files are changed, you can either manually reload the page or you can implement your own live reloading infrastructure instead of using esbuild's built-in behavior. The EventSource API is supposed to automatically reconnect for you. However, there's a bug in Firefox that breaks this if the server is ever temporarily unreachable. Workarounds are to use any other browser, to manually reload the page if this happens, or to write more complicated code that manually closes and re-creates the EventSource object if there is a connection error. Browser vendors have decided to not implement HTTP/2 without TLS. This means that when using the http:// protocol, each /esbuild event source will take up one of your precious 6 simultaneous per-domain HTTP/1.1 connections. So if you open more than six HTTP tabs that use this live-reloading technique, you will be unable to use live reloading in some of those tabs (and other things will likely also break). The workaround is to enable the https:// protocol. The code sample below enables \"hot reloading\" for CSS, which is when the CSS is automatically updated in place without reloading the page. If an event arrives that isn't CSS-related, then the whole page will be reloaded as a EventSource('/esbuild').addEventListener('change', e => { const { added, removed, updated } = JSON.parse(e.data) if (!added.length && !removed.length && updated.length === 1) { for (const link of document.getElementsByTagName(\"link\")) { const url = new URL(link.href) if (url.host === location.host && url.pathname === updated[0]) { const next = link.cloneNode() next.href = updated[0] + '?' + Math.random().toString(36).slice(2) next.onload = () => link.remove() link.parentNode.insertBefore(next, link.nextSibling) return } } } location.reload() })#Hot-reloading for JavaScriptHot-reloading for JavaScript is not currently implemented by esbuild. It's possible to transparently implement hot-reloading for CSS because CSS is stateless, but JavaScript is stateful so you cannot transparently implement hot-reloading for JavaScript like you can for CSS.Some other development servers implement hot-reloading for JavaScript anyway, but it requires additional APIs, sometimes requires framework-specific hacks, and sometimes introduces transient state-related bugs during an editing session. Doing this is outside of esbuild's scope. You are welcome to use other tools instead of esbuild if hot-reloading for JavaScript is one of your requirements.However, with esbuild's live-reloading you can persist your app's current JavaScript state in sessionStorage to more easily restore your app's JavaScript state after a page reload. If your app loads quickly (which it already should for your users' sake), live-reloading with JavaScript can be almost as fast as hot-reloading with JavaScript would be.#PlatformSupported and TransformBy default, esbuild's bundler is configured to generate code intended for the browser. If your bundled code is intended to run in node instead, you should set the platform to JS Go esbuild app.js --bundle --platform=node import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , platform: 'node', outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , , }) if len(result.Errors) > 0 { os.Exit(1) } } When the platform is set to browser (the default value): When bundling is enabled the default output format is set to iife, which wraps the generated JavaScript code in an immediately-invoked function expression to prevent variables from leaking into the global scope. If a package specifies a map for the browser field in its package.json file, esbuild will use that map to replace specific files or modules with their browser-friendly versions. For example, a package might contain a substitution of path with path-browserify. The main fields setting is set to browser,module,main but with some additional special a package provides module and main entry points but not a browser entry point then main is used instead of module if that package is ever imported using require(). This behavior improves compatibility with CommonJS modules that export a function by assigning it to module.exports. If you want to disable this additional special behavior, you can explicitly set the main fields setting to browser,module,main. The conditions setting automatically includes the browser condition. This changes how the exports field in package.json files is interpreted to prefer browser-specific code. If no custom conditions are configured, the Webpack-specific module condition is also included. The module condition is used by package authors to provide a tree-shakable ESM alternative to a CommonJS file without creating a dual package hazard. You can prevent the module condition from being included by explicitly configuring some custom conditions (even an empty list). When using the build API, all process.env.NODE_ENV expressions are automatically defined to \"production\" if all minification options are enabled and \"development\" otherwise. This only happens if process, process.env, and process.env.NODE_ENV are not already defined. This substitution is necessary to avoid React-based code crashing instantly (since process is a node API, not a web API). The character sequence </script> will be escaped in JavaScript code and the character sequence </style> will be escaped in CSS code. This is done in case you inline esbuild's output directly into an HTML file. This can be disabled with esbuild's supported feature by setting inline-script (for JavaScript) and/or inline-style (for CSS) to false. When the platform is set to bundling is enabled the default output format is set to cjs, which stands for CommonJS (the module format used by node). ES6-style exports using export statements will be converted into getters on the CommonJS exports object. All built-in node modules such as fs are automatically marked as external so they don't cause errors when the bundler tries to bundle them. The main fields setting is set to main,module. This means tree shaking will likely not happen for packages that provide both module and main since tree shaking works with ECMAScript modules but not with CommonJS modules. Unfortunately some packages incorrectly treat module as meaning \"browser code\" instead of \"ECMAScript module code\" so this default behavior is required for compatibility. You can manually configure the main fields setting to module,main if you want to enable tree shaking and know it is safe to do so. The conditions setting automatically includes the node condition. This changes how the exports field in package.json files is interpreted to prefer node-specific code. If no custom conditions are configured, the Webpack-specific module condition is also included. The module condition is used by package authors to provide a tree-shakable ESM alternative to a CommonJS file without creating a dual package hazard. You can prevent the module condition from being included by explicitly configuring some custom conditions (even an empty list). When the format is set to cjs but the entry point is ESM, esbuild will add special annotations for any named exports to enable importing those named exports using ESM syntax from the resulting CommonJS file. Node's documentation has more information about node's detection of CommonJS named exports. The binary loader will make use of node's built-in Buffer.from API to decode the base64 data embedded in the bundle into a Uint8Array. This is faster than what esbuild can do otherwise since it's implemented by node in native code. When the platform is set to bundling is enabled the default output format is set to esm, which uses the export syntax introduced with ECMAScript 2015 (i.e. ES6). You can change the output format if this default is not appropriate. The main fields setting is empty by default. If you want to use npm-style packages, you will likely have to configure this to be something else such as main for the standard main field used by node. The conditions setting does not automatically include any platform-specific values. See also bundling for the browser and bundling for node.#RebuildSupported may want to use this API if your use case involves calling esbuild's build API repeatedly with the same options. For example, this is useful if you are implementing your own file watcher service. Rebuilding is more efficient than building again because some of the data from the previous build is cached and can be reused if the original files haven't changed since the previous build. There are currently two forms of caching used by the rebuild are stored in memory and are not re-read from the file system if the file metadata hasn't changed since the last build. This optimization only applies to file system paths. It does not apply to virtual modules created by plugins. Parsed ASTs are stored in memory and re-parsing the AST is avoided if the file contents haven't changed since the last build. This optimization applies to virtual modules created by plugins in addition to file system modules, as long as the virtual module path remains the same. Here's how to do a JS Go # The CLI does not have an API for \"rebuild\" import * as esbuild from 'esbuild' let ctx = await esbuild.context({ entryPoints: ['app.js'], , outfile: 'out.js', }) // Call \"rebuild\" as many times as you want for (let i = 0; i < 5; i++) { let result = await ctx.rebuild() } // Call \"dispose\" when you're done to free up resources ctx.dispose() package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", }) if err != nil { os.Exit(1) } // Call \"Rebuild\" as many times as you want for i := 0; i < 5; i++ { result := ctx.Rebuild() if len(result.Errors) > 0 { os.Exit(1) } } // Call \"Dispose\" when you're done to free up resources ctx.Dispose() } ) let { hosts, port } = await ctx.serve({ servedir: 'www', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"src/app.ts\"}, Outdir: \"www/js\", , }) if err != nil { os.Exit(1) } server, err2 := ctx.Serve(api.ServeOptions{ Servedir: \"www\", }) if err2 != nil { os.Exit(1) } // Returning from main() exits immediately in Go. // Block forever so we keep serving and don't exit. <-make(chan struct{}) } If you create the file www/index.html with the following contents, the code contained in src/app.ts will load when you navigate to http://localhost:8000/:<script src=\"js/app.js\"></script>One benefit of using esbuild's built-in web server instead of another web server is that whenever you reload, the files that esbuild serves are always up to date. That's not necessarily the case with other development setups. One common setup is to run a local file watcher that rebuilds output files whenever their input files change, and then separately to run a local file server to serve those output files. But that means reloading after an edit may reload the old output files if the rebuild hasn't finished yet. With esbuild's web server, each incoming request starts a rebuild if one is not already in progress, and then waits for the current rebuild to complete before serving the file. This means esbuild never serves stale build results.Note that this web server is intended to only be used in development. Do not use this in production.#ArgumentsThe arguments to the serve API are as JS Go # Enable serve mode --serve # Set the port --serve=9000 # Set the host and port (IPv4) --serve=127.0.0.1:9000 # Set the host and port (IPv6) --serve=[::1]:9000 # Set the directory to serve --servedir=www # Enable HTTPS --keyfile=your.key --certfile=your.cert # Specify a fallback HTML file --serve-fallback=some-file.html interface ServeOptions { port?: number host?: string servedir?: string keyfile?: string certfile?: string fallback?: string cors?: CORSOptions onRequest?: (args: ServeOnRequestArgs) => void } interface CORSOptions { origin?: string | string[] } interface ServeOnRequestArgs { } type ServeOptions struct { Port uint16 Host string Servedir string Keyfile string Certfile string Fallback string CORS CORSOptions OnRequest func(ServeOnRequestArgs) } type CORSOptions struct { Origin []string } type ServeOnRequestArgs struct { RemoteAddress string Method string Path string Status int TimeInMS int } host By default, esbuild makes the web server available on all IPv4 network interfaces. This corresponds to a host address of 0.0.0.0. If you would like to configure a different host (for example, to only serve on the 127.0.0.1 loopback interface without exposing anything to the network), you can specify the host using this argument. If you need to use IPv6 instead of IPv4, you just need to specify an IPv6 host address. The equivalent to the 127.0.0.1 loopback interface in IPv6 is ::1 and the equivalent to the 0.0.0.0 universal interface in IPv6 is ::. port The HTTP port can optionally be configured here. If omitted, it will default to an open port with a preference for ports in the range 8000 to 8009. Note that the Go API differs from the CLI and JS API regarding port 0. Unix reserves the port 0 to mean \"pick a random ephemeral port\" but esbuild reserves the port 0 for the default behavior described above, as 0 is the default value of an integer field in Go. Instead esbuild uses a sentinel value of -1 to pick a random ephemeral port in Go. The CLI and JS APIs don't have this problem and allow you to specify a port of 0 to pick a random ephemeral port just like other standard Unix APIs. servedir This is a directory of extra content for esbuild's HTTP server to serve instead of a 404 when incoming requests don't match any of the generated output file paths. This lets you use esbuild as a general-purpose local web server. For example, you might want to create an index.html file and then set servedir to \".\" to serve the current directory (which includes the index.html file). If you don't set servedir then esbuild will only serve the build results, but not any other files. keyfile and certfile If you pass a private key and certificate to esbuild using keyfile and certfile, then esbuild's web server will use the https:// protocol instead of the http:// protocol. See enabling HTTPS for more information. fallback This is a HTML file for esbuild's HTTP server to serve instead of a 404 when incoming requests don't match any of the generated output file paths. You can use this for a custom \"not found\" page. You can also use this as the entry point of a single-page application that mutates the current URL and therefore needs to be served from many different URLs simultaneously. cors This is for Cross-Origin Request Sharing. See that link for more information. onRequest This is called once for each incoming request with some information about the request. This callback is used by the CLI to print out a log message for each request. The time field is the time to generate the data for the request, but it does not include the time to stream the request to the client. Note that this is called after the request has completed. It's not possible to use this callback to modify the request in any way. If you want to do this, you should put a proxy in front of esbuild instead. type ServeResult struct { Hosts []string Port uint16 } hosts This is an array of hosts that ended up being used by the web server. If the host is an unspecified address (which it is by default), then the array includes the loopback interface as well as any other network interfaces that are currently active, such as the interface for your WiFi network. For example, the unspecified IPv4 address 0.0.0.0 might cause the array to contain both 127.0.0.1 and 192.168.0.1, and the unspecified IPv6 address :: might cause the array to contain both ::1 and fe80::b0ba:cafe. The actual hosts returned for an unspecified host depends on your current network configuration. port This is the port that ended up being used by the web server. You'll want to use this if you don't specify a port since esbuild will end up picking an arbitrary open port, and you need to know which port it picked to be able to connect to it. ) // The return value tells us where esbuild's local server is let { hosts, port } = await ctx.serve({ servedir: '.' }) // Then start a proxy server on port 3000 http.createServer((req, res) => { const options = { [0], , , , , } // 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, { }) }) // Forward the body of the request to esbuild req.pipe(proxyReq, { }) }).listen(3000)This code starts esbuild's server on random local port and then starts a proxy server on port 3000. During development you would load http://localhost:3000 in your browser, which talks to the proxy. This example demonstrates modifying a response after esbuild has handled the request, but you can also modify or replace the request before esbuild has handled it.You can do many things with a proxy like this your own 404 page (the example above)Customizing the mapping of routes to files on the file systemRedirecting some routes to an API server instead of to esbuildYou can also use a real proxy such as nginx if you have more advanced needs.#Cross-Origin Resource SharingBy default, esbuild's development server does not allow access from arbitrary origins. This ensures that visiting a malicious website in your browser doesn't allow that website to access esbuild's development server, which could divulge confidential information (source code, API keys, directory listing, etc.).However, you may want to grant access to esbuild's development server for certain origins that you control. This can be done with Cross-Origin Resource Sharing (a.k.a. CORS). Specifically, passing your origin(s) to esbuild will cause esbuild to set the Access-Control-Allow-Origin response header when the request has a matching Origin header.Here is a simple example that allows any page on https://example.com to access esbuild's development JS Go esbuild --servedir=. --cors-origin=https://example.com import * as esbuild from 'esbuild' let ctx = await esbuild.context({}) await ctx.serve({ servedir: '.', cors: { origin: 'https://example.com', }, }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{}) if err != nil { os.Exit(1) } result, err2 := ctx.Serve(api.ServeOptions{ Servedir: \".\", { Origin: []string{\"https://example.com\"}, }, }) if err2 != nil { os.Exit(1) } } You can also provide an array of multiple origins to allow, and you can match many origins with a single pattern by using a * wildcard character. The following example matches both https://example.com and all subdomains that match https://*.example.com: CLI JS Go esbuild --servedir=. \"--cors-origin=https://example.com,https://*.example.com\" import * as esbuild from 'esbuild' let ctx = await esbuild.context({}) await ctx.serve({ servedir: '.', cors: { origin: [ 'https://example.com', 'https://*.example.com', ], }, }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{}) if err != nil { os.Exit(1) } result, err2 := ctx.Serve(api.ServeOptions{ Servedir: \".\", { Origin: []string{ \"https://example.com\", \"https://*.example.com\", }, }, }) if err2 != nil { os.Exit(1) } } Note that this feature currently only works for simple requests, which are requests that don't send a preflight OPTIONS request, as esbuild's development server doesn't currently support OPTIONS requests.#TsconfigSupported the build API automatically discovers tsconfig.json files and reads their contents during a build. However, you can also configure a custom tsconfig.json file to use instead. This can be useful if you need to do multiple builds of the same code with different JS Go esbuild app.ts --bundle --tsconfig=custom-tsconfig.json import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.ts'], , tsconfig: 'custom-tsconfig.json', outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Tsconfig: \"custom-tsconfig.json\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ' | esbuild --loader=ts --tsconfig-raw='{\"compilerOptions\":{\"useDefineForClassFields\":false}}' import * as esbuild from 'esbuild' let ts = 'class Foo { foo }' let result = await esbuild.transform(ts, { loader: 'ts', tsconfigRaw: `{ \"compilerOptions\": { \"useDefineForClassFields\": false, }, }`, }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { ts := \"class Foo { foo }\" result := api.Transform(ts, api.TransformOptions{ , TsconfigRaw: `{ \"compilerOptions\": { \"useDefineForClassFields\": false, }, }`, }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } ) await ctx.watch() console.log('watching...') package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, Outfile: \"out.js\", , , }) if err != nil { os.Exit(1) } err2 := ctx.Watch(api.WatchOptions{}) if err2 != nil { os.Exit(1) } fmt.Printf(\"watching...\\n\") // Returning from main() exits immediately in Go. // Block forever so we keep watching and don't exit. <-make(chan struct{}) } Note that the JavaScript and Go watch APIs complete as soon as watch mode has started. They do not wait for the initial build to finish. If you want to wait for an initial build to finish, you should additionally call rebuild and wait for it to complete.If you want to stop watch mode at some point in the future, you can call dispose on the context object to terminate the file JS Go # Use Ctrl+C to stop the CLI in watch mode import * as esbuild from 'esbuild' let ctx = await esbuild.context({ entryPoints: ['app.js'], outfile: 'out.js', , }) await ctx.watch() console.log('watching...') await new Promise(r => setTimeout(r, 10 * 1000)) await ctx.dispose() console.log('stopped watching') package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" import \"time\" func main() { ctx, err := api.Context(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, Outfile: \"out.js\", , , }) if err != nil { os.Exit(1) } err2 := ctx.Watch(api.WatchOptions{}) if err2 != nil { os.Exit(1) } fmt.Printf(\"watching...\\n\") time.Sleep(10 * time.Second) ctx.Dispose() fmt.Printf(\"stopped watching\\n\") } Watch mode in esbuild is implemented using polling instead of OS-specific file system APIs for portability. The polling system is designed to use relatively little CPU vs. a more traditional polling system that scans the whole directory tree at once. The file system is still scanned regularly but each scan only checks a random subset of your files, which means a change to a file will be picked up soon after the change is made but not necessarily instantly.With the current heuristics, large projects should be completely scanned around every 2 seconds so in the worst case it could take up to 2 seconds for a change to be noticed. However, after a change has been noticed the change's path goes on a short list of recently changed paths which are checked on every scan, so further changes to recently changed files should be noticed almost instantly.Note that it is still possible to implement watch mode yourself using esbuild's rebuild API and a file watcher library of your choice if you don't want to use a polling-based approach.If you are using the CLI, keep in mind that watch mode will be terminated when esbuild's stdin is closed. This prevents esbuild from accidentally outliving the parent process and unexpectedly continuing to consume resources on the system. If you have a use case that requires esbuild to continue to watch forever even when the parent process has finished, you may use --watch=forever instead of --watch.#ArgumentsThe optional arguments to the watch API are as JS Go # Wait 500ms before rebuilding after a change --watch-delay=500 interface WatchOptions { delay?: number } type WatchOptions struct { Delay int } delay If specified, esbuild waits this many milliseconds before rebuilding after a change is detected. The default value is 0 which means esbuild rebuilds immediately after the first detected change. If you use a tool that regenerates multiple source files very slowly, rebuilding immediately after the first change could cause esbuild to generate a broken intermediate build before generating a successful final build, which can be confusing and/or distracting. Using this option to introduce a delay before rebuilding can give extra time to such a tool and avoid this situation. ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"home.ts\", \"settings.ts\"}, , , Outdir: \"out\", }) if len(result.Errors) > 0 { os.Exit(1) } } This will generate two output files, out/home.js and out/settings.js corresponding to the two entry points home.ts and settings.ts.For further control over how the paths of the output files are derived from the corresponding input entry points, you should look into these namesOut extensionOutbaseOutdirOutfileIn addition, you can also specify a fully custom output path for each individual entry point using an alternative entry point JS Go esbuild out1=home.ts out2=settings.ts --bundle --outdir=out import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: [ { out: 'out1', in: 'home.ts'}, { out: 'out2', in: 'settings.ts'}, ], , , outdir: 'out', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPointsAdvanced: []api.EntryPoint{{ OutputPath: \"out1\", InputPath: \"home.ts\", }, { OutputPath: \"out2\", InputPath: \"settings.ts\", }}, , , Outdir: \"out\", }) if len(result.Errors) > 0 { os.Exit(1) } } This will generate two output files, out/out1.js and out/out2.js corresponding to the two entry points home.ts and settings.ts.#Glob-style entry pointsIf an entry point contains the * character, then it's considered to be a glob pattern. This means esbuild will use that entry point as a pattern to search for files on the file system and will then replace that entry point with any matching files that were found. So for example, an entry point of *.js will cause esbuild to consider all files in the current directory that end in ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".png\": api.LoaderDataURL, \".svg\": api.LoaderText, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } This option is specified differently if you are using the build API with input from stdin, since stdin does not have a file extension. Configuring a loader for stdin with the build API looks like JS Go echo 'import pkg = require(\"./pkg\")' | esbuild --loader=ts --bundle import * as esbuild from 'esbuild' await esbuild.build({ stdin: { contents: 'import pkg = require(\"./pkg\")', loader: 'ts', resolveDir: '.', }, , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ Stdin: &api.StdinOptions{ Contents: \"import pkg = require('./pkg')\", , ResolveDir: \".\", }, , }) if len(result.Errors) > 0 { os.Exit(1) } } The transform API call just takes a single loader since it doesn't involve interacting with the file system, and therefore doesn't deal with file extensions. Configuring a loader (in this case the ts loader) for the transform API looks like JS Go echo 'let = 1' | esbuild --loader=ts let x = 1; import * as esbuild from 'esbuild' let ts = 'let = 1' let result = await esbuild.transform(ts, { loader: 'ts', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { ts := \"let = 1\" result := api.Transform(ts, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ Stdin: &api.StdinOptions{ Contents: \"export * from './another-file'\", // These are all : \"./src\", Sourcefile: \"imaginary-file.js\", , }, , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, [string]string{ \"js\": \"//comment\", \"css\": \"/*comment*/\", }, }) if len(result.Errors) > 0 { os.Exit(1) } } This is similar to footer which inserts at the end instead of the beginning.Note that if you are inserting non-comment code into a CSS file, be aware that CSS ignores all @import rules that come after a non-@import rule (other than a @charset rule), so using a banner to inject CSS rules may accidentally disable imports of external stylesheets.Unlike the build API, the banner for the transform API is just a single string. There is no need to specify a separate banner for JS and CSS files since the content type for the transform API is already unambiguously specified via the loader setting. Here is an example using the transform JS Go echo '1+2' | esbuild --banner=//comment //comment 1 + 2; import * as esbuild from 'esbuild' let result = await esbuild.transform('1+2', { banner: '//comment', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"1+2\", api.TransformOptions{ Banner: \"//comment\", }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } )).code 'let π = Math.PI;\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"let π = Math.PI\" result1 := api.Transform(js, api.TransformOptions{}) if len(result1.Errors) == 0 { fmt.Printf(\"%s\", result1.Code) } result2 := api.Transform(js, api.TransformOptions{ , }) if len(result2.Errors) == 0 { fmt.Printf(\"%s\", result2.Code) } } Some does not yet escape non-ASCII characters embedded in regular expressions. This is because esbuild does not currently parse the contents of regular expressions at all. The flag was added despite this limitation because it's still useful for code that doesn't contain cases like this. This flag does not apply to comments. I believe preserving non-ASCII data in comments should be fine because even if the encoding is wrong, the run time environment should completely ignore the contents of all comments. For example, the V8 blog post mentions an optimization that avoids decoding comment contents completely. And all comments other than license-related comments are stripped out by esbuild anyway. This option simultaneously applies to all output file types (JavaScript, CSS, and JSON). So if you configure your web server to send the correct Content-Type header and want to use the UTF-8 charset, make sure your web server is configured to treat both ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, [string]string{ \"js\": \"//comment\", \"css\": \"/*comment*/\", }, }) if len(result.Errors) > 0 { os.Exit(1) } } This is similar to banner which inserts at the beginning instead of the end.Unlike the build API, the footer for the transform API is just a single string. There is no need to specify a separate footer for JS and CSS files since the content type for the transform API is already unambiguously specified via the loader setting. Here is an example using the transform JS Go echo '1+2' | esbuild --footer=//comment 1 + 2; //comment import * as esbuild from 'esbuild' let result = await esbuild.transform('1+2', { footer: '//comment', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"1+2\", api.TransformOptions{ Footer: \"//comment\", }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } )(); import * as esbuild from 'esbuild' let js = 'alert(\"test\")' let result = await esbuild.transform(js, { format: 'iife', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"alert(\\\"test\\\")\" result := api.Transform(js, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } ; __export(stdin_exports, { default: () => stdin_default }); module.exports = __toCommonJS(stdin_exports); var stdin_default = \"test\"; import * as esbuild from 'esbuild' let js = 'export default \"test\"' let result = await esbuild.transform(js, { format: 'cjs', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"export default 'test'\" result := api.Transform(js, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } ); export default require_stdin(); import * as esbuild from 'esbuild' let js = 'module.exports = \"test\"' let result = await esbuild.transform(js, { format: 'esm', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"module.exports = 'test'\" result := api.Transform(js, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } The esm format can be used either in the browser or in node, but you have to explicitly load it as a module. This happens automatically if you import it from another module. the browser, you can load a module using <script src=\"file.js\" type=\"module\"></script>. Do not forget type=\"module\" as this will break your code in subtle and confusing ways (omitting type=\"module\" means that all top-level variables will end up in the global scope, which will then collide with top-level variables that have the same name in other JavaScript files). In node, you can load a module using node file.mjs. Note that node requires the ) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"module.exports = 'test'\" result := api.Transform(js, api.TransformOptions{ , GlobalName: \"xyz\", }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } Specifying the global name with the iife format will generate code that looks something like xyz = (() => { ... var require_stdin = __commonJS((exports, module) => { module.exports = \"test\"; }); return require_stdin(); })();The global name can also be a compound property expression, in which case esbuild will generate a global variable with that property. Existing global variables that conflict will not be overwritten. This can be used to implement \"namespacing\" where multiple independent scripts add their exports onto the same global object. For JS Go echo 'module.exports = \"test\"' | esbuild --format=iife --global-name='example.versions[\"1.0\"]' import * as esbuild from 'esbuild' let js = 'module.exports = \"test\"' let result = await esbuild.transform(js, { format: 'iife', globalName: 'example.versions[\"1.0\"]', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"module.exports = 'test'\" result := api.Transform(js, api.TransformOptions{ , GlobalName: `example.versions[\"1.0\"]`, }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } The compound global name used above generates code that looks like example = example || {}; example.versions = example.versions || {}; example.versions[\"1.0\"] = (() => { ... var require_stdin = __commonJS((exports, module) => { module.exports = \"test\"; }); return require_stdin(); })();#Legal commentsSupported and TransformA \"legal comment\" is considered to be any statement-level comment in JS or rule-level comment in CSS that contains @license or @preserve or that starts with //! or /*!. These comments are preserved in output files by default since that follows the intent of the original authors of the code. However, this behavior can be configured by using one of the following not preserve any legal comments.inlinePreserve all legal comments.eofMove all legal comments to the end of the file.linkedMove all legal comments to a ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } Note that \"statement-level\" for JS and \"rule-level\" for CSS means the comment must appear in a context where multiple statements or rules are allowed such as in the top-level scope or in a statement or rule block. So comments inside expressions or at the declaration level are not considered legal comments.#Line limitSupported and TransformThis setting is a way to prevent esbuild from generating output files with really long lines, which can help editing performance in poorly-implemented text editors. Set this to a positive integer to tell esbuild to end a given line soon after it passes that number of bytes. For example, this wraps long lines soon after they pass ~80 JS Go esbuild app.ts --line-limit=80 import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.ts'], , }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } Lines are truncated after they pass the limit instead of before because it's simpler to check when the limit is passed than to predict when the limit is about to be passed, and because it's faster to avoid backing up and rewriting things when generating an output file. So the limit is only approximate.This setting applies to both JavaScript and CSS, and works even when minification is disabled. Note that turning this setting on will make your files bigger, as the extra newlines take up additional space in the file (even after gzip compression).#SplittingSupported splitting is still a work in progress. It currently only works with the esm output format. There is also a known ordering issue with import statements across code splitting chunks. You can follow the tracking issue for updates about this feature.This enables \"code splitting\" which serves two shared between multiple entry points is split off into a separate shared file that both entry points import. That way if the user first browses to one page and then to another page, they don't have to download all of the JavaScript for the second page from scratch if the shared part has already been downloaded and cached by their browser. Code referenced through an asynchronous import() expression will be split off into a separate file and only loaded when that expression is evaluated. This allows you to improve the initial download time of your app by only downloading the code you need at startup, and then lazily downloading additional code if needed later. Without code splitting enabled, an import() expression becomes Promise.resolve().then(() => require()) instead. This still preserves the asynchronous semantics of the expression but it means the imported code is included in the same bundle instead of being split off into a separate file. When you enable code splitting you must also configure the output directory using the outdir JS Go esbuild home.ts about.ts --bundle --splitting --outdir=out --format=esm import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['home.ts', 'about.ts'], , , outdir: 'out', format: 'esm', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"home.ts\", \"about.ts\"}, , , Outdir: \"out\", , , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, Outdir: \".\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, AssetNames: \"assets/[name]-[hash]\", [string]api.Loader{ \".png\": api.LoaderFile, }, , Outdir: \"out\", }) if len(result.Errors) > 0 { os.Exit(1) } } There are four placeholders that can be used in asset path templates:[dir] This is the relative path from the directory containing the asset file to the outbase directory. Its purpose is to help asset output paths look more aesthetically pleasing by mirroring the input directory structure inside of the output directory. [name] This is the original file name of the asset without the extension. For example, if the asset was originally named image.png then [name] will be substituted with image in the template. It is not necessary to use this placeholder; it only exists to provide human-friendly asset names to make debugging easier. [hash] This is the content hash of the asset, which is useful to avoid name collisions. For example, your code may import components/button/icon.png and components/select/icon.png in which case you'll need the hash to distinguish between the two assets that are both named icon. [ext] This is the file extension of the asset (i.e. everything after the end of the last . character). It can be used to put different types of assets into different directories. For example, --asset-names=assets/[ext]/[name]-[hash] might write out an asset named image.png as assets/png/image-CQFGD2NG.png. Asset path templates do not need to include a file extension. The original file extension of the asset will be automatically added to the end of the output path after template substitution.This option is similar to the chunk names and entry names options.#Chunk namesSupported option controls the file names of the chunks of shared code that are automatically generated when code splitting is enabled. It configures the output paths using a template with placeholders that will be substituted with values specific to the chunk when the output path is generated. For example, specifying a chunk name template of chunks/[name]-[hash] puts all generated chunks into a subdirectory called chunks inside of the output directory and includes the content hash of the chunk in the file name. Doing that looks like JS Go esbuild app.js --chunk-names=chunks/[name]-[hash] --bundle --outdir=out --splitting --format=esm import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], chunkNames: 'chunks/[name]-[hash]', , outdir: 'out', , format: 'esm', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, ChunkNames: \"chunks/[name]-[hash]\", , Outdir: \"out\", , , }) if len(result.Errors) > 0 { os.Exit(1) } } There are three placeholders that can be used in chunk path templates:[name] This will currently always be the text chunk, although this placeholder may take on additional values in future releases. [hash] This is the content hash of the chunk. Including this is necessary to distinguish different chunks from each other in the case where multiple chunks of shared code are generated. [ext] This is the file extension of the chunk (i.e. everything after the end of the last . character). It can be used to put different types of chunks into different directories. For example, --chunk-names=chunks/[ext]/[name]-[hash] might write out a chunk as chunks/css/chunk-DEFJT7KY.css. Chunk path templates do not need to include a file extension. The configured out extension for the appropriate content type will be automatically added to the end of the output path after template substitution.Note that this option only controls the names for automatically-generated chunks of shared code. It does not control the names for output files related to entry points. The names of these are currently determined from the path of the original entry point file relative to the outbase directory, and this behavior cannot be changed. An additional API option will be added in the future to let you change the file names of entry point output files.This option is similar to the asset names and entry names options.#Entry namesSupported option controls the file names of the output files corresponding to each input entry point file. It configures the output paths using a template with placeholders that will be substituted with values specific to the file when the output path is generated. For example, specifying an entry name template of [dir]/[name]-[hash] includes a hash of the output file in the file name and puts the files into the output directory, potentially under a subdirectory (see the details about [dir] below). Doing that looks like JS Go esbuild src/main-app/app.js --entry-names=[dir]/[name]-[hash] --outbase=src --bundle --outdir=out import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['src/main-app/app.js'], entryNames: '[dir]/[name]-[hash]', outbase: 'src', , outdir: 'out', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"src/main-app/app.js\"}, EntryNames: \"[dir]/[name]-[hash]\", Outbase: \"src\", , Outdir: \"out\", }) if len(result.Errors) > 0 { os.Exit(1) } } There are four placeholders that can be used in entry path templates:[dir] This is the relative path from the directory containing the input entry point file to the outbase directory. Its purpose is to help you avoid collisions between identically-named entry points in different subdirectories. For example, if there are two entry points src/pages/home/index.ts and src/pages/about/index.ts, the outbase directory is src, and the entry names template is [dir]/[name], the output directory will contain pages/home/index.js and pages/about/index.js. If the entry names template had been just [name] instead, bundling would have failed because there would have been two output files with the same output path index.js inside the output directory. [name] This is the original file name of the entry point without the extension. For example, if the input entry point file is named app.js then [name] will be substituted with app in the template. [hash] This is the content hash of the output file, which can be used to take optimal advantage of browser caching. Adding [hash] to your entry point names means esbuild will calculate a hash that relates to all content in the corresponding output file (and any output file it imports if code splitting is active). The hash is designed to change if and only if any of the input files relevant to that output file are changed. After that, you can have your web server tell browsers that to cache these files forever (in practice you can say they expire a very long time from now such as in a year). You can then use the information in the metafile to determine which output file path corresponds to which input entry point so you know what path to include in your <script> tag. [ext] This is the file extension that the entry point file will be written out to (i.e. the out extension setting, not the original file extension). It can be used to put different types of entry points into different directories. For example, --entry-names=entries/[ext]/[name] might write the output file for app.ts to entries/js/app.js. Entry path templates do not need to include a file extension. The appropriate out extension based on the file type will be automatically added to the end of the output path after template substitution.This option is similar to the asset names and chunk names options.#Out extensionSupported option lets you customize the file extension of the files that esbuild generates to something other than ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outdir: \"dist\", [string]string{ \".js\": \".mjs\", }, , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{ \"src/pages/home/index.ts\", \"src/pages/about/index.ts\", }, , Outdir: \"out\", Outbase: \"src\", }) if len(result.Errors) > 0 { os.Exit(1) } } If the outbase directory isn't specified, it defaults to the lowest common ancestor directory among all input entry point paths. This is src/pages in the example above, which means by default the output directory will contain home/index.js and about/index.js instead.#OutdirSupported option sets the output directory for the build operation. For example, this command will generate a directory called JS Go esbuild app.js --bundle --outdir=out import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , outdir: 'out', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outdir: \"out\", , }) if len(result.Errors) > 0 { os.Exit(1) } } The output directory will be generated if it does not already exist, but it will not be cleared if it already contains some files. Any generated files will silently overwrite existing files with the same name. You should clear the output directory yourself before running esbuild if you want the output directory to only contain files from the current run of esbuild.If your build contains multiple entry points in separate directories, the directory structure will be replicated into the output directory starting from the lowest common ancestor directory among all input entry point paths. For example, if there are two entry points src/home/index.ts and src/about/index.ts, the output directory will contain home/index.js and about/index.js. If you want to customize this behavior, you should change the outbase directory.#OutfileSupported option sets the output file name for the build operation. This is only applicable if there is a single entry point. If there are multiple entry points, you must use the outdir option instead to specify an output directory. Using outfile looks like JS Go esbuild app.js --bundle --outfile=out.js import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , [string]api.Loader{ \".png\": api.LoaderFile, }, Outdir: \"out\", PublicPath: \"https://www.example.com/v1\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ) for (let out of result.outputFiles) { console.log(out.path, out.contents, out.hash, out.text) } package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , Outdir: \"out\", }) if len(result.Errors) > 0 { os.Exit(1) } for _, out := range result.OutputFiles { fmt.Printf(\"%v %v %s\\n\", out.Path, out.Contents, out.Hash) } } The hash property is a hash of the contents field and has been provided for convenience. The hash algorithm (currently XXH64) is implementation-dependent and may be changed at any time in between esbuild versions.#Path resolution#AliasSupported feature lets you substitute one package for another when bundling. The example below substitutes the package oldpkg with the package JS Go esbuild app.js --bundle =newpkg import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , , alias: { 'oldpkg': 'newpkg', }, }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , [string]string{ \"oldpkg\": \"newpkg\", }, }) if len(result.Errors) > 0 { os.Exit(1) } } These new substitutions happen first before all of esbuild's other path resolution logic. One use case for this feature is replacing a node-only package with a browser-friendly package in third-party code that you don't control.Note that when an import path is substituted using an alias, the resulting import path is resolved in the working directory instead of in the directory containing the source file with the import path. If needed, the working directory that esbuild uses can be set with the working directory feature.#ConditionsSupported feature controls how the exports field in package.json is interpreted. Custom conditions can be added using the conditions setting. You can specify as many of these as you want and the meaning of these is entirely up to package authors. Node has currently only endorsed the development and production custom conditions for recommended use. Here is an example of adding the custom conditions custom1 and JS Go esbuild src/app.js --bundle --conditions=custom1,custom2 import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['src/app.js'], , conditions: ['custom1', 'custom2'], }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"src/app.js\"}, , Conditions: []string{\"custom1\", \"custom2\"}, }) if len(result.Errors) > 0 { os.Exit(1) } } #How conditions workConditions allow you to redirect the same import path to different file locations in different situations. The redirect map containing the conditions and paths is stored in the exports field in the package's package.json file. For example, this would remap require('pkg/foo') to pkg/required.cjs and import 'pkg/foo' to pkg/imported.mjs using the import and require conditions:{ \"name\": \"pkg\", \"exports\": { \"./foo\": { \"import\": \"./imported.mjs\", \"require\": \"./required.cjs\", \"default\": \"./fallback.js\" } } }Conditions are checked in the order that they appear within the JSON file. So the example above behaves sort of like (importPath === './foo') { if (conditions.has('import')) return './imported.mjs' if (conditions.has('require')) return './required.cjs' return './fallback.js' }By default there are five conditions with special behavior that are built in to esbuild, and cannot be This condition is always active. It is intended to come last and lets you provide a fallback for when no other condition applies. This condition is also active when you run your code natively in node. import This condition is only active when the import path is from an ESM import statement or import() expression. It can be used to provide ESM-specific code. This condition is also active when you run your code natively in node (but only in an ESM context). require This condition is only active when the import path is from a CommonJS require() call. It can be used to provide CommonJS-specific code. This condition is also active when you run your code natively in node (but only in a CommonJS context). browser This condition is only active when esbuild's platform setting is set to browser. It can be used to provide browser-specific code. This condition is not active when you run your code natively in node. node This condition is only active when esbuild's platform setting is set to node. It can be used to provide node-specific code. This condition is also active when you run your code natively in node. The following condition is also automatically included when the platform is set to either browser or node and no custom conditions are configured. If there are any custom conditions configured (even an empty list) then this condition will no longer be automatically This condition can be used to tell esbuild to pick the ESM variant for a given import path to provide better tree-shaking when bundling. This condition is not active when you run your code natively in node. It is specific to bundlers, and originated from Webpack. Note that when you use the require and import conditions, your package may end up in the bundle multiple times! This is a subtle issue that can cause bugs due to duplicate copies of your code's state in addition to bloating the resulting bundle. This is commonly known as the dual package hazard.One way of avoiding the dual package hazard that works both for bundlers and when running natively in node is to put all of your code in the require condition as CommonJS and have the import condition just be a light ESM wrapper that calls require on your package and re-exports the package using ESM syntax. This approach doesn't provide good tree-shaking, however, as esbuild doesn't tree-shake CommonJS modules.Another way of avoiding a dual package hazard is to use the bundler-specific module condition to direct bundlers to always load the ESM version of your package while letting node always fall back to the CommonJS version of your package. Both import and module are intended to be used with ESM but unlike import, the module condition is always active even if the import path was loaded using a require call. This works well with bundlers because bundlers support loading ESM using require, but it's not something that can work with node because node deliberately doesn't implement loading ESM using require.#ExternalSupported can mark a file or a package as external to exclude it from your build. Instead of being bundled, the import will be preserved (using require for the iife and cjs formats and using import for the esm format) and will be evaluated at run time instead.This has several uses. First of all, it can be used to trim unnecessary code from your bundle for a code path that you know will never be executed. For example, a package may contain code that only runs in node but you will only be using that package in the browser. It can also be used to import code in node at run time from a package that cannot be bundled. For example, the fsevents package contains a native extension, which esbuild doesn't support. Marking something as external looks like JS Go echo 'require(\"fsevents\")' > app.js esbuild app.js --bundle --platform=node // app.js require(\"fsevents\"); import * as esbuild from 'esbuild' import fs from 'node:fs' fs.writeFileSync('app.js', 'require(\"fsevents\")') await esbuild.build({ entryPoints: ['app.js'], outfile: 'out.js', , platform: 'node', external: ['fsevents'], }) package main import \"io/ioutil\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { ioutil.WriteFile(\"app.js\", []byte(\"require(\\\"fsevents\\\")\"), 0644) result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, Outfile: \"out.js\", , , , External: []string{\"fsevents\"}, }) if len(result.Errors) > 0 { os.Exit(1) } } You can also use the * wildcard character in an external path to mark all files matching that pattern as external. For example, you can use *.png to remove all ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, Outfile: \"out.js\", , , External: []string{\"*.png\", \"/images/*\"}, }) if len(result.Errors) > 0 { os.Exit(1) } } External paths are applied both before and after path resolution, which lets you match against both the import path in the source code and the absolute file system path. The path is considered to be external if the external path matches in either case. The specific behavior is as path resolution begins, import paths are checked against all external paths. In addition, if the external path looks like a package path (i.e. doesn't start with / or ./ or ../), import paths are checked to see if they have that package path as a path prefix. This means that --external:@foo/bar implicitly also means --external:@foo/bar/* which matches the import path @foo/bar/baz. So it marks all paths inside the @foo/bar package as external too. After path resolution ends, the resolved absolute paths are checked against all external paths that don't look like a package path (i.e. those that start with / or ./ or ../). But before checking, the external path is joined with the current working directory and then normalized, becoming an absolute path (even if it contains a * wildcard character). This means that you can mark everything in the directory dir as external using /dir/*. Note that the leading ./ is important. Using /* instead is treated as a package path and is not checked for after path resolution ends. ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , MainFields: []string{\"module\", \"main\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } The main field is expected to be CommonJS while the module field is expected to be ESM. The decision about which module format to use is independent from the decision about whether to use a browser-specific or node-specific variant. If you omit one of these four entries, then you risk the wrong variant being chosen. For example, if you omit the entry for the CommonJS browser build, then the CommonJS node build could be chosen instead.Note that using main, module, and browser is the old way of doing this. There is also a newer way to do this that you may prefer to use exports field in package.json. It provides a different set of trade-offs. For example, it gives you more precise control over imports for all sub-paths in your package (while main fields only give you control over the entry point), but it may cause your package to be imported multiple times depending on how you configure it.#Node pathsSupported 's module resolution algorithm supports an environment variable called NODE_PATH that contains a list of global directories to use when resolving import paths. These paths are searched for packages in addition to the node_modules directories in all parent directories. You can pass this list of directories to esbuild using an environment variable with the CLI and using an array with the JS and Go JS Go NODE_PATH=someDir esbuild app.js --bundle --outfile=out.js import * as esbuild from 'esbuild' await esbuild.build({ nodePaths: ['someDir'], entryPoints: ['app.js'], , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ NodePaths: []string{\"someDir\"}, EntryPoints: []string{\"app.js\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } If you are using the CLI and want to pass multiple directories using NODE_PATH, you will have to separate them Unix and ; on Windows. This is the same format that Node itself uses.#PackagesSupported this setting to control whether all of your package's dependencies are excluded from the bundle or not. This is useful when bundling for node because many npm packages use node-specific features that esbuild doesn't support while bundling (such as __dirname, import.meta.url, fs.readFileSync, and *.node native binary modules). There are two possible This is the default value. It means that package imports are allowed to be bundled. Note that this value doesn't mean all packages will be bundled, just that they are allowed to be. You can still exclude individual packages from the bundle using external. external This means that all package imports considered external to the bundle, and are not bundled. Note that your dependencies must still be present on the file system when your bundle is run. It has the same effect as manually passing each dependency to external but is more concise. If you want to customize which of your dependencies are external and which ones aren't, then you should set this to bundle instead and then use external for individual dependencies. This setting considers all import paths that \"look like\" package imports in the original source code to be package imports. Specifically import paths that don't start with a path segment of / or . or .. are considered to be package imports. The only two exceptions to this rule are subpath imports (which start with a # character) and TypeScript path remappings via paths and/or baseUrl in tsconfig.json (which are applied first). Using it looks like JS Go esbuild app.js --bundle --packages=external import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , packages: 'external', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , }) if len(result.Errors) > 0 { os.Exit(1) } } Note that this setting only has an effect when bundling is enabled. Also note that marking an import path as external happens after the import path is rewritten by any configured aliases, so the alias feature still has an effect when this setting is used.#Preserve symlinksSupported setting mirrors the --preserve-symlinks setting in node. If you use that setting (or the similar resolve.symlinks setting in Webpack), you will likely need to enable this setting in esbuild too. It can be enabled like JS Go esbuild app.js --bundle --preserve-symlinks --outfile=out.js import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , Outfile: \"out.js\", }) if len(result.Errors) > 0 { os.Exit(1) } } Enabling this setting causes esbuild to determine file identity by the original file path (i.e. the path without following symlinks) instead of the real file path (i.e. the path after following symlinks). This can be beneficial with certain directory structures. Keep in mind that this means a file may be given multiple identities if there are multiple symlinks pointing to it, which can result in it appearing multiple times in generated output files.Note: The term \"symlink\" means symbolic link and refers to a file system feature where a path can redirect to another path.#Resolve extensionsSupported resolution algorithm used by node supports implicit file extensions. You can require('./file') and it will check for ./file, ./file.js, ./file.json, and ./file.node in that order. Modern bundlers including esbuild extend this concept to other file types as well. The full order of implicit file extensions in esbuild can be customized using the resolve extensions setting, which defaults to ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , ResolveExtensions: []string{\".ts\", \".js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } Note that esbuild deliberately does not include the new ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"file.js\"}, AbsWorkingDir: \"/var/tmp/custom/working/directory\", Outfile: \"out.js\", }) if len(result.Errors) > 0 { os.Exit(1) } } you are using Yarn Plug'n'Play, keep in mind that this working directory is used to search for Yarn's manifest file. If you are running esbuild from an unrelated directory, you will have to set this working directory to the directory containing the manifest file (or one of its child directories) for the manifest file to be found by esbuild.#Transformation#JSXSupported and TransformThis option tells esbuild what to do about JSX syntax. Here are the available This tells esbuild to transform JSX to JS using a general-purpose transform that's shared between many libraries that use JSX syntax. Each JSX element is turned into a call to the JSX factory function with the element's component (or with the JSX fragment for fragments) as the first argument. The second argument is an array of props (or null if there are no props). Any child elements present become additional arguments after the second argument. If you want to configure this setting on a per-file basis, you can do that by using a // @jsxRuntime classic comment. This is a convention from Babel's JSX plugin that esbuild follows. preserve This preserves the JSX syntax in the output instead of transforming it into function calls. JSX elements are treated as first-class syntax and are still affected by other settings such as minification and property mangling. Note that this means the output files are no longer valid JavaScript code. This feature is intended to be used when you want to transform the JSX syntax in esbuild's output files by another tool after bundling. automatic This transform was introduced in React 17+ and is very specific to React. It automatically generates import statements from the JSX import source and introduces many special cases regarding how the syntax is handled. The details are too complicated to describe here. For more information, please read React's documentation about their new JSX transform. If you want to enable the development mode version of this transform, you need to additionally enable the JSX dev setting. If you want to configure this setting on a per-file basis, you can do that by using a // @jsxRuntime automatic comment. This is a convention from Babel's JSX plugin that esbuild follows. Here's an example of setting the JSX transform to JS Go echo '<div/>' | esbuild --jsx=preserve --loader=jsx <div />; import * as esbuild from 'esbuild' let result = await esbuild.transform('<div/>', { jsx: 'preserve', loader: 'jsx', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"<div/>\", api.TransformOptions{ , , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } from \"react/jsx-runtime\"; /* @__PURE__ */ jsx(\"a\", {}); echo '<a/>' | esbuild --loader=jsx --jsx=automatic --jsx-dev import { jsxDEV } from \"react/jsx-dev-runtime\"; /* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, { fileName: \"<stdin>\", , }, this); import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.jsx'], , jsx: 'automatic', outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, , , Outfile: \"out.js\", }) if len(result.Errors) > 0 { os.Exit(1) } } ) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"<div/>\", api.TransformOptions{ JSXFactory: \"h\", , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } Alternatively, if you are using TypeScript, you can just configure JSX for TypeScript by adding this to your tsconfig.json file and esbuild should pick it up automatically without needing to be configured:{ \"compilerOptions\": { \"jsxFactory\": \"h\" } }If you want to configure this on a per-file basis, you can do that by using a // @jsx h comment. Note that this setting does not apply when the JSX transform has been set to automatic.#JSX fragmentSupported and TransformThis sets the function that is called for each JSX fragment. Normally a JSX fragment expression such as this:<>Stuff</>is compiled into a use of the React.Fragment component like (React.Fragment, null, \"Stuff\");You can use a component other than React.Fragment by changing the JSX fragment. For example, to use the component Fragment instead (which is used by other libraries such as Preact): CLI JS Go echo '<>x</>' | esbuild --jsx-fragment=Fragment --loader=jsx /* @__PURE__ */ React.createElement(Fragment, null, \"x\"); import * as esbuild from 'esbuild' let result = await esbuild.transform('<>x</>', { jsxFragment: 'Fragment', loader: 'jsx', }) console.log(result.code) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"<>x</>\", api.TransformOptions{ JSXFragment: \"Fragment\", , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } Alternatively, if you are using TypeScript, you can just configure JSX for TypeScript by adding this to your tsconfig.json file and esbuild should pick it up automatically without needing to be configured:{ \"compilerOptions\": { \"jsxFragmentFactory\": \"Fragment\" } }If you want to configure this on a per-file basis, you can do that by using a // @jsxFrag Fragment comment. Note that this setting does not apply when the JSX transform has been set to automatic.#JSX import sourceSupported and TransformIf the JSX transform has been set to automatic, then setting this lets you change which library esbuild uses to automatically import its JSX helper functions from. Note that this only works with the JSX transform that's specific to React 17+. If you set the JSX import source to your-pkg, then that package must expose at least the following { createElement } from \"your-pkg\" import { Fragment, jsx, jsxs } from \"your-pkg/jsx-runtime\" import { Fragment, jsxDEV } from \"your-pkg/jsx-dev-runtime\"The /jsx-runtime and /jsx-dev-runtime subpaths are hard-coded by design and cannot be changed. The jsx and jsxs imports are used when JSX dev mode is off and the jsxDEV import is used when JSX dev mode is on. The meaning of these is described in React's documentation about their new JSX transform. The createElement import is used regardless of the JSX dev mode when an element has a prop spread followed by a key prop, which looks like <div {...props} key={key} />Here's an example of setting the JSX import source to JS Go esbuild app.jsx --jsx-import-source=preact --jsx=automatic import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.jsx'], jsxImportSource: 'preact', jsx: 'automatic', outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, JSXImportSource: \"preact\", , Outfile: \"out.js\", }) if len(result.Errors) > 0 { os.Exit(1) } } Alternatively, if you are using TypeScript, you can just configure the JSX import source for TypeScript by adding this to your tsconfig.json file and esbuild should pick it up automatically without needing to be configured:{ \"compilerOptions\": { \"jsx\": \"react-jsx\", \"jsxImportSource\": \"preact\" } }And if you want to control this setting on the per-file basis, you can do that with a // @jsxImportSource your-pkg comment in each file. You may also need to add a // @jsxRuntime automatic comment as well if the JSX transform has not already been set by other means, or if you want that to be set on a per-file basis as well.#JSX side effectsSupported and TransformBy default esbuild assumes that JSX expressions are side-effect free, which means they are annoated with /* @__PURE__ */ comments and are removed during bundling when they are unused. This follows the common use of JSX for virtual DOM and applies to the vast majority of JSX libraries. However, some people have written JSX libraries that don't have this property (specifically JSX expressions can have arbitrary side effects and can't be removed when unused). If you are using such a library, you can use this setting to tell esbuild that JSX expressions have side JS Go esbuild app.jsx --jsx-side-effects import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.jsx'], outfile: 'out.js', , }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.jsx\"}, Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, [string]bool{ \"bigint\": false, }, }) if len(result.Errors) > 0 { os.Exit(1) } } Syntax features are specified using esbuild-specific feature names. The full set of feature names is as : arbitrary-module-namespace-names array-spread arrow async-await async-generator bigint class class-field class-private-accessor class-private-brand-check class-private-field class-private-method class-private-static-accessor class-private-static-field class-private-static-method class-static-blocks class-static-field const-and-let decorators default-argument destructuring dynamic-import exponent-operator export-star-as for-await for-of from-base64 function-name-configurable function-or-class-property-access generator hashbang import-assertions import-attributes import-meta inline-script logical-assignment nested-rest-binding new-target node-colon-prefix-import node-colon-prefix-require nullish-coalescing object-accessors object-extensions object-rest-spread optional-catch-binding optional-chain regexp-dot-all-flag regexp-lookbehind-assertions regexp-match-indices regexp-named-capture-groups regexp-set-notation regexp-sticky-and-unicode-flags regexp-unicode-property-escapes rest-argument template-literal top-level-await typeof-exotic-object-is-object unicode-escapes using gradient-double-position gradient-interpolation gradient-midpoints hwb hex-rgba inline-style inset-property is-pseudo-class media-range modern-rgb-hsl nesting rebecca-purple ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , Engines: []api.Engine{ {Name: api.EngineChrome, Version: \"58\"}, {Name: api.EngineEdge, Version: \"16\"}, {Name: api.EngineFirefox, Version: \"57\"}, {Name: api.EngineNode, Version: \"12\"}, {Name: api.EngineSafari, Version: \"11\"}, }, , }) if len(result.Errors) > 0 { os.Exit(1) } } You can refer to the JavaScript loader for the details about which syntax features were introduced with which language versions. Keep in mind that while JavaScript language versions such as es2020 are identified by year, that is the year the specification is approved. It has nothing to do with the year all major browsers implement that specification which often happens earlier or later than that year.If you use a syntax feature that esbuild doesn't yet have support for transforming to your current language target, esbuild will generate an error where the unsupported syntax is used. This is often the case when targeting the es5 language version, for example, since esbuild only supports transforming most newer JavaScript syntax features to es6.If you need to customize the set of supported syntax features at the individual feature level in addition to or instead of what target provides, you can do that with the supported setting.#Optimization#DefineSupported and TransformThis feature provides a way to replace global identifiers with constant expressions. It can be a way to change the behavior some code between builds without changing the code JS Go echo 'hooks = DEBUG && require(\"hooks\")' | esbuild =true hooks = require(\"hooks\"); echo 'hooks = DEBUG && require(\"hooks\")' | esbuild =false hooks = false; import * as esbuild from 'esbuild'let js = 'hooks = DEBUG && require(\"hooks\")'(await esbuild.transform(js, { define: { DEBUG: 'true' }, })).code 'hooks = require(\"hooks\");\\n' (await esbuild.transform(js, { define: { DEBUG: 'false' }, })).code 'hooks = false;\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"hooks = DEBUG && require('hooks')\" result1 := api.Transform(js, api.TransformOptions{ [string]string{\"DEBUG\": \"true\"}, }) if len(result1.Errors) == 0 { fmt.Printf(\"%s\", result1.Code) } result2 := api.Transform(js, api.TransformOptions{ [string]string{\"DEBUG\": \"false\"}, }) if len(result2.Errors) == 0 { fmt.Printf(\"%s\", result2.Code) } } Each define entry maps an identifier to a string of code containing an expression. The expression in the string must either be a JSON object (null, boolean, number, string, array, or object) or a single identifier. Replacement expressions other than arrays and objects are substituted inline, which means that they can participate in constant folding. Array and object replacement expressions are stored in a variable and then referenced using an identifier instead of being substituted inline, which avoids substituting repeated copies of the value but means that the values don't participate in constant folding.If you want to replace something with a string literal, keep in mind that the replacement value passed to esbuild must itself contain quotes because each define entry maps to a string containing code. Omitting the quotes means the replacement value is an identifier instead. This is demonstrated in the example JS Go echo 'id, str' | esbuild =text =\\\"text\\\" text, \"text\"; import * as esbuild from 'esbuild'(await esbuild.transform('id, str', { define: { id: 'text', str: '\"text\"' }, })).code 'text, \"text\";\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { result := api.Transform(\"id, text\", api.TransformOptions{ [string]string{ \"id\": \"text\", \"str\": \"\\\"text\\\"\", }, }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } If you're using the CLI, keep in mind that different shells have different rules for how to escape double-quote characters (which are necessary when the replacement value is a string). Use a \\\" backslash escape because it works in both bash and Windows command prompt. Other methods of escaping double quotes that work in bash such as surrounding them with single quotes will not work on Windows, since Windows command prompt does not remove the single quotes. This is relevant when using the CLI from a npm script in your package.json file, which people will expect to work on all platforms:{ \"scripts\": { \"build\": \"esbuild =\\\\\\\"production\\\\\\\" app.js\" } }If you still run into cross-platform quote escaping issues with different shells, you will probably want to switch to using the JavaScript API instead. There you can use regular JavaScript syntax to eliminate cross-platform differences.If you're looking for a more advanced form of the define feature that can replace an expression with something other than a constant (e.g. replacing a global variable with a shim), you may be able to use the similar inject feature to do that.#DropSupported and TransformThis tells esbuild to edit your source code before building to drop certain constructs. There are currently two possible things that can be Passing this flag causes all debugger statements to be removed from the output. This is similar to the flag available in the popular UglifyJS and Terser JavaScript minifiers. JavaScript's debugger statements cause the active debugger to treat the statement as an automatically-configured breakpoint. Code containing this statement will automatically be paused when the debugger is open. If no debugger is open, the statement does nothing. Dropping these statements from your code just prevents the debugger from automatically stopping when your code runs. You can drop debugger statements like JS Go esbuild app.js import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], drop: ['debugger'], }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } console Passing this flag causes all console API calls to be removed from the output. This is similar to the flag available in the popular UglifyJS and Terser JavaScript minifiers. Using this flag can introduce bugs into your code! This flag removes the entire call expression including all call arguments. This is intentional because removing the evaluation of call arguments is useful for improving performance in production if those call arguments are expensive to compute. However, if any of those arguments had important side effects, using this flag will change the behavior of your code. Be very careful when using this flag. If you want to remove console API calls without removing the arguments with side effects (so you do not introduce bugs), you should mark the relevant API calls as pure instead. For example, you can mark console.log as pure using This will cause these API calls to be removed safely when minification is enabled. You can drop console API calls like JS Go esbuild app.js import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], drop: ['console'], }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } If you use this option to drop all labels named DEV, then esbuild will give you example() { return normalCodePath(); }You can configure this feature like this (which will drop both the DEV and TEST labels): CLI JS Go esbuild app.js --drop-labels=DEV,TEST import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], dropLabels: ['DEV', 'TEST'], }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, DropLabels: []string{\"DEV\", \"TEST\"}, }) if len(result.Errors) > 0 { os.Exit(1) } } Note that this is not the only way to conditionally remove code. Another more common way is to use the define feature to replace specific global variables with a boolean value. For example, consider the following example() { DEV && doAnExpensiveCheck() return normalCodePath() }If you define DEV to false, then esbuild will give you example() { return normalCodePath(); }This is pretty much the same thing as using a label. However, an advantage of using a label instead of a global variable to conditionally remove code is that you don't have to worry about the global variable not being defined because someone forgot to configure esbuild to replace it with something. Some drawbacks of using the label approach are that it makes conditionally removing code when the label is not dropped slightly harder to read, and it doesn't work for code embedded within nested expressions. Which approach to use for a given project comes down to personal preference.#Ignore annotationsSupported and TransformSince JavaScript is a dynamic language, identifying unused code is sometimes very difficult for a compiler, so the community has developed certain annotations to help tell compilers what code should be considered side-effect free and available for removal. Currently there are two forms of side-effect annotations that esbuild /* @__PURE__ */ comments before function calls tell esbuild that the function call can be removed if the resulting value isn't used. See the pure API option for more information. The sideEffects field in package.json can be used to tell esbuild which files in your package can be removed if all imports from that file end up being unused. This is a convention from Webpack and many libraries published to npm already have this field in their package definition. You can learn more about this field in Webpack's documentation for this field. These annotations can be problematic because the compiler depends completely on developers for accuracy, and developers occasionally publish packages with incorrect annotations. The sideEffects field is particularly error-prone for developers because by default it causes all files in your package to be considered dead code if no imports are used. If you add a new file containing side effects and forget to update that field, your package will likely break when people try to bundle it.This is why esbuild includes a way to ignore side-effect annotations. You should only enable this if you encounter a problem where the bundle is broken because necessary code was unexpectedly removed from the JS Go esbuild app.js --bundle --ignore-annotations import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , }) if len(result.Errors) > 0 { os.Exit(1) } } Enabling this means esbuild will no longer respect /* @__PURE__ */ comments or the sideEffects field. It will still do automatic tree shaking of unused imports, however, since that doesn't rely on annotations from developers. Ideally this flag is only a temporary workaround. You should report these issues to the maintainer of the package to get them fixed since they indicate a problem with the package and they will likely trip up other people too.#InjectSupported option allows you to automatically replace a global variable with an import from another file. This can be a useful tool for adapting code that you don't control to a new environment. For example, assume you have a file called process-cwd-shim.js that exports a shim using the export name process.cwd:// process-cwd-shim.js let processCwdShim = () => '' export { processCwdShim as 'process.cwd' }// entry.js console.log(process.cwd())This is intended to replace uses of node's process.cwd() function to prevent packages that call it from crashing when run in the browser. You can use the inject feature to replace all references to the global property process.cwd with an import from that JS Go esbuild entry.js /process-cwd-shim.js --outfile=out.js import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['entry.js'], inject: ['./process-cwd-shim.js'], outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"entry.js\"}, Inject: []string{\"./process-cwd-shim.js\"}, Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } That results in something like this:// out.js var processCwdShim = () => \"\"; console.log(processCwdShim());You can think of the inject feature as similar to the define feature, except it replaces an expression with an import to a file instead of with a constant, and the expression to replace is specified using an export name in a file instead of using an inline string in esbuild's API.#Auto-import for JSXReact (the library for which JSX syntax was originally created) has a mode they call automatic where you don't have to import anything to use JSX syntax. Instead, the JSX-to-JS transformer will automatically import the correct JSX factory function for you. You can enable automatic JSX mode with esbuild's jsx setting. If you want auto-import for JSX and you are using a sufficiently new version of React, then you should be using the automatic JSX mode.However, setting jsx to automatic unfortunately also means you are using a highly React-specific JSX transform instead of the default general-purpose JSX transform. This means writing a JSX factory function is more complicated, and it also means that the automatic mode doesn't work with libraries that expect to be used with the standard JSX transform (including older versions of React).You can use esbuild's inject feature to automatically import the factory and fragment for JSX expressions when the JSX transform is not set to automatic. Here's an example file that can be injected to do { createElement, Fragment } = require('react') export { createElement as 'React.createElement', Fragment as 'React.Fragment', }This code uses the React library as an example, but you can use this approach with any other JSX library as well with appropriate changes.#Injecting files without importsYou can also use this feature with files that have no exports. In that case the injected file just comes first before the rest of the output as if every input file contained import \"./file.js\". Because of the way ECMAScript modules work, this injection is still \"hygienic\" in that symbols with the same name in different files are renamed so they don't collide with each other.#Conditionally injecting a fileIf you want to conditionally import a file only if the export is actually used, you should mark the injected file as not having side effects by putting it in a package and adding \"sideEffects\": false in that package's package.json file. This setting is a convention from Webpack that esbuild respects for any imported file, not just files used with inject.#Keep namesSupported and TransformIn JavaScript the name property on functions and classes defaults to a nearby identifier in the source code. These syntax forms all set the name property of the function to \"fn\":function fn() {} let fn = function() {}; fn = function() {}; let [fn = function() {}] = []; let {fn = function() {}} = {}; [fn = function() {}] = []; ({fn = function() {}} = {});However, minification renames symbols to reduce code size and bundling sometimes need to rename symbols to avoid collisions. That changes value of the name property for many of these cases. This is usually fine because the name property is normally only used for debugging. However, some frameworks rely on the name property for registration and binding purposes. If this is the case, you can enable this option to preserve the original name values even in minified JS Go esbuild app.js --minify --keep-names import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , , , }) if len(result.Errors) > 0 { os.Exit(1) } } Note that this feature is unavailable if the target has been set to an old environment that doesn't allow esbuild to mutate the name property on functions and classes. This is the case for environments that don't support ES6.#Mangle propsSupported and TransformUsing this feature can break your code in subtle ways. Do not use this feature unless you know what you are doing, and you know exactly how it will affect both your code and all of your dependencies.This setting lets you pass a regular expression to esbuild to tell esbuild to automatically rename all properties that match this regular expression. It's useful when you want to minify certain property names in your code either to make the generated code smaller or to somewhat obfuscate your code's intent.Here's an example that uses the regular expression _$ to mangle all properties ending in an underscore, such as foo_. This mangles print({ }.foo_) into print({ }.a): CLI JS Go esbuild app.js --mangle-props=_$ import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], mangleProps: /_$/, }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, MangleProps: \"_$\", }) if len(result.Errors) > 0 { os.Exit(1) } } Only mangling properties that end in an underscore is a reasonable heuristic because normal JS code doesn't typically contain identifiers like that. Browser APIs also don't use this naming convention so this also avoids conflicts with browser APIs. If you want to avoid mangling names such as __defineGetter__ you could consider using a more complex regular expression such as [^_]_$ (i.e. must end in a non-underscore followed by an underscore).This is a separate setting instead of being part of the minify setting because it's an unsafe transformation that does not work on arbitrary JavaScript code. It only works if the provided regular expression matches all of the properties that you want mangled and does not match any of the properties that you don't want mangled. It also only works if you do not under any circumstances reference a mangled property indirectly. For example, it means you can't use obj[prop] to reference a property where prop is a string containing the property name. Specifically the following syntax constructs are the only ones eligible for property Example Dot property accesses x.foo_ Dot optional chains x?.foo_ Object properties x = { } Object methods x = { foo_() {} } Class fields class x { foo_ = y } Class methods class x { foo_() {} } Object destructuring bindings let { } = y Object destructuring assignments ({ } = y) JSX element member expression <X.foo_></X.foo_> JSX attribute names <X foo_={y} /> TypeScript namespace exports namespace x { export let foo_ = y } TypeScript parameter properties class x { constructor(public foo_) {} } When using this feature, keep in mind that property names are only consistently mangled within a single esbuild API call but not across esbuild API calls. Each esbuild API call does an independent property mangling operation so output files generated by two different API calls may mangle the same property to two different names, which could cause the resulting code to behave incorrectly.#Quoted properties By default, esbuild doesn't modify the contents of string literals. This means you can avoid property mangling for an individual property by quoting it as a string. However, you must consistently use quotes or no quotes for a given property everywhere for this to work. For example, print({ }.foo_) will be mangled into print({ }.a) while print({ 'foo_': 0 }['foo_']) will not be mangled.If you would like for esbuild to also mangle the contents of string literals, you can explicitly enable that behavior like JS Go esbuild app.js --mangle-props=_$ --mangle-quoted import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], mangleProps: /_$/, , }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, MangleProps: \"_$\", , }) if len(result.Errors) > 0 { os.Exit(1) } } Enabling this makes the following syntax constructs also eligible for property Example Quoted property accesses x['foo_'] Quoted optional chains x?.['foo_'] Quoted object properties x = { 'foo_': y } Quoted object methods x = { 'foo_'() {} } Quoted class fields class x { 'foo_' = y } Quoted class methods class x { 'foo_'() {} } Quoted object destructuring bindings let { 'foo_': x } = y Quoted object destructuring assignments ({ 'foo_': x } = y) String literals to the left of in 'foo_' in x Object.defineProperty( obj, /* @__KEY__ */ 'foo_', { get: () => 123 }, ) console.log(obj.foo_)This will cause the contents of the string 'foo_' to be mangled as a property name (assuming property mangling is enabled and foo_ is eligible for renaming). The /* @__KEY__ */ comment is a convention from Terser, a popular JavaScript minifier with a similar property mangling feature.#Preventing renaming If you would like to exclude certain properties from mangling, you can reserve them with an additional setting. For example, this uses the regular expression ^__.*__$ to reserve all properties that start and end with two underscores, such as JS Go esbuild app.js --mangle-props=_$ \"--reserve-props=^__.*__$\" import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], mangleProps: /_$/, reserveProps: /^__.*__$/, }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, MangleProps: \"_$\", ReserveProps: \"^__.*__$\", }) if len(result.Errors) > 0 { os.Exit(1) } } );If we want customRenaming_ to be renamed to cR_ and we don't want disabledRenaming_ to be renamed at all, we can pass the following mangle cache JSON to esbuild:{ \"customRenaming_\": \"cR_\", \"disabledRenaming_\": false }The mangle cache JSON can be passed to esbuild like JS Go esbuild app.js --mangle-props=_$ --mangle-cache=cache.json import * as esbuild from 'esbuild' let result = await esbuild.build({ entryPoints: ['app.js'], mangleProps: /_$/, mangleCache: { customRenaming_: \"cR_\", }, }) console.log('updated mangle cache:', result.mangleCache) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, MangleProps: \"_$\", [string]interface{}{ \"customRenaming_\": \"cR_\", \"disabledRenaming_\": false, }, }) if len(result.Errors) > 0 { os.Exit(1) } fmt.Println(\"updated mangle cache:\", result.MangleCache) } When property naming is enabled, that will result in the following output ({ , , });And the following updated mangle cache:{ \"customRenaming_\": \"cR_\", \"disabledRenaming_\": false, \"someProp_\": \"a\" }#MinifySupported and TransformWhen enabled, the generated code will be minified instead of pretty-printed. Minified code is generally equivalent to non-minified code but is smaller, which means it downloads faster but is harder to debug. Usually you minify code in production but not in development.Enabling minification in esbuild looks like JS Go echo 'fn = obj => { return obj.x }' | esbuild --minify fn=n=>n.x; import * as esbuild from 'esbuild'var js = 'fn = obj => { return obj.x }' (await esbuild.transform(js, { , })).code 'fn=n=>n.x;\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"fn = obj => { return obj.x }\" result := api.Transform(js, api.TransformOptions{ , , , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } This option does three separate things in removes whitespace, it rewrites your syntax to be more compact, and it renames local variables to be shorter. Usually you want to do all of these things, but these options can also be enabled individually if JS Go echo 'fn = obj => { return obj.x }' | esbuild --minify-whitespace fn=obj=>{return obj.x}; echo 'fn = obj => { return obj.x }' | esbuild --minify-identifiers fn = (n) => { return n.x; }; echo 'fn = obj => { return obj.x }' | esbuild --minify-syntax fn = (obj) => obj.x; import * as esbuild from 'esbuild'var js = 'fn = obj => { return obj.x }' (await esbuild.transform(js, { , })).code 'fn=obj=>{return obj.x};\\n' (await esbuild.transform(js, { , })).code 'fn = (n) => {\\n return n.x;\\n};\\n' (await esbuild.transform(js, { , })).code 'fn = (obj) => obj.x;\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { css := \"div { }\" result1 := api.Transform(css, api.TransformOptions{ , , }) if len(result1.Errors) == 0 { fmt.Printf(\"%s\", result1.Code) } result2 := api.Transform(css, api.TransformOptions{ , , }) if len(result2.Errors) == 0 { fmt.Printf(\"%s\", result2.Code) } result3 := api.Transform(css, api.TransformOptions{ , , }) if len(result3.Errors) == 0 { fmt.Printf(\"%s\", result3.Code) } } These same concepts also apply to CSS, not just to JS Go echo 'div { }' | esbuild --loader=css --minify div{color:#ff0} import * as esbuild from 'esbuild'var css = 'div { }' (await esbuild.transform(css, { loader: 'css', , })).code 'div{color:#ff0}\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { css := \"div { }\" result := api.Transform(css, api.TransformOptions{ , , , , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } The JavaScript minification algorithm in esbuild usually generates output that is very close to the minified output size of industry-standard JavaScript minification tools. This benchmark has an example comparison of output sizes between different minifiers. While esbuild is not the optimal JavaScript minifier in all cases (and doesn't try to be), it strives to generate minified output within a few percent of the size of dedicated minification tools for most code, and of course to do so much faster than other tools.#ConsiderationsHere are some things to keep in mind when using esbuild as a should probably also set the target option when minification is enabled. By default esbuild takes advantage of modern JavaScript features to make your code smaller. For example, a === undefined || a === null ? could be minified to a ?? 1. If you do not want esbuild to take advantage of modern JavaScript features when minifying, you should use an older language target such as --target=es6. The character escape sequence \\n will be replaced with a newline character in JavaScript template literals. String literals will also be converted into template literals if the target supports them and if doing so would result in smaller output. This is not a bug. Minification means you are asking for smaller output, and the escape sequence \\n takes two bytes while the newline character takes one byte. You can read more about this in the FAQ entry on this topic. By default esbuild won't minify the names of top-level declarations. This is because esbuild doesn't know what you will be doing with the output. You might be injecting the minified code into the middle of some other code, in which case minifying top-level declaration names would be unsafe. Setting an output format (or enabling bundling, which picks an output format for you if you haven't set one) tells esbuild that the output will be run within its own scope, which means it's then safe to minify top-level declaration names. Minification is not safe for 100% of all JavaScript code. This is true for esbuild as well as for other popular JavaScript minifiers such as terser. In particular, esbuild is not designed to preserve the value of calling )).code '/* @__PURE__ */ document.createElement(elemName());\\n' (await esbuild.transform(js, { pure: ['document.createElement'], , })).code 'elemName();\\n' package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"document.createElement(elemName())\" result1 := api.Transform(js, api.TransformOptions{ Pure: []string{\"document.createElement\"}, }) if len(result1.Errors) == 0 { fmt.Printf(\"%s\", result1.Code) } result2 := api.Transform(js, api.TransformOptions{ Pure: []string{\"document.createElement\"}, , }) if len(result2.Errors) == 0 { fmt.Printf(\"%s\", result2.Code) } } Note that if you are trying to remove all calls to console API methods such as console.log and also want to remove the evaluation of arguments with side effects, there is a special case available for can use the drop feature instead of marking console API calls as pure. However, this mechanism is specific to the console API and doesn't work with other call expressions.#Tree shakingSupported and TransformTree shaking is the term the JavaScript community uses for dead code elimination, a common compiler optimization that automatically removes unreachable code. Within esbuild, this term specifically refers to declaration-level dead code removal.Tree shaking is easiest to explain with an example. Consider the following file. There is one used function and one unused function:// input.js function one() { console.log('one') } function two() { console.log('two') } one()If you bundle this file with esbuild --bundle input.js --outfile=output.js, the unused function will automatically be discarded leaving you with the following output:// input.js function one() { console.log(\"one\"); } one();This even works if we split our functions off into a separate library file and import them using an import statement:// lib.js export function one() { console.log('one') } export function two() { console.log('two') }// input.js import * as lib from './lib.js' lib.one()If you bundle this file with esbuild --bundle input.js --outfile=output.js, the unused function and unused import will still be automatically discarded leaving you with the following output:// lib.js function one() { console.log(\"one\"); } // input.js one();This way esbuild will only bundle the parts of your packages that you actually use, which can sometimes be a substantial size savings. Note that esbuild's tree shaking implementation relies on the use of ECMAScript module import and export statements. It does not work with CommonJS modules. Many packages on npm include both formats and esbuild tries to pick the format that works with tree shaking by default. You can customize which format esbuild picks using the main fields and/or conditions options depending on the package.By default, tree shaking is only enabled either when bundling is enabled or when the output format is set to iife, otherwise tree shaking is disabled. You can force-enable tree shaking by setting it to JS Go esbuild app.js --tree-shaking=true import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } You can also force-disable tree shaking by setting it to JS Go esbuild app.js --tree-shaking=false import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } ; // These are not considered side-effect free // since they could cause some code to run let x = \"ab\" + cd; let y = foo.bar; let z = { [x]: x };Sometimes it's desirable to allow some code to be tree shaken even if that code can't be automatically determined to have no side effects. This can be done with a pure annotation comment which tells esbuild to trust the author of the code that there are no side effects within the annotated code. The annotation comment is /* @__PURE__ */ and can only precede a new or call expression. You can annotate an immediately-invoked function expression and put arbitrary side effects inside the function body:// This is considered side-effect free due to // the annotation, and will be removed if unused let gammaTable = /* @__PURE__ */ (() => { // Side-effect detection is skipped in here let table = new Uint8Array(256); for (let i = 0; i < 256; i++) table[i] = Math.pow(i / 255, 2.2) * 255; return table; })();While the fact that /* @__PURE__ */ only works on call expressions can sometimes make code more verbose, a big benefit of this syntax is that it's portable across many other tools in the JavaScript ecosystem including the popular UglifyJS and Terser JavaScript minifiers (which are used by other major tools including Webpack and Parcel).Note that the annotations cause esbuild to assume that the annotated code is side-effect free. If the annotations are wrong and the code actually does have important side effects, these annotations can result in broken code. If you are bundling third-party code with annotations that have been authored incorrectly, you may need to enable ignoring annotations to make sure the bundled code is correct.#Source maps#Source rootSupported and TransformThis feature is only relevant when source maps are enabled. It lets you set the value of the sourceRoot field in the source map, which specifies the path that all other paths in the source map are relative to. If this field is not present, all paths in the source map are interpreted as being relative to the directory containing the source map instead.You can configure sourceRoot like JS Go esbuild app.js --sourcemap --source-root=https://raw.githubusercontent.com/some/repo/v1.2.3/ import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], , sourceRoot: 'https://raw.githubusercontent.com/some/repo/v1.2.3/', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , SourceRoot: \"https://raw.githubusercontent.com/some/repo/v1.2.3/\", }) if len(result.Errors) > 0 { os.Exit(1) } } ) console.log(result.code) package main import \"fmt\" import \"io/ioutil\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js, err := ioutil.ReadFile(\"app.js\") if err != nil { panic(err) } result := api.Transform(string(js), api.TransformOptions{ Sourcefile: \"example.js\", , }) if len(result.Errors) == 0 { fmt.Printf(\"%s %s\", result.Code) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } external This mode means the source map is generated into a separate ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } inline This mode means the source map is appended to the end of the ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } both This mode is a combination of inline and external. The source map is appended inline to the end of the ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.ts\"}, , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } The build API supports all four source map modes listed above, but the transform API does not support the linked mode. This is because the output returned from the transform API does not have an associated filename. If you want the output of the transform API to have a source map comment, you can append one yourself. In addition, the CLI form of the transform API only supports the inline mode because the output is written to stdout so generating multiple output files is not possible.If you want to \"peek under the hood\" to see what a source map does (or to debug problems with your source map), you can upload the relevant output file and the associated source map Map Visualization.#Using source mapsIn the browser, source maps should be automatically picked up by the browser's developer tools as long as the source map setting is enabled. Note that the browser only uses the source maps to alter the display of stack traces when they are logged to the console. The stack traces themselves are not modified so inspecting error.stack in your code will still give the unmapped stack trace containing compiled code. Here's how to enable this setting in your browser's developer : ⚙ → Enable JavaScript source mapsSafari: ⚙ → Sources → Enable source mapsFirefox: ··· → Enable Source MapsIn node, source maps are supported natively starting with version v12.12.0. This feature is disabled by default but can be enabled with a flag. Unlike in the browser, the actual stack traces are also modified in node so inspecting error.stack in your code will give the mapped stack trace containing your original source code. Here's how to enable this setting in node (the --enable-source-maps flag must come before the script file name):node --enable-source-maps app.js#Sources contentSupported and TransformSource maps are generated using version 3 of the source map format, which is by far the most widely-supported variant. Each source map will look something like this:{ \"version\": 3, \"sources\": [\"bar.js\", \"foo.js\"], \"sourcesContent\": [\"bar()\", \"foo()\\nimport './bar'\"], \"mappings\": \";AAAA;;;ACAA;\", \"names\": [] }The sourcesContent field is an optional field that contains all of the original source code. This is helpful for debugging because it means the original source code will be available in the debugger.However, it's not needed in some scenarios. For example, if you are just using source maps in production to generate stack traces that contain the original file name, you don't need the original source code because there is no debugger involved. In that case it can be desirable to omit the sourcesContent field to make the source map JS Go esbuild --bundle app.js --sourcemap --sources-content=false import * as esbuild from 'esbuild' await esbuild.build({ , entryPoints: ['app.js'], , , outfile: 'out.js', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ , EntryPoints: []string{\"app.js\"}, , , }) if len(result.Errors) > 0 { os.Exit(1) } } ) console.log(await esbuild.analyzeMetafile(result.metafile)) package main import \"github.com/evanw/esbuild/pkg/api\" import \"fmt\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"example.jsx\"}, Outfile: \"out.js\", , , , , }) if len(result.Errors) > 0 { os.Exit(1) } fmt.Printf(\"%s\", api.AnalyzeMetafile(result.Metafile, api.AnalyzeMetafileOptions{})) } The information shows which input files ended up in each output file as well as the percentage of the output file they ended up taking up. If you would like additional information, you can enable the \"verbose\" mode. This currently shows the import path from the entry point to each input file which tells you why a given input file is being included in the JS Go esbuild --bundle example.jsx --outfile=out.js --minify --analyze=verbose out.js ─────────────────────────────────────────────────────────────────── 27.6kb ─ 100.0% ├ node_modules/react-dom/cjs/react-dom-server.browser.production.min.js ─ 19.2kb ── 69.7% │ └ node_modules/react-dom/server.browser.js │ └ example.jsx ├ node_modules/react/cjs/react.production.min.js ───────────────────────── 5.9kb ── 21.4% │ └ node_modules/react/index.js │ └ example.jsx ├ node_modules/object-assign/index.js ──────────────────────────────────── 962b ──── 3.4% │ └ node_modules/react-dom/cjs/react-dom-server.browser.production.min.js │ └ node_modules/react-dom/server.browser.js │ └ example.jsx ├ example.jsx ──────────────────────────────────────────────────────────── 137b ──── 0.5% ├ node_modules/react-dom/server.browser.js ──────────────────────────────── 50b ──── 0.2% │ └ example.jsx └ node_modules/react/index.js ───────────────────────────────────────────── 50b ──── 0.2% └ example.jsx ... import * as esbuild from 'esbuild' let result = await esbuild.build({ entryPoints: ['example.jsx'], outfile: 'out.js', , , }) console.log(await esbuild.analyzeMetafile(result.metafile, { , })) package main import \"github.com/evanw/esbuild/pkg/api\" import \"fmt\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"example.jsx\"}, Outfile: \"out.js\", , , , , }) if len(result.Errors) > 0 { os.Exit(1) } fmt.Printf(\"%s\", api.AnalyzeMetafile(result.Metafile, api.AnalyzeMetafileOptions{ , })) } This analysis is just a visualization of the information that can be found in the metafile. If this analysis doesn't exactly suit your needs, you are welcome to build your own visualization using the information in the metafile.Note that this formatted analysis summary is intended for humans, not machines. The specific formatting may change over time which will likely break any tools that try to parse it. You should not write a tool to parse this data. You should be using the information in the JSON metadata file instead. Everything in this visualization is derived from the JSON metadata so you are not losing out on any information by not parsing esbuild's formatted analysis summary.#MetafileSupported option tells esbuild to produce some metadata about the build in JSON format. The following example puts the metadata in a file called meta.json: CLI JS Go esbuild app.js --bundle --metafile=meta.json --outfile=out.js import * as esbuild from 'esbuild' import fs from 'node:fs' let result = await esbuild.build({ entryPoints: ['app.js'], , , outfile: 'out.js', }) fs.writeFileSync('meta.json', JSON.stringify(result.metafile)) package main import \"io/ioutil\" import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , , Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } ioutil.WriteFile(\"meta.json\", []byte(result.Metafile), 0644) } This data can then be analyzed by other tools. For an interactive visualization, you can use esbuild's own Bundle Size Analyzer. For a quick textual analysis, you can use esbuild's build-in analyze feature. Or you can write your own analysis which uses this information.The metadata JSON format looks like this (described using a TypeScript interface):interface Metafile { inputs: { [path: string]: { imports: { external?: boolean original?: string with?: Record<string, string> }[] format?: string with?: Record<string, string> } } outputs: { [path: string]: { inputs: { [path: string]: { } } imports: { external?: boolean }[] [] entryPoint?: string cssBundle?: string } } }All paths in the metafile are relative by default. If you would like them to be absolute paths instead, you can configure that with the abs paths setting.#Logging#Abs pathsUse this feature to tell esbuild to refer to files by absolute paths instead of relative paths. By default, esbuild uses relative paths instead of absolute paths because they are necessary for build output to be reproducible across different machines and operating systems.Absolute paths can be useful with certain terminal emulators that automatically turn absolute paths in the terminal text into clickable links. They can also be useful when esbuild is being automatically invoked from several different directories by another script and the log messages are all merged together.There are currently three supported situations where absolute paths can be controls paths in comments and string literalslog controls paths in log messagesmetafile controls paths in JSON build metadataHere is an example of configuring absolute paths in log messages and build JS Go esbuild app.js --abs-paths=log,metafile --outfile=out.js --metafile=meta.json import * as esbuild from 'esbuild' let result = await esbuild.build({ entryPoints: ['app.js'], absPaths: ['log', 'metafile'], outfile: 'out.js', , }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, | api.MetafileAbsPath, Outfile: \"out.js\", , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"typeof x == 'null'\" result := api.Transform(js, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } Colored output can also be set to false to disable colors.In addition, esbuild respects the informally-standard NO_COLOR environment variable. So if you want esbuild (and many other CLI programs) to have color output disabled by default without needing to explicitly disable it on the command line, you should export the NO_COLOR=1 environment variable in your shell's configuration file. You can read more about this convention at https://no-color.org/.#Format messagesSupported and TransformThis API call can be used to format the log errors and warnings returned by the build API and transform APIs as a string using the same formatting that esbuild itself uses. This is useful if you want to customize the way esbuild's logging works, such as processing the log messages before they are printed or printing them to somewhere other than to the console. Here's an Go import * as esbuild from 'esbuild' let formatted = await esbuild.formatMessages([ { text: 'This is an error', location: { file: 'app.js', , , , lineText: 'let foo = bar', }, }, ], { kind: 'error', , , }) console.log(formatted.join('\\n')) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" import \"strings\" func main() { formatted := api.FormatMessages([]api.Message{ { Text: \"This is an error\", Location: &api.Location{ File: \"app.js\", , , , LineText: \"let foo = bar\", }, }, }, api.FormatMessagesOptions{ , , , }) fmt.Printf(\"%s\", strings.Join(formatted, \"\\n\")) } type FormatMessagesOptions struct { Kind MessageKind Color bool TerminalWidth int LogStyle LogStyle } kind Controls whether these log messages are printed as errors or warnings.color If this is true, Unix-style terminal escape codes are included for colored output.terminalWidth Provide a positive value to wrap long lines so that they don't overflow past the provided column width. Provide 0 to disable word wrapping.logStyle Can be used to change the style of log message to adapt esbuild's output for different tools. See the log style setting for the available style options.#Log levelSupported and TransformThe log level can be changed to prevent esbuild from printing warning and/or error messages to the terminal. The six log levels not show any log output. This is the default log level when using the JS transform API.errorOnly show errors.warningOnly show warnings and errors. This is the default log level when using the JS build API.infoShow warnings, errors, and an output file summary. This is the default log level when using the CLI.debugLog everything from info and some additional messages that may help you debug a broken bundle. This log level has a performance impact and some of the messages may be false positives, so this information is not shown by default.verboseThis generates a torrent of log messages and was added to debug issues with file system drivers. It's not intended for general use.The log level can be set like JS Go echo 'typeof x == \"null\"' | esbuild --log-level=error import * as esbuild from 'esbuild' let js = 'typeof x == \"null\"' await esbuild.transform(js, { logLevel: 'error', }) package main import \"fmt\" import \"github.com/evanw/esbuild/pkg/api\" func main() { js := \"typeof x == 'null'\" result := api.Transform(js, api.TransformOptions{ , }) if len(result.Errors) == 0 { fmt.Printf(\"%s\", result.Code) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } ) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, [string]api.LogLevel{ \"unsupported-regexp\": api.LogLevelWarning, }, Engines: []api.Engine{ {Name: api.EngineChrome, Version: \"50\"}, }, }) if len(result.Errors) > 0 { os.Exit(1) } } The log level for each message type can be overridden to any value supported by the log level setting. All currently-available message types are listed below (click on each one for an example log message): ▲ [WARNING] The \"assert\" keyword is not supported in the configured target environment [assert-to-with] example.js:1:31: 1 │ import data from \"./data.json\" assert { type: \"json\" } │ ~~~~~~ ╵ with Did you mean to use \"with\" instead of \"assert\"? assert-type-json▲ [WARNING] Non-default import \"value\" is undefined with a JSON import assertion [assert-type-json] example.js:1:78: 1 │ import * as data from \"./data.json\" assert { type: \"json\" }; console.log(data.value) ╵ ~~~~~ The JSON import assertion is :1:45: 1 │ import * as data from \"./data.json\" assert { type: \"json\" }; console.log(data.value) ╵ ~~~~~~~~~~~~ You can either keep the import assertion and only use the \"default\" import, or you can remove the import assertion and use the \"value\" import. assign-to-constant▲ [WARNING] This assignment will throw because \"foo\" is a constant [assign-to-constant] example.js:1:15: 1 │ const foo = 1; foo = 2 ╵ ~~~ The symbol \"foo\" was declared a constant :1:6: 1 │ const foo = 1; foo = 2 ╵ ~~~ assign-to-define▲ [WARNING] Suspicious assignment to defined constant \"DEFINE\" [assign-to-define] example.js:1:0: 1 │ DEFINE = false ╵ ~~~~~~ The expression \"DEFINE\" has been configured to be replaced with a constant using the \"define\" feature. If this expression is supposed to be a compile-time constant, then it doesn't make sense to assign to it here. Or if this expression is supposed to change at run-time, this \"define\" substitution should be removed. assign-to-import▲ [WARNING] This assignment will throw because \"foo\" is an import [assign-to-import] example.js:1:23: 1 │ import foo from \"foo\"; foo = null ╵ ~~~ Imports are immutable in JavaScript. To modify the value of this import, you must export a setter function in the imported file (e.g. \"setFoo\") and then import and call that function here instead. call-import-namespace▲ [WARNING] Calling \"foo\" will crash at run-time because it's an import namespace object, not a function [call-import-namespace] example.js:1:28: 1 │ import * as foo from \"foo\"; foo() ╵ ~~~ Consider changing \"foo\" to a default import :1:7: 1 │ import * as foo from \"foo\"; foo() │ ~~~~~~~~ ╵ foo class-name-will-throw▲ [WARNING] Accessing class \"Foo\" before initialization will throw [class-name-will-throw] example.js:1:40: 1 │ class Foo { static key = \"foo\"; static [Foo.key] = 123 } ╵ ~~~ commonjs-variable-in-esm▲ [WARNING] The CommonJS \"exports\" variable is treated as a global variable in an ECMAScript module and may not work as expected [commonjs-variable-in-esm] example.js:1:0: 1 │ exports.foo = 1; export let bar = 2 ╵ ~~~~~~~ This file is considered to be an ECMAScript module because of the \"export\" keyword :1:17: 1 │ exports.foo = 1; export let bar = 2 ╵ ~~~~~~ confusing-typescript-cast▲ [WARNING] Operator \"*\" should not directly follow a TypeScript type cast after the \"+\" operator [confusing-typescript-cast] example.ts:1:16: 1 │ 1 + 2 as number * 3 ╵ ^ This is a syntax error in newer versions of TypeScript because the type cast has unintuitive precedence in this case. Surround the inner expression in parentheses to silence this :1:0: 1 │ 1 + 2 as number * 3 │ ~~~~~~~~~~~~~~~ ╵ ( ) delete-super-property▲ [WARNING] Attempting to delete a property of \"super\" will throw a ReferenceError [delete-super-property] example.js:1:42: 1 │ class Foo extends Object { foo() { delete super.foo } } ╵ ~~~~~ direct-eval▲ [WARNING] Using direct eval with a bundler is not recommended and may cause problems [direct-eval] example.js:1:22: 1 │ let apparentlyUnused; eval(\"actuallyUse(apparentlyUnused)\") ╵ ~~~~ You can read more about direct eval and bundling ://esbuild.github.io/link/direct-eval duplicate-case▲ [WARNING] This case clause will never be evaluated because it duplicates an earlier case clause [duplicate-case] example.js:1:33: 1 │ switch (foo) { case 1; case 2 } ╵ ~~~~ The earlier case clause is :1:15: 1 │ switch (foo) { case 1; case 2 } ╵ ~~~~ duplicate-class-member▲ [WARNING] Duplicate member \"x\" in class body [duplicate-class-member] example.js:1:19: 1 │ class Foo { x = 1; x = 2 } ╵ ^ The original member \"x\" is :1:12: 1 │ class Foo { x = 1; x = 2 } ╵ ^ duplicate-object-key▲ [WARNING] Duplicate key \"bar\" in object literal [duplicate-object-key] example.js:1:16: 1 │ foo = { , } ╵ ~~~ The original key \"bar\" is :1:8: 1 │ foo = { , } ╵ ~~~ empty-import-meta▲ [WARNING] \"import.meta\" is not available in the configured target environment (\"chrome50\") and will be empty [empty-import-meta] example.js:1:6: 1 │ foo = import.meta ╵ ~~~~~~~~~~~ equals-nan▲ [WARNING] Comparison with NaN using the \"!==\" operator here is always true [equals-nan] example.js:1:24: 1 │ foo = foo.filter(x => x !== NaN) ╵ ~~~ Floating-point equality is defined such that NaN is never equal to anything, so \"x === NaN\" always returns false. You need to use \"Number.isNaN(x)\" instead to test for NaN. equals-negative-zero▲ [WARNING] Comparison with -0 using the \"!==\" operator will also match 0 [equals-negative-zero] example.js:1:28: 1 │ foo = foo.filter(x => x !== -0) ╵ ~~ Floating-point equality is defined such that 0 and -0 are equal, so \"x === -0\" returns true for both 0 and -0. You need to use \"Object.is(x, -0)\" instead to test for -0. equals-new-object▲ [WARNING] Comparison using the \"!==\" operator here is always true [equals-new-object] example.js:1:24: 1 │ foo = foo.filter(x => x !== []) ╵ ~~~ Equality with a new object is always false in JavaScript because the equality operator tests object identity. You need to write code to compare the contents of the object instead. For example, use \"Array.isArray(x) && x.length === 0\" instead of \"x === []\" to test for an empty array. html-comment-in-js▲ [WARNING] Treating \"<!--\" as the start of a legacy HTML single-line comment [html-comment-in-js] example.js:1:0: 1 │ <!-- comment --> ╵ ~~~~ impossible-typeof▲ [WARNING] The \"typeof\" operator will never evaluate to \"null\" [impossible-typeof] example.js:1:32: 1 │ foo = foo.map(x => typeof x !== \"null\") ╵ ~~~~~~ The expression \"typeof x\" actually evaluates to \"object\" in JavaScript, not \"null\". You need to use \"x === null\" to test for null. indirect-require▲ [WARNING] Indirect calls to \"require\" will not be bundled [indirect-require] example.js:1:8: 1 │ let r = require, fs = r(\"fs\") ╵ ~~~~~~~ private-name-will-throw▲ [WARNING] Writing to getter-only property \"#foo\" will throw [private-name-will-throw] example.js:1:39: 1 │ class Foo { get bar() { this.#foo++ } } ╵ ~~~~ semicolon-after-return▲ [WARNING] The following expression is not returned because of an automatically-inserted semicolon [semicolon-after-return] example.js:1:6: 1 │ return ╵ ^ suspicious-boolean-not▲ [WARNING] Suspicious use of the \"!\" operator inside the \"in\" operator [suspicious-boolean-not] example.js:1:4: 1 │ if (!foo in bar) { │ ~~~~ ╵ (!foo) The code \"!x in y\" is parsed as \"(!x) in y\". You need to insert parentheses to get \"!(x in y)\" instead. suspicious-define▲ [WARNING] \"process.env.NODE_ENV\" is defined as an identifier instead of a string (surround \"production\" with quotes to get a string) [suspicious-define] <js>:1:34: 1 │ define: { 'process.env.NODE_ENV': 'production' } │ ~~~~~~~~~~~~ ╵ '\"production\"' suspicious-logical-operator▲ [WARNING] The \"&&\" operator here will always return the left operand [suspicious-logical-operator] example.js:1:25: 1 │ const isInRange = x => 0 && x <= 1 ╵ ~~ The \"=>\" symbol creates an arrow function expression in JavaScript. Did you mean to use the greater-than-or-equal-to operator \">=\" here instead? example.js:1:20: 1 │ const isInRange = x => 0 && x <= 1 │ ~~ ╵ >= suspicious-nullish-coalescing▲ [WARNING] The \"??\" operator here will always return the left operand [suspicious-nullish-coalescing] example.js:1:26: 1 │ return name === user.name ?? \"\" ╵ ~~ The left operand of the \"??\" operator here will never be null or undefined, so it will always be returned. This usually indicates a bug in your :1:7: 1 │ return name === user.name ?? \"\" ╵ ~~~~~~~~~~~~~~~~~~ this-is-undefined-in-esm▲ [WARNING] Top-level \"this\" will be replaced with undefined since this file is an ECMAScript module [this-is-undefined-in-esm] example.js:1:0: 1 │ this.foo = 1; export let bar = 2 │ ~~~~ ╵ undefined This file is considered to be an ECMAScript module because of the \"export\" keyword :1:14: 1 │ this.foo = 1; export let bar = 2 ╵ ~~~~~~ unsupported-dynamic-import▲ [WARNING] This \"import\" expression will not be bundled because the argument is not a string literal [unsupported-dynamic-import] example.js:1:0: 1 │ import(foo) ╵ ~~~~~~ unsupported-jsx-comment▲ [WARNING] Invalid JSX [unsupported-jsx-comment] example.jsx:1:8: 1 │ // @jsx 123 ╵ ~~~ unsupported-regexp▲ [WARNING] The regular expression flag \"d\" is not available in the configured target environment (\"chrome50\") [unsupported-regexp] example.js:1:3: 1 │ /./d ╵ ^ This regular expression literal has been converted to a \"new RegExp()\" constructor to avoid generating code with a syntax error. However, you will need to include a polyfill for \"RegExp\" for your code to have the correct behavior at run-time. unsupported-require-call▲ [WARNING] This call to \"require\" will not be bundled because the argument is not a string literal [unsupported-require-call] example.js:1:0: 1 │ require(foo) ╵ ~~~~~~~ ▲ [WARNING] Expected identifier but found \"]\" [css-syntax-error] example.css:1:4: 1 │ div[] { ╵ ^ invalid-@charset▲ [WARNING] \"@charset\" must be the first rule in the file [invalid-@charset] example.css:1:19: 1 │ div { } @charset \"UTF-8\"; ╵ ~~~~~~~~ This rule cannot come before a \"@charset\" rule example.css:1:0: 1 │ div { } @charset \"UTF-8\"; ╵ ^ invalid-@import▲ [WARNING] All \"@import\" rules must come first [invalid-@import] example.css:1:19: 1 │ div { } @import \"foo.css\"; ╵ ~~~~~~~ This rule cannot come before an \"@import\" rule example.css:1:0: 1 │ div { } @import \"foo.css\"; ╵ ^ invalid-@layer▲ [WARNING] \"initial\" cannot be used as a layer name [invalid-@layer] example.css:1:7: 1 │ @layer initial { ╵ ~~~~~~~ invalid-calc▲ [WARNING] \"-\" can only be used as an infix operator, not a prefix operator [invalid-calc] example.css:1:20: 1 │ div { (-(1+2)); } ╵ ^ ▲ [WARNING] The \"+\" operator only works if there is whitespace on both sides [invalid-calc] example.css:1:23: 1 │ div { (-(1+2)); } ╵ ^ js-comment-in-css▲ [WARNING] Comments in CSS use \"/* ... */\" instead of \"//\" [js-comment-in-css] example.css:1:0: 1 │ // comment ╵ ~~ undefined-composes-from▲ [WARNING] The value of \"zoom\" in the \"foo\" class is undefined [undefined-composes-from] example.module.css:1:1: 1 │ ╵ ~~~ The first definition of \"zoom\" is :1:7: 1 │ ╵ ~~~~ The second definition of \"zoom\" is :1:44: 1 │ ╵ ~~~~ The specification of \"composes\" does not define an order when class declarations from separate files are composed together. The value of the \"zoom\" property for \"foo\" may change unpredictably as the code is edited. Make sure that all definitions of \"zoom\" for \"foo\" are in a single file. unsupported-@charset▲ [WARNING] \"UTF-8\" will be used instead of unsupported charset \"ASCII\" [unsupported-@charset] example.css:1:9: 1 │ @charset \"ASCII\"; ╵ ~~~~~~~ unsupported-@namespace▲ [WARNING] \"@namespace\" rules are not supported [unsupported-@namespace] example.css:1:0: 1 │ @namespace \"ns\"; ╵ ~~~~~~~~~~ unsupported-css-property▲ [WARNING] \"widht\" is not a known CSS property [unsupported-css-property] example.css:1:6: 1 │ div { } │ ~~~~~ ╵ width Did you mean \"width\" instead? unsupported-css-nesting▲ [WARNING] Transforming this CSS nesting syntax is not supported in the configured target environment (\"chrome50\") [unsupported-css-nesting] example.css:2:5: 2 │ .foo & { ╵ ^ The nesting transform for this case must generate an \":is(...)\" but the configured target environment does not support the \":is\" pseudo-class. ▲ [WARNING] Re-export of \"foo\" in \"example.js\" is ambiguous and has been removed [ambiguous-reexport] One definition of \"foo\" comes from \"a.js\" :1:11: 1 │ export let foo = 1 ╵ ~~~ Another definition of \"foo\" comes from \"b.js\" :1:11: 1 │ export let foo = 2 ╵ ~~~ different-path-case▲ [WARNING] Use \"foo.js\" instead of \"Foo.js\" to avoid issues with case-sensitive file systems [different-path-case] example.js:2:7: 2 │ import \"./Foo.js\" ╵ ~~~~~~~~~~ empty-glob▲ [WARNING] The glob pattern import(\"./icon-*.json\") did not match any files [empty-glob] example.js:2:16: 2 │ return import(\"./icon-\" + name + \".json\") ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~ ignored-bare-import▲ [WARNING] Ignoring this import because \"node_modules/foo/index.js\" was marked as having no side effects [ignored-bare-import] example.js:1:7: 1 │ import \"foo\" ╵ ~~~~~ \"sideEffects\" is false in the enclosing \"package.json\" /foo/package.json:2:2: 2 │ \"sideEffects\": false ╵ ~~~~~~~~~~~~~ ignored-dynamic-import▲ [WARNING] Importing \"foo\" was allowed even though it could not be resolved because dynamic import failures appear to be handled here: [ignored-dynamic-import] example.js:1:7: 1 │ import(\"foo\").catch(e => { ╵ ~~~~~ The handler for dynamic import failures is :1:14: 1 │ import(\"foo\").catch(e => { ╵ ~~~~~ import-is-undefined▲ [WARNING] Import \"foo\" will always be undefined because the file \"foo.js\" has no exports [import-is-undefined] example.js:1:9: 1 │ import { foo } from \"./foo\" ╵ ~~~ require-resolve-not-external▲ [WARNING] \"foo\" should be marked as external for use with \"require.resolve\" [require-resolve-not-external] example.js:1:26: 1 │ let foo = require.resolve(\"foo\") ╵ ~~~~~ Source ▲ [WARNING] Bad \"mappings\" data in source map at character original column [invalid-source-mappings] example.js.map:2:18: 2 │ \"mappings\": \"aAAFA,UAAU;;\" ╵ ^ The source map \"example.js.map\" was referenced by the file \"example.js\" :1:21: 1 │ //# sourceMappingURL=example.js.map ╵ ~~~~~~~~~~~~~~ missing-source-map▲ [WARNING] Cannot read file \".\": is a directory [missing-source-map] example.js:1:21: 1 │ //# sourceMappingURL=. ╵ ^ unsupported-source-map-comment▲ [WARNING] Unsupported source map not decode percent-escaped URL escape \"%\\\"\" [unsupported-source-map-comment] example.js:1:21: 1 │ //# sourceMappingURL=data:application/json,\"%\" ╵ ~~~~~~~~~~~~~~~~~~~~~~~~~ ▲ [WARNING] \"esm\" is not a valid value for the \"type\" field [package.json] package.json:1:10: 1 │ { \"type\": \"esm\" } ╵ ~~~~~ The \"type\" field must be set to either \"commonjs\" or \"module\". tsconfig.json▲ [WARNING] Unrecognized target environment \"ES4\" [tsconfig.json] tsconfig.json:1:33: 1 │ { \"compilerOptions\": { \"target\": \"ES4\" } } ╵ ~~~~~ These message types should be reasonably stable but new ones may be added and old ones may occasionally be removed in the future. If a message type is removed, any overrides for that message type will just be silently ignored.#Log styleSupported and TransformThis can be used to adapt esbuild's log output to different tools that expect a certain style of log messages. Here is an example of configuring the log JS Go esbuild app.js --log-style=visualstudio import * as esbuild from 'esbuild' await esbuild.build({ entryPoints: ['app.js'], logStyle: 'visualstudio', }) package main import \"github.com/evanw/esbuild/pkg/api\" import \"os\" func main() { result := api.Build(api.BuildOptions{ EntryPoints: []string{\"app.js\"}, , }) if len(result.Errors) > 0 { os.Exit(1) } } Available log This is esbuild's default log style, and normally doesn't need to be configured explicitly.visualstudio This allows esbuild to integrate with Visual Studio's built-in problem matcher for custom build rules. Without this, the IDE will fail to understand esbuild's log output and won't show errors and/or warnigns from esbuild in the IDE.\n\nExample:\n```text\nesbuild app.ts --bundle --outdir=dist\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'dist',\n})\nconsole.log(result)\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Bundle:      true,\n    Outdir:      \"dist\",\n  })\n  if len(result.Errors) != 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --bundle --outdir=dist --watch\n[watch] build finished, watching for changes...\n```\n\nExample:\n```javascript\nlet ctx = await esbuild.context({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'dist',\n})\n\nawait ctx.watch()\n```\n\nExample:\n```text\nctx, err := api.Context(api.BuildOptions{\n  EntryPoints: []string{\"app.ts\"},\n  Bundle:      true,\n  Outdir:      \"dist\",\n})\n\nerr2 := ctx.Watch(api.WatchOptions{})\n```\n\nExample:\n```text\nesbuild app.ts --bundle --outdir=dist --serve\n\n > Local:   http://127.0.0.1:8000/\n > Network: http://192.168.0.1:8000/\n\n127.0.0.1:61302 - \"GET /\" 200 [1ms]\n```\n\nExample:\n```javascript\nlet ctx = await esbuild.context({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'dist',\n})\n\nlet { hosts, port } = await ctx.serve()\n```\n\nExample:\n```text\nctx, err := api.Context(api.BuildOptions{\n  EntryPoints: []string{\"app.ts\"},\n  Bundle:      true,\n  Outdir:      \"dist\",\n})\n\nserver, err2 := ctx.Serve(api.ServeOptions{})\n```\n\nExample:\n```text\n# The CLI does not have an API for \"rebuild\"\n```\n\nExample:\n```javascript\nlet ctx = await esbuild.context({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'dist',\n})\n\nfor (let i = 0; i < 5; i++) {\n  let result = await ctx.rebuild()\n}\n```\n\nExample:\n```text\nctx, err := api.Context(api.BuildOptions{\n  EntryPoints: []string{\"app.ts\"},\n  Bundle:      true,\n  Outdir:      \"dist\",\n})\n\nfor i := 0; i < 5; i++ {\n  result := ctx.Rebuild()\n}\n```\n\nExample:\n```text\necho 'let x: number = 1' | esbuild --loader=ts\nlet x = 1;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ts = 'let x: number = 1'\nlet result = await esbuild.transform(ts, {\n  loader: 'ts',\n})\nconsole.log(result)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  ts := \"let x: number = 1\"\n  result := api.Transform(ts, api.TransformOptions{\n    Loader: api.LoaderTS,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nimport * as esbuild from 'esbuild'\n\nlet result1 = await esbuild.transform(code, options)\nlet result2 = await esbuild.build(options)\n```\n\nExample:\n```text\nlet esbuild = require('esbuild')\n\nlet result1 = esbuild.transformSync(code, options)\nlet result2 = esbuild.buildSync(options)\n```\n\nExample:\n```text\nnpm install esbuild-wasm\n```\n\nExample:\n```text\nimport * as esbuild from 'esbuild-wasm'\n\nawait esbuild.initialize({\n  wasmURL: './node_modules/esbuild-wasm/esbuild.wasm',\n})\n\nlet result1 = await esbuild.transform(code, options)\nlet result2 = esbuild.build(options)\n```\n\nExample:\n```text\n<script src=\"./node_modules/esbuild-wasm/lib/browser.min.js\"></script>\n<script>\n  esbuild.initialize({\n    wasmURL: './node_modules/esbuild-wasm/esbuild.wasm',\n  }).then(() => {\n    ...\n  })\n</script>\n```\n\nExample:\n```text\n<script type=\"module\">\n  import * as esbuild from './node_modules/esbuild-wasm/esm/browser.min.js'\n\n  await esbuild.initialize({\n    wasmURL: './node_modules/esbuild-wasm/esbuild.wasm',\n  })\n\n  ...\n</script>\n```\n\nExample:\n```text\nesbuild in.js --bundle\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nconsole.log(await esbuild.build({\n  entryPoints: ['in.js'],\n  bundle: true,\n  outfile: 'out.js',\n}))\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"in.js\"},\n    Bundle:      true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n// Analyzable imports (will be bundled by esbuild)\nimport 'pkg';\nimport('pkg');\nrequire('pkg');\nimport(`./locale-${foo}.json`);\nrequire(`./locale-${foo}.json`);\n\n// Non-analyzable imports (will not be bundled by esbuild)\nimport(`pkg/${foo}`);\nrequire(`pkg/${foo}`);\n['pkg'].map(require);\n```\n\nExample:\n```text\n// These two forms are equivalent\nconst json1 = require('./data/' + kind + '.json')\nconst json2 = require(`./data/${kind}.json`)\n```\n\nExample:\n```text\n// data/bar.json\nvar require_bar = ...;\n\n// data/foo.json\nvar require_foo = ...;\n\n// require(\"./data/**/*.json\") in example.js\nvar globRequire_data_json = __glob({\n  \"./data/bar.json\": () => require_bar(),\n  \"./data/foo.json\": () => require_foo()\n});\n\n// example.js\nvar json1 = globRequire_data_json(\"./data/\" + kind + \".json\");\nvar json2 = globRequire_data_json(`./data/${kind}.json`);\n```\n\nExample:\n```text\n// This will be bundled\nconst json1 = require('./data/' + kind + '.json')\n\n// This will not be bundled\nconst path = './data/' + kind + '.json'\nconst json2 = require(path)\n```\n\nExample:\n```text\n# The CLI does not have an API for \"cancel\"\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport process from 'node:process'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'www',\n  logLevel: 'info',\n})\n\n// Whenever we get some data over stdin\nprocess.stdin.on('data', async () => {\n  try {\n    // Cancel the already-running build\n    await ctx.cancel()\n\n    // Then start a new build\n    console.log('build:', await ctx.rebuild())\n  } catch (err) {\n    console.error(err)\n  }\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Bundle:      true,\n    Outdir:      \"www\",\n    LogLevel:    api.LogLevelInfo,\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  // Whenever we get some data over stdin\n  buf := make([]byte, 100)\n  for {\n    if n, err := os.Stdin.Read(buf); err != nil || n == 0 {\n      break\n    }\n    go func() {\n      // Cancel the already-running build\n      ctx.Cancel()\n\n      // Then start a new build\n      result := ctx.Rebuild()\n      fmt.Fprintf(os.Stderr, \"build: %v\\n\", result)\n    }()\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --bundle --outdir=www --watch --servedir=www\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  outdir: 'www',\n})\n\nawait ctx.watch()\n\nlet { hosts, port } = await ctx.serve({\n  servedir: 'www',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Bundle:      true,\n    Outdir:      \"www\",\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  err2 := ctx.Watch(api.WatchOptions{})\n  if err2 != nil {\n    os.Exit(1)\n  }\n\n  result, err3 := ctx.Serve(api.ServeOptions{\n    Servedir: \"www\",\n  })\n  if err3 != nil {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nnew EventSource('/esbuild').addEventListener('change', () => location.reload())\n```\n\nExample:\n```text\ninterface ChangeEvent {\n  added: string[]\n  removed: string[]\n  updated: string[]\n}\n```\n\nExample:\n```text\nnew EventSource('/esbuild').addEventListener('change', e => {\n  const { added, removed, updated } = JSON.parse(e.data)\n\n  if (!added.length && !removed.length && updated.length === 1) {\n    for (const link of document.getElementsByTagName(\"link\")) {\n      const url = new URL(link.href)\n\n      if (url.host === location.host && url.pathname === updated[0]) {\n        const next = link.cloneNode()\n        next.href = updated[0] + '?' + Math.random().toString(36).slice(2)\n        next.onload = () => link.remove()\n        link.parentNode.insertBefore(next, link.nextSibling)\n        return\n      }\n    }\n  }\n\n  location.reload()\n})\n```\n\nExample:\n```text\nesbuild app.js --bundle --platform=node\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  platform: 'node',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Platform:    api.PlatformNode,\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n})\n\n// Call \"rebuild\" as many times as you want\nfor (let i = 0; i < 5; i++) {\n  let result = await ctx.rebuild()\n}\n\n// Call \"dispose\" when you're done to free up resources\nctx.dispose()\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  // Call \"Rebuild\" as many times as you want\n  for i := 0; i < 5; i++ {\n    result := ctx.Rebuild()\n    if len(result.Errors) > 0 {\n      os.Exit(1)\n    }\n  }\n\n  // Call \"Dispose\" when you're done to free up resources\n  ctx.Dispose()\n}\n```\n\nExample:\n```text\nesbuild src/app.ts --outdir=www/js --bundle --servedir=www\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['src/app.ts'],\n  outdir: 'www/js',\n  bundle: true,\n})\n\nlet { hosts, port } = await ctx.serve({\n  servedir: 'www',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"src/app.ts\"},\n    Outdir:     \"www/js\",\n    Bundle:      true,\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  server, err2 := ctx.Serve(api.ServeOptions{\n    Servedir: \"www\",\n  })\n  if err2 != nil {\n    os.Exit(1)\n  }\n\n  // Returning from main() exits immediately in Go.\n  // Block forever so we keep serving and don't exit.\n  <-make(chan struct{})\n}\n```\n\nExample:\n```text\n<script src=\"js/app.js\"></script>\n```\n\nExample:\n```text\n# Enable serve mode\n--serve\n\n# Set the port\n--serve=9000\n\n# Set the host and port (IPv4)\n--serve=127.0.0.1:9000\n\n# Set the host and port (IPv6)\n--serve=[::1]:9000\n\n# Set the directory to serve\n--servedir=www\n\n# Enable HTTPS\n--keyfile=your.key --certfile=your.cert\n\n# Specify a fallback HTML file\n--serve-fallback=some-file.html\n```\n\nExample:\n```javascript\ninterface ServeOptions {\n  port?: number\n  host?: string\n  servedir?: string\n  keyfile?: string\n  certfile?: string\n  fallback?: string\n  cors?: CORSOptions\n  onRequest?: (args: ServeOnRequestArgs) => void\n}\n\ninterface CORSOptions {\n  origin?: string | string[]\n}\n\ninterface ServeOnRequestArgs {\n  remoteAddress: string\n  method: string\n  path: string\n  status: number\n  timeInMS: number\n}\n```\n\nExample:\n```text\ntype ServeOptions struct {\n  Port      uint16\n  Host      string\n  Servedir  string\n  Keyfile   string\n  Certfile  string\n  Fallback  string\n  CORS      CORSOptions\n  OnRequest func(ServeOnRequestArgs)\n}\n\ntype CORSOptions struct {\n  Origin []string\n}\n\ntype ServeOnRequestArgs struct {\n  RemoteAddress string\n  Method        string\n  Path          string\n  Status        int\n  TimeInMS      int\n}\n```\n\nExample:\n```text\n# The CLI will print the hosts and port like this:\n\n > Local:   http://127.0.0.1:8000/\n > Network: http://192.168.0.1:8000/\n```\n\nExample:\n```javascript\ninterface ServeResult {\n  hosts: string[]\n  port: number\n}\n```\n\nExample:\n```text\ntype ServeResult struct {\n  Hosts []string\n  Port  uint16\n}\n```\n\nExample:\n```text\nopenssl req -x509 -newkey rsa:4096 -keyout your.key -out your.cert -days 9999 -nodes -subj /CN=127.0.0.1\n```\n\nExample:\n```text\nimport * as esbuild from 'esbuild'\nimport http from 'node:http'\n\n// Start esbuild's server on a random local port\nlet ctx = await esbuild.context({\n  // ... your build options go here ...\n})\n\n// The return value tells us where esbuild's local server is\nlet { hosts, port } = await ctx.serve({ servedir: '.' })\n\n// Then start a proxy server on port 3000\nhttp.createServer((req, res) => {\n  const options = {\n    hostname: hosts[0],\n    port: port,\n    path: req.url,\n    method: req.method,\n    headers: req.headers,\n  }\n\n  // Forward each incoming request to esbuild\n  const proxyReq = http.request(options, proxyRes => {\n    // If esbuild returns \"not found\", send a custom 404 page\n    if (proxyRes.statusCode === 404) {\n      res.writeHead(404, { 'Content-Type': 'text/html' })\n      res.end('<h1>A custom 404 page</h1>')\n      return\n    }\n\n    // Otherwise, forward the response from esbuild to the client\n    res.writeHead(proxyRes.statusCode, proxyRes.headers)\n    proxyRes.pipe(res, { end: true })\n  })\n\n  // Forward the body of the request to esbuild\n  req.pipe(proxyReq, { end: true })\n}).listen(3000)\n```\n\nExample:\n```text\nesbuild --servedir=. --cors-origin=https://example.com\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({})\n\nawait ctx.serve({\n  servedir: '.',\n  cors: {\n    origin: 'https://example.com',\n  },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{})\n  if err != nil {\n    os.Exit(1)\n  }\n\n  result, err2 := ctx.Serve(api.ServeOptions{\n    Servedir: \".\",\n    CORS: api.CORSOptions{\n      Origin: []string{\"https://example.com\"},\n    },\n  })\n  if err2 != nil {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild --servedir=. \"--cors-origin=https://example.com,https://*.example.com\"\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({})\n\nawait ctx.serve({\n  servedir: '.',\n  cors: {\n    origin: [\n      'https://example.com',\n      'https://*.example.com',\n    ],\n  },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{})\n  if err != nil {\n    os.Exit(1)\n  }\n\n  result, err2 := ctx.Serve(api.ServeOptions{\n    Servedir: \".\",\n    CORS: api.CORSOptions{\n      Origin: []string{\n        \"https://example.com\",\n        \"https://*.example.com\",\n      },\n    },\n  })\n  if err2 != nil {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --bundle --tsconfig=custom-tsconfig.json\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  bundle: true,\n  tsconfig: 'custom-tsconfig.json',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Bundle:      true,\n    Tsconfig:    \"custom-tsconfig.json\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho 'class Foo { foo }' | esbuild --loader=ts --tsconfig-raw='{\"compilerOptions\":{\"useDefineForClassFields\":false}}'\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ts = 'class Foo { foo }'\nlet result = await esbuild.transform(ts, {\n  loader: 'ts',\n  tsconfigRaw: `{\n    \"compilerOptions\": {\n      \"useDefineForClassFields\": false,\n    },\n  }`,\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  ts := \"class Foo { foo }\"\n\n  result := api.Transform(ts, api.TransformOptions{\n    Loader: api.LoaderTS,\n    TsconfigRaw: `{\n      \"compilerOptions\": {\n        \"useDefineForClassFields\": false,\n      },\n    }`,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --outfile=out.js --bundle --watch\n[watch] build finished, watching for changes...\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['app.js'],\n  outfile: 'out.js',\n  bundle: true,\n})\n\nawait ctx.watch()\nconsole.log('watching...')\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Outfile:     \"out.js\",\n    Bundle:      true,\n    Write:       true,\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  err2 := ctx.Watch(api.WatchOptions{})\n  if err2 != nil {\n    os.Exit(1)\n  }\n  fmt.Printf(\"watching...\\n\")\n\n  // Returning from main() exits immediately in Go.\n  // Block forever so we keep watching and don't exit.\n  <-make(chan struct{})\n}\n```\n\nExample:\n```text\n# Use Ctrl+C to stop the CLI in watch mode\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ctx = await esbuild.context({\n  entryPoints: ['app.js'],\n  outfile: 'out.js',\n  bundle: true,\n})\n\nawait ctx.watch()\nconsole.log('watching...')\n\nawait new Promise(r => setTimeout(r, 10 * 1000))\nawait ctx.dispose()\nconsole.log('stopped watching')\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\nimport \"time\"\n\nfunc main() {\n  ctx, err := api.Context(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Outfile:     \"out.js\",\n    Bundle:      true,\n    Write:       true,\n  })\n  if err != nil {\n    os.Exit(1)\n  }\n\n  err2 := ctx.Watch(api.WatchOptions{})\n  if err2 != nil {\n    os.Exit(1)\n  }\n  fmt.Printf(\"watching...\\n\")\n\n  time.Sleep(10 * time.Second)\n  ctx.Dispose()\n  fmt.Printf(\"stopped watching\\n\")\n}\n```\n\nExample:\n```text\n# Wait 500ms before rebuilding after a change\n--watch-delay=500\n```\n\nExample:\n```javascript\ninterface WatchOptions {\n  delay?: number\n}\n```\n\nExample:\n```text\ntype WatchOptions struct {\n  Delay int\n}\n```\n\nExample:\n```text\nesbuild home.ts settings.ts --bundle --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['home.ts', 'settings.ts'],\n  bundle: true,\n  write: true,\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"home.ts\", \"settings.ts\"},\n    Bundle:      true,\n    Write:       true,\n    Outdir:      \"out\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild out1=home.ts out2=settings.ts --bundle --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: [\n    { out: 'out1', in: 'home.ts'},\n    { out: 'out2', in: 'settings.ts'},\n  ],\n  bundle: true,\n  write: true,\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPointsAdvanced: []api.EntryPoint{{\n      OutputPath: \"out1\",\n      InputPath:  \"home.ts\",\n    }, {\n      OutputPath: \"out2\",\n      InputPath:  \"settings.ts\",\n    }},\n    Bundle: true,\n    Write:  true,\n    Outdir: \"out\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nimport url from './example.png'\nlet image = new Image\nimage.src = url\ndocument.body.appendChild(image)\n\nimport svg from './example.svg'\nlet doc = new DOMParser().parseFromString(svg, 'application/xml')\nlet node = document.importNode(doc.documentElement, true)\ndocument.body.appendChild(node)\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.png=dataurl --loader:.svg=text\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: {\n    '.png': 'dataurl',\n    '.svg': 'text',\n  },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderDataURL,\n      \".svg\": api.LoaderText,\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho 'import pkg = require(\"./pkg\")' | esbuild --loader=ts --bundle\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  stdin: {\n    contents: 'import pkg = require(\"./pkg\")',\n    loader: 'ts',\n    resolveDir: '.',\n  },\n  bundle: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    Stdin: &api.StdinOptions{\n      Contents:   \"import pkg = require('./pkg')\",\n      Loader:     api.LoaderTS,\n      ResolveDir: \".\",\n    },\n    Bundle: true,\n  })\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet ts = 'let x: number = 1'\nlet result = await esbuild.transform(ts, {\n  loader: 'ts',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\necho 'export * from \"./another-file\"' | esbuild --bundle --sourcefile=imaginary-file.js --loader=ts --format=cjs\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  stdin: {\n    contents: `export * from \"./another-file\"`,\n\n    // These are all optional:\n    resolveDir: './src',\n    sourcefile: 'imaginary-file.js',\n    loader: 'ts',\n  },\n  format: 'cjs',\n  write: false,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    Stdin: &api.StdinOptions{\n      Contents: \"export * from './another-file'\",\n\n      // These are all optional:\n      ResolveDir: \"./src\",\n      Sourcefile: \"imaginary-file.js\",\n      Loader:     api.LoaderTS,\n    },\n    Format: api.FormatCommonJS,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --banner:js=//comment --banner:css=/*comment*/\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  banner: {\n    js: '//comment',\n    css: '/*comment*/',\n  },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Banner: map[string]string{\n      \"js\":  \"//comment\",\n      \"css\": \"/*comment*/\",\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho '1+2' | esbuild --banner=//comment\n//comment\n1 + 2;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.transform('1+2', {\n  banner: '//comment',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"1+2\", api.TransformOptions{\n    Banner: \"//comment\",\n  })\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'let π = Math.PI' | esbuild\nlet \\u03C0 = Math.PI;\necho 'let π = Math.PI' | esbuild --charset=utf8\nlet π = Math.PI;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nlet js = 'let π = Math.PI'\n(await esbuild.transform(js)).code\n'let \\\\u03C0 = Math.PI;\\n'\n(await esbuild.transform(js, {\n  charset: 'utf8',\n})).code\n'let π = Math.PI;\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"let π = Math.PI\"\n\n  result1 := api.Transform(js, api.TransformOptions{})\n\n  if len(result1.Errors) == 0 {\n    fmt.Printf(\"%s\", result1.Code)\n  }\n\n  result2 := api.Transform(js, api.TransformOptions{\n    Charset: api.CharsetUTF8,\n  })\n\n  if len(result2.Errors) == 0 {\n    fmt.Printf(\"%s\", result2.Code)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --footer:js=//comment --footer:css=/*comment*/\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  footer: {\n    js: '//comment',\n    css: '/*comment*/',\n  },\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Footer: map[string]string{\n      \"js\":  \"//comment\",\n      \"css\": \"/*comment*/\",\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho '1+2' | esbuild --footer=//comment\n1 + 2;\n//comment\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.transform('1+2', {\n  footer: '//comment',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"1+2\", api.TransformOptions{\n    Footer: \"//comment\",\n  })\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'alert(\"test\")' | esbuild --format=iife\n(() => {\n  alert(\"test\");\n})();\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'alert(\"test\")'\nlet result = await esbuild.transform(js, {\n  format: 'iife',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"alert(\\\"test\\\")\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Format: api.FormatIIFE,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'export default \"test\"' | esbuild --format=cjs\n...\nvar stdin_exports = {};\n__export(stdin_exports, {\n  default: () => stdin_default\n});\nmodule.exports = __toCommonJS(stdin_exports);\nvar stdin_default = \"test\";\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'export default \"test\"'\nlet result = await esbuild.transform(js, {\n  format: 'cjs',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"export default 'test'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Format: api.FormatCommonJS,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'module.exports = \"test\"' | esbuild --format=esm\n...\nvar require_stdin = __commonJS({\n  \"<stdin>\"(exports, module) {\n    module.exports = \"test\";\n  }\n});\nexport default require_stdin();\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'module.exports = \"test\"'\nlet result = await esbuild.transform(js, {\n  format: 'esm',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"module.exports = 'test'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Format: api.FormatESModule,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'module.exports = \"test\"' | esbuild --format=iife --global-name=xyz\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'module.exports = \"test\"'\nlet result = await esbuild.transform(js, {\n  format: 'iife',\n  globalName: 'xyz',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"module.exports = 'test'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Format:     api.FormatIIFE,\n    GlobalName: \"xyz\",\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nvar xyz = (() => {\n  ...\n  var require_stdin = __commonJS((exports, module) => {\n    module.exports = \"test\";\n  });\n  return require_stdin();\n})();\n```\n\nExample:\n```text\necho 'module.exports = \"test\"' | esbuild --format=iife --global-name='example.versions[\"1.0\"]'\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'module.exports = \"test\"'\nlet result = await esbuild.transform(js, {\n  format: 'iife',\n  globalName: 'example.versions[\"1.0\"]',\n})\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"module.exports = 'test'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Format:     api.FormatIIFE,\n    GlobalName: `example.versions[\"1.0\"]`,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nvar example = example || {};\nexample.versions = example.versions || {};\nexample.versions[\"1.0\"] = (() => {\n  ...\n  var require_stdin = __commonJS((exports, module) => {\n    module.exports = \"test\";\n  });\n  return require_stdin();\n})();\n```\n\nExample:\n```text\nesbuild app.js --legal-comments=eof\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  legalComments: 'eof',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:   []string{\"app.js\"},\n    LegalComments: api.LegalCommentsEndOfFile,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --line-limit=80\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  lineLimit: 80,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    LineLimit:   80,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild home.ts about.ts --bundle --splitting --outdir=out --format=esm\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['home.ts', 'about.ts'],\n  bundle: true,\n  splitting: true,\n  outdir: 'out',\n  format: 'esm',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"home.ts\", \"about.ts\"},\n    Bundle:      true,\n    Splitting:   true,\n    Outdir:      \"out\",\n    Format:      api.FormatESModule,\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --outdir=. --allow-overwrite\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  outdir: '.',\n  allowOverwrite: true,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:    []string{\"app.js\"},\n    Outdir:         \".\",\n    AllowOverwrite: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --asset-names=assets/[name]-[hash] --loader:.png=file --bundle --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  assetNames: 'assets/[name]-[hash]',\n  loader: { '.png': 'file' },\n  bundle: true,\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    AssetNames:  \"assets/[name]-[hash]\",\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderFile,\n    },\n    Bundle: true,\n    Outdir: \"out\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --chunk-names=chunks/[name]-[hash] --bundle --outdir=out --splitting --format=esm\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  chunkNames: 'chunks/[name]-[hash]',\n  bundle: true,\n  outdir: 'out',\n  splitting: true,\n  format: 'esm',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    ChunkNames:  \"chunks/[name]-[hash]\",\n    Bundle:      true,\n    Outdir:      \"out\",\n    Splitting:   true,\n    Format:      api.FormatESModule,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild src/main-app/app.js --entry-names=[dir]/[name]-[hash] --outbase=src --bundle --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['src/main-app/app.js'],\n  entryNames: '[dir]/[name]-[hash]',\n  outbase: 'src',\n  bundle: true,\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"src/main-app/app.js\"},\n    EntryNames:  \"[dir]/[name]-[hash]\",\n    Outbase:     \"src\",\n    Bundle:      true,\n    Outdir:      \"out\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --outdir=dist --out-extension:.js=.mjs\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outdir: 'dist',\n  outExtension: { '.js': '.mjs' },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outdir:      \"dist\",\n    OutExtension: map[string]string{\n      \".js\": \".mjs\",\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild src/pages/home/index.ts src/pages/about/index.ts --bundle --outdir=out --outbase=src\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: [\n    'src/pages/home/index.ts',\n    'src/pages/about/index.ts',\n  ],\n  bundle: true,\n  outdir: 'out',\n  outbase: 'src',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\n      \"src/pages/home/index.ts\",\n      \"src/pages/about/index.ts\",\n    },\n    Bundle:  true,\n    Outdir:  \"out\",\n    Outbase: \"src\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outdir:      \"out\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --loader:.png=file --public-path=https://www.example.com/v1 --outdir=out\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  loader: { '.png': 'file' },\n  publicPath: 'https://www.example.com/v1',\n  outdir: 'out',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Loader: map[string]api.Loader{\n      \".png\": api.LoaderFile,\n    },\n    Outdir:     \"out\",\n    PublicPath: \"https://www.example.com/v1\",\n    Write:      true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['app.js'],\n  sourcemap: 'external',\n  write: false,\n  outdir: 'out',\n})\n\nfor (let out of result.outputFiles) {\n  console.log(out.path, out.contents, out.hash, out.text)\n}\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Sourcemap:   api.SourceMapExternal,\n    Write:       false,\n    Outdir:      \"out\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n\n  for _, out := range result.OutputFiles {\n    fmt.Printf(\"%v %v %s\\n\", out.Path, out.Contents, out.Hash)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --alias:oldpkg=newpkg\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  write: true,\n  alias: {\n    'oldpkg': 'newpkg',\n  },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Write:       true,\n    Alias: map[string]string{\n      \"oldpkg\": \"newpkg\",\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild src/app.js --bundle --conditions=custom1,custom2\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['src/app.js'],\n  bundle: true,\n  conditions: ['custom1', 'custom2'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"src/app.js\"},\n    Bundle:      true,\n    Conditions:  []string{\"custom1\", \"custom2\"},\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"name\": \"pkg\",\n  \"exports\": {\n    \"./foo\": {\n      \"import\": \"./imported.mjs\",\n      \"require\": \"./required.cjs\",\n      \"default\": \"./fallback.js\"\n    }\n  }\n}\n```\n\nExample:\n```text\nif (importPath === './foo') {\n  if (conditions.has('import')) return './imported.mjs'\n  if (conditions.has('require')) return './required.cjs'\n  return './fallback.js'\n}\n```\n\nExample:\n```text\necho 'require(\"fsevents\")' > app.js\nesbuild app.js --bundle --external:fsevents --platform=node\n// app.js\nrequire(\"fsevents\");\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport fs from 'node:fs'\n\nfs.writeFileSync('app.js', 'require(\"fsevents\")')\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  outfile: 'out.js',\n  bundle: true,\n  platform: 'node',\n  external: ['fsevents'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"io/ioutil\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  ioutil.WriteFile(\"app.js\", []byte(\"require(\\\"fsevents\\\")\"), 0644)\n\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Outfile:     \"out.js\",\n    Bundle:      true,\n    Write:       true,\n    Platform:    api.PlatformNode,\n    External:    []string{\"fsevents\"},\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle \"--external:*.png\" \"--external:/images/*\"\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  outfile: 'out.js',\n  bundle: true,\n  external: ['*.png', '/images/*'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Outfile:     \"out.js\",\n    Bundle:      true,\n    Write:       true,\n    External:    []string{\"*.png\", \"/images/*\"},\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --main-fields=module,main\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  mainFields: ['module', 'main'],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    MainFields:  []string{\"module\", \"main\"},\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"main\": \"./node-cjs.js\",\n  \"module\": \"./node-esm.js\",\n  \"browser\": {\n    \"./node-cjs.js\": \"./browser-cjs.js\",\n    \"./node-esm.js\": \"./browser-esm.js\"\n  }\n}\n```\n\nExample:\n```text\nNODE_PATH=someDir esbuild app.js --bundle --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  nodePaths: ['someDir'],\n  entryPoints: ['app.js'],\n  bundle: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    NodePaths:   []string{\"someDir\"},\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --packages=external\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  packages: 'external',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Packages:    api.PackagesExternal,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --preserve-symlinks --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  preserveSymlinks: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:      []string{\"app.js\"},\n    Bundle:           true,\n    PreserveSymlinks: true,\n    Outfile:          \"out.js\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --resolve-extensions=.ts,.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  resolveExtensions: ['.ts', '.js'],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"app.js\"},\n    Bundle:            true,\n    ResolveExtensions: []string{\".ts\", \".js\"},\n    Write:             true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\ncd \"/var/tmp/custom/working/directory\"\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['file.js'],\n  absWorkingDir: '/var/tmp/custom/working/directory',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:   []string{\"file.js\"},\n    AbsWorkingDir: \"/var/tmp/custom/working/directory\",\n    Outfile:       \"out.js\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho '<div/>' | esbuild --jsx=preserve --loader=jsx\n<div />;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.transform('<div/>', {\n  jsx: 'preserve',\n  loader: 'jsx',\n})\n\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"<div/>\", api.TransformOptions{\n    JSX:    api.JSXPreserve,\n    Loader: api.LoaderJSX,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho '<a/>' | esbuild --loader=jsx --jsx=automatic\nimport { jsx } from \"react/jsx-runtime\";\n/* @__PURE__ */ jsx(\"a\", {});\necho '<a/>' | esbuild --loader=jsx --jsx=automatic --jsx-dev\nimport { jsxDEV } from \"react/jsx-dev-runtime\";\n/* @__PURE__ */ jsxDEV(\"a\", {}, void 0, false, {\n  fileName: \"<stdin>\",\n  lineNumber: 1,\n  columnNumber: 1\n}, this);\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.jsx'],\n  jsxDev: true,\n  jsx: 'automatic',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.jsx\"},\n    JSXDev:      true,\n    JSX:         api.JSXAutomatic,\n    Outfile:     \"out.js\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nReact.createElement(\"div\", null, \"Example text\");\n```\n\nExample:\n```text\necho '<div/>' | esbuild --jsx-factory=h --loader=jsx\n/* @__PURE__ */ h(\"div\", null);\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.transform('<div/>', {\n  jsxFactory: 'h',\n  loader: 'jsx',\n})\n\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"<div/>\", api.TransformOptions{\n    JSXFactory: \"h\",\n    Loader:     api.LoaderJSX,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"compilerOptions\": {\n    \"jsxFactory\": \"h\"\n  }\n}\n```\n\nExample:\n```text\n<>Stuff</>\n```\n\nExample:\n```text\nReact.createElement(React.Fragment, null, \"Stuff\");\n```\n\nExample:\n```text\necho '<>x</>' | esbuild --jsx-fragment=Fragment --loader=jsx\n/* @__PURE__ */ React.createElement(Fragment, null, \"x\");\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.transform('<>x</>', {\n  jsxFragment: 'Fragment',\n  loader: 'jsx',\n})\n\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"<>x</>\", api.TransformOptions{\n    JSXFragment: \"Fragment\",\n    Loader:      api.LoaderJSX,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"compilerOptions\": {\n    \"jsxFragmentFactory\": \"Fragment\"\n  }\n}\n```\n\nExample:\n```text\nimport { createElement } from \"your-pkg\"\nimport { Fragment, jsx, jsxs } from \"your-pkg/jsx-runtime\"\nimport { Fragment, jsxDEV } from \"your-pkg/jsx-dev-runtime\"\n```\n\nExample:\n```text\nreturn <div {...props} key={key} />\n```\n\nExample:\n```text\nesbuild app.jsx --jsx-import-source=preact --jsx=automatic\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.jsx'],\n  jsxImportSource: 'preact',\n  jsx: 'automatic',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:     []string{\"app.jsx\"},\n    JSXImportSource: \"preact\",\n    JSX:             api.JSXAutomatic,\n    Outfile:         \"out.js\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"compilerOptions\": {\n    \"jsx\": \"react-jsx\",\n    \"jsxImportSource\": \"preact\"\n  }\n}\n```\n\nExample:\n```text\nesbuild app.jsx --jsx-side-effects\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.jsx'],\n  outfile: 'out.js',\n  jsxSideEffects: true,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:    []string{\"app.jsx\"},\n    Outfile:        \"out.js\",\n    JSXSideEffects: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --supported:bigint=false\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  supported: {\n    'bigint': false,\n  },\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Supported: map[string]bool{\n      \"bigint\": false,\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --target=es2020,chrome58,edge16,firefox57,node12,safari11\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  target: [\n    'es2020',\n    'chrome58',\n    'edge16',\n    'firefox57',\n    'node12',\n    'safari11',\n  ],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Target:      api.ES2020,\n    Engines: []api.Engine{\n      {Name: api.EngineChrome, Version: \"58\"},\n      {Name: api.EngineEdge, Version: \"16\"},\n      {Name: api.EngineFirefox, Version: \"57\"},\n      {Name: api.EngineNode, Version: \"12\"},\n      {Name: api.EngineSafari, Version: \"11\"},\n    },\n    Write: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\necho 'hooks = DEBUG && require(\"hooks\")' | esbuild --define:DEBUG=true\nhooks = require(\"hooks\");\necho 'hooks = DEBUG && require(\"hooks\")' | esbuild --define:DEBUG=false\nhooks = false;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'let js = 'hooks = DEBUG && require(\"hooks\")'(await esbuild.transform(js, {\n  define: { DEBUG: 'true' },\n})).code\n'hooks = require(\"hooks\");\\n'\n(await esbuild.transform(js, {\n  define: { DEBUG: 'false' },\n})).code\n'hooks = false;\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"hooks = DEBUG && require('hooks')\"\n\n  result1 := api.Transform(js, api.TransformOptions{\n    Define: map[string]string{\"DEBUG\": \"true\"},\n  })\n\n  if len(result1.Errors) == 0 {\n    fmt.Printf(\"%s\", result1.Code)\n  }\n\n  result2 := api.Transform(js, api.TransformOptions{\n    Define: map[string]string{\"DEBUG\": \"false\"},\n  })\n\n  if len(result2.Errors) == 0 {\n    fmt.Printf(\"%s\", result2.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'id, str' | esbuild --define:id=text --define:str=\\\"text\\\"\ntext, \"text\";\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'(await esbuild.transform('id, str', {\n  define: { id: 'text', str: '\"text\"' },\n})).code\n'text, \"text\";\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  result := api.Transform(\"id, text\", api.TransformOptions{\n    Define: map[string]string{\n      \"id\":  \"text\",\n      \"str\": \"\\\"text\\\"\",\n    },\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\n{\n  \"scripts\": {\n    \"build\": \"esbuild --define:process.env.NODE_ENV=\\\\\\\"production\\\\\\\" app.js\"\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --drop:debugger\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  drop: ['debugger'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Drop:        api.DropDebugger,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --drop:console\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  drop: ['console'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Drop:        api.DropConsole,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nfunction example() {\n  DEV: doAnExpensiveCheck()\n  return normalCodePath()\n}\n```\n\nExample:\n```text\nfunction example() {\n  return normalCodePath();\n}\n```\n\nExample:\n```text\nesbuild app.js --drop-labels=DEV,TEST\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  dropLabels: ['DEV', 'TEST'],\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    DropLabels:  []string{\"DEV\", \"TEST\"},\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nfunction example() {\n  DEV && doAnExpensiveCheck()\n  return normalCodePath()\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --ignore-annotations\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  ignoreAnnotations: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"app.js\"},\n    Bundle:            true,\n    IgnoreAnnotations: true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n// process-cwd-shim.js\nlet processCwdShim = () => ''\nexport { processCwdShim as 'process.cwd' }\n```\n\nExample:\n```text\n// entry.js\nconsole.log(process.cwd())\n```\n\nExample:\n```text\nesbuild entry.js --inject:./process-cwd-shim.js --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['entry.js'],\n  inject: ['./process-cwd-shim.js'],\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"entry.js\"},\n    Inject:      []string{\"./process-cwd-shim.js\"},\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n// out.js\nvar processCwdShim = () => \"\";\nconsole.log(processCwdShim());\n```\n\nExample:\n```text\nconst { createElement, Fragment } = require('react')\nexport {\n  createElement as 'React.createElement',\n  Fragment as 'React.Fragment',\n}\n```\n\nExample:\n```text\nfunction fn() {}\nlet fn = function() {};\nfn = function() {};\nlet [fn = function() {}] = [];\nlet {fn = function() {}} = {};\n[fn = function() {}] = [];\n({fn = function() {}} = {});\n```\n\nExample:\n```text\nesbuild app.js --minify --keep-names\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  minify: true,\n  keepNames: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"app.js\"},\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n    KeepNames:         true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --mangle-props=_$\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  mangleProps: /_$/,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    MangleProps: \"_$\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --mangle-props=_$ --mangle-quoted\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  mangleProps: /_$/,\n  mangleQuoted: true,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:  []string{\"app.js\"},\n    MangleProps:  \"_$\",\n    MangleQuoted: api.MangleQuotedTrue,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nlet obj = {}\nObject.defineProperty(\n  obj,\n  /* @__KEY__ */ 'foo_',\n  { get: () => 123 },\n)\nconsole.log(obj.foo_)\n```\n\nExample:\n```text\nesbuild app.js --mangle-props=_$ \"--reserve-props=^__.*__$\"\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  mangleProps: /_$/,\n  reserveProps: /^__.*__$/,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:  []string{\"app.js\"},\n    MangleProps:  \"_$\",\n    ReserveProps: \"^__.*__$\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nconsole.log({\n  someProp_: 1,\n  customRenaming_: 2,\n  disabledRenaming_: 3\n});\n```\n\nExample:\n```text\n{\n  \"customRenaming_\": \"cR_\",\n  \"disabledRenaming_\": false\n}\n```\n\nExample:\n```text\nesbuild app.js --mangle-props=_$ --mangle-cache=cache.json\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['app.js'],\n  mangleProps: /_$/,\n  mangleCache: {\n    customRenaming_: \"cR_\",\n    disabledRenaming_: false\n  },\n})\n\nconsole.log('updated mangle cache:', result.mangleCache)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    MangleProps: \"_$\",\n    MangleCache: map[string]interface{}{\n      \"customRenaming_\":   \"cR_\",\n      \"disabledRenaming_\": false,\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n\n  fmt.Println(\"updated mangle cache:\", result.MangleCache)\n}\n```\n\nExample:\n```text\nconsole.log({\n  a: 1,\n  cR_: 2,\n  disabledRenaming_: 3\n});\n```\n\nExample:\n```text\n{\n  \"customRenaming_\": \"cR_\",\n  \"disabledRenaming_\": false,\n  \"someProp_\": \"a\"\n}\n```\n\nExample:\n```text\necho 'fn = obj => { return obj.x }' | esbuild --minify\nfn=n=>n.x;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'var js = 'fn = obj => { return obj.x }'\n(await esbuild.transform(js, {\n  minify: true,\n})).code\n'fn=n=>n.x;\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"fn = obj => { return obj.x }\"\n\n  result := api.Transform(js, api.TransformOptions{\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'fn = obj => { return obj.x }' | esbuild --minify-whitespace\nfn=obj=>{return obj.x};\necho 'fn = obj => { return obj.x }' | esbuild --minify-identifiers\nfn = (n) => {\n  return n.x;\n};\necho 'fn = obj => { return obj.x }' | esbuild --minify-syntax\nfn = (obj) => obj.x;\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'var js = 'fn = obj => { return obj.x }'\n(await esbuild.transform(js, {\n  minifyWhitespace: true,\n})).code\n'fn=obj=>{return obj.x};\\n'\n(await esbuild.transform(js, {\n  minifyIdentifiers: true,\n})).code\n'fn = (n) => {\\n  return n.x;\\n};\\n'\n(await esbuild.transform(js, {\n  minifySyntax: true,\n})).code\n'fn = (obj) => obj.x;\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  css := \"div { color: yellow }\"\n\n  result1 := api.Transform(css, api.TransformOptions{\n    Loader:           api.LoaderCSS,\n    MinifyWhitespace: true,\n  })\n\n  if len(result1.Errors) == 0 {\n    fmt.Printf(\"%s\", result1.Code)\n  }\n\n  result2 := api.Transform(css, api.TransformOptions{\n    Loader:            api.LoaderCSS,\n    MinifyIdentifiers: true,\n  })\n\n  if len(result2.Errors) == 0 {\n    fmt.Printf(\"%s\", result2.Code)\n  }\n\n  result3 := api.Transform(css, api.TransformOptions{\n    Loader:       api.LoaderCSS,\n    MinifySyntax: true,\n  })\n\n  if len(result3.Errors) == 0 {\n    fmt.Printf(\"%s\", result3.Code)\n  }\n}\n```\n\nExample:\n```text\necho 'div { color: yellow }' | esbuild --loader=css --minify\ndiv{color:#ff0}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'var css = 'div { color: yellow }'\n(await esbuild.transform(css, {\n  loader: 'css',\n  minify: true,\n})).code\n'div{color:#ff0}\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  css := \"div { color: yellow }\"\n\n  result := api.Transform(css, api.TransformOptions{\n    Loader:            api.LoaderCSS,\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\n// Direct eval (will disable minification for the whole file)\nlet result = eval(something)\n```\n\nExample:\n```text\n// Indirect eval (has no effect on the surrounding code)\nlet result = (0, eval)(something)\n```\n\nExample:\n```text\nlet button = /* @__PURE__ */ React.createElement(Button, null);\n```\n\nExample:\n```text\necho 'document.createElement(elemName())' | esbuild --pure:document.createElement\n/* @__PURE__ */ document.createElement(elemName());\necho 'document.createElement(elemName())' | esbuild --pure:document.createElement --minify\nelemName();\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'let js = 'document.createElement(elemName())'\n(await esbuild.transform(js, {\n  pure: ['document.createElement'],\n})).code\n'/* @__PURE__ */ document.createElement(elemName());\\n'\n(await esbuild.transform(js, {\n  pure: ['document.createElement'],\n  minify: true,\n})).code\n'elemName();\\n'\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"document.createElement(elemName())\"\n\n  result1 := api.Transform(js, api.TransformOptions{\n    Pure: []string{\"document.createElement\"},\n  })\n\n  if len(result1.Errors) == 0 {\n    fmt.Printf(\"%s\", result1.Code)\n  }\n\n  result2 := api.Transform(js, api.TransformOptions{\n    Pure:         []string{\"document.createElement\"},\n    MinifySyntax: true,\n  })\n\n  if len(result2.Errors) == 0 {\n    fmt.Printf(\"%s\", result2.Code)\n  }\n}\n```\n\nExample:\n```text\n// input.js\nfunction one() {\n  console.log('one')\n}\nfunction two() {\n  console.log('two')\n}\none()\n```\n\nExample:\n```text\n// input.js\nfunction one() {\n  console.log(\"one\");\n}\none();\n```\n\nExample:\n```text\n// lib.js\nexport function one() {\n  console.log('one')\n}\nexport function two() {\n  console.log('two')\n}\n```\n\nExample:\n```text\n// input.js\nimport * as lib from './lib.js'\nlib.one()\n```\n\nExample:\n```text\n// lib.js\nfunction one() {\n  console.log(\"one\");\n}\n\n// input.js\none();\n```\n\nExample:\n```text\nesbuild app.js --tree-shaking=true\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  treeShaking: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    TreeShaking: api.TreeShakingTrue,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --tree-shaking=false\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  treeShaking: false,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    TreeShaking: api.TreeShakingFalse,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n// These are considered side-effect free\nlet a = 12.34;\nlet b = \"abcd\";\nlet c = { a: a };\n\n// These are not considered side-effect free\n// since they could cause some code to run\nlet x = \"ab\" + cd;\nlet y = foo.bar;\nlet z = { [x]: x };\n```\n\nExample:\n```text\n// This is considered side-effect free due to\n// the annotation, and will be removed if unused\nlet gammaTable = /* @__PURE__ */ (() => {\n  // Side-effect detection is skipped in here\n  let table = new Uint8Array(256);\n  for (let i = 0; i < 256; i++)\n    table[i] = Math.pow(i / 255, 2.2) * 255;\n  return table;\n})();\n```\n\nExample:\n```text\nesbuild app.js --sourcemap --source-root=https://raw.githubusercontent.com/some/repo/v1.2.3/\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  sourcemap: true,\n  sourceRoot: 'https://raw.githubusercontent.com/some/repo/v1.2.3/',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Sourcemap:   api.SourceMapInline,\n    SourceRoot:  \"https://raw.githubusercontent.com/some/repo/v1.2.3/\",\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\ncat app.js | esbuild --sourcefile=example.js --sourcemap\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport fs from 'node:fs'\n\nlet js = fs.readFileSync('app.js', 'utf8')\nlet result = await esbuild.transform(js, {\n  sourcefile: 'example.js',\n  sourcemap: 'inline',\n})\n\nconsole.log(result.code)\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"io/ioutil\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js, err := ioutil.ReadFile(\"app.js\")\n  if err != nil {\n    panic(err)\n  }\n\n  result := api.Transform(string(js),\n    api.TransformOptions{\n      Sourcefile: \"example.js\",\n      Sourcemap:  api.SourceMapInline,\n    })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s %s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --sourcemap --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  sourcemap: true,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Sourcemap:   api.SourceMapLinked,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --sourcemap=external --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  sourcemap: 'external',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Sourcemap:   api.SourceMapExternal,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --sourcemap=inline --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  sourcemap: 'inline',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Sourcemap:   api.SourceMapInline,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.ts --sourcemap=both --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.ts'],\n  sourcemap: 'both',\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.ts\"},\n    Sourcemap:   api.SourceMapInlineAndExternal,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nnode --enable-source-maps app.js\n```\n\nExample:\n```text\n{\n  \"version\": 3,\n  \"sources\": [\"bar.js\", \"foo.js\"],\n  \"sourcesContent\": [\"bar()\", \"foo()\\nimport './bar'\"],\n  \"mappings\": \";AAAA;;;ACAA;\",\n  \"names\": []\n}\n```\n\nExample:\n```text\nesbuild --bundle app.js --sourcemap --sources-content=false\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  bundle: true,\n  entryPoints: ['app.js'],\n  sourcemap: true,\n  sourcesContent: false,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    Bundle:         true,\n    EntryPoints:    []string{\"app.js\"},\n    Sourcemap:      api.SourceMapInline,\n    SourcesContent: api.SourcesContentExclude,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild --bundle example.jsx --outfile=out.js --minify --analyze\n\n  out.js                                                                    27.6kb  100.0%\n   ├ node_modules/react-dom/cjs/react-dom-server.browser.production.min.js  19.2kb   69.7%\n   ├ node_modules/react/cjs/react.production.min.js                          5.9kb   21.4%\n   ├ node_modules/object-assign/index.js                                     962b     3.4%\n   ├ example.jsx                                                             137b     0.5%\n   ├ node_modules/react-dom/server.browser.js                                 50b     0.2%\n   └ node_modules/react/index.js                                              50b     0.2%\n\n...\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['example.jsx'],\n  outfile: 'out.js',\n  minify: true,\n  metafile: true,\n})\n\nconsole.log(await esbuild.analyzeMetafile(result.metafile))\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"fmt\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"example.jsx\"},\n    Outfile:           \"out.js\",\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n    Metafile:          true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n\n  fmt.Printf(\"%s\", api.AnalyzeMetafile(result.Metafile, api.AnalyzeMetafileOptions{}))\n}\n```\n\nExample:\n```text\nesbuild --bundle example.jsx --outfile=out.js --minify --analyze=verbose\n\n  out.js ─────────────────────────────────────────────────────────────────── 27.6kb ─ 100.0%\n   ├ node_modules/react-dom/cjs/react-dom-server.browser.production.min.js ─ 19.2kb ── 69.7%\n   │  └ node_modules/react-dom/server.browser.js\n   │     └ example.jsx\n   ├ node_modules/react/cjs/react.production.min.js ───────────────────────── 5.9kb ── 21.4%\n   │  └ node_modules/react/index.js\n   │     └ example.jsx\n   ├ node_modules/object-assign/index.js ──────────────────────────────────── 962b ──── 3.4%\n   │  └ node_modules/react-dom/cjs/react-dom-server.browser.production.min.js\n   │     └ node_modules/react-dom/server.browser.js\n   │        └ example.jsx\n   ├ example.jsx ──────────────────────────────────────────────────────────── 137b ──── 0.5%\n   ├ node_modules/react-dom/server.browser.js ──────────────────────────────── 50b ──── 0.2%\n   │  └ example.jsx\n   └ node_modules/react/index.js ───────────────────────────────────────────── 50b ──── 0.2%\n      └ example.jsx\n\n...\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['example.jsx'],\n  outfile: 'out.js',\n  minify: true,\n  metafile: true,\n})\n\nconsole.log(await esbuild.analyzeMetafile(result.metafile, {\n  verbose: true,\n}))\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"fmt\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints:       []string{\"example.jsx\"},\n    Outfile:           \"out.js\",\n    MinifyWhitespace:  true,\n    MinifyIdentifiers: true,\n    MinifySyntax:      true,\n    Metafile:          true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n\n  fmt.Printf(\"%s\", api.AnalyzeMetafile(result.Metafile, api.AnalyzeMetafileOptions{\n    Verbose: true,\n  }))\n}\n```\n\nExample:\n```text\nesbuild app.js --bundle --metafile=meta.json --outfile=out.js\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\nimport fs from 'node:fs'\n\nlet result = await esbuild.build({\n  entryPoints: ['app.js'],\n  bundle: true,\n  metafile: true,\n  outfile: 'out.js',\n})\n\nfs.writeFileSync('meta.json', JSON.stringify(result.metafile))\n```\n\nExample:\n```text\npackage main\n\nimport \"io/ioutil\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    Bundle:      true,\n    Metafile:    true,\n    Outfile:     \"out.js\",\n    Write:       true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n\n  ioutil.WriteFile(\"meta.json\", []byte(result.Metafile), 0644)\n}\n```\n\nExample:\n```text\ninterface Metafile {\n  inputs: {\n    [path: string]: {\n      bytes: number\n      imports: {\n        path: string\n        kind: string\n        external?: boolean\n        original?: string\n        with?: Record<string, string>\n      }[]\n      format?: string\n      with?: Record<string, string>\n    }\n  }\n  outputs: {\n    [path: string]: {\n      bytes: number\n      inputs: {\n        [path: string]: {\n          bytesInOutput: number\n        }\n      }\n      imports: {\n        path: string\n        kind: string\n        external?: boolean\n      }[]\n      exports: string[]\n      entryPoint?: string\n      cssBundle?: string\n    }\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --abs-paths=log,metafile --outfile=out.js --metafile=meta.json\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet result = await esbuild.build({\n  entryPoints: ['app.js'],\n  absPaths: ['log', 'metafile'],\n  outfile: 'out.js',\n  metafile: true,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    AbsPaths:    api.LogAbsPath | api.MetafileAbsPath,\n    Outfile:     \"out.js\",\n    Metafile:    true,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n▲ [WARNING] The \"typeof\" operator will never evaluate to \"null\" [impossible-typeof]\n\n    example.js:2:16:\n      2 │ log(typeof x == \"null\")\n        ╵                 ~~~~~~\n\n  The expression \"typeof x\" actually evaluates to \"object\" in JavaScript, not \"null\". You need to\n  use \"x === null\" to test for null.\n\n✘ [ERROR] Could not resolve \"logger\"\n\n    example.js:1:16:\n      1 │ import log from \"logger\"\n        ╵                 ~~~~~~~~\n\n  You can mark the path \"logger\" as external to exclude it from the bundle, which will remove this\n  error and leave the unresolved path in the bundle.\n```\n\nExample:\n```text\necho 'typeof x == \"null\"' | esbuild --color=true 2> stderr.txt\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'typeof x == \"null\"'\nawait esbuild.transform(js, {\n  color: true,\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"typeof x == 'null'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    Color: api.ColorAlways,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet formatted = await esbuild.formatMessages([\n  {\n    text: 'This is an error',\n    location: {\n      file: 'app.js',\n      line: 10,\n      column: 4,\n      length: 3,\n      lineText: 'let foo = bar',\n    },\n  },\n], {\n  kind: 'error',\n  color: false,\n  terminalWidth: 100,\n})\n\nconsole.log(formatted.join('\\n'))\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"strings\"\n\nfunc main() {\n  formatted := api.FormatMessages([]api.Message{\n    {\n      Text: \"This is an error\",\n      Location: &api.Location{\n        File:     \"app.js\",\n        Line:     10,\n        Column:   4,\n        Length:   3,\n        LineText: \"let foo = bar\",\n      },\n    },\n  }, api.FormatMessagesOptions{\n    Kind:          api.ErrorMessage,\n    Color:         false,\n    TerminalWidth: 100,\n  })\n\n  fmt.Printf(\"%s\", strings.Join(formatted, \"\\n\"))\n}\n```\n\nExample:\n```javascript\ninterface FormatMessagesOptions {\n  kind: 'error' | 'warning';\n  color?: boolean;\n  terminalWidth?: number;\n  logStyle?: LogStyle;\n}\n```\n\nExample:\n```text\ntype FormatMessagesOptions struct {\n  Kind          MessageKind\n  Color         bool\n  TerminalWidth int\n  LogStyle      LogStyle\n}\n```\n\nExample:\n```text\necho 'typeof x == \"null\"' | esbuild --log-level=error\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nlet js = 'typeof x == \"null\"'\nawait esbuild.transform(js, {\n  logLevel: 'error',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"fmt\"\nimport \"github.com/evanw/esbuild/pkg/api\"\n\nfunc main() {\n  js := \"typeof x == 'null'\"\n\n  result := api.Transform(js, api.TransformOptions{\n    LogLevel: api.LogLevelError,\n  })\n\n  if len(result.Errors) == 0 {\n    fmt.Printf(\"%s\", result.Code)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --log-limit=0\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  logLimit: 0,\n  outfile: 'out.js',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    LogLimit:    0,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\nesbuild app.js --log-override:unsupported-regexp=warning --target=chrome50\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  logOverride: {\n    'unsupported-regexp': 'warning',\n  },\n  target: 'chrome50',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    LogOverride: map[string]api.LogLevel{\n      \"unsupported-regexp\": api.LogLevelWarning,\n    },\n    Engines: []api.Engine{\n      {Name: api.EngineChrome, Version: \"50\"},\n    },\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\nExample:\n```text\n▲ [WARNING] The \"assert\" keyword is not supported in the configured target environment [assert-to-with]\n\n    example.js:1:31:\n      1 │ import data from \"./data.json\" assert { type: \"json\" }\n        │                                ~~~~~~\n        ╵                                with\n\n  Did you mean to use \"with\" instead of \"assert\"?\n```\n\nExample:\n```text\n▲ [WARNING] Non-default import \"value\" is undefined with a JSON import assertion [assert-type-json]\n\n    example.js:1:78:\n      1 │ import * as data from \"./data.json\" assert { type: \"json\" }; console.log(data.value)\n        ╵                                                                               ~~~~~\n\n  The JSON import assertion is here:\n\n    example.js:1:45:\n      1 │ import * as data from \"./data.json\" assert { type: \"json\" }; console.log(data.value)\n        ╵                                              ~~~~~~~~~~~~\n\n  You can either keep the import assertion and only use the \"default\" import, or you can remove the\n  import assertion and use the \"value\" import.\n```\n\nExample:\n```text\n▲ [WARNING] This assignment will throw because \"foo\" is a constant [assign-to-constant]\n\n    example.js:1:15:\n      1 │ const foo = 1; foo = 2\n        ╵                ~~~\n\n  The symbol \"foo\" was declared a constant here:\n\n    example.js:1:6:\n      1 │ const foo = 1; foo = 2\n        ╵       ~~~\n```\n\nExample:\n```text\n▲ [WARNING] Suspicious assignment to defined constant \"DEFINE\" [assign-to-define]\n\n    example.js:1:0:\n      1 │ DEFINE = false\n        ╵ ~~~~~~\n\n  The expression \"DEFINE\" has been configured to be replaced with a constant using the \"define\"\n  feature. If this expression is supposed to be a compile-time constant, then it doesn't make sense\n  to assign to it here. Or if this expression is supposed to change at run-time, this \"define\"\n  substitution should be removed.\n```\n\nExample:\n```text\n▲ [WARNING] This assignment will throw because \"foo\" is an import [assign-to-import]\n\n    example.js:1:23:\n      1 │ import foo from \"foo\"; foo = null\n        ╵                        ~~~\n\n  Imports are immutable in JavaScript. To modify the value of this import, you must export a setter\n  function in the imported file (e.g. \"setFoo\") and then import and call that function here instead.\n```\n\nExample:\n```text\n▲ [WARNING] Calling \"foo\" will crash at run-time because it's an import namespace object, not a function [call-import-namespace]\n\n    example.js:1:28:\n      1 │ import * as foo from \"foo\"; foo()\n        ╵                             ~~~\n\n  Consider changing \"foo\" to a default import instead:\n\n    example.js:1:7:\n      1 │ import * as foo from \"foo\"; foo()\n        │        ~~~~~~~~\n        ╵        foo\n```\n\nExample:\n```text\n▲ [WARNING] Accessing class \"Foo\" before initialization will throw [class-name-will-throw]\n\n    example.js:1:40:\n      1 │ class Foo { static key = \"foo\"; static [Foo.key] = 123 }\n        ╵                                         ~~~\n```\n\nExample:\n```text\n▲ [WARNING] The CommonJS \"exports\" variable is treated as a global variable in an ECMAScript module and may not work as expected [commonjs-variable-in-esm]\n\n    example.js:1:0:\n      1 │ exports.foo = 1; export let bar = 2\n        ╵ ~~~~~~~\n\n  This file is considered to be an ECMAScript module because of the \"export\" keyword here:\n\n    example.js:1:17:\n      1 │ exports.foo = 1; export let bar = 2\n        ╵                  ~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Operator \"*\" should not directly follow a TypeScript type cast after the \"+\" operator [confusing-typescript-cast]\n\n    example.ts:1:16:\n      1 │ 1 + 2 as number * 3\n        ╵                 ^\n\n  This is a syntax error in newer versions of TypeScript because the type cast has unintuitive\n  precedence in this case. Surround the inner expression in parentheses to silence this warning:\n\n    example.ts:1:0:\n      1 │ 1 + 2 as number * 3\n        │ ~~~~~~~~~~~~~~~\n        ╵ (             )\n```\n\nExample:\n```text\n▲ [WARNING] Attempting to delete a property of \"super\" will throw a ReferenceError [delete-super-property]\n\n    example.js:1:42:\n      1 │ class Foo extends Object { foo() { delete super.foo } }\n        ╵                                           ~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Using direct eval with a bundler is not recommended and may cause problems [direct-eval]\n\n    example.js:1:22:\n      1 │ let apparentlyUnused; eval(\"actuallyUse(apparentlyUnused)\")\n        ╵                       ~~~~\n\n  You can read more about direct eval and bundling here: https://esbuild.github.io/link/direct-eval\n```\n\nExample:\n```text\n▲ [WARNING] This case clause will never be evaluated because it duplicates an earlier case clause [duplicate-case]\n\n    example.js:1:33:\n      1 │ switch (foo) { case 1: return 1; case 1: return 2 }\n        ╵                                  ~~~~\n\n  The earlier case clause is here:\n\n    example.js:1:15:\n      1 │ switch (foo) { case 1: return 1; case 1: return 2 }\n        ╵                ~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Duplicate member \"x\" in class body [duplicate-class-member]\n\n    example.js:1:19:\n      1 │ class Foo { x = 1; x = 2 }\n        ╵                    ^\n\n  The original member \"x\" is here:\n\n    example.js:1:12:\n      1 │ class Foo { x = 1; x = 2 }\n        ╵             ^\n```\n\nExample:\n```text\n▲ [WARNING] Duplicate key \"bar\" in object literal [duplicate-object-key]\n\n    example.js:1:16:\n      1 │ foo = { bar: 1, bar: 2 }\n        ╵                 ~~~\n\n  The original key \"bar\" is here:\n\n    example.js:1:8:\n      1 │ foo = { bar: 1, bar: 2 }\n        ╵         ~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"import.meta\" is not available in the configured target environment (\"chrome50\") and will be empty [empty-import-meta]\n\n    example.js:1:6:\n      1 │ foo = import.meta\n        ╵       ~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Comparison with NaN using the \"!==\" operator here is always true [equals-nan]\n\n    example.js:1:24:\n      1 │ foo = foo.filter(x => x !== NaN)\n        ╵                         ~~~\n\n  Floating-point equality is defined such that NaN is never equal to anything, so \"x === NaN\" always\n  returns false. You need to use \"Number.isNaN(x)\" instead to test for NaN.\n```\n\nExample:\n```text\n▲ [WARNING] Comparison with -0 using the \"!==\" operator will also match 0 [equals-negative-zero]\n\n    example.js:1:28:\n      1 │ foo = foo.filter(x => x !== -0)\n        ╵                             ~~\n\n  Floating-point equality is defined such that 0 and -0 are equal, so \"x === -0\" returns true for\n  both 0 and -0. You need to use \"Object.is(x, -0)\" instead to test for -0.\n```\n\nExample:\n```text\n▲ [WARNING] Comparison using the \"!==\" operator here is always true [equals-new-object]\n\n    example.js:1:24:\n      1 │ foo = foo.filter(x => x !== [])\n        ╵                         ~~~\n\n  Equality with a new object is always false in JavaScript because the equality operator tests\n  object identity. You need to write code to compare the contents of the object instead. For\n  example, use \"Array.isArray(x) && x.length === 0\" instead of \"x === []\" to test for an empty\n  array.\n```\n\nExample:\n```text\n▲ [WARNING] Treating \"<!--\" as the start of a legacy HTML single-line comment [html-comment-in-js]\n\n    example.js:1:0:\n      1 │ <!-- comment -->\n        ╵ ~~~~\n```\n\nExample:\n```text\n▲ [WARNING] The \"typeof\" operator will never evaluate to \"null\" [impossible-typeof]\n\n    example.js:1:32:\n      1 │ foo = foo.map(x => typeof x !== \"null\")\n        ╵                                 ~~~~~~\n\n  The expression \"typeof x\" actually evaluates to \"object\" in JavaScript, not \"null\". You need to\n  use \"x === null\" to test for null.\n```\n\nExample:\n```text\n▲ [WARNING] Indirect calls to \"require\" will not be bundled [indirect-require]\n\n    example.js:1:8:\n      1 │ let r = require, fs = r(\"fs\")\n        ╵         ~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Writing to getter-only property \"#foo\" will throw [private-name-will-throw]\n\n    example.js:1:39:\n      1 │ class Foo { get #foo() {} bar() { this.#foo++ } }\n        ╵                                        ~~~~\n```\n\nExample:\n```text\n▲ [WARNING] The following expression is not returned because of an automatically-inserted semicolon [semicolon-after-return]\n\n    example.js:1:6:\n      1 │ return\n        ╵       ^\n```\n\nExample:\n```text\n▲ [WARNING] Suspicious use of the \"!\" operator inside the \"in\" operator [suspicious-boolean-not]\n\n    example.js:1:4:\n      1 │ if (!foo in bar) {\n        │     ~~~~\n        ╵     (!foo)\n\n  The code \"!x in y\" is parsed as \"(!x) in y\". You need to insert parentheses to get \"!(x in y)\"\n  instead.\n```\n\nExample:\n```text\n▲ [WARNING] \"process.env.NODE_ENV\" is defined as an identifier instead of a string (surround \"production\" with quotes to get a string) [suspicious-define]\n\n    <js>:1:34:\n      1 │ define: { 'process.env.NODE_ENV': 'production' }\n        │                                   ~~~~~~~~~~~~\n        ╵                                   '\"production\"'\n```\n\nExample:\n```text\n▲ [WARNING] The \"&&\" operator here will always return the left operand [suspicious-logical-operator]\n\n    example.js:1:25:\n      1 │ const isInRange = x => 0 && x <= 1\n        ╵                          ~~\n\n  The \"=>\" symbol creates an arrow function expression in JavaScript. Did you mean to use the\n  greater-than-or-equal-to operator \">=\" here instead?\n\n    example.js:1:20:\n      1 │ const isInRange = x => 0 && x <= 1\n        │                     ~~\n        ╵                     >=\n```\n\nExample:\n```text\n▲ [WARNING] The \"??\" operator here will always return the left operand [suspicious-nullish-coalescing]\n\n    example.js:1:26:\n      1 │ return name === user.name ?? \"\"\n        ╵                           ~~\n\n  The left operand of the \"??\" operator here will never be null or undefined, so it will always be\n  returned. This usually indicates a bug in your code:\n\n    example.js:1:7:\n      1 │ return name === user.name ?? \"\"\n        ╵        ~~~~~~~~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Top-level \"this\" will be replaced with undefined since this file is an ECMAScript module [this-is-undefined-in-esm]\n\n    example.js:1:0:\n      1 │ this.foo = 1; export let bar = 2\n        │ ~~~~\n        ╵ undefined\n\n  This file is considered to be an ECMAScript module because of the \"export\" keyword here:\n\n    example.js:1:14:\n      1 │ this.foo = 1; export let bar = 2\n        ╵               ~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] This \"import\" expression will not be bundled because the argument is not a string literal [unsupported-dynamic-import]\n\n    example.js:1:0:\n      1 │ import(foo)\n        ╵ ~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Invalid JSX factory: 123 [unsupported-jsx-comment]\n\n    example.jsx:1:8:\n      1 │ // @jsx 123\n        ╵         ~~~\n```\n\nExample:\n```text\n▲ [WARNING] The regular expression flag \"d\" is not available in the configured target environment (\"chrome50\") [unsupported-regexp]\n\n    example.js:1:3:\n      1 │ /./d\n        ╵    ^\n\n  This regular expression literal has been converted to a \"new RegExp()\" constructor to avoid\n  generating code with a syntax error. However, you will need to include a polyfill for \"RegExp\" for\n  your code to have the correct behavior at run-time.\n```\n\nExample:\n```text\n▲ [WARNING] This call to \"require\" will not be bundled because the argument is not a string literal [unsupported-require-call]\n\n    example.js:1:0:\n      1 │ require(foo)\n        ╵ ~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Expected identifier but found \"]\" [css-syntax-error]\n\n    example.css:1:4:\n      1 │ div[] {\n        ╵     ^\n```\n\nExample:\n```text\n▲ [WARNING] \"@charset\" must be the first rule in the file [invalid-@charset]\n\n    example.css:1:19:\n      1 │ div { color: red } @charset \"UTF-8\";\n        ╵                    ~~~~~~~~\n\n  This rule cannot come before a \"@charset\" rule\n\n    example.css:1:0:\n      1 │ div { color: red } @charset \"UTF-8\";\n        ╵ ^\n```\n\nExample:\n```text\n▲ [WARNING] All \"@import\" rules must come first [invalid-@import]\n\n    example.css:1:19:\n      1 │ div { color: red } @import \"foo.css\";\n        ╵                    ~~~~~~~\n\n  This rule cannot come before an \"@import\" rule\n\n    example.css:1:0:\n      1 │ div { color: red } @import \"foo.css\";\n        ╵ ^\n```\n\nExample:\n```text\n▲ [WARNING] \"initial\" cannot be used as a layer name [invalid-@layer]\n\n    example.css:1:7:\n      1 │ @layer initial {\n        ╵        ~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"-\" can only be used as an infix operator, not a prefix operator [invalid-calc]\n\n    example.css:1:20:\n      1 │ div { z-index: calc(-(1+2)); }\n        ╵                     ^\n\n▲ [WARNING] The \"+\" operator only works if there is whitespace on both sides [invalid-calc]\n\n    example.css:1:23:\n      1 │ div { z-index: calc(-(1+2)); }\n        ╵                        ^\n```\n\nExample:\n```text\n▲ [WARNING] Comments in CSS use \"/* ... */\" instead of \"//\" [js-comment-in-css]\n\n    example.css:1:0:\n      1 │ // comment\n        ╵ ~~\n```\n\nExample:\n```text\n▲ [WARNING] The value of \"zoom\" in the \"foo\" class is undefined [undefined-composes-from]\n\n    example.module.css:1:1:\n      1 │ .foo { composes: bar from \"lib.module.css\"; zoom: 1; }\n        ╵  ~~~\n\n  The first definition of \"zoom\" is here:\n\n    lib.module.css:1:7:\n      1 │ .bar { zoom: 2 }\n        ╵        ~~~~\n\n  The second definition of \"zoom\" is here:\n\n    example.module.css:1:44:\n      1 │ .foo { composes: bar from \"lib.module.css\"; zoom: 1; }\n        ╵                                             ~~~~\n\n  The specification of \"composes\" does not define an order when class declarations from separate\n  files are composed together. The value of the \"zoom\" property for \"foo\" may change unpredictably\n  as the code is edited. Make sure that all definitions of \"zoom\" for \"foo\" are in a single file.\n```\n\nExample:\n```text\n▲ [WARNING] \"UTF-8\" will be used instead of unsupported charset \"ASCII\" [unsupported-@charset]\n\n    example.css:1:9:\n      1 │ @charset \"ASCII\";\n        ╵          ~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"@namespace\" rules are not supported [unsupported-@namespace]\n\n    example.css:1:0:\n      1 │ @namespace \"ns\";\n        ╵ ~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"widht\" is not a known CSS property [unsupported-css-property]\n\n    example.css:1:6:\n      1 │ div { widht: 1px }\n        │       ~~~~~\n        ╵       width\n\n  Did you mean \"width\" instead?\n```\n\nExample:\n```text\n▲ [WARNING] Transforming this CSS nesting syntax is not supported in the configured target environment (\"chrome50\") [unsupported-css-nesting]\n\n    example.css:2:5:\n      2 │ .foo & {\n        ╵      ^\n\n  The nesting transform for this case must generate an \":is(...)\" but the configured target\n  environment does not support the \":is\" pseudo-class.\n```\n\nExample:\n```text\n▲ [WARNING] Re-export of \"foo\" in \"example.js\" is ambiguous and has been removed [ambiguous-reexport]\n\n  One definition of \"foo\" comes from \"a.js\" here:\n\n    a.js:1:11:\n      1 │ export let foo = 1\n        ╵            ~~~\n\n  Another definition of \"foo\" comes from \"b.js\" here:\n\n    b.js:1:11:\n      1 │ export let foo = 2\n        ╵            ~~~\n```\n\nExample:\n```text\n▲ [WARNING] Use \"foo.js\" instead of \"Foo.js\" to avoid issues with case-sensitive file systems [different-path-case]\n\n    example.js:2:7:\n      2 │ import \"./Foo.js\"\n        ╵        ~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] The glob pattern import(\"./icon-*.json\") did not match any files [empty-glob]\n\n    example.js:2:16:\n      2 │   return import(\"./icon-\" + name + \".json\")\n        ╵                 ~~~~~~~~~~~~~~~~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Ignoring this import because \"node_modules/foo/index.js\" was marked as having no side effects [ignored-bare-import]\n\n    example.js:1:7:\n      1 │ import \"foo\"\n        ╵        ~~~~~\n\n  \"sideEffects\" is false in the enclosing \"package.json\" file:\n\n    node_modules/foo/package.json:2:2:\n      2 │   \"sideEffects\": false\n        ╵   ~~~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Importing \"foo\" was allowed even though it could not be resolved because dynamic import failures appear to be handled here: [ignored-dynamic-import]\n\n    example.js:1:7:\n      1 │ import(\"foo\").catch(e => {\n        ╵        ~~~~~\n\n  The handler for dynamic import failures is here:\n\n    example.js:1:14:\n      1 │ import(\"foo\").catch(e => {\n        ╵               ~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Import \"foo\" will always be undefined because the file \"foo.js\" has no exports [import-is-undefined]\n\n    example.js:1:9:\n      1 │ import { foo } from \"./foo\"\n        ╵          ~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"foo\" should be marked as external for use with \"require.resolve\" [require-resolve-not-external]\n\n    example.js:1:26:\n      1 │ let foo = require.resolve(\"foo\")\n        ╵                           ~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Bad \"mappings\" data in source map at character 3: Invalid original column value: -2 [invalid-source-mappings]\n\n    example.js.map:2:18:\n      2 │   \"mappings\": \"aAAFA,UAAU;;\"\n        ╵                   ^\n\n  The source map \"example.js.map\" was referenced by the file \"example.js\" here:\n\n    example.js:1:21:\n      1 │ //# sourceMappingURL=example.js.map\n        ╵                      ~~~~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] Cannot read file \".\": is a directory [missing-source-map]\n\n    example.js:1:21:\n      1 │ //# sourceMappingURL=.\n        ╵                      ^\n```\n\nExample:\n```text\n▲ [WARNING] Unsupported source map comment: could not decode percent-escaped data: invalid URL escape \"%\\\"\" [unsupported-source-map-comment]\n\n    example.js:1:21:\n      1 │ //# sourceMappingURL=data:application/json,\"%\"\n        ╵                      ~~~~~~~~~~~~~~~~~~~~~~~~~\n```\n\nExample:\n```text\n▲ [WARNING] \"esm\" is not a valid value for the \"type\" field [package.json]\n\n    package.json:1:10:\n      1 │ { \"type\": \"esm\" }\n        ╵           ~~~~~\n\n  The \"type\" field must be set to either \"commonjs\" or \"module\".\n```\n\nExample:\n```text\n▲ [WARNING] Unrecognized target environment \"ES4\" [tsconfig.json]\n\n    tsconfig.json:1:33:\n      1 │ { \"compilerOptions\": { \"target\": \"ES4\" } }\n        ╵                                  ~~~~~\n```\n\nExample:\n```text\nesbuild app.js --log-style=visualstudio\n```\n\nExample:\n```javascript\nimport * as esbuild from 'esbuild'\n\nawait esbuild.build({\n  entryPoints: ['app.js'],\n  logStyle: 'visualstudio',\n})\n```\n\nExample:\n```text\npackage main\n\nimport \"github.com/evanw/esbuild/pkg/api\"\nimport \"os\"\n\nfunc main() {\n  result := api.Build(api.BuildOptions{\n    EntryPoints: []string{\"app.js\"},\n    LogStyle:    api.LogStyleVisualStudio,\n  })\n\n  if len(result.Errors) > 0 {\n    os.Exit(1)\n  }\n}\n```\n\n<|endofdoc|>","metadata":{"transformedAt":"2026-08-18T15:17:31.416Z","totalSectionsIncluded":1,"totalCodeBlocksIncluded":416,"totalLines":5447,"estimatedTokens":64014}}9