An extremely fast JavaScript bundler and minifier

Overview

esbuild: An extremely fast JavaScript bundler
Website | Getting started | Documentation | Plugins | FAQ

Why?

Our current build tools for the web are 10-100x slower than they could be:

Bar chart with benchmark results

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 features:

Check out the getting started instructions if you want to give esbuild a try.

Issues
  • When used with `require()` and `node`, does not honor

    When used with `require()` and `node`, does not honor "main" field in package.json if "module" is present

    EDIT: Originally ran into this with node-fetch, but it seems to have surfaced a larger issue which is that esbuild doesn't prioritize the main field in package.json if you're using require() with node. This means that esbuild diverges from how Node.js/CommonJS would require the same package.

    It appears from the comments that this is by design:

    We support ES6 so we always prefer the "module" field over the "main" field.

    https://github.com/evanw/esbuild/blob/99f587a133b34794c235be5fff9919f57b56297e/internal/resolver/resolver.go#L272-L280

    But this means that certain packages just don't work with require(), such as node-fetch:

    To reproduce:

    $ node --version
    v12.18.3
    
    $ npm install node-fetch
    
    $ node -p "typeof require('node-fetch')"
    function
    
    $ node -p "$(echo "typeof require('node-fetch')" | npx esbuild --bundle --platform=node)"
    object
    

    Would be great if esbuild supported the same behavior as Node.js for require'ing modules – if not out-of-the-box, then possibly via a flag?

    opened by mhart 44
  • a few assorted issues

    a few assorted issues

    esbuild-minify is a dumb wrapper script over esbuild --minify - it's not important other than to demonstrate the following minification issues.

    Default argument scope:

    $ cat esb1.js 
    let a="PASS";((x=a)=>{let a="FAIL";console.log(x)})();
    
    $ cat esb1.js | node
    PASS
    
    $ cat esb1.js | esbuild-minify | node
    [stdin]:1
    let c="PASS";((a=b)=>{let b="FAIL";console.log(a)})();
                     ^
    ReferenceError: b is not defined
    

    Switch expression scope:

    $ cat esb2.js 
    var x="FAIL";switch(x){default:let x="PASS";console.log(x)}
    
    $ cat esb2.js | node
    PASS
    
    $ cat esb2.js | esbuild-minify | node
    [stdin]:1
    var b="FAIL";switch(a){default:let a="PASS";console.log(a)}
                        ^
    ReferenceError: a is not defined
    

    Object literal computed property output:

    $ cat esb3.js 
    var x=1;o={[(++x,5)]:x=>++x};console.log(x,o[5](x),--x);
    
    $ cat esb3.js | node
    2 3 1
    
    $ cat esb3.js | esbuild-minify | node
    [stdin]:1
    var a=1;o={[++a,5]:b=>++b},console.log(a,o[5](a),--a);
                   ^
    SyntaxError: Unexpected token ,
    

    Class method computed property output:

    $ cat esb4.js 
    var x=1;o=new class{[(++x,5)](x){return++x}};console.log(x,o[5](x),--x);
    
    $ cat esb4.js | node
    2 3 1
    
    $ cat esb4.js | esbuild-minify | node
    [stdin]:1
    var a=1;o=new class{[++a,5](b){return++b}}(),console.log(a,o[5](a),--a);
                            ^
    SyntaxError: Unexpected token ,
    
    opened by kzc 37
  • [Feature] Inline const enum values in TypeScript

    [Feature] Inline const enum values in TypeScript

    Right now const enum statements in TypeScript are treated like regular enum statements. This is consistent with how the TypeScript compiler itself behaves when the isolatedModules setting is enabled.

    But it'd be nice if the values were inlined, since that would be better for run-time performance and code size. It should be possible for esbuild to do this since it bundles everything end-to-end and has the original TypeScript source code.

    I'm not going to do this right now but I'm adding this issue now so I don't forget.

    opened by evanw 36
  • [MVP] Watch mode

    [MVP] Watch mode

    I want esbuild to demonstrate that it's possible for a normal web development workflow to have high-performance tools. I consider watch mode a part of my initial MVP feature set for esbuild since I believe development builds should be virtually instant. This issue tracks the watch mode part of my MVP.

    Watch mode involves automatically rebuilding when files on disk have been changed. While esbuild is much faster than other bundlers, very large code bases may still take around a second to build. I consider that too long for a development workflow. Watch mode will keep the previous build in memory and only rebuild the changed files between builds.

    This may or may not involve disabling certain cross-file optimizations while in watch mode depending on what the performance looks like. I may also implement a local HTTP server that can be queried for the latest build, which is a nice way to avoid a page reload accidentally picking up a stale build.

    opened by evanw 32
  • Can't esbuild multiple files unless I use unix find

    Can't esbuild multiple files unless I use unix find

    I also don't see index.html file in dist directory.

    The command I used was

    find . -name 'src/*.js' -exec esbuild {} --bundle --outdir=dist --minify --sourcemap --loader:.js=jsx --external:common/Loadable --external:components/MainContent/ThemeChooser --external:components/MainContent/BuildInfoRegion --external:stores/ThemeStylesStore --external:helpers/ThemeManager --external:stores/ThemeStylesStore --external:common/StyledListItem --external:common/StyledSubheader \;
    

    I'm also wondering why I have to add --external since I wrote them.

    It's a ReactJS application.

    opened by c0debreaker 31
  • support deno

    support deno

    Hi guy! Deno's excellence made me give up node, but I need a build tool like esbuild.

    I want to transform npm modules to esm to run in deno, which allows deno to have the entire web ecosystem.

    I know swc, but it is not reliable yet, the worst case is that it will transform to wrong code, so I need esbuild, just like node, but not webAssembly(esbuild-wasm).

    opened by sessionboy 29
  • Support jsx automatic runtime

    Support jsx automatic runtime

    React 17 will be adding jsx automatic runtime. It's now available in the latest release candidate.

    More info here.

    i.e. react/jsx-runtime and react/jsx-dev-runtime

    Thanks!

    opened by re-thc 29
  • Inline and erase local const enums

    Inline and erase local const enums

    The aim of this PR is to partially address https://github.com/evanw/esbuild/issues/128

    This PR changes the behavior of handling const enums:

    1. For unexported const enums:
      1. Inline and erase if they are used only as known property access
      2. Inline values, but do not erase the enum if it is used in some other way than known property access (e.g. using the enum object in a function call)
    2. For exported const enums and const enums inside namespaces:
      1. Preserve them, i.e. keep the existing logic

    Changes in this PR:

    1. Detect const enums (IsConst field on SEnum)

    2. Display errors when non-literals are used in a const enum

    3. Add warnings when an unknown member of an enum is referenced (this is for both const and regular enums)

    4. Mark local const enums as CanBeRemovedIfUnused and DoesNotAffectTreeShaking. Combined with calling not calling recordUsage on the enum, this lets the existing mangler (I think) erase the declaration if it is not used in any other way.

      I thought this way is probably the most elegant.

    Keep in mind this is one of my first contributions to esbuild, and one of my first lines of go code, so please point out any mistakes/suggestions πŸ˜„

    opened by Gelio 28
  • Error: The package

    Error: The package "esbuild-linux-64" could not be found, and is needed by esbuild

    ❯ uname -a
    Linux ltl065 5.10.0-8-amd64 #1 SMP Debian 5.10.46-5 (2021-09-23) x86_64 GNU/Linux
    # debian bullseye (stable)
    
    ❯ yarn --version
    1.22.5
    
    ❯ node --version
    v16.10.0
    

    example project using a js framework/bundler that uses esbuild

    git clone https://github.com/christopher-caldwell/vite-material-ui
    yarn install
    
    yarn install v1.22.5
    warning package.json: No license field
    info No lockfile found.
    warning [email protected]: No license field
    [1/4] Resolving packages...
    warning react-scripts > [email protected]: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.
    warning react-scripts > webpack-dev-server > [email protected]: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
    warning react-scripts > webpack-dev-server > chokidar > [email protected]: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
    warning react-scripts > @pmmmwh/react-refresh-webpack-plugin > native-url > [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
    warning react-scripts > webpack-dev-server > url > [email protected]: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
    warning react-scripts > webpack-dev-server > sockjs > [email protected]: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
    warning react-scripts > webpack-dev-server > webpack-log > [email protected]: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
    warning react-scripts > workbox-webpack-plugin > workbox-build > [email protected]: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-babel.
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/[email protected]: Switch to 'npm install joi'
    warning react-scripts > webpack > watchpack > watchpack-chokidar2 > [email protected]: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
    warning react-scripts > babel-jest > @jest/transform > jest-haste-map > [email protected]: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added
    warning react-scripts > postcss-preset-env > postcss-color-functional-notation > postcss-values-parser > [email protected]: flatten is deprecated in favor of utility frameworks such as lodash.
    warning react-scripts > resolve-url-loader > rework > css > [email protected]: Please see https://github.com/lydell/urix#deprecated
    warning react-scripts > webpack > micromatch > snapdragon > source-map-resolve > [email protected]: Please see https://github.com/lydell/urix#deprecated
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/joi > @hapi/[email protected]: Moved to 'npm install @sideway/address'
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/joi > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
    warning react-scripts > workbox-webpack-plugin > workbox-build > @hapi/joi > @hapi/topo > @hapi/[email protected]: This version has been deprecated and is no longer supported or maintained
    warning react-scripts > webpack > micromatch > snapdragon > source-map-resolve > [email protected]: https://github.com/lydell/resolve-url#deprecated
    warning react-scripts > workbox-webpack-plugin > workbox-build > strip-comments > babel-plugin-transform-object-rest-spread > babel-runtime > [email protected]: [email protected]<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.
    [2/4] Fetching packages...
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    warning [email protected]: The engine "vscode" appears to be invalid.
    [3/4] Linking dependencies...
    warning " > @caldwell619/[email protected]" has unmet peer dependency "[email protected]>=11".
    warning "@emotion/styled > @emotion/[email protected]" has unmet peer dependency "@babel/[email protected]^7.0.0".
    warning "@emotion/styled > @emotion/babel-plugin > @babel/[email protected]" has unmet peer dependency "@babel/[email protected]^7.0.0-0".
    [4/4] Building fresh packages...
    [-/5] β‘€ waiting...
    [-/5] β‘€ waiting...
    [-/5] β‘€ waiting...
    [-/5] β‘€ waiting...
    error /home/david/Develop/test/vite-mui-christoper-caldwell/node_modules/esbuild: Command failed.
    Exit code: 1
    Command: node install.js
    Arguments: 
    Directory: /home/david/Develop/test/vite-mui-christoper-caldwell/node_modules/esbuild
    Output:
    /home/david/Develop/test/vite-mui-christoper-caldwell/node_modules/esbuild/install.js:45
          throw new Error(`The package "${pkg}" could not be found, and is needed by esbuild.
          ^
    
    Error: The package "esbuild-linux-64" could not be found, and is needed by esbuild.
    
    If you are installing esbuild with npm, make sure that you don't specify the
    "--no-optional" flag. The "optionalDependencies" package.json feature is used
    by esbuild to install the correct binary executable for your current platform.
        at binPathForCurrentPlatform (/home/david/Develop/test/vite-mui-christoper-caldwell/node_modules/esbuild/install.js:45:13)
        at Object.<anonymous> (/home/david/Develop/test/vite-mui-christoper-caldwell/node_modules/esbuild/install.js:90:15)
        at Module._compile (node:internal/modules/cjs/loader:1101:14)
        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
        at Module.load (node:internal/modules/cjs/loader:981:32)
    
    

    direcltly installing and using esbuild by itself works, even globally but global installation is not recognized by the bundler (https://vitejs.dev/)

    ❯ yarn global add esbuild
    yarn global v1.22.5
    warning package.json: No license field
    [1/4] Resolving packages...
    [2/4] Fetching packages...
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The platform "linux" is incompatible with this module.
    info "[email protected]" is an optional dependency and failed compatibility check. Excluding it from installation.
    info [email protected]: The CPU architecture "x64" is incompatible with this module.
    [3/4] Linking dependencies...
    [4/4] Building fresh packages...
    success Installed "[email protected]" with binaries:
          - esbuild
    Done in 0.86s.
    
    opened by zeromancer 27
  • module2.require is not a function when bundling for node

    module2.require is not a function when bundling for node

    Given:

    test.js:

    require('./test2')
    

    test2.js:

    console.log(typeof module.require('crypto'))
    

    And running:

    $ node test.js 
    object
    
    $ esbuild --version
    0.7.15
    
    $ node <(npx esbuild --bundle --platform=node test.js)
    /dev/fd/11:11
      console.log(typeof module2.require("crypto"));
                                 ^
    
    TypeError: module2.require is not a function
    

    When I look at the bundled output, it seems that no arguments are passed in to require_test2:

    var __commonJS = (callback, module2) => () => {
      if (!module2) {
        module2 = {exports: {}};
        callback(module2.exports, module2);
      }
      return module2.exports;
    };
    
    // test2.js
    var require_test2 = __commonJS((exports, module2) => {
      console.log(typeof module2.require("crypto"));
    });
    
    // test.js
    require_test2();
    

    This pattern is used in the real world, for example here:

    https://github.com/apollographql/apollo-server/blob/570f548b88750a06fbf5f67a4abe78fb0f870ccd/packages/apollo-server-core/src/utils/createSHA.ts#L5-L7

    I've also tried passing --define:module.require=require and --define:module2.require=require but neither of them seem to have any effect (should I open a separate bug for that?)

    opened by mhart 26
  • Different strategy for installing platform-specific binaries

    Different strategy for installing platform-specific binaries

    Hi! πŸ‘‹πŸ»

    We're looking to integrate esbuild with the Netlify CLI and some users are reporting permission-related errors when installing the application, which trace back to https://github.com/evanw/esbuild/issues/369.

    I understand that this is a result of the UID/GID switching that npm does when running scripts, which is problematic when the package is installed as root.

    Rather than manually fetching the appropriate binary as part of the postinstall script, could the esbuild package list the various platform-specific packages as optionalDependencies, and shift to npm itself the responsibility of figuring out which packages to installed based on the cpu and os properties? We're doing this for one of our packages that also includes a Go binary and it works well.

    I'm happy to contribute with a pull request, but I wanted to check whether this is something you'd be interested in, or even if it's something you've already considered and discarded for a particular reason.

    Thanks in advance!

    opened by eduardoboucas 25
  • pnp: `esbuild@0.15.3` unable to resolve esm packages

    pnp: `[email protected]` unable to resolve esm packages

    To Reproduce

    yarn init -2
    yarn add strtok3 esbuild
    echo "import * as strtok3 from 'strtok3';" > index.js
    yarn esbuild index.js --bundle
    

    Result

    ✘ [ERROR] Could not resolve "strtok3"
    
        index.js:1:25:
          1 β”‚ import * as strtok3 from 'strtok3';
            β•΅                          ~~~~~~~~~
    
      You can mark the path "strtok3" as external to exclude it from the bundle, which will remove this
      error.
    
    opened by YXL76 0
  • Feature Request: Expose `OnRebuild` to the CLI e.g. --on-rebuild=./my-script.sh

    Feature Request: Expose `OnRebuild` to the CLI e.g. --on-rebuild=./my-script.sh

    I am really enjoying using the CLI exclusively for a small project. No build scripts in sight and have gotten pretty far. It feels great! Thank you for making ESBuild ❀️‍πŸ”₯

    I am hoping to run an unrelated external command after the watcher rebuild completes. I know I can do this if I switch to using the JS API. I would just love to stay the course with the CLI.

    After reading through the discussion on this earlier issue (https://github.com/evanw/esbuild/issues/1688), I am left wondering what reasons there may be for the CLI not having this functionalityβ€”or if I could open a PR to add it in there. I'm not super familiar with GO, but I'm happy to give it a go. Ha ha πŸ’€πŸ”¨

    For example:

    esbuild ./entry.ts --outfile=./build/app.js --bundle --minify --sourcemap --tree-shaking=true '--external:*.otf' --loader:.svg=dataurl --watch --on-rebuild='./my-script.sh'
    
    esbuild ./entry.ts --outfile=./build/app.js --bundle --minify --sourcemap --tree-shaking=true '--external:*.otf' --loader:.svg=dataurl --watch --on-rebuild='echo "OK Cool"'
    
    opened by johnnybenson 0
  • Include `new URL(

    Include `new URL("...", import.meta.url)` references in the import graph.

    There are important use cases when it is valuable to get the bundled URL of a file, such as for web worker instantiation: https://github.com/evanw/esbuild/issues/312

    This PR allows esbuild to handle the most portable way to instantiate a module web worker (which works natively in browsers/node, and is understood by a lot of other bundlers already):

    const workerURL = new URL("./worker.js", import.meta.url);
    
    // Either construct directly:
    new Worker(workerURL, { type: "module" });
    
    // Or construct using a trampoline (needed if the worker code is on a different origin than the current page, e.g. on a CDN):
    const blob = new Blob([`import "${workerURL}";`], { type: "text/javascript" });
    new Worker(URL.createObjectURL(blob), { type: "module" });
    

    This PR implements support by recording such relative URLs in the import graph during AST parsing, thanks in part to @firien here. However, it still has issues:

    • It's currently hardcoded to detect .ts and .js suffixes so I can test it. But:
      • In TypeScript, it should be possible to use import paths without a file extension.
      • Other file types (e.g. .tsx and .jsx) should be included by default, possibly any file types as long as the file exists at the referenced relative path (to fully address #795).
    • Given that this relies on import.meta.url, it should probably be disabled (or even error) for CJS output.
    • Is it okay to hardcode detection for new URL as opposed to looking for URL constructors in other ways?
    • I haven't added tests yet.

    @evanw Could I ask if you think the approach in this PR will work, and the best way to address the issues listed above?

    opened by lgarron 0
  • bug(v0.14.51): TSConfig JSX settings override API arguments for `--bundle` mode

    bug(v0.14.51): TSConfig JSX settings override API arguments for `--bundle` mode

    The recent TSConfig inference seems to have introduced a small bug where, in bundle mode, the provided { jsx, jsxFactory } args will be overridden by the local TSConfig.

    I have a project where we have { jsx: "preserve" } in TSConfig, and I am telling ESBuild to build({ bundle: true, jsx: "transform", jsxFactory: "React.createElement" }), but it is emitting the JSX syntax in the output rather than transforming it (i.e. tsconfig.jsons preserve setting is taking precedence). The untransformed output is not a valid program, and Node throws "unexpected character <". Building with { bundle: false } does not reproduce this issue.

    breaking 
    opened by ctjlewis 6
  • fix: don't write pnpapi binary into own pkg

    fix: don't write pnpapi binary into own pkg

    583569e8f5a16b64e8e1ca23e224f9092ad4712d changed the PnP workaround so that the binary is copied into the esbuild package location instead of a global cache dir. However, packages should never write into their own folder as it (usually) is read-only: https://yarnpkg.com/advanced/rulebook/#packages-should-never-write-inside-their-own-folder-outside-of-postinstall

    In most cases this worked because esbuild is automatically unplugged due to its postinstall script and therefore its folder becomes writeable. However, as soon as you disable scripts for the package or globally in .yarnrc.yml, esbuild won't be unplugged any longer, its folder becomes read-only and everything breaks. So instead, this PR writes the PnP binary to node_modules/.esbuild/<version>/.

    opened by jonaskuske 1
  • Treeshaking Objects with constant string field

    Treeshaking Objects with constant string field

    Good day!

    The module ./ab.js is exporting two objects:

    const keyB = "b";
    
    export const a = {
      a: 1,
    };
    export const b = {
      [keyB]: 1,
    };
    

    Both objects are side effect free, but even if the main.js entry file is re-exporting the module like:

    export { a } from './ab';
    

    The resulting output is:

    var keyB = "b";
    var a = {
      a: 1
    };
    var b = {
      [keyB]: 1
    };
    export {
      a
    };
    

    Only when I change ./ab.js to:

    export const a = {
      a: 1,
    };
    export const b = {
      b: 1,
    };
    

    The b object is treeshaken.

    Here is a link to the esbuild playground: https://hyrious.me/esbuild-repl/?version=0.14.54&mode=build&modules=%5B%5B%22main.js%22%2C%22export+%7B+a+%7D+from+%27.%2Fab%27%3B%22%2C1%5D%2C%5B%22ab.js%22%2C%22const+keyB+%3D+%5C%22b%5C%22%3B%5Cn%5Cnexport+const+a+%3D+%7B%5Cn++a%3A+1%2C%5Cn%7D%3B%5Cnexport+const+b+%3D+%7B%5Cn++%5BkeyB%5D%3A+1%2C%5Cn%7D%3B%22%2C0%5D%5D&buildOptions=%7B%22bundle%22%3Atrue%2C%22format%22%3A%22esm%22%2C%22splitting%22%3Atrue%7D

    And this is how rollup is handling it: https://rollupjs.org/repl/?version=2.77.2&shareable=JTdCJTIybW9kdWxlcyUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjJtYWluLmpzJTIyJTJDJTIyY29kZSUyMiUzQSUyMmV4cG9ydCUyMCU3QiUyMGElMjAlN0QlMjBmcm9tJTIwJy4lMkZhYiclM0IlMjIlMkMlMjJpc0VudHJ5JTIyJTNBdHJ1ZSU3RCUyQyU3QiUyMm5hbWUlMjIlM0ElMjJhYi5qcyUyMiUyQyUyMmNvZGUlMjIlM0ElMjJjb25zdCUyMGtleUIlMjAlM0QlMjAlNUMlMjJiJTVDJTIyJTNCJTVDbiU1Q25leHBvcnQlMjBjb25zdCUyMGElMjAlM0QlMjAlN0IlNUNuJTIwJTIwYSUzQSUyMDElMkMlNUNuJTdEJTNCJTVDbmV4cG9ydCUyMGNvbnN0JTIwYiUyMCUzRCUyMCU3QiU1Q24lMjAlMjAlNUJrZXlCJTVEJTNBJTIwMSUyQyU1Q24lN0QlM0IlMjIlMkMlMjJpc0VudHJ5JTIyJTNBZmFsc2UlN0QlNUQlMkMlMjJvcHRpb25zJTIyJTNBJTdCJTIyZm9ybWF0JTIyJTNBJTIyZXMlMjIlMkMlMjJuYW1lJTIyJTNBJTIybXlCdW5kbGUlMjIlMkMlMjJhbWQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMiUyMiU3RCUyQyUyMmdsb2JhbHMlMjIlM0ElN0IlN0QlN0QlMkMlMjJleGFtcGxlJTIyJTNBbnVsbCU3RA==

    opened by KingSora 0
Releases(v0.15.3)
  • v0.15.3(Aug 14, 2022)

    • Change the Yarn PnP manifest to a singleton (#2463)

      Previously esbuild searched for the Yarn PnP manifest in the parent directories of each file. But with Yarn's enableGlobalCache setting it's possible to configure Yarn PnP's implementation to reach outside of the directory subtree containing the Yarn PnP manifest. This was causing esbuild to fail to bundle projects with the enableGlobalCache setting enabled.

      To handle this case, esbuild will now only search for the Yarn PnP manifest in the current working directory of the esbuild process. If you're using esbuild's CLI, this means you will now have to cd into the appropriate directory first. If you're using esbuild's API, you can override esbuild's value for the current working directory with the absWorkingDir API option.

    • Fix Yarn PnP resolution failures due to backslashes in paths on Windows (#2462)

      Previously dependencies of a Yarn PnP virtual dependency failed to resolve on Windows. This was because Windows uses \ instead of / as a path separator, and the path manipulation algorithms used for Yarn PnP expected /. This release converts \ into / in Windows paths, which fixes this issue.

    • Fix sideEffects patterns containing slashes on Windows (#2465)

      The sideEffects field in package.json lets you specify an array of patterns to mark which files have side effects (which causes all other files to be considered to not have side effects by exclusion). That looks like this:

      "sideEffects": [
        "**/index.js",
        "**/index.prod.js"
      ]
      

      However, the presence of the / character in the pattern meant that the pattern failed to match Windows-style paths, which broke sideEffects on Windows in this case. This release fixes this problem by adding additional code to handle Windows-style paths.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.2(Aug 12, 2022)

    • Fix Yarn PnP issue with packages containing index.js (#2455, #2461)

      Yarn PnP's tests require the resolved paths to end in /. That's not how the rest of esbuild's internals work, however, and doing this messed up esbuild's node module path resolution regarding automatically-detected index.js files. Previously packages that relied on implicit index.js resolution rules didn't work with esbuild under Yarn PnP. Removing this slash has fixed esbuild's path resolution behavior regarding index.js, which should now the same both with and without Yarn PnP.

    • Fix Yarn PnP support for extends in tsconfig.json (#2456)

      Previously using extends in tsconfig.json with a path in a Yarn PnP package didn't work. This is because the process of setting up package path resolution rules requires parsing tsconfig.json files (due to the baseUrl and paths features) and resolving extends to a package path requires package path resolution rules to already be set up, which is a circular dependency. This cycle is broken by using special rules for extends in tsconfig.json that bypasses esbuild's normal package path resolution process. This is why using extends with a Yarn PnP package didn't automatically work. With this release, these special rules have been modified to check for a Yarn PnP manifest so this case should work now.

    • Fix Yarn PnP support in esbuild-wasm (#2458)

      When running esbuild via WebAssembly, Yarn PnP support previously failed because Go's file system internals return EINVAL when trying to read a .zip file as a directory when run with WebAssembly. This was unexpected because Go's file system internals return ENOTDIR for this case on native. This release updates esbuild to treat EINVAL like ENOTDIR in this case, which fixes using esbuild-wasm to bundle a Yarn PnP project.

      Note that to be able to use esbuild-wasm for Yarn PnP successfully, you currently have to run it using node instead of yarn node. This is because the file system shim that Yarn overwrites node's native file system API with currently generates invalid file descriptors with negative values when inside a .zip file. This prevents esbuild from working correctly because Go's file system internals don't expect syscalls that succeed without an error to return an invalid file descriptor. Yarn is working on fixing their use of invalid file descriptors.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.1(Aug 10, 2022)

    • Update esbuild's Yarn Plug'n'Play implementation to match the latest specification changes (#2452, #2453)

      This release updates esbuild's implementation of Yarn Plug'n'Play to match some changes to Yarn's specification that just landed. The changes are as follows:

      • Check for platform-specific absolute paths instead of always for the / prefix

        The specification previously said that Yarn Plug'n'Play path resolution rules should not apply for paths that start with /. The intent was to avoid accidentally processing absolute paths. However, absolute paths on Windows such as C:\project start with drive letters instead of with /. So the specification was changed to instead explicitly avoid processing absolute paths.

      • Make $$virtual an alias for __virtual__

        Supporting Yarn-style path resolution requires implementing a custom Yarn-specific path traversal scheme where certain path segments are considered no-ops. Specifically any path containing segments of the form __virtual__/<whatever>/<n> where <n> is an integer must be treated as if they were n times the .. operator instead (the <whatever> path segment is ignored). So /path/to/project/__virtual__/xyz/2/foo.js maps to the underlying file /path/to/project/../../foo.js. This scheme makes it possible for Yarn to get node (and esbuild) to load the same file multiple times (which is sometimes required for correctness) without actually duplicating the file on the file system.

        However, old versions of Yarn used to use $$virtual instead of __virtual__. This was changed because $$virtual was error-prone due to the use of the $ character, which can cause bugs when it's not correctly escaped within regular expressions. Now that esbuild makes $$virtual an alias for __virtual__, esbuild should now work with manifests from these old Yarn versions.

      • Ignore PnP manifests in virtual directories

        The specification describes the algorithm for how to find the Plug'n'Play manifest when starting from a certain point in the file system: search through all parent directories in reverse order until the manifest is found. However, this interacts poorly with virtual paths since it can end up finding a virtual copy of the manifest instead of the original. To avoid this, esbuild now ignores manifests in virtual directories so that the search for the manifest will continue and find the original manifest in another parent directory later on.

      These fixes mean that esbuild's implementation of Plug'n'Play now matches Yarn's implementation more closely, and esbuild can now correctly build more projects that use Plug'n'Play.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.0(Aug 10, 2022)

    This release contains backwards-incompatible changes. Since esbuild is before version 1.0.0, these changes have been released as a new minor version to reflect this (as recommended by npm). You should either be pinning the exact version of esbuild in your package.json file or be using a version range syntax that only accepts patch upgrades such as ~0.14.0. See the documentation about semver for more information.

    • Implement the Yarn Plug'n'Play module resolution algorithm (#154, #237, #1263, #2451)

      Node comes with a package manager called npm, which installs packages into a node_modules folder. Node and esbuild both come with built-in rules for resolving import paths to packages within node_modules, so packages installed via npm work automatically without any configuration. However, many people use an alternative package manager called Yarn. While Yarn can install packages using node_modules, it also offers a different package installation strategy called Plug'n'Play, which is often shortened to "PnP" (not to be confused with pnpm, which is an entirely different unrelated package manager).

      Plug'n'Play installs packages as .zip files on your file system. The packages are never actually unzipped. Since Node doesn't know anything about Yarn's package installation strategy, this means you can no longer run your code with Node as it won't be able to find your packages. Instead, you need to run your code with Yarn, which applies patches to Node's file system APIs before running your code. These patches attempt to make zip files seem like normal directories. When running under Yarn, using Node's file system API to read ./some.zip/lib/file.js actually automatically extracts lib/file.js from ./some.zip at run-time as if it was a normal file. Other file system APIs behave similarly. However, these patches don't work with esbuild because esbuild is not written in JavaScript; it's a native binary executable that interacts with the file system directly through the operating system.

      Previously the workaround for using esbuild with Plug'n'Play was to use the @yarnpkg/esbuild-plugin-pnp plugin with esbuild's JavaScript API. However, this wasn't great because the plugin needed to potentially intercept every single import path and file load to check whether it was a Plug'n'Play package, which has an unusually high performance cost. It also meant that certain subtleties of path resolution rules within a .zip file could differ slightly from the way esbuild normally works since path resolution inside .zip files was implemented by Yarn, not by esbuild (which is due to a limitation of esbuild's plugin API).

      With this release, esbuild now contains an independent implementation of Yarn's Plug'n'Play algorithm (which is used when esbuild finds a .pnp.js, .pnp.cjs, or .pnp.data.json file in the directory tree). Creating additional implementations of this algorithm recently became possible because Yarn's package manifest format was recently documented: https://yarnpkg.com/advanced/pnp-spec/. This should mean that you can now use esbuild to bundle Plug'n'Play projects without any additional configuration (so you shouldn't need @yarnpkg/esbuild-plugin-pnp anymore). Bundling these projects should now happen much faster as Yarn no longer even needs to be run at all. Bundling the Yarn codebase itself with esbuild before and after this change seems to demonstrate over a 10x speedup (3.4s to 0.24s). And path resolution rules within Yarn packages should now be consistent with how esbuild handles regular Node packages. For example, fields such as module and browser in package.json files within .zip files should now be respected.

      Keep in mind that this is brand new code and there may be some initial issues to work through before esbuild's implementation is solid. Yarn's Plug'n'Play specification is also brand new and may need some follow-up edits to guide new implementations to match Yarn's exact behavior. If you try this out, make sure to test it before committing to using it, and let me know if anything isn't working as expected. Should you need to debug esbuild's path resolution, you may find --log-level=verbose helpful.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.54(Aug 8, 2022)

    • Fix optimizations for calls containing spread arguments (#2445)

      This release fixes the handling of spread arguments in the optimization of /* @__PURE__ */ comments, empty functions, and identity functions:

      // Original code
      function empty() {}
      function identity(x) { return x }
      /* @__PURE__ */ a(...x)
      /* @__PURE__ */ new b(...x)
      empty(...x)
      identity(...x)
      
      // Old output (with --minify --tree-shaking=true)
      ...x;...x;...x;...x;
      
      // New output (with --minify --tree-shaking=true)
      function identity(n){return n}[...x];[...x];[...x];identity(...x);
      

      Previously esbuild assumed arguments with side effects could be directly inlined. This is almost always true except for spread arguments, which are not syntactically valid on their own and which have the side effect of causing iteration, which might have further side effects. Now esbuild will wrap these elements in an unused array so that they are syntactically valid and so that the iteration side effects are preserved.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.53(Aug 2, 2022)

    This release fixes a minor issue with the previous release: I had to rename the package esbuild-linux-loong64 to @esbuild/linux-loong64 in the contributed PR because someone registered the package name before I could claim it, and I missed a spot. Hopefully everything is working after this release. I plan to change all platform-specific package names to use the @esbuild/ scope at some point to avoid this problem in the future.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.52(Aug 2, 2022)

    • Allow binary data as input to the JS transform and build APIs (#2424)

      Previously esbuild's transform and build APIs could only take a string. However, some people want to use esbuild to convert binary data to base64 text. This is problematic because JavaScript strings represent UTF-16 text and esbuild internally operates on arrays of bytes, so all strings coming from JavaScript undergo UTF-16 to UTF-8 conversion before use. This meant that using esbuild in this way was doing base64 encoding of the UTF-8 encoding of the text, which was undesired.

      With this release, esbuild now accepts Uint8Array in addition to string as an input format for the transform and build APIs. Now you can use esbuild to convert binary data to base64 text:

      // Original code
      import esbuild from 'esbuild'
      console.log([
        (await esbuild.transform('\xFF', { loader: 'base64' })).code,
        (await esbuild.build({ stdin: { contents: '\xFF', loader: 'base64' }, write: false })).outputFiles[0].text,
      ])
      console.log([
        (await esbuild.transform(new Uint8Array([0xFF]), { loader: 'base64' })).code,
        (await esbuild.build({ stdin: { contents: new Uint8Array([0xFF]), loader: 'base64' }, write: false })).outputFiles[0].text,
      ])
      
      // Old output
      [ 'module.exports = "w78=";\n', 'module.exports = "w78=";\n' ]
      /* ERROR: The input to "transform" must be a string */
      
      // New output
      [ 'module.exports = "w78=";\n', 'module.exports = "w78=";\n' ]
      [ 'module.exports = "/w==";\n', 'module.exports = "/w==";\n' ]
      
    • Update the getter for text in build results (#2423)

      Output files in build results returned from esbuild's JavaScript API have both a contents and a text property to return the contents of the output file. The contents property is a binary UTF-8 Uint8Array and the text property is a JavaScript UTF-16 string. The text property is a getter that does the UTF-8 to UTF-16 conversion only if it's needed for better performance.

      Previously if you mutate the build results object, you had to overwrite both contents and text since the value returned from the text getter is the original text returned by esbuild. Some people find this confusing so with this release, the getter for text has been updated to do the UTF-8 to UTF-16 conversion on the current value of the contents property instead of the original value.

    • Publish builds for Linux LoongArch 64-bit (#1804, #2373)

      This release upgrades to Go 1.19, which now includes support for LoongArch 64-bit processors. LoongArch 64-bit builds of esbuild will now be published to npm, which means that in theory they can now be installed with npm install esbuild. This was contributed by @beyond-1234.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.51(Jul 28, 2022)

    • Add support for React 17's automatic JSX transform (#334, #718, #1172, #2318, #2349)

      This adds support for the new "automatic" JSX runtime from React 17+ to esbuild for both the build and transform APIs.

      New CLI flags and API options:

      • --jsx, jsx β€” Set this to "automatic" to opt in to this new transform
      • --jsx-dev, jsxDev β€” Toggles development mode for the automatic runtime
      • --jsx-import-source, jsxImportSource β€” Overrides the root import for runtime functions (default "react")

      New JSX pragma comments:

      • @jsxRuntime β€” Sets the runtime (automatic or classic)
      • @jsxImportSource β€” Sets the import source (only valid with automatic runtime)

      The existing @jsxFragment and @jsxFactory pragma comments are only valid with "classic" runtime.

      TSConfig resolving: Along with accepting the new options directly via CLI or API, option inference from tsconfig.json compiler options was also implemented:

      • "jsx": "preserve" or "jsx": "react-native" β†’ Same as --jsx=preserve in esbuild
      • "jsx": "react" β†’ Same as --jsx=transform in esbuild (which is the default behavior)
      • "jsx": "react-jsx" β†’ Same as --jsx=automatic in esbuild
      • "jsx": "react-jsxdev" β†’ Same as --jsx=automatic --jsx-dev in esbuild

      It also reads the value of "jsxImportSource" from tsconfig.json if specified.

      For react-jsx it's important to note that it doesn't implicitly disable --jsx-dev. This is to support the case where a user sets "react-jsx" in their tsconfig.json but then toggles development mode directly in esbuild.

      esbuild vs Babel vs TS vs...

      There are a few differences between the various technologies that implement automatic JSX runtimes. The JSX transform in esbuild follows a mix of Babel's and TypeScript's behavior:

      • When an element has __source or __self props:

        • Babel: Print an error about a deprecated transform plugin
        • TypeScript: Allow the props
        • swc: Hard crash
        • esbuild: Print an error β€” Following Babel was chosen for this one because this might help people catch configuration issues where JSX files are being parsed by multiple tools
      • Element has an "implicit true" key prop, e.g. <a key />:

        • Babel: Print an error indicating that "key" props require an explicit value
        • TypeScript: Silently omit the "key" prop
        • swc: Hard crash
        • esbuild: Print an error like Babel β€” This might help catch legitimate programming mistakes
      • Element has spread children, e.g. <a>{...children}</a>

        • Babel: Print an error stating that React doesn't support spread children
        • TypeScript: Use static jsx function and pass children as-is, including spread operator
        • swc: same as Babel
        • esbuild: Same as TypeScript

      Also note that TypeScript has some bugs regarding JSX development mode and the generation of lineNumber and columnNumber values. Babel's values are accurate though, so esbuild's line and column numbers match Babel. Both numbers are 1-based and columns are counted in terms of UTF-16 code units.

      This feature was contributed by @jgoz.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.50(Jul 25, 2022)

    • Emit names in source maps (#1296)

      The source map specification includes an optional names field that can associate an identifier with a mapping entry. This can be used to record the original name for an identifier, which is useful if the identifier was renamed to something else in the generated code. When esbuild was originally written, this field wasn't widely used, but now there are some debuggers that make use of it to provide better debugging of minified code. With this release, esbuild now includes a names field in the source maps that it generates. To save space, the original name is only recorded when it's different from the final name.

    • Update parser for arrow functions with initial default type parameters in .tsx files (#2410)

      TypeScript 4.6 introduced a change to the parsing of JSX syntax in .tsx files. Now a < token followed by an identifier and then a = token is parsed as an arrow function with a default type parameter instead of as a JSX element. This release updates esbuild's parser to match TypeScript's parser.

    • Fix an accidental infinite loop with --define substitution (#2407)

      This is a fix for a regression that was introduced in esbuild version 0.14.44 where certain --define substitutions could result in esbuild crashing with a stack overflow. The problem was an incorrect fix for #2292. The fix merged the code paths for --define and --jsx-factory rewriting since the value substitution is now the same for both. However, doing this accidentally made --define substitution recursive since the JSX factory needs to be able to match against --define substitutions to integrate with the --inject feature. The fix is to only do one additional level of matching against define substitutions, and to only do this for JSX factories. Now these cases are able to build successfully without a stack overflow.

    • Include the "public path" value in hashes (#2403)

      The --public-path= configuration value affects the paths that esbuild uses to reference files from other files and is used in various situations such as cross-chunk imports in JS and references to asset files from CSS files. However, it wasn't included in the hash calculations used for file names due to an oversight. This meant that changing the public path setting incorrectly didn't result in the hashes in file names changing even though the contents of the files changed. This release fixes the issue by including a hash of the public path in all non-asset output files.

    • Fix a cross-platform consistency bug (#2383)

      Previously esbuild would minify 0xFFFF_FFFF_FFFF_FFFF as 0xffffffffffffffff (18 bytes) on arm64 chips and as 18446744073709552e3 (19 bytes) on x86_64 chips. The reason was that the number was converted to a 64-bit unsigned integer internally for printing as hexadecimal, the 64-bit floating-point number 0xFFFF_FFFF_FFFF_FFFF is actually 0x1_0000_0000_0000_0180 (i.e. it's rounded up, not down), and converting float64 to uint64 is implementation-dependent in Go when the input is out of bounds. This was fixed by changing the upper limit for which esbuild uses hexadecimal numbers during minification to 0xFFFF_FFFF_FFFF_F800, which is the next representable 64-bit floating-point number below 0x1_0000_0000_0000_0180, and which fits in a uint64. As a result, esbuild will now consistently never minify 0xFFFF_FFFF_FFFF_FFFF as 0xffffffffffffffff anymore, which means the output should now be consistent across platforms.

    • Fix a hang with the synchronous API when the package is corrupted (#2396)

      An error message is already thrown when the esbuild package is corrupted and esbuild can't be run. However, if you are using a synchronous call in the JavaScript API in worker mode, esbuild will use a child worker to initialize esbuild once so that the overhead of initializing esbuild can be amortized across multiple synchronous API calls. However, errors thrown during initialization weren't being propagated correctly which resulted in a hang while the main thread waited forever for the child worker to finish initializing. With this release, initialization errors are now propagated correctly so calling a synchronous API call when the package is corrupted should now result in an error instead of a hang.

    • Fix tsconfig.json files that collide with directory names (#2411)

      TypeScript lets you write tsconfig.json files with extends clauses that refer to another config file using an implicit .json file extension. However, if the config file without the .json extension existed as a directory name, esbuild and TypeScript had different behavior. TypeScript ignores the directory and continues looking for the config file by adding the .json extension while esbuild previously terminated the search and then failed to load the config file (because it's a directory). With this release, esbuild will now ignore exact matches when resolving extends fields in tsconfig.json files if the exact match results in a directory.

    • Add platform to the transform API (#2362)

      The platform option is mainly relevant for bundling because it mostly affects path resolution (e.g. activating the "browser" field in package.json files), so it was previously only available for the build API. With this release, it has additionally be made available for the transform API for a single reason: you can now set --platform=node when transforming a string so that esbuild will add export annotations for node, which is only relevant when --format=cjs is also present.

      This has to do with an implementation detail of node that parses the AST of CommonJS files to discover named exports when importing CommonJS from ESM. However, this new addition to esbuild's API is of questionable usefulness. Node's loader API (the main use case for using esbuild's transform API like this) actually bypasses the content returned from the loader and parses the AST that's present on the file system, so you won't actually be able to use esbuild's API for this. See the linked issue for more information.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.49(Jul 10, 2022)

    • Keep inlined constants when direct eval is present (#2361)

      Version 0.14.19 of esbuild added inlining of certain const variables during minification, which replaces all references to the variable with the initializer and then removes the variable declaration. However, this could generate incorrect code when direct eval is present because the direct eval could reference the constant by name. This release fixes the problem by preserving the const variable declaration in this case:

      // Original code
      console.log((() => { const x = 123; return x + eval('x') }))
      
      // Old output (with --minify)
      console.log(()=>123+eval("x"));
      
      // New output (with --minify)
      console.log(()=>{const x=123;return 123+eval("x")});
      
    • Fix an incorrect error in TypeScript when targeting ES5 (#2375)

      Previously when compiling TypeScript code to ES5, esbuild could incorrectly consider the following syntax forms as a transformation error:

      0 ? ([]) : 1 ? ({}) : 2;
      

      The error messages looked like this:

      ✘ [ERROR] Transforming destructuring to the configured target environment ("es5") is not supported yet
      
          example.ts:1:5:
            1 β”‚ 0 ? ([]) : 1 ? ({}) : 2;
              β•΅      ^
      
      ✘ [ERROR] Transforming destructuring to the configured target environment ("es5") is not supported yet
      
          example.ts:1:16:
            1 β”‚ 0 ? ([]) : 1 ? ({}) : 2;
              β•΅                 ^
      

      These parenthesized literals followed by a colon look like the start of an arrow function expression followed by a TypeScript return type (e.g. ([]) : 1 could be the start of the TypeScript arrow function ([]): 1 => 1). Unlike in JavaScript, parsing arrow functions in TypeScript requires backtracking. In this case esbuild correctly determined that this expression wasn't an arrow function after all but the check for destructuring was incorrectly not covered under the backtracking process. With this release, the error message is now only reported if the parser successfully parses an arrow function without backtracking.

    • Fix generated TypeScript enum comments containing */ (#2369, #2371)

      TypeScript enum values that are equal to a number or string literal are inlined (references to the enum are replaced with the literal value) and have a /* ... */ comment after them with the original enum name to improve readability. However, this comment is omitted if the enum name contains the character sequence */ because that would end the comment early and cause a syntax error:

      // Original TypeScript
      enum Foo { '/*' = 1, '*/' = 2 }
      console.log(Foo['/*'], Foo['*/'])
      
      // Generated JavaScript
      console.log(1 /* /* */, 2);
      

      This was originally handled correctly when TypeScript enum inlining was initially implemented since it was only supported within a single file. However, when esbuild was later extended to support TypeScript enum inlining across files, this special case where the enum name contains */ was not handled in that new code. Starting with this release, esbuild will now handle enums with names containing */ correctly when they are inlined across files:

      // foo.ts
      export enum Foo { '/*' = 1, '*/' = 2 }
      
      // bar.ts
      import { Foo } from './foo'
      console.log(Foo['/*'], Foo['*/'])
      
      // Old output (with --bundle --format=esm)
      console.log(1 /* /* */, 2 /* */ */);
      
      // New output (with --bundle --format=esm)
      console.log(1 /* /* */, 2);
      

      This fix was contributed by @magic-akari.

    • Allow declare class fields to be initialized (#2380)

      This release fixes an oversight in the TypeScript parser that disallowed initializers for declare class fields. TypeScript actually allows the following limited initializer expressions for readonly fields:

      declare const enum a { b = 0 }
      
      class Foo {
        // These are allowed by TypeScript
        declare readonly a = 0
        declare readonly b = -0
        declare readonly c = 0n
        declare readonly d = -0n
        declare readonly e = 'x'
        declare readonly f = `x`
        declare readonly g = a.b
        declare readonly h = a['b']
      
        // These are not allowed by TypeScript
        declare readonly x = (0)
        declare readonly y = null
        declare readonly z = -a.b
      }
      

      So with this release, esbuild now allows initializers for declare class fields too. To future-proof this in case TypeScript allows more expressions as initializers in the future (such as null), esbuild will allow any expression as an initializer and will leave the specifics of TypeScript's special-casing here to the TypeScript type checker.

    • Fix a bug in esbuild's feature compatibility table generator (#2365)

      Passing specific JavaScript engines to esbuild's --target flag restricts esbuild to only using JavaScript features that are supported on those engines in the output files that esbuild generates. The data for this feature is automatically derived from this compatibility table with a script: https://kangax.github.io/compat-table/.

      However, the script had a bug that could incorrectly consider a JavaScript syntax feature to be supported in a given engine even when it doesn't actually work in that engine. Specifically this bug happened when a certain aspect of JavaScript syntax has always worked incorrectly in that engine and the bug in that engine has never been fixed. This situation hasn't really come up before because previously esbuild pretty much only targeted JavaScript engines that always fix their bugs, but the two new JavaScript engines that were added in the previous release (Hermes and Rhino) have many aspects of the JavaScript specification that have never been implemented, and may never be implemented. For example, the let and const keywords are not implemented correctly in those engines.

      With this release, esbuild's compatibility table generator script has been fixed and as a result, esbuild will now correctly consider a JavaScript syntax feature to be unsupported in a given engine if there is some aspect of that syntax that is broken in all known versions of that engine. This means that the following JavaScript syntax features are no longer considered to be supported by these engines (represented using esbuild's internal names for these syntax features):

      Hermes:

      • arrow
      • const-and-let
      • default-argument
      • generator
      • optional-catch-binding
      • optional-chain
      • rest-argument
      • template-literal

      Rhino:

      • arrow
      • const-and-let
      • destructuring
      • for-of
      • generator
      • object-extensions
      • template-literal

      IE:

      • const-and-let
    Source code(tar.gz)
    Source code(zip)
  • v0.14.48(Jun 30, 2022)

    • Enable using esbuild in Deno via WebAssembly (#2323)

      The native implementation of esbuild is much faster than the WebAssembly version, but some people don't want to give Deno the --allow-run permission necessary to run esbuild and are ok waiting longer for their builds to finish when using the WebAssembly backend. With this release, you can now use esbuild via WebAssembly in Deno. To do this you will need to import from wasm.js instead of mod.js:

      import * as esbuild from 'https://deno.land/x/[email protected]/wasm.js'
      const ts = 'let test: boolean = true'
      const result = await esbuild.transform(ts, { loader: 'ts' })
      console.log('result:', result)
      

      Make sure you run Deno with --allow-net so esbuild can download the WebAssembly module. Using esbuild like this starts up a worker thread that runs esbuild in parallel (unless you call esbuild.initialize({ worker: false }) to tell esbuild to run on the main thread). If you want to, you can call esbuild.stop() to terminate the worker if you won't be using esbuild anymore and you want to reclaim the memory.

      Note that Deno appears to have a bug where background WebAssembly optimization can prevent the process from exiting for many seconds. If you are trying to use Deno and WebAssembly to run esbuild quickly, you may need to manually call Deno.exit(0) after your code has finished running.

    • Add support for font file MIME types (#2337)

      This release adds support for font file MIME types to esbuild, which means they are now recognized by the built-in local web server and they are now used when a font file is loaded using the dataurl loader. The full set of newly-added file extension MIME type mappings is as follows:

      • .eot => application/vnd.ms-fontobject
      • .otf => font/otf
      • .sfnt => font/sfnt
      • .ttf => font/ttf
      • .woff => font/woff
      • .woff2 => font/woff2
    • Remove "use strict"; when targeting ESM (#2347)

      All ES module code is automatically in strict mode, so a "use strict"; directive is unnecessary. With this release, esbuild will now remove the "use strict"; directive if the output format is ESM. This change makes the generated output file a few bytes smaller:

      // Original code
      'use strict'
      export let foo = 123
      
      // Old output (with --format=esm --minify)
      "use strict";let t=123;export{t as foo};
      
      // New output (with --format=esm --minify)
      let t=123;export{t as foo};
      
    • Attempt to have esbuild work with Deno on FreeBSD (#2356)

      Deno doesn't support FreeBSD, but it's possible to build Deno for FreeBSD with some additional patches on top. This release of esbuild changes esbuild's Deno installer to download esbuild's FreeBSD binary in this situation. This configuration is unsupported although in theory everything should work.

    • Add some more target JavaScript engines (#2357)

      This release adds the Rhino and Hermes JavaScript engines to the set of engine identifiers that can be passed to the --target flag. You can use this to restrict esbuild to only using JavaScript features that are supported on those engines in the output files that esbuild generates.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.47(Jun 20, 2022)

    • Make global names more compact when ||= is available (#2331)

      With this release, the code esbuild generates for the --global-name= setting is now slightly shorter when you don't configure esbuild such that the ||= operator is unsupported (e.g. with --target=chrome80 or --supported:logical-assignment=false):

      // Original code
      exports.foo = 123
      
      // Old output (with --format=iife --global-name=foo.bar.baz --minify)
      var foo=foo||{};foo.bar=foo.bar||{};foo.bar.baz=(()=>{var b=(a,o)=>()=>(o||a((o={exports:{}}).exports,o),o.exports);var c=b(f=>{f.foo=123});return c();})();
      
      // New output (with --format=iife --global-name=foo.bar.baz --minify)
      var foo;((foo||={}).bar||={}).baz=(()=>{var b=(a,o)=>()=>(o||a((o={exports:{}}).exports,o),o.exports);var c=b(f=>{f.foo=123});return c();})();
      
    • Fix --mangle-quoted=false with --minify-syntax=true

      If property mangling is active and --mangle-quoted is disabled, quoted properties are supposed to be preserved. However, there was a case when this didn't happen if --minify-syntax was enabled, since that internally transforms x['y'] into x.y to reduce code size. This issue has been fixed:

      // Original code
      x.foo = x['bar'] = { foo: y, 'bar': z }
      
      // Old output (with --mangle-props=. --mangle-quoted=false --minify-syntax=true)
      x.a = x.b = { a: y, bar: z };
      
      // New output (with --mangle-props=. --mangle-quoted=false --minify-syntax=true)
      x.a = x.bar = { a: y, bar: z };
      

      Notice how the property foo is always used unquoted but the property bar is always used quoted, so foo should be consistently mangled while bar should be consistently not mangled.

    • Fix a minification bug regarding this and property initializers

      When minification is enabled, esbuild attempts to inline the initializers of variables that have only been used once into the start of the following expression to reduce code size. However, there was a bug where this transformation could change the value of this when the initializer is a property access and the start of the following expression is a call expression. This release fixes the bug:

      // Original code
      function foo(obj) {
        let fn = obj.prop;
        fn();
      }
      
      // Old output (with --minify)
      function foo(f){f.prop()}
      
      // New output (with --minify)
      function foo(o){let f=o.prop;f()}
      
    Source code(tar.gz)
    Source code(zip)
  • v0.14.46(Jun 18, 2022)

    • Add the ability to override support for individual syntax features (#2060, #2290, #2308)

      The target setting already lets you configure esbuild to restrict its output by only making use of syntax features that are known to be supported in the configured target environment. For example, setting target to chrome50 causes esbuild to automatically transform optional chain expressions into the equivalent older JavaScript and prevents you from using BigInts, among many other things. However, sometimes you may want to customize this set of unsupported syntax features at the individual feature level.

      Some examples of why you might want to do this:

      • JavaScript runtimes often do a quick implementation of newer syntax features that is slower than the equivalent older JavaScript, and you can get a speedup by telling esbuild to pretend this syntax feature isn't supported. For example, V8 has a long-standing performance bug regarding object spread that can be avoided by manually copying properties instead of using object spread syntax. Right now esbuild hard-codes this optimization if you set target to a V8-based runtime.

      • There are many less-used JavaScript runtimes in addition to the ones present in browsers, and these runtimes sometimes just decide not to implement parts of the specification, which might make sense for runtimes intended for embedded environments. For example, the developers behind Facebook's JavaScript runtime Hermes have decided to not implement classes despite it being a major JavaScript feature that was added seven years ago and that is used in virtually every large JavaScript project.

      • You may be processing esbuild's output with another tool, and you may want esbuild to transform certain features and the other tool to transform certain other features. For example, if you are using esbuild to transform files individually to ES5 but you are then feeding the output into Webpack for bundling, you may want to preserve import() expressions even though they are a syntax error in ES5.

      With this release, you can now use --supported:feature=false to force feature to be unsupported. This will cause esbuild to either rewrite code that uses the feature into older code that doesn't use the feature (if esbuild is able to), or to emit a build error (if esbuild is unable to). For example, you can use --supported:arrow=false to turn arrow functions into function expressions and --supported:bigint=false to make it an error to use a BigInt literal. You can also use --supported:feature=true to force it to be supported, which means esbuild will pass it through without transforming it. Keep in mind that this is an advanced feature. For most use cases you will probably want to just use target instead of using this.

      The full set of currently-allowed features are as follows:

      JavaScript:

      • 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
      • default-argument
      • destructuring
      • dynamic-import
      • exponent-operator
      • export-star-as
      • for-await
      • for-of
      • generator
      • hashbang
      • import-assertions
      • import-meta
      • 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-sticky-and-unicode-flags
      • regexp-unicode-property-escapes
      • rest-argument
      • template-literal
      • top-level-await
      • typeof-exotic-object-is-object
      • unicode-escapes

      CSS:

      • hex-rgba
      • rebecca-purple
      • modern-rgb-hsl
      • inset-property
      • nesting

      Since you can now specify --supported:object-rest-spread=false yourself to work around the V8 performance issue mentioned above, esbuild will no longer automatically transform all instances of object spread when targeting a V8-based JavaScript runtime going forward.

      Note that JavaScript feature transformation is very complex and allowing full customization of the set of supported syntax features could cause bugs in esbuild due to new interactions between multiple features that were never possible before. Consider this to be an experimental feature.

    • Implement extends constraints on infer type variables (#2330)

      TypeScript 4.7 introduced the ability to write an extends constraint after an infer type variable, which looks like this:

      type FirstIfString<T> =
        T extends [infer S extends string, ...unknown[]]
          ? S
          : never;
      

      You can read the blog post for more details: https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#extends-constraints-on-infer-type-variables. Previously this was a syntax error in esbuild but with this release, esbuild can now parse this syntax correctly.

    • Allow define to match optional chain expressions (#2324)

      Previously esbuild's define feature only matched member expressions that did not use optional chaining. With this release, esbuild will now also match those that use optional chaining:

      // Original code
      console.log(a.b, a?.b)
      
      // Old output (with --define:a.b=c)
      console.log(c, a?.b);
      
      // New output (with --define:a.b=c)
      console.log(c, c);
      

      This is for compatibility with Webpack's DefinePlugin, which behaves the same way.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.45(Jun 17, 2022)

    • Add a log message for ambiguous re-exports (#2322)

      In JavaScript, you can re-export symbols from another file using export * from './another-file'. When you do this from multiple files that export different symbols with the same name, this creates an ambiguous export which is causes that name to not be exported. This is harmless if you don't plan on using the ambiguous export name, so esbuild doesn't have a warning for this. But if you do want a warning for this (or if you want to make it an error), you can now opt-in to seeing this log message with --log-override:ambiguous-reexport=warning or --log-override:ambiguous-reexport=error. The log message looks like this:

      β–² [WARNING] Re-export of "common" in "example.js" is ambiguous and has been removed [ambiguous-reexport]
      
        One definition of "common" comes from "a.js" here:
      
          a.js:2:11:
            2 β”‚ export let common = 2
              β•΅            ~~~~~~
      
        Another definition of "common" comes from "b.js" here:
      
          b.js:3:14:
            3 β”‚ export { b as common }
              β•΅               ~~~~~~
      
    • Optimize the output of the JSON loader (#2161)

      The json loader (which is enabled by default for .json files) parses the file as JSON and generates a JavaScript file with the parsed expression as the default export. This behavior is standard and works in both node and the browser (well, as long as you use an import assertion). As an extension, esbuild also allows you to import additional top-level properties of the JSON object directly as a named export. This is beneficial for tree shaking. For example:

      import { version } from 'esbuild/package.json'
      console.log(version)
      

      If you bundle the above code with esbuild, you'll get something like the following:

      // node_modules/esbuild/package.json
      var version = "0.14.44";
      
      // example.js
      console.log(version);
      

      Most of the package.json file is irrelevant and has been omitted from the output due to tree shaking. The way esbuild implements this is to have the JavaScript file that's generated from the JSON look something like this with a separate exported variable for each property on the top-level object:

      // node_modules/esbuild/package.json
      export var name = "esbuild";
      export var version = "0.14.44";
      export var repository = "https://github.com/evanw/esbuild";
      export var bin = {
        esbuild: "bin/esbuild"
      };
      ...
      export default {
        name,
        version,
        repository,
        bin,
        ...
      };
      

      However, this means that if you import the default export instead of a named export, you will get non-optimal output. The default export references all top-level properties, leading to many unnecessary variables in the output. With this release esbuild will now optimize this case to only generate additional variables for top-level object properties that are actually imported:

      // Original code
      import all, { bar } from 'data:application/json,{"foo":[1,2,3],"bar":[4,5,6]}'
      console.log(all, bar)
      
      // Old output (with --bundle --minify --format=esm)
      var a=[1,2,3],l=[4,5,6],r={foo:a,bar:l};console.log(r,l);
      
      // New output (with --bundle --minify --format=esm)
      var l=[4,5,6],r={foo:[1,2,3],bar:l};console.log(r,l);
      

      Notice how there is no longer an unnecessary generated variable for foo since it's never imported. And if you only import the default export, esbuild will now reproduce the original JSON object in the output with all top-level properties compactly inline.

    • Add id to warnings returned from the API

      With this release, warnings returned from esbuild's API now have an id property. This identifies which kind of log message it is, which can be used to more easily filter out certain warnings. For example, reassigning a const variable will generate a message with an id of "assign-to-constant". This also gives you the identifier you need to apply a log override for that kind of message: https://esbuild.github.io/api/#log-override.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.44(Jun 15, 2022)

    • Add a copy loader (#2255)

      You can configure the "loader" for a specific file extension in esbuild, which is a way of telling esbuild how it should treat that file. For example, the text loader means the file is imported as a string while the binary loader means the file is imported as a Uint8Array. If you want the imported file to stay a separate file, the only option was previously the file loader (which is intended to be similar to Webpack's file-loader package). This loader copies the file to the output directory and imports the path to that output file as a string. This is useful for a web application because you can refer to resources such as .png images by importing them for their URL. However, it's not helpful if you need the imported file to stay a separate file but to still behave the way it normally would when the code is run without bundling.

      With this release, there is now a new loader called copy that copies the loaded file to the output directory and then rewrites the path of the import statement or require() call to point to the copied file instead of the original file. This will automatically add a content hash to the output name by default (which can be configured with the --asset-names= setting). You can use this by specifying copy for a specific file extension, such as with --loader:.png=copy.

    • Fix a regression in arrow function lowering (#2302)

      This release fixes a regression with lowering arrow functions to function expressions in ES5. This feature was introduced in version 0.7.2 and regressed in version 0.14.30.

      In JavaScript, regular function expressions treat this as an implicit argument that is determined by how the function is called, but arrow functions treat this as a variable that is captured in the closure from the surrounding lexical scope. This is emulated in esbuild by storing the value of this in a variable before changing the arrow function into a function expression.

      However, the code that did this didn't treat this expressions as a usage of that generated variable. Version 0.14.30 began omitting unused generated variables, which caused the transformation of this to break. This regression happened due to missing test coverage. With this release, the problem has been fixed:

      // Original code
      function foo() {
        return () => this
      }
      
      // Old output (with --target=es5)
      function foo() {
        return function() {
          return _this;
        };
      }
      
      // New output (with --target=es5)
      function foo() {
        var _this = this;
        return function() {
          return _this;
        };
      }
      

      This fix was contributed by @nkeynes.

    • Allow entity names as define values (#2292)

      The "define" feature allows you to replace certain expressions with certain other expressions at compile time. For example, you might want to replace the global identifier IS_PRODUCTION with the boolean value true when building for production. Previously the only expressions you could substitute in were either identifier expressions or anything that is valid JSON syntax. This limitation exists because supporting more complex expressions is more complex (for example, substituting in a require() call could potentially pull in additional files, which would need to be handled). With this release, you can now also now define something as a member expression chain of the form foo.abc.xyz.

    • Implement package self-references (#2312)

      This release implements a rarely-used feature in node where a package can import itself by name instead of using relative imports. You can read more about this feature here: https://nodejs.org/api/packages.html#self-referencing-a-package-using-its-name. For example, assuming the package.json in a given package looks like this:

      // package.json
      {
        "name": "a-package",
        "exports": {
          ".": "./main.mjs",
          "./foo": "./foo.js"
        }
      }
      

      Then any module in that package can reference an export in the package itself:

      // ./a-module.mjs
      import { something } from 'a-package'; // Imports "something" from ./main.mjs.
      

      Self-referencing is also available when using require, both in an ES module, and in a CommonJS one. For example, this code will also work:

      // ./a-module.js
      const { something } = require('a-package/foo'); // Loads from ./foo.js.
      
    • Add a warning for assigning to an import (#2319)

      Import bindings are immutable in JavaScript, and assigning to them will throw an error. So instead of doing this:

      import { foo } from 'foo'
      foo++
      

      You need to do something like this instead:

      import { foo, setFoo } from 'foo'
      setFoo(foo + 1)
      

      This is already an error if you try to bundle this code with esbuild. However, this was previously allowed silently when bundling is disabled, which can lead to confusion for people who don't know about this aspect of how JavaScript works. So with this release, there is now a warning when you do this:

      β–² [WARNING] This assignment will throw because "foo" is an import [assign-to-import]
      
          example.js:2:0:
            2 β”‚ foo++
              β•΅ ~~~
      
        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.
      

      This new warning can be turned off with --log-override:assign-to-import=silent if you don't want to see it.

    • Implement alwaysStrict in tsconfig.json (#2264)

      This release adds alwaysStrict to the set of TypeScript tsconfig.json configuration values that esbuild supports. When this is enabled, esbuild will forbid syntax that isn't allowed in strict mode and will automatically insert "use strict"; at the top of generated output files. This matches the behavior of the TypeScript compiler: https://www.typescriptlang.org/tsconfig#alwaysStrict.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.43(Jun 8, 2022)

    • Fix TypeScript parse error whe a generic function is the first type argument (#2306)

      In TypeScript, the << token may need to be split apart into two < tokens if it's present in a type argument context. This was already correctly handled for all type expressions and for identifier expressions such as in the following code:

      // These cases already worked in the previous release
      let foo: Array<<T>() => T>;
      bar<<T>() => T>;
      

      However, normal expressions of the following form were previously incorrectly treated as syntax errors:

      // These cases were broken but have now been fixed
      foo.bar<<T>() => T>;
      foo?.<<T>() => T>();
      

      With this release, these cases now parsed correctly.

    • Fix minification regression with pure IIFEs (#2279)

      An Immediately Invoked Function Expression (IIFE) is a function call to an anonymous function, and is a way of introducing a new function-level scope in JavaScript since JavaScript lacks a way to do this otherwise. And a pure function call is a function call with the special /* @__PURE__ */ comment before it, which tells JavaScript build tools that the function call can be considered to have no side effects (and can be removed if it's unused).

      Version 0.14.9 of esbuild introduced a regression that changed esbuild's behavior when these two features were combined. If the IIFE body contains a single expression, the resulting output still contained that expression instead of being empty. This is a minor regression because you normally wouldn't write code like this, so this shouldn't come up in practice, and it doesn't cause any correctness issues (just larger-than-necessary output). It's unusual that you would tell esbuild "remove this if the result is unused" and then not store the result anywhere, since the result is unused by construction. But regardless, the issue has now been fixed.

      For example, the following code is a pure IIFE, which means it should be completely removed when minification is enabled. Previously it was replaced by the contents of the IIFE but it's now completely removed:

      // Original code
      /* @__PURE__ */ (() => console.log(1))()
      
      // Old output (with --minify)
      console.log(1);
      
      // New output (with --minify)
      
    • Add log messages for indirect require references (#2231)

      A long time ago esbuild used to warn about indirect uses of require because they break esbuild's ability to analyze the dependencies of the code and cause dependencies to not be bundled, resulting in a potentially broken bundle. However, this warning was removed because many people wanted the warning to be removed. Some packages have code that uses require like this but on a code path that isn't used at run-time, so their code still happens to work even though the bundle is incomplete. For example, the following code will not bundle bindings:

      // Prevent React Native packager from seeing modules required with this
      const nodeRequire = require;
      
      function getRealmConstructor(environment) {
        switch (environment) {
          case "node.js":
          case "electron":
            return nodeRequire("bindings")("realm.node").Realm;
        }
      }
      

      Version 0.11.11 of esbuild removed this warning, which means people no longer have a way to know at compile time whether their bundle is broken in this way. Now that esbuild has custom log message levels, this warning can be added back in a way that should make both people happy. With this release, there is now a log message for this that defaults to the debug log level, which normally isn't visible. You can either do --log-override:indirect-require=warning to make this log message a warning (and therefore visible) or use --log-level=debug to see this and all other debug log messages.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.42(May 29, 2022)

    • Fix a parser hang on invalid CSS (#2276)

      Previously invalid CSS with unbalanced parentheses could cause esbuild's CSS parser to hang. An example of such an input is the CSS file :x(. This hang has been fixed.

    • Add support for custom log message levels

      This release allows you to override the default log level of esbuild's individual log messages. For example, CSS syntax errors are treated as warnings instead of errors by default because CSS grammar allows for rules containing syntax errors to be ignored. However, if you would like for esbuild to consider CSS syntax errors to be build errors, you can now configure that like this:

      • CLI

        $ esbuild example.css --log-override:css-syntax-error=error
        
      • JS API

        let result = await esbuild.build({
          entryPoints: ['example.css'],
          logOverride: {
            'css-syntax-error': 'error',
          },
        })
        
      • Go API

        result := api.Build(api.BuildOptions{
          EntryPoints: []string{"example.ts"},
          LogOverride: map[string]api.LogLevel{
            "css-syntax-error": api.LogLevelError,
          },
        })
        

      You can also now use this feature to silence warnings that you are not interested in. Log messages are referred to by their identifier. Each identifier is stable (i.e. shouldn't change over time) except there is no guarantee that the log message will continue to exist. A given log message may potentially be removed in the future, in which case esbuild will ignore log levels set for that identifier. The current list of supported log level identifiers for use with this feature can be found below:

      JavaScript:

      • assign-to-constant
      • call-import-namespace
      • commonjs-variable-in-esm
      • delete-super-property
      • direct-eval
      • duplicate-case
      • duplicate-object-key
      • empty-import-meta
      • equals-nan
      • equals-negative-zero
      • equals-new-object
      • html-comment-in-js
      • impossible-typeof
      • private-name-will-throw
      • semicolon-after-return
      • suspicious-boolean-not
      • this-is-undefined-in-esm
      • unsupported-dynamic-import
      • unsupported-jsx-comment
      • unsupported-regexp
      • unsupported-require-call

      CSS:

      Bundler:

      • different-path-case
      • ignored-bare-import
      • ignored-dynamic-import
      • import-is-undefined
      • package.json
      • require-resolve-not-external
      • tsconfig.json

      Source maps:

      • invalid-source-mappings
      • sections-in-source-map
      • missing-source-map
      • unsupported-source-map-comment

      Documentation about which identifiers correspond to which log messages will be added in the future, but hasn't been written yet. Note that it's not possible to configure the log level for a build error. This is by design because changing that would cause esbuild to incorrectly proceed in the building process generate invalid build output. You can only configure the log level for non-error log messages (although you can turn non-errors into errors).

    Source code(tar.gz)
    Source code(zip)
  • v0.14.41(May 27, 2022)

    • Fix a minification regression in 0.14.40 (#2270, #2271, #2273)

      Version 0.14.40 substituted string property keys with numeric property keys if the number has the same string representation as the original string. This was done in three places: computed member expressions, object literal properties, and class fields. However, negative numbers are only valid in computed member expressions while esbuild incorrectly applied this substitution for negative numbers in all places. This release fixes the regression by only doing this substitution for negative numbers in computed member expressions.

      This fix was contributed by @susiwen8.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.40(May 27, 2022)

    • Correct esbuild's implementation of "preserveValueImports": true (#2268)

      TypeScript's preserveValueImports setting tells the compiler to preserve unused imports, which can sometimes be necessary because otherwise TypeScript will remove unused imports as it assumes they are type annotations. This setting is useful for programming environments that strip TypeScript types as part of a larger code transformation where additional code is appended later that will then make use of those unused imports, such as with Svelte or Vue.

      This release fixes an issue where esbuild's implementation of preserveValueImports diverged from the official TypeScript compiler. If the import clause is present but empty of values (even if it contains types), then the import clause should be considered a type-only import clause. This was an oversight, and has now been fixed:

      // Original code
      import "keep"
      import { k1 } from "keep"
      import k2, { type t1 } from "keep"
      import {} from "remove"
      import { type t2 } from "remove"
      
      // Old output under "preserveValueImports": true
      import "keep";
      import { k1 } from "keep";
      import k2, {} from "keep";
      import {} from "remove";
      import {} from "remove";
      
      // New output under "preserveValueImports": true (matches the TypeScript compiler)
      import "keep";
      import { k1 } from "keep";
      import k2 from "keep";
      
    • Avoid regular expression syntax errors in older browsers (#2215)

      Previously esbuild always passed JavaScript regular expression literals through unmodified from the input to the output. This is undesirable when the regular expression uses newer features that the configured target environment doesn't support. For example, the d flag (i.e. the match indices feature) is new in ES2022 and doesn't work in older browsers. If esbuild generated a regular expression literal containing the d flag, then older browsers would consider esbuild's output to be a syntax error and none of the code would run.

      With this release, esbuild now detects when an unsupported feature is being used and converts the regular expression literal into a new RegExp() constructor instead. One consequence of this is that the syntax error is transformed into a run-time error, which allows the output code to run (and to potentially handle the run-time error). Another consequence of this is that it allows you to include a polyfill that overwrites the RegExp constructor in older browsers with one that supports modern features. Note that esbuild does not handle polyfills for you, so you will need to include a RegExp polyfill yourself if you want one.

      // Original code
      console.log(/b/d.exec('abc').indices)
      
      // New output (with --target=chrome90)
      console.log(/b/d.exec("abc").indices);
      
      // New output (with --target=chrome89)
      console.log(new RegExp("b", "d").exec("abc").indices);
      

      This is currently done transparently without a warning. If you would like to debug this transformation to see where in your code esbuild is transforming regular expression literals and why, you can pass --log-level=debug to esbuild and review the information present in esbuild's debug logs.

    • Add Opera to more internal feature compatibility tables (#2247, #2252)

      The internal compatibility tables that esbuild uses to determine which environments support which features are derived from multiple sources. Most of it is automatically derived from these ECMAScript compatibility tables, but missing information is manually copied from MDN, GitHub PR comments, and various other websites. Version 0.14.35 of esbuild introduced Opera as a possible target environment which was automatically picked up by the compatibility table script, but the manually-copied information wasn't updated to include Opera. This release fixes this omission so Opera feature compatibility should now be accurate.

      This was contributed by @lbwa.

    • Ignore EPERM errors on directories (#2261)

      Previously bundling with esbuild when inside a sandbox environment which does not have permission to access the parent directory did not work because esbuild would try to read the directory to search for a node_modules folder and would then fail the build when that failed. In practice this caused issues with running esbuild with sandbox-exec on macOS. With this release, esbuild will treat directories with permission failures as empty to allow for the node_modules search to continue past the denied directory and into its parent directory. This means it should now be possible to bundle with esbuild in these situations. This fix is similar to the fix in version 0.9.1 but is for EPERM while that fix was for EACCES.

    • Remove an irrelevant extra "use strict" directive (#2264)

      The presence of a "use strict" directive in the output file is controlled by the presence of one in the entry point. However, there was a bug that would include one twice if the output format is ESM. This bug has been fixed.

    • Minify strings into integers inside computed properties (#2214)

      This release now minifies a["0"] into a[0] when the result is equivalent:

      // Original code
      console.log(x['0'], { '0': x }, class { '0' = x })
      
      // Old output (with --minify)
      console.log(x["0"],{"0":x},class{"0"=x});
      
      // New output (with --minify)
      console.log(x[0],{0:x},class{0=x});
      

      This transformation currently only happens when the numeric property represents an integer within the signed 32-bit integer range.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.39(May 11, 2022)

    • Fix code generation for export default and /* @__PURE__ */ call (#2203)

      The /* @__PURE__ */ comment annotation can be added to function calls to indicate that they are side-effect free. These annotations are passed through into the output by esbuild since many JavaScript tools understand them. However, there was an edge case where printing this comment before a function call caused esbuild to fail to parenthesize a function literal because it thought it was no longer at the start of the expression. This problem has been fixed:

      // Original code
      export default /* @__PURE__ */ (function() {
      })()
      
      // Old output
      export default /* @__PURE__ */ function() {
      }();
      
      // New output
      export default /* @__PURE__ */ (function() {
      })();
      
    • Preserve ... before JSX child expressions (#2245)

      TypeScript 4.5 changed how JSX child expressions that start with ... are emitted. Previously the ... was omitted but starting with TypeScript 4.5, the ... is now preserved instead. This release updates esbuild to match TypeScript's new output in this case:

      // Original code
      console.log(<a>{...b}</a>)
      
      // Old output
      console.log(/* @__PURE__ */ React.createElement("a", null, b));
      
      // New output
      console.log(/* @__PURE__ */ React.createElement("a", null, ...b));
      

      Note that this behavior is TypeScript-specific. Babel doesn't support the ... token at all (it gives the error "Spread children are not supported in React").

    • Slightly adjust esbuild's handling of the browser field in package.json (#2239)

      This release changes esbuild's interpretation of browser path remapping to fix a regression that was introduced in esbuild version 0.14.21. Browserify has a bug where it incorrectly matches package paths to relative paths in the browser field, and esbuild replicates this bug for compatibility with Browserify. I have a set of tests that I use to verify that esbuild's replication of this Browserify is accurate here: https://github.com/evanw/package-json-browser-tests. However, I was missing a test case and esbuild's behavior diverges from Browserify in this case. This release now handles this edge case as well:

      • entry.js:

        require('pkg/sub')
        
      • node_modules/pkg/package.json:

        {
          "browser": {
            "./sub": "./sub/foo.js",
            "./sub/sub.js": "./sub/foo.js"
          }
        }
        
      • node_modules/pkg/sub/foo.js:

        require('sub')
        
      • node_modules/sub/index.js:

        console.log('works')
        

      The import path sub in require('sub') was previously matching the remapping "./sub/sub.js": "./sub/foo.js" but with this release it should now no longer match that remapping. Now require('sub') will only match the remapping "./sub/sub": "./sub/foo.js" (without the trailing .js). Browserify apparently only matches without the .js suffix here.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.38(Apr 21, 2022)

    • Further fixes to TypeScript 4.7 instantiation expression parsing (#2201)

      This release fixes some additional edge cases with parsing instantiation expressions from the upcoming version 4.7 of TypeScript. Previously it was allowed for an instantiation expression to precede a binary operator but with this release, that's no longer allowed. This was sometimes valid in the TypeScript 4.7 beta but is no longer allowed in the latest version of TypeScript 4.7. Fixing this also fixed a regression that was introduced by the previous release of esbuild:

      | Code | TS 4.6.3 | TS 4.7.0 beta | TS 4.7.0 nightly | esbuild 0.14.36 | esbuild 0.14.37 | esbuild 0.14.38 | |----------------|--------------|---------------|------------------|-----------------|-----------------|-----------------| | a<b> == c<d> | Invalid | a == c | Invalid | a == c | a == c | Invalid | | a<b> in c<d> | Invalid | Invalid | Invalid | Invalid | a in c | Invalid | | a<b>>=c<d> | Invalid | Invalid | Invalid | Invalid | a >= c | Invalid | | a<b>=c<d> | Invalid | a < b >= c | a = c | a < b >= c | a = c | a = c | | a<b>>c<d> | a < b >> c | a < b >> c | a < b >> c | a < b >> c | a > c | a < b >> c |

      This table illustrates some of the more significant changes between all of these parsers. The most important part is that esbuild 0.14.38 now matches the behavior of the latest TypeScript compiler for all of these cases.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.37(Apr 21, 2022)

    • Add support for TypeScript's moduleSuffixes field from TypeScript 4.7

      The upcoming version of TypeScript adds the moduleSuffixes field to tsconfig.json that introduces more rules to import path resolution. Setting moduleSuffixes to [".ios", ".native", ""] will try to look at the the relative files ./foo.ios.ts, ./foo.native.ts, and finally ./foo.ts for an import path of ./foo. Note that the empty string "" in moduleSuffixes is necessary for TypeScript to also look-up ./foo.ts. This was announced in the TypeScript 4.7 beta blog post.

    • Match the new ASI behavior from TypeScript nightly builds (#2188)

      This release updates esbuild to match some very recent behavior changes in the TypeScript parser regarding automatic semicolon insertion. For more information, see TypeScript issues #48711 and #48654 (I'm not linking to them directly to avoid Dependabot linkback spam on these issues due to esbuild's popularity). The result is that the following TypeScript code is now considered valid TypeScript syntax:

      class A<T> {}
      new A<number> /* ASI now happens here */
      if (0) {}
      
      interface B {
        (a: number): typeof a /* ASI now happens here */
        <T>(): void
      }
      

      This fix was contributed by @g-plane.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.36(Apr 12, 2022)

    • Revert path metadata validation for now (#2177)

      This release reverts the path metadata validation that was introduced in the previous release. This validation has uncovered a potential issue with how esbuild handles onResolve callbacks in plugins that will need to be fixed before path metadata validation is re-enabled.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.35(Apr 12, 2022)

    • Add support for parsing typeof on #private fields from TypeScript 4.7 (#2174)

      The upcoming version of TypeScript now lets you use #private fields in typeof type expressions:

      https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#typeof-on-private-fields

      class Container {
        #data = "hello!";
      
        get data(): typeof this.#data {
          return this.#data;
        }
      
        set data(value: typeof this.#data) {
          this.#data = value;
        }
      }
      

      With this release, esbuild can now parse these new type expressions as well. This feature was contributed by @magic-akari.

    • Add Opera and IE to internal CSS feature support matrix (#2170)

      Version 0.14.18 of esbuild added Opera and IE as available target environments, and added them to the internal JS feature support matrix. CSS feature support was overlooked, however. This release adds knowledge of Opera and IE to esbuild's internal CSS feature support matrix:

      /* Original input */
      a {
        color: rgba(0, 0, 0, 0.5);
      }
      
      /* Old output (with --target=opera49 --minify) */
      a{color:rgba(0,0,0,.5)}
      
      /* New output (with --target=opera49 --minify) */
      a{color:#00000080}
      

      The fix for this issue was contributed by @sapphi-red.

    • Change TypeScript class field behavior when targeting ES2022

      TypeScript 4.3 introduced a breaking change where class field behavior changes from assign semantics to define semantics when the target setting in tsconfig.json is set to ESNext. Specifically, the default value for TypeScript's useDefineForClassFields setting when unspecified is true if and only if target is ESNext. TypeScript 4.6 introduced another change where this behavior now happens for both ESNext and ES2022. Presumably this will be the case for ES2023 and up as well. With this release, esbuild's behavior has also been changed to match. Now configuring esbuild with --target=es2022 will also cause TypeScript files to use the new class field behavior.

    • Validate that path metadata returned by plugins is consistent

      The plugin API assumes that all metadata for the same path returned by a plugin's onResolve callback is consistent. Previously this assumption was just assumed without any enforcement. Starting with this release, esbuild will now enforce this by generating a build error if this assumption is violated. The lack of validation has not been an issue (I have never heard of this being a problem), but it still seems like a good idea to enforce it. Here's a simple example of a plugin that generates inconsistent sideEffects metadata:

      let buggyPlugin = {
        name: 'buggy',
        setup(build) {
          let count = 0
          build.onResolve({ filter: /^react$/ }, args => {
            return {
              path: require.resolve(args.path),
              sideEffects: count++ > 0,
            }
          })
        },
      }
      

      Since esbuild processes everything in parallel, the set of metadata that ends up being used for a given path is essentially random since it's whatever the task scheduler decides to schedule first. Thus if a plugin does not consistently provide the same metadata for a given path, subsequent builds may return different results. This new validation check prevents this problem.

      Here's the new error message that's shown when this happens:

      ✘ [ERROR] [plugin buggy] Detected inconsistent metadata for the path "node_modules/react/index.js" when it was imported here:
      
          button.tsx:1:30:
            1 β”‚ import { createElement } from 'react'
              β•΅                               ~~~~~~~
      
        The original metadata for that path comes from when it was imported here:
      
          app.tsx:1:23:
            1 β”‚ import * as React from 'react'
              β•΅                        ~~~~~~~
      
        The difference in metadata is displayed below:
      
         {
        -  "sideEffects": true,
        +  "sideEffects": false,
         }
      
        This is a bug in the "buggy" plugin. Plugins provide metadata for a given path in an "onResolve"
        callback. All metadata provided for the same path must be consistent to ensure deterministic
        builds. Due to parallelism, one set of provided metadata will be randomly chosen for a given path,
        so providing inconsistent metadata for the same path can cause non-determinism.
      
    • Suggest enabling a missing condition when exports map fails (#2163)

      This release adds another suggestion to the error message that happens when an exports map lookup fails if the failure could potentially be fixed by adding a missing condition. Here's what the new error message looks like (which now suggests --conditions=module as a possible workaround):

      ✘ [ERROR] Could not resolve "@sentry/electron/main"
      
          index.js:1:24:
            1 β”‚ import * as Sentry from '@sentry/electron/main'
              β•΅                         ~~~~~~~~~~~~~~~~~~~~~~~
      
        The path "./main" is not currently exported by package "@sentry/electron":
      
          node_modules/@sentry/electron/package.json:8:13:
            8 β”‚   "exports": {
              β•΅              ^
      
        None of the conditions provided ("require", "module") match any of the currently active conditions
        ("browser", "default", "import"):
      
          node_modules/@sentry/electron/package.json:16:14:
            16 β”‚     "./main": {
               β•΅               ^
      
        Consider enabling the "module" condition if this package expects it to be enabled. You can use
        "--conditions=module" to do that:
      
          node_modules/@sentry/electron/package.json:18:6:
            18 β”‚       "module": "./esm/main/index.js"
               β•΅       ~~~~~~~~
      
        Consider using a "require()" call to import this file, which will work because the "require"
        condition is supported by this package:
      
          index.js:1:24:
            1 β”‚ import * as Sentry from '@sentry/electron/main'
              β•΅                         ~~~~~~~~~~~~~~~~~~~~~~~
      
        You can mark the path "@sentry/electron/main" as external to exclude it from the bundle, which
        will remove this error.
      

      This particular package had an issue where it was using the Webpack-specific module condition without providing a default condition. It looks like the intent in this case was to use the standard import condition instead. This specific change wasn't suggested here because this error message is for package consumers, not package authors.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.34(Apr 7, 2022)

  • v0.14.33(Apr 7, 2022)

    • Fix a regression regarding super (#2158)

      This fixes a regression from the previous release regarding classes with a super class, a private member, and a static field in the scenario where the static field needs to be lowered but where private members are supported by the configured target environment. In this scenario, esbuild could incorrectly inject the instance field initializers that use this into the constructor before the call to super(), which is invalid. This problem has now been fixed (notice that this is now used after super() instead of before):

      // Original code
      class Foo extends Object {
        static FOO;
        constructor() {
          super();
        }
        #foo;
      }
      
      // Old output (with --bundle)
      var _foo;
      var Foo = class extends Object {
        constructor() {
          __privateAdd(this, _foo, void 0);
          super();
        }
      };
      _foo = new WeakMap();
      __publicField(Foo, "FOO");
      
      // New output (with --bundle)
      var _foo;
      var Foo = class extends Object {
        constructor() {
          super();
          __privateAdd(this, _foo, void 0);
        }
      };
      _foo = new WeakMap();
      __publicField(Foo, "FOO");
      

      During parsing, esbuild scans the class and makes certain decisions about the class such as whether to lower all static fields, whether to lower each private member, or whether calls to super() need to be tracked and adjusted. Previously esbuild made two passes through the class members to compute this information. However, with the new super() call lowering logic added in the previous release, we now need three passes to capture the whole dependency chain for this case: 1) lowering static fields requires 2) lowering private members which requires 3) adjusting super() calls.

      The reason lowering static fields requires lowering private members is because lowering static fields moves their initializers outside of the class body, where they can't access private members anymore. Consider this code:

      class Foo {
        get #foo() {}
        static bar = new Foo().#foo
      }
      

      We can't just lower static fields without also lowering private members, since that causes a syntax error:

      class Foo {
        get #foo() {}
      }
      Foo.bar = new Foo().#foo;
      

      And the reason lowering private members requires adjusting super() calls is because the injected private member initializers use this, which is only accessible after super() calls in the constructor.

    • Fix an issue with --keep-names not keeping some names (#2149)

      This release fixes a regression with --keep-names from version 0.14.26. PR #2062 attempted to remove superfluous calls to the __name helper function by omitting calls of the form __name(foo, "foo") where the name of the symbol in the first argument is equal to the string in the second argument. This was assuming that the initializer for the symbol would automatically be assigned the expected .name property by the JavaScript VM, which turned out to be an incorrect assumption. To fix the regression, this PR has been reverted.

      The assumption is true in many cases but isn't true when the initializer is moved into another automatically-generated variable, which can sometimes be necessary during the various syntax transformations that esbuild does. For example, consider the following code:

      class Foo {
        static get #foo() { return Foo.name }
        static get foo() { return this.#foo }
      }
      let Bar = Foo
      Foo = { name: 'Bar' }
      console.log(Foo.name, Bar.name)
      

      This code should print Bar Foo. With --keep-names --target=es6 that code is lowered by esbuild into the following code (omitting the helper function definitions for brevity):

      var _foo, foo_get;
      const _Foo = class {
        static get foo() {
          return __privateGet(this, _foo, foo_get);
        }
      };
      let Foo = _Foo;
      __name(Foo, "Foo");
      _foo = new WeakSet();
      foo_get = /* @__PURE__ */ __name(function() {
        return _Foo.name;
      }, "#foo");
      __privateAdd(Foo, _foo);
      let Bar = Foo;
      Foo = { name: "Bar" };
      console.log(Foo.name, Bar.name);
      

      The injection of the automatically-generated _Foo variable is necessary to preserve the semantics of the captured Foo binding for methods defined within the class body, even when the definition needs to be moved outside of the class body during code transformation. Due to a JavaScript quirk, this binding is immutable and does not change even if Foo is later reassigned. The PR that was reverted was incorrectly removing the call to __name(Foo, "Foo"), which turned out to be necessary after all in this case.

    • Print some large integers using hexadecimal when minifying (#2162)

      When --minify is active, esbuild will now use one fewer byte to represent certain large integers:

      // Original code
      x = 123456787654321;
      
      // Old output (with --minify)
      x=123456787654321;
      
      // New output (with --minify)
      x=0x704885f926b1;
      

      This works because a hexadecimal representation can be shorter than a decimal representation starting at around 1012 and above.

      This optimization made me realize that there's probably an opportunity to optimize printed numbers for smaller gzipped size instead of or in addition to just optimizing for minimal uncompressed byte count. The gzip algorithm does better with repetitive sequences, so for example 0xFFFFFFFF is probably a better representation than 4294967295 even though the byte counts are the same. As far as I know, no JavaScript minifier does this optimization yet. I don't know enough about how gzip works to know if this is a good idea or what the right metric for this might be.

    • Add Linux ARM64 support for Deno (#2156)

      This release adds Linux ARM64 support to esbuild's Deno API implementation, which allows esbuild to be used with Deno on a Raspberry Pi.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.32(Apr 6, 2022)

    • Fix super usage in lowered private methods (#2039)

      Previously esbuild failed to transform super property accesses inside private methods in the case when private methods have to be lowered because the target environment doesn't support them. The generated code still contained the super keyword even though the method was moved outside of the class body, which is a syntax error in JavaScript. This release fixes this transformation issue and now produces valid code:

      // Original code
      class Derived extends Base {
        #foo() { super.foo() }
        bar() { this.#foo() }
      }
      
      // Old output (with --target=es6)
      var _foo, foo_fn;
      class Derived extends Base {
        constructor() {
          super(...arguments);
          __privateAdd(this, _foo);
        }
        bar() {
          __privateMethod(this, _foo, foo_fn).call(this);
        }
      }
      _foo = new WeakSet();
      foo_fn = function() {
        super.foo();
      };
      
      // New output (with --target=es6)
      var _foo, foo_fn;
      const _Derived = class extends Base {
        constructor() {
          super(...arguments);
          __privateAdd(this, _foo);
        }
        bar() {
          __privateMethod(this, _foo, foo_fn).call(this);
        }
      };
      let Derived = _Derived;
      _foo = new WeakSet();
      foo_fn = function() {
        __superGet(_Derived.prototype, this, "foo").call(this);
      };
      

      Because of this change, lowered super property accesses on instances were rewritten so that they can exist outside of the class body. This rewrite affects code generation for all super property accesses on instances including those inside lowered async functions. The new approach is different but should be equivalent to the old approach:

      // Original code
      class Foo {
        foo = async () => super.foo()
      }
      
      // Old output (with --target=es6)
      class Foo {
        constructor() {
          __publicField(this, "foo", () => {
            var __superGet = (key) => super[key];
            return __async(this, null, function* () {
              return __superGet("foo").call(this);
            });
          });
        }
      }
      
      // New output (with --target=es6)
      class Foo {
        constructor() {
          __publicField(this, "foo", () => __async(this, null, function* () {
            return __superGet(Foo.prototype, this, "foo").call(this);
          }));
        }
      }
      
    • Fix some tree-shaking bugs regarding property side effects

      This release fixes some cases where side effects in computed properties were not being handled correctly. Specifically primitives and private names as properties should not be considered to have side effects, and object literals as properties should be considered to have side effects:

      // Original code
      let shouldRemove = { [1]: 2 }
      let shouldRemove2 = class { #foo }
      let shouldKeep = class { [{ toString() { sideEffect() } }] }
      
      // Old output (with --tree-shaking=true)
      let shouldRemove = { [1]: 2 };
      let shouldRemove2 = class {
        #foo;
      };
      
      // New output (with --tree-shaking=true)
      let shouldKeep = class {
        [{ toString() {
          sideEffect();
        } }];
      };
      
    • Add the wasmModule option to the initialize JS API (#1093)

      The initialize JS API must be called when using esbuild in the browser to provide the WebAssembly module for esbuild to use. Previously the only way to do that was using the wasmURL API option like this:

      await esbuild.initialize({
        wasmURL: '/node_modules/esbuild-wasm/esbuild.wasm',
      })
      console.log(await esbuild.transform('1+2'))
      

      With this release, you can now also initialize esbuild using a WebAssembly.Module instance using the wasmModule API option instead. The example above is equivalent to the following code:

      await esbuild.initialize({
        wasmModule: await WebAssembly.compileStreaming(fetch('/node_modules/esbuild-wasm/esbuild.wasm'))
      })
      console.log(await esbuild.transform('1+2'))
      

      This could be useful for environments where you want more control over how the WebAssembly download happens or where downloading the WebAssembly module is not possible.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.31(Apr 4, 2022)

    • Add support for parsing "optional variance annotations" from TypeScript 4.7 (#2102)

      The upcoming version of TypeScript now lets you specify in and/or out on certain type parameters (specifically only on a type alias, an interface declaration, or a class declaration). These modifiers control type paramemter covariance and contravariance:

      type Provider<out T> = () => T;
      type Consumer<in T> = (x: T) => void;
      type Mapper<in T, out U> = (x: T) => U;
      type Processor<in out T> = (x: T) => T;
      

      With this release, esbuild can now parse these new type parameter modifiers. This feature was contributed by @magic-akari.

    • Improve support for super() constructor calls in nested locations (#2134)

      In JavaScript, derived classes must call super() somewhere in the constructor method before being able to access this. Class public instance fields, class private instance fields, and TypeScript constructor parameter properties can all potentially cause code which uses this to be inserted into the constructor body, which must be inserted after the super() call. To make these insertions straightforward to implement, the TypeScript compiler doesn't allow calling super() somewhere other than in a root-level statement in the constructor body in these cases.

      Previously esbuild's class transformations only worked correctly when super() was called in a root-level statement in the constructor body, just like the TypeScript compiler. But with this release, esbuild should now generate correct code as long as the call to super() appears anywhere in the constructor body:

      // Original code
      class Foo extends Bar {
        constructor(public skip = false) {
          if (skip) {
            super(null)
            return
          }
          super({ keys: [] })
        }
      }
      
      // Old output (incorrect)
      class Foo extends Bar {
        constructor(skip = false) {
          if (skip) {
            super(null);
            return;
          }
          super({ keys: [] });
          this.skip = skip;
        }
      }
      
      // New output (correct)
      class Foo extends Bar {
        constructor(skip = false) {
          var __super = (...args) => {
            super(...args);
            this.skip = skip;
          };
          if (skip) {
            __super(null);
            return;
          }
          __super({ keys: [] });
        }
      }
      
    • Add support for the new @container CSS rule (#2127)

      This release adds support for @container in CSS files. This means esbuild will now pretty-print and minify these rules better since it now better understands the internal structure of these rules:

      /* Original code */
      @container (width <= 150px) {
        #inner {
          color: yellow;
        }
      }
      
      /* Old output (with --minify) */
      @container (width <= 150px){#inner {color: yellow;}}
      
      /* New output (with --minify) */
      @container (width <= 150px){#inner{color:#ff0}}
      

      This was contributed by @yisibl.

    • Avoid CSS cascade-dependent keywords in the font-family property (#2135)

      In CSS, initial, inherit, and unset are CSS-wide keywords which means they have special behavior when they are specified as a property value. For example, while font-family: 'Arial' (as a string) and font-family: Arial (as an identifier) are the same, font-family: 'inherit' (as a string) uses the font family named inherit but font-family: inherit (as an identifier) inherits the font family from the parent element. This means esbuild must not unquote these CSS-wide keywords (and default, which is also reserved) during minification to avoid changing the meaning of the minified CSS.

      The current draft of the new CSS Cascading and Inheritance Level 5 specification adds another concept called cascade-dependent keywords of which there are two: revert and revert-layer. This release of esbuild guards against unquoting these additional keywords as well to avoid accidentally breaking pages that use a font with the same name:

      /* Original code */
      a { font-family: 'revert'; }
      b { font-family: 'revert-layer', 'Segoe UI', serif; }
      
      /* Old output (with --minify) */
      a{font-family:revert}b{font-family:revert-layer,Segoe UI,serif}
      
      /* New output (with --minify) */
      a{font-family:"revert"}b{font-family:"revert-layer",Segoe UI,serif}
      

      This fix was contributed by @yisibl.

    Source code(tar.gz)
    Source code(zip)
  • v0.14.30(Apr 2, 2022)

    • Change the context of TypeScript parameter decorators (#2147)

      While TypeScript parameter decorators are expressions, they are not evaluated where they exist in the code. They are moved to after the class declaration and evaluated there instead. Specifically this TypeScript code:

      class Class {
        method(@decorator() arg) {}
      }
      

      becomes this JavaScript code:

      class Class {
        method(arg) {}
      }
      __decorate([
        __param(0, decorator())
      ], Class.prototype, "method", null);
      

      This has several consequences:

      • Whether await is allowed inside a decorator expression or not depends on whether the class declaration itself is in an async context or not. With this release, you can now use await inside a decorator expression when the class declaration is either inside an async function or is at the top-level of an ES module and top-level await is supported. Note that the TypeScript compiler currently has a bug regarding this edge case: https://github.com/microsoft/TypeScript/issues/48509.

        // Using "await" inside a decorator expression is now allowed
        async function fn(foo: Promise<any>) {
          class Class {
            method(@decorator(await foo) arg) {}
          }
          return Class
        }
        

        Also while TypeScript currently allows await to be used like this in async functions, it doesn't currently allow yield to be used like this in generator functions. It's not yet clear whether this behavior with yield is a bug or by design, so I haven't made any changes to esbuild's handling of yield inside decorator expressions in this release.

      • Since the scope of a decorator expression is the scope enclosing the class declaration, they cannot access private identifiers. Previously this was incorrectly allowed but with this release, esbuild no longer allows this. Note that the TypeScript compiler currently has a bug regarding this edge case: https://github.com/microsoft/TypeScript/issues/48515.

        // Using private names inside a decorator expression is no longer allowed
        class Class {
          static #priv = 123
          method(@decorator(Class.#priv) arg) {}
        }
        
      • Since the scope of a decorator expression is the scope enclosing the class declaration, identifiers inside parameter decorator expressions should never be resolved to a parameter of the enclosing method. Previously this could happen, which was a bug with esbuild. This bug no longer happens in this release.

        // Name collisions now resolve to the outer name instead of the inner name
        let arg = 1
        class Class {
          method(@decorator(arg) arg = 2) {}
        }
        

        Specifically previous versions of esbuild generated the following incorrect JavaScript (notice the use of arg2):

        let arg = 1;
        class Class {
          method(arg2 = 2) {
          }
        }
        __decorateClass([
          __decorateParam(0, decorator(arg2))
        ], Class.prototype, "method", 1);
        

        This release now generates the following correct JavaScript (notice the use of arg):

        let arg = 1;
        class Class {
          method(arg2 = 2) {
          }
        }
        __decorateClass([
          __decorateParam(0, decorator(arg))
        ], Class.prototype, "method", 1);
        
    • Fix some obscure edge cases with super property access

      This release fixes the following obscure problems with super when targeting an older JavaScript environment such as --target=es6:

      1. The compiler could previously crash when a lowered async arrow function contained a class with a field initializer that used a super property access:

        let foo = async () => class extends Object {
          bar = super.toString
        }
        
      2. The compiler could previously generate incorrect code when a lowered async method of a derived class contained a nested class with a computed class member involving a super property access on the derived class:

        class Base {
          foo() { return 'bar' }
        }
        class Derived extends Base {
          async foo() {
            return new class { [super.foo()] = 'success' }
          }
        }
        new Derived().foo().then(obj => console.log(obj.bar))
        
      3. The compiler could previously generate incorrect code when a default-exported class contained a super property access inside a lowered static private class field:

        class Foo {
          static foo = 123
        }
        export default class extends Foo {
          static #foo = super.foo
          static bar = this.#foo
        }
        
    Source code(tar.gz)
    Source code(zip)
  • v0.14.29(Mar 30, 2022)

    • Fix a minification bug with a double-nested if inside a label followed by else (#2139)

      This fixes a minification bug that affects the edge case where if is followed by else and the if contains a label that contains a nested if. Normally esbuild's AST printer automatically wraps the body of a single-statement if in braces to avoid the "dangling else" if/else ambiguity common to C-like languages (where the else accidentally becomes associated with the inner if instead of the outer if). However, I was missing automatic wrapping of label statements, which did not have test coverage because they are a rarely-used feature. This release fixes the bug:

      // Original code
      if (a)
        b: {
          if (c) break b
        }
      else if (d)
        e()
      
      // Old output (with --minify)
      if(a)e:if(c)break e;else d&&e();
      
      // New output (with --minify)
      if(a){e:if(c)break e}else d&&e();
      
    • Fix edge case regarding baseUrl and paths in tsconfig.json (#2119)

      In tsconfig.json, TypeScript forbids non-relative values inside paths if baseUrl is not present, and esbuild does too. However, TypeScript checked this after the entire tsconfig.json hierarchy was parsed while esbuild incorrectly checked this immediately when parsing the file containing the paths map. This caused incorrect warnings to be generated for tsconfig.json files that specify a baseUrl value and that inherit a paths value from an extends clause. Now esbuild will only check for non-relative paths values after the entire hierarchy has been parsed to avoid generating incorrect warnings.

    • Better handle errors where the esbuild binary executable is corrupted or missing (#2129)

      If the esbuild binary executable is corrupted or missing, previously there was one situation where esbuild's JavaScript API could hang instead of generating an error. This release changes esbuild's library code to generate an error instead in this case.

    Source code(tar.gz)
    Source code(zip)
GoReleaser builds Go binaries as fast and easily as possible

GoReleaser builds Go binaries for several platforms, creates a GitHub release and then pushes a Homebrew formula to a tap repository. All that wrapped in your favorite CI.

GoReleaser 10.5k Aug 17, 2022
Monitoring changes in the source file and automatically compile and run (restart).

dogo Monitoring changes in the source file and automatically compile and run (restart). δΈ­ζ–‡ Install go get github.com/liudng/dogo Create config Here's

null 248 Jul 6, 2022
Builds and restarts a Go project when it crashes or some watched file changes

gaper Used to build and restart a Go project when it crashes or some watched file changes Aimed to be used in development only. Changelog See Releases

Max Claus Nunes 55 Jun 21, 2022
Realize is the #1 Golang Task Runner which enhance your workflow by automating the most common tasks and using the best performing Golang live reloading.

#1 Golang live reload and task runner Content - ⭐️ Top Features - ???? Get started - ?? Config sample - ?? Commands List - ?? Support and Suggestions

Oxequa 4.3k Aug 11, 2022
Various tools for usage with Golang like installer, github tool and cloud features.

Gopei2 (Go Programming Environment Installer) Gopei shell install Go compiler, LiteIDE and configure for you the entire environment, variables, paths,

George Calianu 100 May 23, 2022
a build tool for Go, with a focus on cross-compiling, packaging and deployment

goxc NOTE: goxc has long been in maintenance mode. Ever since Go1.5 supported simple cross-compilation, this tool lost much of its value. There are st

Am Laher 1.7k Jul 28, 2022
Build system and task runner for Go projects

Gilbert is task runner that aims to provide declarative way to define and run tasks like in other projects like Gradle, Maven and etc.

Gilbert 101 Aug 8, 2022
A small utility that aims to automate and simplify some tasks related to software release cycles.

Stork is a small utility that aims to automate and simplify some tasks related to software release cycles such as reading the current version from a f

Simone Margaritelli 42 Jul 23, 2022
πŸš€ gowatch is a command line tool that builds and (re)starts your go project everytime you save a Go or template file.

gowatch δΈ­ζ–‡ζ–‡ζ‘£ gowatch is a command line tool that builds and (re)starts your go project everytime you save a Go or template file. Installation To insta

silenceper 718 Aug 16, 2022
Build and (re)start go web apps after saving/creating/deleting source files.

unmaintained Fresh Fresh is a command line tool that builds and (re)starts your web application everytime you save a Go or template file. If the web f

Andrea Franz 3.4k Aug 10, 2022
NFPM is Not FPM - a simple deb, rpm and apk packager written in Go

NFPM NFPM is Not FPM - a simple deb, rpm and apk packager written in Go. Why While fpm is great, for me, it is a bummer that it depends on ruby, tar a

GoReleaser 1.5k Aug 13, 2022
KintoHub is an open source build and deployment platform designed with a developer-friendly interface for Kubernetes.

What is Kintohub? KintoHub is an open source build and deployment platform designed with a developer-friendly interface for Kubernetes. Build your cod

KintoHub 30 Jun 7, 2022
Moldy CLI the best project starter and manager of the world

Moldy The best project starter of the world ?? What is Moldy ? Hey I present Moldy this beautiful tool that will solve your life in creating, managing

Moldy Community 23 Jun 26, 2022
A simple dependency manager for Go (golang), inspired by Bundler.

Goop A dependency manager for Go (golang), inspired by Bundler. It is different from other dependency managers in that it does not force you to mess w

Peter Jihoon Kim 776 Jul 27, 2022
Data structure and relevant algorithms for extremely fast prefix/fuzzy string searching.

Trie Data structure and relevant algorithms for extremely fast prefix/fuzzy string searching. Usage Create a Trie with: t := trie.New() Add Keys with:

Derek Parker 599 Aug 10, 2022
An extremely fast UUID alternative written in golang

Overview WUID is a globally unique number generator, while it is NOT a UUID implementation. WUID is 10-135 times faster than UUID and 4600 times faste

Edwin 468 Jul 29, 2022
An extremely fast Go (golang) HTTP router that supports regular expression route matching. Comes with full support for building RESTful APIs.

ozzo-routing You may consider using go-rest-api to jumpstart your new RESTful applications with ozzo-routing. Description ozzo-routing is a Go package

Ozzo Framework 441 Aug 8, 2022
An extremely fast UUID alternative written in golang

Overview WUID is a globally unique number generator, while it is NOT a UUID implementation. WUID is 10-135 times faster than UUID and 4600 times faste

Edwin 11 May 10, 2021
RapidMQ is a pure, extremely productive, lightweight and reliable library for managing of the local messages queue

RapidMQ RapidMQ is a pure, extremely productive, lightweight and reliable library for managing of the local messages queue in the Go programming langu

Vadim Shakun 64 Aug 5, 2022
Extremely flexible golang deep comparison, extends the go testing package and tests HTTP APIs

go-testdeep Extremely flexible golang deep comparison, extends the go testing package. Latest news Synopsis Description Installation Functions Availab

Maxime SoulΓ© 313 Aug 8, 2022
Extremely flexible golang deep comparison, extends the go testing package, tests HTTP APIs and provides tests suite

go-testdeep Extremely flexible golang deep comparison, extends the go testing package. Latest news Synopsis Description Installation Functions Availab

Maxime SoulΓ© 313 Aug 8, 2022
The extremely customizable and themeable shell prompt.

kitch-prompt Kitch-prompt is a cross-platform tool for displaying a shell prompt, which can be extensively customized both in terms of what is shown,

Jason Walton 2 Jul 14, 2022
An extremely opinionated TypeScript monorepo tool.

Unirepo is an extremely opinionated TypeScript build tool. Typical monorepo management tools in the Node.js ecosystem provide automation aroun

Brandon Bloom 224 Jun 10, 2022
An extremely opinionated TypeScript monorepo tool.

Unirepo Unirepo is an extremely opinionated TypeScript build tool. Typical monorepo management tools in the Node.js ecosystem provide automation aroun

Deref 224 Jun 10, 2022
(WIP) Extremely simple unixway GitHub webhook listener for push event

(WIP) puffy Puffy is an extremely simple unixway GitHub webhook listener and handler for push events Todo Add payload signature validation (WIP) Depen

Egor 3 Dec 30, 2021
This is an extremely basic 2 player online game.

myba This is an extremely basic 2 player online game. How to play Player one moves with WASD, player 2 moves with UHJK. Once both players are either h

Laz 1 Dec 7, 2021
Gbio - Extremely minimalist RPC framework - Go but interface only

gbio !!! ?? WIP ?? !!! Go but interface only. gbio is a(n): Extremely minimalist

ANQUR 3 Jan 3, 2022
❄️ Elsa is a minimal, fast and secure runtime for JavaScript and TypeScript written in Go

Elsa Elsa is a minimal, fast and secure runtime for JavaScript and TypeScript written in Go, leveraging the power from QuickJS. Features URL based imp

Elsa 2.7k Aug 12, 2022
Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

quickjs Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter. These bindings are a WIP and do not match full parity wit

Kenta Iwasaki 127 Aug 5, 2022