An extremely fast JavaScript and CSS 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.

Comments
  • 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
  • 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]: core-js@<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 "next@>=11".
    warning "@emotion/styled > @emotion/[email protected]" has unmet peer dependency "@babel/core@^7.0.0".
    warning "@emotion/styled > @emotion/babel-plugin > @babel/[email protected]" has unmet peer dependency "@babel/core@^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 35
  • [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 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 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
  • 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
  • Node.js default interop case

    Node.js default interop case

    I'm posting this here, which is a discussion that came up between Node.js and RollupJS but has grown to include members from other projects as well. See https://github.com/rollup/plugins/issues/635 for the original issue.

    @evanw I would really value your feedback here as interop is one of those things where it happens too quickly in a brief moment, and then we are stuck with it for years. Even if the action is do nothing, we need to make sure it is a considered do nothing.

    If you have a chance to read that thread or have any questions I would value your input. Perhaps we may just have to live with some thrashing. I still hope not. Best case we get alignment between bundlers.

    opened by guybedford 26
  • 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
  • jsxImportSource and dependencies

    jsxImportSource and dependencies

    My scenario is that I am building an application in a yarn workspaces setup. The application imports a local dependency that is also part of the workspace.

    Workspace:

    app/
    ├─ app.tsx
    ├─ package.json
    ├─ tsconfig.json
    ui/
    ├─ index.tsx
    ├─ package.json
    ├─ tsconfig.json
    package.json
    
    

    All code is written in typescript and each project in the workspace has its own tsconfig.json with the following relevant options:

        "jsx": "react-jsx",
        "jsxImportSource": "@emotion/react",
    
    // app.tsx
    import React from "react";
    import { CacheProvider } from "@emotion/react";
    
    import { PageHeader } from "ui";
    import * as Server from "react-dom/server";
    
    import createCache from "@emotion/cache";
    
    function createEmotionCache() {
      return createCache({ key: "hw-css" });
    }
    
    export interface ServerStyleContextData {
      key: string;
      ids: Array<string>;
      css: string;
    }
    const ServerStyleContext = React.createContext<null | ServerStyleContextData[]>(
      null
    );
    
    const cache = createEmotionCache();
    
    let Greet = () => (
      <div>
        <h1 css={{ color: "tomato" }}>Hello, world!</h1>
        <PageHeader>Page Header</PageHeader>
      </div>
    );
    
    console.log(
      Server.renderToString(
        <ServerStyleContext.Provider value={null}>
          <CacheProvider value={cache}>
            <Greet />
          </CacheProvider>
        </ServerStyleContext.Provider>
      )
    );
    
    
    
    // ui/index.tsx
    
    import React from "react";
    
    interface PageHeaderProps {
      children: React.ReactNode;
    }
    
    export const PageHeader = ({ children }: PageHeaderProps) => {
      return (
        <h2 className="page-header" css={{ color: "red" }}>
          {children}
        </h2>
      );
    };
    
    

    When bundling (esbuild src/app.tsx --bundle --outfile=dist/bundle.js --sourcemap --platform=node) the css prop in /app are handled but the one in /ui is not and results in css="[object Object]" in the dom.

    // npm run build && node --enable-source-maps dist/bundle.js
    <div><style data-emotion="hw-css tq928n">.hw-css-tq928n{color:tomato;}</style><h1 class="hw-css-tq928n">Hello, world!</h1><h2 class="page-header" css="[object Object]">Page Header</h2></div>
    

    Is there a way to get esbuild to also apply jsxImportSource to dependencies? Maybe exclusively to dependencies within the same workspace?

    tsconfig 
    opened by nathanforce 4
  • Static Attributes and Static Blocks are incompatible in certain cases

    Static Attributes and Static Blocks are incompatible in certain cases

    I haven't been able to fully track down this issue, but here's what I know.

    esbuild version: 0.16.14

    Input:

    class Foo {
      static {
        this.prototype.thing = "value"
      }
    }
    
    class Bar {
      static thing = "value"
    }
    
    class Baz {
      static thing = "value"
      static {
        this.prototype.thing = "value"
      }
    }
    
    // This exists only to prevent dead code removal.
    console.log(Foo, Bar, Baz)
    

    The specific classes, properties, and values aren't important.

    When esbuild test.js is run directly, these classes are compiled as follows:

      var _Foo = class {
      };
      var Foo = _Foo;
      (() => {
        _Foo.prototype.thing = "value";
      })();
    
      var Bar = class {
      };
      __publicField(Bar, "thing", "value");
    
      var _Baz = class {
      };
      var Baz = _Baz;
      __publicField(Baz, "thing", "value");
      (() => {
        _Baz.prototype.thing = "value";
      })();
    

    This interpretation seems completely sensible, and functions as expected. The same results occur when run with --bundle.

    When esbuild --target=esnext test.js is run, the output is (effectively) the same as the input, as might be expected.

    When the --bundle and --target=esnext options are combined, however, the output is the following (commentary my own):

      // This seems a reasonable compromise.
      var Foo = class {
        static {
          this.prototype.thing = "value";
        }
      };
    
      // This doesn't seem like it should be necessary, but it still works.
      var Bar = class {
      };
      __publicField(Bar, "thing", "value");
    
      // This doesn't work.
      var _Baz = class {
        static {
          // This line is executed before the class body has been closed, so
          // the `_Baz` variable is still `undefined`, and this line fails.
          _Baz.prototype.thing = "value";
        }
      };
      var Baz = _Baz;
      __publicField(Baz, "thing", "value");
    

    It appears that the behavior of rewriting static blocks for older browsers is behaving inconsistently with --target=esnext (or --target=2022) — standalone static blocks are neither rewritten nor extracted, but when a static attribute is introduced, the blocks are only rewritten and not extracted.

    (Interestingly, this also seems to reveal an issue in the documentation — the target option is documented as defaulting to esnext, but there's clearly a change in behavior when the value is explicitly provided.)

    opened by pvande 0
  • Doubts and possible Features

    Doubts and possible Features

    Hey,

    Quick summary I'm a senior Nodejs Developer/Architect, and currently, for my own entertainment I'm building a kind of Framework for React with Typescript support, I was using webpack for bundling, but since I was using esbuild transform API for the typescript and jsx, I thought of giving esbuild build API a shot.

    First, one thing that I cannot find and do in esbuild, without using regex on the output code, is transforming imports to window references, this was something that I was able to configure in webpack without having a post-processor, it would be great if this was an option for the resolver plugin, like you have currently for the external option, something like global.

    And finally, my last "issue" is performance when I'm running two different instances of Build API for different files, at basically the same time, this is required by my project since I want an active file watch system. What I am observing is that the different builds wait for each other, they all end at the same time...

    image

    opened by tiagomta 3
  • Looking to build a plugin offering APM support

    Looking to build a plugin offering APM support

    I'm working on adding bundler support for the Datadog Node.js APM library. Currently, from my research, none of the popular APM tools fully support bundlers (like esbuild, webpack, etc.) Some of them partially support bundlers, à la adding instrumented modules to the externals list in webpack, but that results in modules being left outside of the bundle and isn't ideal for the end developer. My goal with this issue is to pave a way for Datadog and other APM libraries to support a bundler.

    At a high level the way that Datadog and other APM tools work is that they're delivered as an npm package and contain a list of supported third party packages and version ranges, like pg v3-v4 or redis v5.2-v6.3. Node.js's require function is replaced at runtime in some manner so that when a module in node_modules/ is loaded the name and version are compared with this list. The require-in-the-middle npm package illustrates this. If there's a match then some magic happens, like having package methods get wrapped in a function to track the timing and query information.

    When it comes to building Node.js apps, esbuild concatenate userspace modules into a bundle, basically a single module JavaScript file, and calls to require for userspace modules are instead replaced with a function to lookup the bundled version of the module. Internal Node.js modules like http can be exposed using the original Node.js require call. At this point most APM tools are able to wrap the internal Node.js modules but not third party node_modules/.

    Basic esbuild output might look something like this:

    var __getOwnPropNames = Object.getOwnPropertyNames;
    var __commonJS = (cb, mod) => function __require() {
      return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
    };
    
    // foo.js
    var require_foo = __commonJS({
      "foo.js"(exports, module2) {
        var fs = require("fs");
        module2.exports = "hello";
      }
    });
    
    // app.js
    var foo = require_foo();
    console.log(foo);
    

    At this point I have an idea for to implement such an APM plugin. First, the plugin would need to ship with the list of packages / versions to instrument. At build time the plugin would maintain a map of module locations and versions. It would need to hook into the events for each module that gets loaded. If the name matches then read the appropriate package.json file on disk to check the version. If that happens, then add the module and version information to the map. Once the modules have all been read the map would then be injected into the resulting bundle somehow. The APM library itself would be a dependency of the project and would be included as well. The APM library would then read the injected module / version map somehow. Finally, the APM library would still wrap the built-in require function but would also wrap the __commonJS() function provided by esbuild.

    With this in mind I'm having trouble finding the appropriate plugin APIs to support this. Would anyone be able to tell me if this plan is currently implementable and which APIs correlate to these steps? Also, if you specifically know that any of these operations aren't supported, please let me know as well so that a PR could be made.

    opened by tlhunter 1
  • sideEffects and export * from

    sideEffects and export * from

    Hi, I have that simple structure:

    package.json
    ...
    "sideEffects": false,
    ...
    
    src/components/modal/index.tsx
    import { ModalBody } from './components';
    import { SomeComponent } from './someComponent';
    
    export const Modal = () => <div></div>;
    
    Modal.SomeComponent = SomeComponent;
    Modal.Body = ModalBody;
    
    src/components/modal/components/index.ts
    export * from './body';
    
    src/components/modal/components/body/index.tsx
    import './style.less';
    
    export const ModalBody = () => <div></div>;
    
    src/components/modal/someComponent/index.tsx
    import './style.less';
    
    export const SomeComponent = () => <div></div>;
    

    As you can see src/components/modal/components/index.ts has export * from After build i has that result

    Result with export * from
    {
      'components/modal/index.js': {
        'src/components/modal/components/body/style.less': {}, 
        'src/components/modal/components/body/index.tsx': {},
        'src/components/modal/someComponent/style.less': {},   
        'src/components/modal/someComponent/index.tsx': {},  
        'src/components/modal/index.tsx': {}
      },
      'components/modal/index.css': {
        'src/components/modal/someComponent/style.less': {}
      }
    }
    

    components/modal/index.js has:

    1. src/components/modal/components/body/index.tsx
    2. src/components/modal/components/body/style.less

    But components/modal/index.css have only src/components/modal/someComponent/style.less
    If we change src/components/modal/components/index.ts to this

    Changed src/components/modal/components/index.ts
    export { ModalBody } from './body';
    

    Now we got this result:

    Result with export { ModalBody } from
    {
      'components/modal/index.js': {
        'src/components/modal/components/body/style.less': {},  
        'src/components/modal/components/body/index.tsx': {}, 
        'src/components/modal/components/index.ts': {},
        'src/components/modal/someComponent/style.less': {},    
        'src/components/modal/someComponent/index.tsx': {},   
        'src/components/modal/index.tsx': {}
      },
      'components/modal/index.css': {
        'src/components/modal/components/body/style.less': {},
        'src/components/modal/someComponent/style.less': {}
      }
    }
    

    Now components/modal/index.js has

    1. src/components/modal/components/body/index.tsx
    2. src/components/modal/components/body/style.less
    3. src/components/modal/components/index.ts !!!

    And components/modal/index.css now has src/components/modal/components/body/style.less !!!

    How i can fix that without change export * from to export {...} from or it is bug?

    Thanks.

    opened by nkroe 1
  • esbuild external issues

    esbuild external issues

    I'm trying to migrate from webpack to esbuild, but till now I have several issues with externals

    1- node modules are resolved to relative paths which is not an expected behavior for example import { something} from "mypackage" is compiled into import { something } to "../../node_modules/mypackage" why it is wrong? because the dist dir is always deployed and then we install the dependencies, node must resolve node modules the same way it always does. also, the relative paths become wrong after the "dist" dir is deployed.

    2- aliases must be kept as it unless there is an option to convert them for example, I added this path @myscope/* to aliases (which is added to tsconfig.compilerOptions.path too) this path alias to a local folder that will be treated after compiling as an external npm package so import something from "@myscope/packageName/myfile" refers to "../packages/packageName/myfile", but it must be kept in the compiled file as it to be treated as an external node package.

    3- allow external to be a function that receives:

    • type: require, import, dynamicImport
    • statement: the imported module path (without resolving)
    • path: the imported module path after resolving aliases
    • fullPath: the full absolute path
    • requester: the file that requested the module

    this function returns a boolean to add the file to external, or a string to change the imported startement

    example:

    {
     external: [
       ({statement})=> statement.startsWith('@src/')? '../src': false
    ]
    }
    
    opened by eng-dibo 1
Releases(v0.16.16)
  • v0.16.16(Jan 8, 2023)

    • Fix a regression caused by comment preservation (#2805)

      The new comment preservation behavior that was added in 0.16.14 introduced a regression where comments in certain locations could cause esbuild to omit certain necessary parentheses in the output. The outermost parentheses were incorrectly removed for the following syntax forms, which then introduced syntax errors:

      (/* comment */ { x: 0 }).x;
      (/* comment */ function () { })();
      (/* comment */ class { }).prototype;
      

      This regression has been fixed.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.15(Jan 7, 2023)

    • Add format to input files in the JSON metafile data

      When --metafile is enabled, input files may now have an additional format field that indicates the export format used by this file. When present, the value will either be cjs for CommonJS-style exports or esm for ESM-style exports. This can be useful in bundle analysis.

      For example, esbuild's new Bundle Size Analyzer now uses this information to visualize whether ESM or CommonJS was used for each directory and file of source code (click on the CJS/ESM bar at the top).

      This information is helpful when trying to reduce the size of your bundle. Using the ESM variant of a dependency instead of the CommonJS variant always results in a faster and smaller bundle because it omits CommonJS wrappers, and also may result in better tree-shaking as it allows esbuild to perform tree-shaking at the statement level instead of the module level.

    • Fix a bundling edge case with dynamic import (#2793)

      This release fixes a bug where esbuild's bundler could produce incorrect output. The problematic edge case involves the entry point importing itself using a dynamic import() expression in an imported file, like this:

      // src/a.js
      export const A = 42;
      
      // src/b.js
      export const B = async () => (await import(".")).A
      
      // src/index.js
      export * from "./a"
      export * from "./b"
      
    • Remove new type syntax from type declarations in the esbuild package (#2798)

      Previously you needed to use TypeScript 4.3 or newer when using the esbuild package from TypeScript code due to the use of a getter in an interface in node_modules/esbuild/lib/main.d.ts. This release removes this newer syntax to allow people with versions of TypeScript as far back as TypeScript 3.5 to use this latest version of the esbuild package. Here is change that was made to esbuild's type declarations:

       export interface OutputFile {
         /** "text" as bytes */
         contents: Uint8Array;
         /** "contents" as text (changes automatically with "contents") */
      -  get text(): string;
      +  readonly text: string;
       }
      
    Source code(tar.gz)
    Source code(zip)
  • v0.16.14(Jan 4, 2023)

    • Preserve some comments in expressions (#2721)

      Various tools give semantic meaning to comments embedded inside of expressions. For example, Webpack and Vite have special "magic comments" that can be used to affect code splitting behavior:

      import(/* webpackChunkName: "foo" */ '../foo');
      import(/* @vite-ignore */ dynamicVar);
      new Worker(/* webpackChunkName: "bar" */ new URL("../bar.ts", import.meta.url));
      new Worker(new URL('./path', import.meta.url), /* @vite-ignore */ dynamicOptions);
      

      Since esbuild can be used as a preprocessor for these tools (e.g. to strip TypeScript types), it can be problematic if esbuild doesn't do additional work to try to retain these comments. Previously esbuild special-cased Webpack comments in these specific locations in the AST. But Vite would now like to use similar comments, and likely other tools as well.

      So with this release, esbuild now will attempt to preserve some comments inside of expressions in more situations than before. This behavior is mainly intended to preserve these special "magic comments" that are meant for other tools to consume, although esbuild will no longer only preserve Webpack-specific comments so it should now be tool-agnostic. There is no guarantee that all such comments will be preserved (especially when --minify-syntax is enabled). So this change does not mean that esbuild is now usable as a code formatter. In particular comment preservation is more likely to happen with leading comments than with trailing comments. You should put comments that you want to be preserved before the relevant expression instead of after it. Also note that this change does not retain any more statement-level comments than before (i.e. comments not embedded inside of expressions). Comment preservation is not enabled when --minify-whitespace is enabled (which is automatically enabled when you use --minify).

    Source code(tar.gz)
    Source code(zip)
  • v0.16.13(Jan 2, 2023)

    • Publish a new bundle visualization tool

      While esbuild provides bundle metadata via the --metafile flag, previously esbuild left analysis of it completely up to third-party tools (well, outside of the rudimentary --analyze flag). However, the esbuild website now has a built-in bundle visualization tool:

      • https://esbuild.github.io/analyze/

      You can pass --metafile to esbuild to output bundle metadata, then upload that JSON file to this tool to visualize your bundle. This is helpful for answering questions such as:

      • Which packages are included in my bundle?
      • How did a specific file get included?
      • How small did a specific file compress to?
      • Was a specific file tree-shaken or not?

      I'm publishing this tool because I think esbuild should provide some answer to "how do I visualize my bundle" without requiring people to reach for third-party tools. At the moment the tool offers two types of visualizations: a radial "sunburst chart" and a linear "flame chart". They serve slightly different but overlapping use cases (e.g. the sunburst chart is more keyboard-accessible while the flame chart is easier with the mouse). This tool may continue to evolve over time.

    • Fix --metafile and --mangle-cache with --watch (#1357)

      The CLI calls the Go API and then also writes out the metafile and/or mangle cache JSON files if those features are enabled. This extra step is necessary because these files are returned by the Go API as in-memory strings. However, this extra step accidentally didn't happen for all builds after the initial build when watch mode was enabled. This behavior used to work but it was broken in version 0.14.18 by the introduction of the mangle cache feature. This release fixes the combination of these features, so the metafile and mangle cache features should now work with watch mode. This behavior was only broken for the CLI, not for the JS or Go APIs.

    • Add an original field to the metafile

      The metadata file JSON now has an additional field: each import in an input file now contains the pre-resolved path in the original field in addition to the post-resolved path in the path field. This means it's now possible to run certain additional analysis over your bundle. For example, you should be able to use this to detect when the same package subpath is represented multiple times in the bundle, either because multiple versions of a package were bundled or because a package is experiencing the dual-package hazard.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.12(Dec 28, 2022)

    • Loader defaults to js for extensionless files (#2776)

      Certain packages contain files without an extension. For example, the yargs package contains the file yargs/yargs which has no extension. Node, Webpack, and Parcel can all understand code that imports yargs/yargs because they assume that the file is JavaScript. However, esbuild was previously unable to understand this code because it relies on the file extension to tell it how to interpret the file. With this release, esbuild will now assume files without an extension are JavaScript files. This can be customized by setting the loader for "" (the empty string, representing files without an extension) to another loader. For example, if you want files without an extension to be treated as CSS instead, you can do that like this:

      • CLI:

        esbuild --bundle --loader:=css
        
      • JS:

        esbuild.build({
          bundle: true,
          loader: { '': 'css' },
        })
        
      • Go:

        api.Build(api.BuildOptions{
          Bundle: true,
          Loader: map[string]api.Loader{"": api.LoaderCSS},
        })
        

      In addition, the "type" field in package.json files now only applies to files with an explicit .js, .jsx, .ts, or .tsx extension. Previously it was incorrectly applied by esbuild to all files that had an extension other than .mjs, .mts, .cjs, or .cts including extensionless files. So for example an extensionless file in a "type": "module" package is now treated as CommonJS instead of ESM.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.11(Dec 27, 2022)

    • Avoid a syntax error in the presence of direct eval (#2761)

      The behavior of nested function declarations in JavaScript depends on whether the code is run in strict mode or not. It would be problematic if esbuild preserved nested function declarations in its output because then the behavior would depend on whether the output was run in strict mode or not instead of respecting the strict mode behavior of the original source code. To avoid this, esbuild transforms nested function declarations to preserve the intended behavior of the original source code regardless of whether the output is run in strict mode or not:

      // Original code
      if (true) {
        function foo() {}
        console.log(!!foo)
        foo = null
        console.log(!!foo)
      }
      console.log(!!foo)
      
      // Transformed code
      if (true) {
        let foo2 = function() {
        };
        var foo = foo2;
        console.log(!!foo2);
        foo2 = null;
        console.log(!!foo2);
      }
      console.log(!!foo);
      

      In the above example, the original code should print true false true because it's not run in strict mode (it doesn't contain "use strict" and is not an ES module). The code that esbuild generates has been transformed such that it prints true false true regardless of whether it's run in strict mode or not.

      However, this transformation is impossible if the code contains direct eval because direct eval "poisons" all containing scopes by preventing anything in those scopes from being renamed. That prevents esbuild from splitting up accesses to foo into two separate variables with different names. Previously esbuild still did this transformation but with two variables both named foo, which is a syntax error. With this release esbuild will now skip doing this transformation when direct eval is present to avoid generating code with a syntax error. This means that the generated code may no longer behave as intended since the behavior depends on the run-time strict mode setting instead of the strict mode setting present in the original source code. To fix this problem, you will need to remove the use of direct eval.

    • Fix a bundling scenario involving multiple symlinks (#2773, #2774)

      This release contains a fix for a bundling scenario involving an import path where multiple path segments are symlinks. Previously esbuild was unable to resolve certain import paths in this scenario, but these import paths should now work starting with this release. This fix was contributed by @onebytegone.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.10(Dec 19, 2022)

    • Change the default "legal comment" behavior again (#2745)

      The legal comments feature automatically gathers comments containing @license or @preserve and puts the comments somewhere (either in the generated code or in a separate file). This behavior used to be on by default but was disabled by default in version 0.16.0 because automatically inserting comments is potentially confusing and misleading. These comments can appear to be assigning the copyright of your code to another entity. And this behavior can be especially problematic if it happens automatically by default since you may not even be aware of it happening. For example, if you bundle the TypeScript compiler the preserving legal comments means your source code would contain this comment, which appears to be assigning the copyright of all of your code to Microsoft:

      /*! *****************************************************************************
      Copyright (c) Microsoft Corporation. All rights reserved.
      Licensed under the Apache License, Version 2.0 (the "License"); you may not use
      this file except in compliance with the License. You may obtain a copy of the
      License at http://www.apache.org/licenses/LICENSE-2.0
      
      THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
      KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
      WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
      MERCHANTABLITY OR NON-INFRINGEMENT.
      
      See the Apache Version 2.0 License for specific language governing permissions
      and limitations under the License.
      ***************************************************************************** */
      

      However, people have asked for this feature to be re-enabled by default. To resolve the confusion about what these comments are applying to, esbuild's default behavior will now be to attempt to describe which package the comments are coming from. So while this feature has been re-enabled by default, the output will now look something like this instead:

      /*! Bundled license information:
      
      typescript/lib/typescript.js:
        (*! *****************************************************************************
        Copyright (c) Microsoft Corporation. All rights reserved.
        Licensed under the Apache License, Version 2.0 (the "License"); you may not use
        this file except in compliance with the License. You may obtain a copy of the
        License at http://www.apache.org/licenses/LICENSE-2.0
      
        THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
        KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
        WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
        MERCHANTABLITY OR NON-INFRINGEMENT.
      
        See the Apache Version 2.0 License for specific language governing permissions
        and limitations under the License.
        ***************************************************************************** *)
      */
      

      Note that you can still customize this behavior with the --legal-comments= flag. For example, you can use --legal-comments=none to turn this off, or you can use --legal-comments=linked to put these comments in a separate .LEGAL.txt file instead.

    • Enable external legal comments with the transform API (#2390)

      Previously esbuild's transform API only supported none, inline, or eof legal comments. With this release, external legal comments are now also supported with the transform API. This only applies to the JS and Go APIs, not to the CLI, and looks like this:

      • JS:

        const { code, legalComments } = await esbuild.transform(input, {
          legalComments: 'external',
        })
        
      • Go:

        result := api.Transform(input, api.TransformOptions{
          LegalComments: api.LegalCommentsEndOfFile,
        })
        code := result.Code
        legalComments := result.LegalComments
        
    • Fix duplicate function declaration edge cases (#2757)

      The change in the previous release to forbid duplicate function declarations in certain cases accidentally forbid some edge cases that should have been allowed. Specifically duplicate function declarations are forbidden in nested blocks in strict mode and at the top level of modules, but are allowed when they are declared at the top level of function bodies. This release fixes the regression by re-allowing the last case.

    • Allow package subpaths with alias (#2715)

      Previously the names passed to the alias feature had to be the name of a package (with or without a package scope). With this release, you can now also use the alias feature with package subpaths. So for example you can now create an alias that substitutes @org/pkg/lib with something else.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.9(Dec 18, 2022)

    • Update to Unicode 15.0.0

      The character tables that determine which characters form valid JavaScript identifiers have been updated from Unicode version 14.0.0 to the newly-released Unicode version 15.0.0. I'm not putting an example in the release notes because all of the new characters will likely just show up as little squares since fonts haven't been updated yet. But you can read https://www.unicode.org/versions/Unicode15.0.0/#Summary for more information about the changes.

    • Disallow duplicate lexically-declared names in nested blocks and in strict mode

      In strict mode or in a nested block, it's supposed to be a syntax error to declare two symbols with the same name unless all duplicate entries are either function declarations or all var declarations. However, esbuild was overly permissive and allowed this when duplicate entries were either function declarations or var declarations (even if they were mixed). This check has now been made more restrictive to match the JavaScript specification:

      // JavaScript allows this
      var a
      function a() {}
      {
        var b
        var b
        function c() {}
        function c() {}
      }
      
      // JavaScript doesn't allow this
      {
        var d
        function d() {}
      }
      
    • Add a type declaration for the new empty loader (#2755)

      I forgot to add this in the previous release. It has now been added.

      This fix was contributed by @fz6m.

    • Add support for the v flag in regular expression literals

      People are currently working on adding a v flag to JavaScript regular expresions. You can read more about this flag here: https://v8.dev/features/regexp-v-flag. This release adds support for parsing this flag, so esbuild will now no longer consider regular expression literals with this flag to be a syntax error. If the target is set to something other than esnext, esbuild will transform regular expression literals containing this flag into a new RegExp() constructor call so the resulting code doesn't have a syntax error. This enables you to provide a polyfill for RegExp that implements the v flag to get your code to work at run-time. While esbuild doesn't typically adopt proposals until they're already shipping in a real JavaScript run-time, I'm adding it now because a) esbuild's implementation doesn't need to change as the proposal evolves, b) this isn't really new syntax since regular expression literals already have flags, and c) esbuild's implementation is a trivial pass-through anyway.

    • Avoid keeping the name of classes with static name properties

      The --keep-names property attempts to preserve the original value of the name property for functions and classes even when identifiers are renamed by the minifier or to avoid a name collision. This is currently done by generating code to assign a string to the name property on the function or class object. However, this should not be done for classes with a static name property since in that case the explicitly-defined name property overwrites the automatically-generated class name. With this release, esbuild will now no longer attempt to preserve the name property for classes with a static name property.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.8(Dec 16, 2022)

    • Allow plugins to resolve injected files (#2754)

      Previously paths passed to the inject feature were always interpreted as file system paths. This meant that onResolve plugins would not be run for them and esbuild's default path resolver would always be used. This meant that the inject feature couldn't be used in the browser since the browser doesn't have access to a file system. This release runs paths passed to inject through esbuild's full path resolution pipeline so plugins now have a chance to handle them using onResolve callbacks. This makes it possible to write a plugin that makes esbuild's inject work in the browser.

    • Add the empty loader (#1541, #2753)

      The new empty loader tells esbuild to pretend that a file is empty. So for example --loader:.css=empty effectively skips all imports of .css files in JavaScript so that they aren't included in the bundle, since import "./some-empty-file" in JavaScript doesn't bundle anything. You can also use the empty loader to remove asset references in CSS files. For example --loader:.png=empty causes esbuild to replace asset references such as url(image.png) with url() so that they are no longer included in the resulting style sheet.

    • Fix </script> and </style> escaping for non-default targets (#2748)

      The change in version 0.16.0 to give control over </script> escaping via --supported:inline-script=false or --supported:inline-script=true accidentally broke automatic escaping of </script> when an explicit target setting is specified. This release restores the correct automatic escaping of </script> (which should not depend on what target is set to).

    • Enable the exports field with NODE_PATHS (#2752)

      Node has a rarely-used feature where you can extend the set of directories that node searches for packages using the NODE_PATHS environment variable. While esbuild supports this too, previously it only supported the old main field path resolution but did not support the new exports field package resolution. This release makes the path resolution rules the same again for both node_modules directories and NODE_PATHS directories.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.7(Dec 14, 2022)

    • Include file loader strings in metafile imports (#2731)

      Bundling a file with the file loader copies that file to the output directory and imports a module with the path to the copied file in the default export. Previously when bundling with the file loader, there was no reference in the metafile from the JavaScript file containing the path string to the copied file. With this release, there will now be a reference in the metafile in the imports array with the kind file-loader:

       {
         ...
         "outputs": {
           "out/image-55CCFTCE.svg": {
             ...
           },
           "out/entry.js": {
             "imports": [
      +        {
      +          "path": "out/image-55CCFTCE.svg",
      +          "kind": "file-loader"
      +        }
             ],
             ...
           }
         }
       }
      
    • Fix byte counts in metafile regarding references to other output files (#2071)

      Previously files that contained references to other output files had slightly incorrect metadata for the byte counts of input files which contributed to that output file. So for example if app.js imports image.png using the file loader and esbuild generates out.js and image-LSAMBFUD.png, the metadata for how many bytes of out.js are from app.js was slightly off (the metadata for the byte count of out.js was still correct). The reason is because esbuild substitutes the final paths for references between output files toward the end of the build to handle cyclic references, and the byte counts needed to be adjusted as well during the path substitution. This release fixes these byte counts (specifically the bytesInOutput values).

    • The alias feature now strips a trailing slash (#2730)

      People sometimes add a trailing slash to the name of one of node's built-in modules to force node to import from the file system instead of importing the built-in module. For example, importing util imports node's built-in module called util but importing util/ tries to find a package called util on the file system. Previously attempting to use esbuild's package alias feature to replace imports to util with a specific file would fail because the file path would also gain a trailing slash (e.g. mapping util to ./file.js turned util/ into ./file.js/). With this release, esbuild will now omit the path suffix if it's a single trailing slash, which should now allow you to successfully apply aliases to these import paths.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.6(Dec 14, 2022)

    • Do not mark subpath imports as external with --packages=external (#2741)

      Node has a feature called subpath imports where special import paths that start with # are resolved using the imports field in the package.json file of the enclosing package. The intent of the newly-added --packages=external setting is to exclude a package's dependencies from the bundle. Since a package's subpath imports are only accessible within that package, it's wrong for them to be affected by --packages=external. This release changes esbuild so that --packages=external no longer affects subpath imports.

    • Forbid invalid numbers in JSON files

      Previously esbuild parsed numbers in JSON files using the same syntax as JavaScript. But starting from this release, esbuild will now parse them with JSON syntax instead. This means the following numbers are no longer allowed by esbuild in JSON files:

      • Legacy octal literals (non-zero integers starting with 0)
      • The 0b, 0o, and 0x numeric prefixes
      • Numbers containing _ such as 1_000
      • Leading and trailing . such as 0. and .0
      • Numbers with a space after the - such as - 1
    • Add external imports to metafile (#905, #1768, #1933, #1939)

      External imports now appear in imports arrays in the metafile (which is present when bundling with metafile: true) next to normal imports, but additionally have external: true to set them apart. This applies both to files in the inputs section and the outputs section. Here's an example:

       {
         "inputs": {
           "style.css": {
             "bytes": 83,
             "imports": [
      +        {
      +          "path": "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css",
      +          "kind": "import-rule",
      +          "external": true
      +        }
             ]
           },
           "app.js": {
             "bytes": 100,
             "imports": [
      +        {
      +          "path": "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js",
      +          "kind": "import-statement",
      +          "external": true
      +        },
               {
                 "path": "style.css",
                 "kind": "import-statement"
               }
             ]
           }
         },
         "outputs": {
           "out/app.js": {
             "imports": [
      +        {
      +          "path": "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js",
      +          "kind": "require-call",
      +          "external": true
      +        }
             ],
             "exports": [],
             "entryPoint": "app.js",
             "cssBundle": "out/app.css",
             "inputs": {
               "app.js": {
                 "bytesInOutput": 113
               },
               "style.css": {
                 "bytesInOutput": 0
               }
             },
             "bytes": 528
           },
           "out/app.css": {
             "imports": [
      +        {
      +          "path": "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css",
      +          "kind": "import-rule",
      +          "external": true
      +        }
             ],
             "inputs": {
               "style.css": {
                 "bytesInOutput": 0
               }
             },
             "bytes": 100
           }
         }
       }
      

      One additional useful consequence of this is that the imports array is now populated when bundling is disabled. So you can now use esbuild with bundling disabled to inspect a file's imports.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.5(Dec 13, 2022)

    • Make it easy to exclude all packages from a bundle (#1958, #1975, #2164, #2246, #2542)

      When bundling for node, it's often necessary to exclude npm packages from the bundle since they weren't designed with esbuild bundling in mind and don't work correctly after being bundled. For example, they may use __dirname and run-time file system calls to load files, which doesn't work after bundling with esbuild. Or they may compile a native .node extension that has similar expectations about the layout of the file system that are no longer true after bundling (even if the .node extension is copied next to the bundle).

      The way to get this to work with esbuild is to use the --external: flag. For example, the fsevents package contains a native .node extension and shouldn't be bundled. To bundle code that uses it, you can pass --external:fsevents to esbuild to exclude it from your bundle. You will then need to ensure that the fsevents package is still present when you run your bundle (e.g. by publishing your bundle to npm as a package with a dependency on fsevents).

      It was possible to automatically do this for all of your dependencies, but it was inconvenient. You had to write some code that read your package.json file and passed the keys of the dependencies, devDependencies, peerDependencies, and/or optionalDependencies maps to esbuild as external packages (either that or write a plugin to mark all package paths as external). Previously esbuild's recommendation for making this easier was to do --external:./node_modules/* (added in version 0.14.13). However, this was a bad idea because it caused compatibility problems with many node packages as it caused esbuild to mark the post-resolve path as external instead of the pre-resolve path. Doing that could break packages that are published as both CommonJS and ESM if esbuild's bundler is also used to do a module format conversion.

      With this release, you can now do the following to automatically exclude all packages from your bundle:

      • CLI:

        esbuild --bundle --packages=external
        
      • JS:

        esbuild.build({
          bundle: true,
          packages: 'external',
        })
        
      • Go:

        api.Build(api.BuildOptions{
          Bundle:   true,
          Packages: api.PackagesExternal,
        })
        

      Doing --external:./node_modules/* is still possible and still has the same behavior, but is no longer recommended. I recommend that you use the new packages feature instead.

    • Fix some subtle bugs with tagged template literals

      This release fixes a bug where minification could incorrectly change the value of this within tagged template literal function calls:

      // Original code
      function f(x) {
        let z = y.z
        return z``
      }
      
      // Old output (with --minify)
      function f(n){return y.z``}
      
      // New output (with --minify)
      function f(n){return(0,y.z)``}
      

      This release also fixes a bug where using optional chaining with --target=es2019 or earlier could incorrectly change the value of this within tagged template literal function calls:

      // Original code
      var obj = {
        foo: function() {
          console.log(this === obj);
        }
      };
      (obj?.foo)``;
      
      // Old output (with --target=es6)
      var obj = {
        foo: function() {
          console.log(this === obj);
        }
      };
      (obj == null ? void 0 : obj.foo)``;
      
      // New output (with --target=es6)
      var __freeze = Object.freeze;
      var __defProp = Object.defineProperty;
      var __template = (cooked, raw) => __freeze(__defProp(cooked, "raw", { value: __freeze(raw || cooked.slice()) }));
      var _a;
      var obj = {
        foo: function() {
          console.log(this === obj);
        }
      };
      (obj == null ? void 0 : obj.foo).call(obj, _a || (_a = __template([""])));
      
    • Some slight minification improvements

      The following minification improvements were implemented:

      • if (~a !== 0) throw x; => if (~a) throw x;
      • if ((a | b) !== 0) throw x; => if (a | b) throw x;
      • if ((a & b) !== 0) throw x; => if (a & b) throw x;
      • if ((a ^ b) !== 0) throw x; => if (a ^ b) throw x;
      • if ((a << b) !== 0) throw x; => if (a << b) throw x;
      • if ((a >> b) !== 0) throw x; => if (a >> b) throw x;
      • if ((a >>> b) !== 0) throw x; => if (a >>> b) throw x;
      • if (!!a || !!b) throw x; => if (a || b) throw x;
      • if (!!a && !!b) throw x; => if (a && b) throw x;
      • if (a ? !!b : !!c) throw x; => if (a ? b : c) throw x;
    Source code(tar.gz)
    Source code(zip)
  • v0.16.4(Dec 10, 2022)

    • Fix binary downloads from the @esbuild/ scope for Deno (#2729)

      Version 0.16.0 of esbuild moved esbuild's binary executables into npm packages under the @esbuild/ scope, which accidentally broke the binary downloader script for Deno. This release fixes this script so it should now be possible to use esbuild version 0.16.4+ with Deno.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.3(Dec 8, 2022)

    • Fix a hang with the JS API in certain cases (#2727)

      A change that was made in version 0.15.13 accidentally introduced a case when using esbuild's JS API could cause the node process to fail to exit. The change broke esbuild's watchdog timer, which detects if the parent process no longer exists and then automatically exits esbuild. This hang happened when you ran node as a child process with the stderr stream set to pipe instead of inherit, in the child process you call esbuild's JS API and pass incremental: true but do not call dispose() on the returned rebuild object, and then call process.exit(). In that case the parent node process was still waiting for the esbuild process that was created by the child node process to exit. The change made in version 0.15.13 was trying to avoid using Go's sync.WaitGroup API incorrectly because the API is not thread-safe. Instead of doing this, I have now reverted that change and implemented a thread-safe version of the sync.WaitGroup API for esbuild to use instead.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.2(Dec 8, 2022)

    • Fix process.env.NODE_ENV substitution when transforming (#2718)

      Version 0.16.0 introduced an unintentional regression that caused process.env.NODE_ENV to be automatically substituted with either "development" or "production" when using esbuild's transform API. This substitution is a necessary feature of esbuild's build API because the React framework crashes when you bundle it without doing this. But the transform API is typically used as part of a larger build pipeline so the benefit of esbuild doing this automatically is not as clear, and esbuild previously didn't do this.

      However, version 0.16.0 switched the default value of the platform setting for the transform API from neutral to browser, both to align it with esbuild's documentation (which says browser is the default value) and because escaping the </script> character sequence is now tied to the browser platform (see the release notes for version 0.16.0 for details). That accidentally enabled automatic substitution of process.env.NODE_ENV because esbuild always did that for code meant for the browser. To fix this regression, esbuild will now only automatically substitute process.env.NODE_ENV when using the build API.

    • Prevent define from substituting constants into assignment position (#2719)

      The define feature lets you replace certain expressions with constants. For example, you could use it to replace references to the global property reference window.DEBUG with false at compile time, which can then potentially help esbuild remove unused code from your bundle. It's similar to DefinePlugin in Webpack.

      However, if you write code such as window.DEBUG = true and then defined window.DEBUG to false, esbuild previously generated the output false = true which is a syntax error in JavaScript. This behavior is not typically a problem because it doesn't make sense to substitute window.DEBUG with a constant if its value changes at run-time (Webpack's DefinePlugin also generates false = true in this case). But it can be alarming to have esbuild generate code with a syntax error.

      So with this release, esbuild will no longer substitute define constants into assignment position to avoid generating code with a syntax error. Instead esbuild will generate a warning, which currently looks like this:

      ▲ [WARNING] Suspicious assignment to defined constant "window.DEBUG" [assign-to-define]
      
          example.js:1:0:
            1 │ window.DEBUG = true
              ╵ ~~~~~~~~~~~~
      
        The expression "window.DEBUG" has been configured to be replaced with a constant using the
        "define" feature. If this expression is supposed to be a compile-time constant, then it doesn't
        make sense to assign to it here. Or if this expression is supposed to change at run-time, this
        "define" substitution should be removed.
      
    • Fix a regression with npm install --no-optional (#2720)

      Normally when you install esbuild with npm install, npm itself is the tool that downloads the correct binary executable for the current platform. This happens because of how esbuild's primary package uses npm's optionalDependencies feature. However, if you deliberately disable this with npm install --no-optional then esbuild's install script will attempt to repair the installation by manually downloading and extracting the binary executable from the package that was supposed to be installed.

      The change in version 0.16.0 to move esbuild's nested packages into the @esbuild/ scope unintentionally broke this logic because of how npm's URL structure is different for scoped packages vs. normal packages. It was actually already broken for a few platforms earlier because esbuild already had packages for some platforms in the @esbuild/ scope, but I didn't discover this then because esbuild's integration tests aren't run on all platforms. Anyway, this release contains some changes to the install script that should hopefully get this scenario working again.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.1(Dec 7, 2022)

    This is a hotfix for the previous release.

    • Re-allow importing JSON with the copy loader using an import assertion

      The previous release made it so when assert { type: 'json' } is present on an import statement, esbuild validated that the json loader was used. This is what an import assertion is supposed to do. However, I forgot about the relatively new copy loader, which sort of behaves as if the import path was marked as external (and thus not loaded at all) except that the file is copied to the output directory and the import path is rewritten to point to the copy. In this case whatever JavaScript runtime ends up running the code is the one to evaluate the import assertion. So esbuild should really allow this case as well. With this release, esbuild now allows both the json and copy loaders when an assert { type: 'json' } import assertion is present.

    Source code(tar.gz)
    Source code(zip)
  • v0.16.0(Dec 7, 2022)

    This release deliberately contains backwards-incompatible changes. To avoid automatically picking up releases like this, you should either be pinning the exact version of esbuild in your package.json file (recommended) or be using a version range syntax that only accepts patch upgrades such as ^0.15.0 or ~0.15.0. See npm's documentation about semver for more information.

    • Move all binary executable packages to the @esbuild/ scope

      Binary package executables for esbuild are published as individual packages separate from the main esbuild package so you only have to download the relevant one for the current platform when you install esbuild. This release moves all of these packages under the @esbuild/ scope to avoid collisions with 3rd-party packages. It also changes them to a consistent naming scheme that uses the os and cpu names from node.

      The package name changes are as follows:

      • @esbuild/linux-loong64 => @esbuild/linux-loong64 (no change)
      • esbuild-android-64 => @esbuild/android-x64
      • esbuild-android-arm64 => @esbuild/android-arm64
      • esbuild-darwin-64 => @esbuild/darwin-x64
      • esbuild-darwin-arm64 => @esbuild/darwin-arm64
      • esbuild-freebsd-64 => @esbuild/freebsd-x64
      • esbuild-freebsd-arm64 => @esbuild/freebsd-arm64
      • esbuild-linux-32 => @esbuild/linux-ia32
      • esbuild-linux-64 => @esbuild/linux-x64
      • esbuild-linux-arm => @esbuild/linux-arm
      • esbuild-linux-arm64 => @esbuild/linux-arm64
      • esbuild-linux-mips64le => @esbuild/linux-mips64el
      • esbuild-linux-ppc64le => @esbuild/linux-ppc64
      • esbuild-linux-riscv64 => @esbuild/linux-riscv64
      • esbuild-linux-s390x => @esbuild/linux-s390x
      • esbuild-netbsd-64 => @esbuild/netbsd-x64
      • esbuild-openbsd-64 => @esbuild/openbsd-x64
      • esbuild-sunos-64 => @esbuild/sunos-x64
      • esbuild-wasm => esbuild-wasm (no change)
      • esbuild-windows-32 => @esbuild/win32-ia32
      • esbuild-windows-64 => @esbuild/win32-x64
      • esbuild-windows-arm64 => @esbuild/win32-arm64
      • esbuild => esbuild (no change)

      Normal usage of the esbuild and esbuild-wasm packages should not be affected. These name changes should only affect tools that hard-coded the individual binary executable package names into custom esbuild downloader scripts.

      This change was not made with performance in mind. But as a bonus, installing esbuild with npm may potentially happen faster now. This is because npm's package installation protocol is inefficient: it always downloads metadata for all past versions of each package even when it only needs metadata about a single version. This makes npm package downloads O(n) in the number of published versions, which penalizes packages like esbuild that are updated regularly. Since most of esbuild's package names have now changed, npm will now need to download much less data when installing esbuild (8.72mb of package manifests before this change → 0.06mb of package manifests after this change). However, this is only a temporary improvement. Installing esbuild will gradually get slower again as further versions of esbuild are published.

    • Publish a shell script that downloads esbuild directly

      In addition to all of the existing ways to install esbuild, you can now also download esbuild directly like this:

      curl -fsSL https://esbuild.github.io/dl/latest | sh
      

      This runs a small shell script that downloads the latest esbuild binary executable to the current directory. This can be convenient on systems that don't have npm installed or when you just want to get a copy of esbuild quickly without any extra steps. If you want a specific version of esbuild (starting with this version onward), you can provide that version in the URL instead of latest:

      curl -fsSL https://esbuild.github.io/dl/v0.16.0 | sh
      

      Note that the download script needs to be able to access registry.npmjs.org to be able to complete the download. This download script doesn't yet support all of the platforms that esbuild supports because I lack the necessary testing environments. If the download script doesn't work for you because you're on an unsupported platform, please file an issue on the esbuild repo so we can add support for it.

    • Fix some parameter names for the Go API

      This release changes some parameter names for the Go API to be consistent with the JavaScript and CLI APIs:

      • OutExtensions => OutExtension
      • JSXMode => JSX
    • Add additional validation of API parameters

      The JavaScript API now does some additional validation of API parameters to catch incorrect uses of esbuild's API. The biggest impact of this is likely that esbuild now strictly only accepts strings with the define parameter. This would already have been a type error with esbuild's TypeScript type definitions, but it was previously not enforced for people using esbuild's API JavaScript without TypeScript.

      The define parameter appears at first glance to take a JSON object if you aren't paying close attention, but this actually isn't true. Values for define are instead strings of JavaScript code. This means you have to use define: { foo: '"bar"' } to replace foo with the string "bar". Using define: { foo: 'bar' } actually replaces foo with the identifier bar. Previously esbuild allowed you to pass define: { foo: false } and false was automatically converted into a string, which made it more confusing to understand what define actually represents. Starting with this release, passing non-string values such as with define: { foo: false } will no longer be allowed. You will now have to write define: { foo: 'false' } instead.

    • Generate shorter data URLs if possible (#1843)

      Loading a file with esbuild's dataurl loader generates a JavaScript module with a data URL for that file in a string as a single default export. Previously the data URLs generated by esbuild all used base64 encoding. However, this is unnecessarily long for most textual data (e.g. SVG images). So with this release, esbuild's dataurl loader will now use percent encoding instead of base64 encoding if the result will be shorter. This can result in ~25% smaller data URLs for large SVGs. If you want the old behavior, you can use the base64 loader instead and then construct the data URL yourself.

    • Avoid marking entry points as external (#2382)

      Previously you couldn't specify --external:* to mark all import paths as external because that also ended up making the entry point itself external, which caused the build to fail. With this release, esbuild's external API parameter no longer applies to entry points so using --external:* is now possible.

      One additional consequence of this change is that the kind parameter is now required when calling the resolve() function in esbuild's plugin API. Previously the kind parameter defaulted to entry-point, but that no longer interacts with external so it didn't seem wise for this to continue to be the default. You now have to specify kind so that the path resolution mode is explicit.

    • Disallow non-default imports when assert { type: 'json' } is present

      There is now standard behavior for importing a JSON file into an ES module using an import statement. However, it requires you to place the assert { type: 'json' } import assertion after the import path. This import assertion tells the JavaScript runtime to throw an error if the import does not end up resolving to a JSON file. On the web, the type of a file is determined by the Content-Type HTTP header instead of by the file extension. The import assertion prevents security problems on the web where a .json file may actually resolve to a JavaScript file containing malicious code, which is likely not expected for an import that is supposed to only contain pure side-effect free data.

      By default, esbuild uses the file extension to determine the type of a file, so this import assertion is unnecessary with esbuild. However, esbuild's JSON import feature has a non-standard extension that allows you to import top-level properties of the JSON object as named imports. For example, esbuild lets you do this:

      import { version } from './package.json'
      

      This is useful for tree-shaking when bundling because it means esbuild will only include the the version field of package.json in your bundle. This is non-standard behavior though and doesn't match the behavior of what happens when you import JSON in a real JavaScript runtime (after adding assert { type: 'json' }). In a real JavaScript runtime the only thing you can import is the default import. So with this release, esbuild will now prevent you from importing non-default import names if assert { type: 'json' } is present. This ensures that code containing assert { type: 'json' } isn't relying on non-standard behavior that won't work everywhere. So the following code is now an error with esbuild when bundling:

      import { version } from './package.json' assert { type: 'json' }
      

      In addition, adding assert { type: 'json' } to an import statement now means esbuild will generate an error if the loader for the file is anything other than json, which is required by the import assertion specification.

    • Provide a way to disable automatic escaping of </script> (#2649)

      If you inject esbuild's output into a script tag in an HTML file, code containing the literal characters </script> will cause the tag to be ended early which will break the code:

      <script>
        console.log("</script>");
      </script>
      

      To avoid this, esbuild automatically escapes these strings in generated JavaScript files (e.g. "</script>" becomes "<\/script>" instead). This also applies to </style> in generated CSS files. Previously this always happened and there wasn't a way to turn this off.

      With this release, esbuild will now only do this if the platform setting is set to browser (the default value). Setting platform to node or neutral will disable this behavior. This behavior can also now be disabled with --supported:inline-script=false (for JS) and --supported:inline-style=false (for CSS).

    • Throw an early error if decoded UTF-8 text isn't a Uint8Array (#2532)

      If you run esbuild's JavaScript API in a broken JavaScript environment where new TextEncoder().encode("") instanceof Uint8Array is false, then esbuild's API will fail with a confusing serialization error message that makes it seem like esbuild has a bug even though the real problem is that the JavaScript environment itself is broken. This can happen when using the test framework called Jest. With this release, esbuild's API will now throw earlier when it detects that the environment is unable to encode UTF-8 text correctly with an error message that makes it more clear that this is not a problem with esbuild.

    • Change the default "legal comment" behavior

      The legal comments feature automatically gathers comments containing @license or @preserve and puts the comments somewhere (either in the generated code or in a separate file). People sometimes want this to happen so that the their dependencies' software licenses are retained in the generated output code. By default esbuild puts these comments at the end of the file when bundling. However, people sometimes find this confusing because these comments can be very generic and may not mention which library they come from. So with this release, esbuild will now discard legal comments by default. You now have to opt-in to preserving them if you want this behavior.

    • Enable the module condition by default (#2417)

      Package authors want to be able to use the new exports field in package.json to provide tree-shakable ESM code for ESM-aware bundlers while simultaneously providing fallback CommonJS code for other cases.

      Node's proposed way to do this involves using the import and require export conditions so that you get the ESM code if you use an import statement and the CommonJS code if you use a require call. However, this has a major drawback: if some code in the bundle uses an import statement and other code in the bundle uses a require call, then you'll get two copies of the same package in the bundle. This is known as the dual package hazard and can lead to bloated bundles or even worse to subtle logic bugs.

      Webpack supports an alternate solution: an export condition called module that takes effect regardless of whether the package was imported using an import statement or a require call. This works because bundlers such as Webpack support importing a ESM using a require call (something node doesn't support). You could already do this with esbuild using --conditions=module but you previously had to explicitly enable this. Package authors are concerned that esbuild users won't know to do this and will get suboptimal output with their package, so they have requested for esbuild to do this automatically.

      So with this release, esbuild will now automatically add the module condition when there aren't any custom conditions already configured. You can disable this with --conditions= or conditions: [] (i.e. explicitly clearing all custom conditions).

    • Rename the master branch to main

      The primary branch for this repository was previously called master but is now called main. This change mirrors a similar change in many other projects.

    • Remove esbuild's _exit(0) hack for WebAssembly (#714)

      Node had an unfortunate bug where the node process is unnecessarily kept open while a WebAssembly module is being optimized: https://github.com/nodejs/node/issues/36616. This means cases where running esbuild should take a few milliseconds can end up taking many seconds instead.

      The workaround was to force node to exit by ending the process early. This was done by esbuild in one of two ways depending on the exit code. For non-zero exit codes (i.e. when there is a build error), the esbuild command could just call process.kill(process.pid) to avoid the hang. But for zero exit codes, esbuild had to load a N-API native node extension that calls the operating system's exit(0) function.

      However, this problem has essentially been fixed in node starting with version 18.3.0. So I have removed this hack from esbuild. If you are using an earlier version of node with esbuild-wasm and you don't want the esbuild command to hang for a while when exiting, you can upgrade to node 18.3.0 or higher to remove the hang.

      The fix came from a V8 upgrade: this commit enabled dynamic tiering for WebAssembly by default for all projects that use V8's WebAssembly implementation. Previously all functions in the WebAssembly module were optimized in a single batch job but with dynamic tiering, V8 now optimizes individual WebAssembly functions as needed. This avoids unnecessary WebAssembly compilation which allows node to exit on time.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.18(Dec 5, 2022)

    • Performance improvements for both JS and CSS

      This release brings noticeable performance improvements for JS parsing and for CSS parsing and printing. Here's an example benchmark for using esbuild to pretty-print a single large minified CSS file and JS file:

      | Test case | Previous release | This release | |----------------|------------------|--------------------| | 4.8mb CSS file | 19ms | 11ms (1.7x faster) | | 5.8mb JS file | 36ms | 32ms (1.1x faster) |

      The performance improvements were very straightforward:

      • Identifiers were being scanned using a generic character advancement function instead of using custom inline code. Advancing past each character involved UTF-8 decoding as well as updating multiple member variables. This was sped up using loop that skips UTF-8 decoding entirely and that only updates member variables once at the end. This is faster because identifiers are plain ASCII in the vast majority of cases, so Unicode decoding is almost always unnecessary.

      • CSS identifiers and CSS strings were still being printed one character at a time. Apparently I forgot to move this part of esbuild's CSS infrastructure beyond the proof-of-concept stage. These were both very obvious in the profiler, so I think maybe I have just never profiled esbuild's CSS printing before?

      • There was unnecessary work being done that was related to source maps when source map output was disabled. I likely haven't observed this before because esbuild's benchmarks always have source maps enabled. This work is now disabled when it's not going to be used.

      I definitely should have caught these performance issues earlier. Better late than never I suppose.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.17(Dec 4, 2022)

    • Search for missing source map code on the file system (#2711)

      Source maps are JSON files that map from compiled code back to the original code. They provide the original source code using two arrays: sources (required) and sourcesContent (optional). When bundling is enabled, esbuild is able to bundle code with source maps that was compiled by other tools (e.g. with Webpack) and emit source maps that map all the way back to the original code (e.g. before Webpack compiled it).

      Previously if the input source maps omitted the optional sourcesContent array, esbuild would use null for the source content in the source map that it generates (since the source content isn't available). However, sometimes the original source code is actually still present on the file system. With this release, esbuild will now try to find the original source code using the path in the sources array and will use that instead of null if it was found.

    • Fix parsing bug with TypeScript infer and extends (#2712)

      This release fixes a bug where esbuild incorrectly failed to parse valid TypeScript code that nests extends inside infer inside extends, such as in the example below:

      type A<T> = {};
      type B = {} extends infer T extends {} ? A<T> : never;
      

      TypeScript code that does this should now be parsed correctly.

    • Use WebAssembly.instantiateStreaming if available (#1036, #1900)

      Currently the WebAssembly version of esbuild uses fetch to download esbuild.wasm and then WebAssembly.instantiate to compile it. There is a newer API called WebAssembly.instantiateStreaming that both downloads and compiles at the same time, which can be a performance improvement if both downloading and compiling are slow. With this release, esbuild now attempts to use WebAssembly.instantiateStreaming and falls back to the original approach if that fails.

      The implementation for this builds on a PR by @lbwa.

    • Preserve Webpack comments inside constructor calls (#2439)

      This improves the use of esbuild as a faster TypeScript-to-JavaScript frontend for Webpack, which has special magic comments inside new Worker() expressions that affect Webpack's behavior.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.16(Nov 27, 2022)

    • Add a package alias feature (#2191)

      With this release, you can now easily substitute one package for another at build time with the new alias feature. For example, --alias:oldpkg=newpkg replaces all imports of oldpkg with newpkg. One use case for this is easily replacing a node-only package with a browser-friendly package in 3rd-party code that you don't control. These new substitutions happen first before all of esbuild's existing path resolution logic.

      Note that when an import path is substituted using an alias, the resulting import path is resolved in the working directory instead of in the directory containing the source file with the import path. If needed, the working directory can be set with the cd command when using the CLI or with the absWorkingDir setting when using the JS or Go APIs.

    • Fix crash when pretty-printing minified JSX with object spread of object literal with computed property (#2697)

      JSX elements are translated to JavaScript function calls and JSX element attributes are translated to properties on a JavaScript object literal. These properties are always either strings (e.g. in <x y />, y is a string) or an object spread (e.g. in <x {...y} />, y is an object spread) because JSX doesn't provide syntax for directly passing a computed property as a JSX attribute. However, esbuild's minifier has a rule that tries to inline object spread with an inline object literal in JavaScript. For example, x = { ...{ y } } is minified to x={y} when minification is enabled. This means that there is a way to generate a non-string non-spread JSX attribute in esbuild's internal representation. One example is with <x {...{ [y]: z }} />. When minification is enabled, esbuild's internal representation of this is something like <x [y]={z} /> due to object spread inlining, which is not valid JSX syntax. If this internal representation is then pretty-printed as JSX using --minify --jsx=preserve, esbuild previously crashed when trying to print this invalid syntax. With this release, esbuild will now print <x {...{[y]:z}}/> in this scenario instead of crashing.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.15(Nov 21, 2022)

    • Remove duplicate CSS rules across files (#2688)

      When two or more CSS rules are exactly the same (even if they are not adjacent), all but the last one can safely be removed:

      /* Before */
      a { color: red; }
      span { font-weight: bold; }
      a { color: red; }
      
      /* After */
      span { font-weight: bold; }
      a { color: red; }
      

      Previously esbuild only did this transformation within a single source file. But with this release, esbuild will now do this transformation across source files, which may lead to smaller CSS output if the same rules are repeated across multiple CSS source files in the same bundle. This transformation is only enabled when minifying (specifically when syntax minification is enabled).

    • Add deno as a valid value for target (#2686)

      The target setting in esbuild allows you to enable or disable JavaScript syntax features for a given version of a set of target JavaScript VMs. Previously Deno was not one of the JavaScript VMs that esbuild supported with target, but it will now be supported starting from this release. For example, versions of Deno older than v1.2 don't support the new ||= operator, so adding e.g. --target=deno1.0 to esbuild now lets you tell esbuild to transpile ||= to older JavaScript.

    • Fix the esbuild-wasm package in Node v19 (#2683)

      A recent change to Node v19 added a non-writable crypto property to the global object: https://github.com/nodejs/node/pull/44897. This conflicts with Go's WebAssembly shim code, which overwrites the global crypto property. As a result, all Go-based WebAssembly code that uses the built-in shim (including esbuild) is now broken on Node v19. This release of esbuild fixes the issue by reconfiguring the global crypto property to be writable before invoking Go's WebAssembly shim code.

    • Fix CSS dimension printing exponent confusion edge case (#2677)

      In CSS, a dimension token has a numeric "value" part and an identifier "unit" part. For example, the dimension token 32px has a value of 32 and a unit of px. The unit can be any valid CSS identifier. The value can be any number in floating-point format including an optional exponent (e.g. -3.14e-0 has an exponent of e-0). The full details of this syntax are here: https://www.w3.org/TR/css-syntax-3/.

      To maintain the integrity of the dimension token through the printing process, esbuild must handle the edge case where the unit looks like an exponent. One such case is the dimension 1e\32 which has the value 1 and the unit e2. It would be bad if this dimension token was printed such that a CSS parser would parse it as a number token with the value 1e2 instead of a dimension token. The way esbuild currently does this is to escape the leading e in the dimension unit, so esbuild would parse 1e\32 but print 1\65 2 (both 1e\32 and 1\65 2 represent a dimension token with a value of 1 and a unit of e2).

      However, there is an even narrower edge case regarding this edge case. If the value part of the dimension token itself has an e, then it's not necessary to escape the e in the dimension unit because a CSS parser won't confuse the unit with the exponent even though it looks like one (since a number can only have at most one exponent). This came up because the grammar for the CSS unicode-range property uses a hack that lets you specify a hexadecimal range without quotes even though CSS has no token for a hexadecimal range. The hack is to allow the hexadecimal range to be parsed as a dimension token and optionally also a number token. Here is the grammar for unicode-range:

      unicode-range =
        <urange>#
      
      <urange> =
        u '+' <ident-token> '?'*            |
        u <dimension-token> '?'*            |
        u <number-token> '?'*               |
        u <number-token> <dimension-token>  |
        u <number-token> <number-token>     |
        u '+' '?'+
      

      and here is an example unicode-range declaration that was problematic for esbuild:

      @font-face {
        unicode-range: U+0e2e-0e2f;
      }
      

      This is parsed as a dimension with a value of +0e2 and a unit of e-0e2f. This was problematic for esbuild because the unit starts with e-0 which could be confused with an exponent when appended after a number, so esbuild was escaping the e character in the unit. However, this escaping is unnecessary because in this case the dimension value already has an exponent in it. With this release, esbuild will no longer unnecessarily escape the e in the dimension unit in these cases, which should fix the printing of unicode-range declarations.

      An aside: You may be wondering why esbuild is trying to escape the e at all and why it doesn't just pass through the original source code unmodified. The reason why esbuild does this is that, for robustness, esbuild's AST generally tries to omit semantically-unrelated information and esbuild's code printers always try to preserve the semantics of the underlying AST. That way the rest of esbuild's internals can just deal with semantics instead of presentation. They don't have to think about how the AST will be printed when changing the AST. This is the same reason that esbuild's JavaScript AST doesn't have a "parentheses" node (e.g. a * (b + c) is represented by the AST multiply(a, add(b, c)) instead of multiply(a, parentheses(add(b, c)))). Instead, the printer automatically inserts parentheses as necessary to maintain the semantics of the AST, which means all of the optimizations that run over the AST don't have to worry about keeping the parentheses up to date. Similarly, the CSS AST for the dimension token stores the actual unit and the printer makes sure the unit is properly escaped depending on what value it's placed after. All of the other code operating on CSS ASTs doesn't have to worry about parsing escapes to compare units or about keeping escapes up to date when the AST is modified. Hopefully that makes sense.

    • Attempt to avoid creating the node_modules/.cache directory for people that use Yarn 2+ in Plug'n'Play mode (#2685)

      When Yarn's PnP mode is enabled, packages installed by Yarn may or may not be put inside .zip files. The specific heuristics for when this happens change over time in between Yarn versions. This is problematic for esbuild because esbuild's JavaScript package needs to execute a binary file inside the package. Yarn makes extensive modifications to Node's file system APIs at run time to pretend that .zip files are normal directories and to make it hard to tell whether a file is real or not (since in theory it doesn't matter). But they haven't modified Node's child_process.execFileSync API so attempting to execute a file inside a zip file fails. To get around this, esbuild previously used Node's file system APIs to copy the binary executable to another location before invoking execFileSync. Under the hood this caused Yarn to extract the file from the zip file into a real file that can then be run.

      However, esbuild copied its executable into node_modules/.cache/esbuild. This is the official recommendation from the Yarn team for where packages are supposed to put these types of files when Yarn PnP is being used. However, users of Yarn PnP with esbuild find this really annoying because they don't like looking at the node_modules directory. With this release, esbuild now sets "preferUnplugged": true in its package.json files, which tells newer versions of Yarn to not put esbuild's packages in a zip file. There may exist older versions of Yarn that don't support preferUnplugged. In that case esbuild should still copy the executable to a cache directory, so it should still run (hopefully, since I haven't tested this myself). Note that esbuild setting "preferUnplugged": true may have the side effect of esbuild taking up more space on the file system in the event that multiple platforms are installed simultaneously, or that you're using an older version of Yarn that always installs packages for all platforms. In that case you may want to update to a newer version of Yarn since Yarn has recently changed to only install packages for the current platform.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.14(Nov 15, 2022)

    • Fix parsing of TypeScript infer inside a conditional extends (#2675)

      Unlike JavaScript, parsing TypeScript sometimes requires backtracking. The infer A type operator can take an optional constraint of the form infer A extends B. However, this syntax conflicts with the similar conditional type operator A extends B ? C : D in cases where the syntax is combined, such as infer A extends B ? C : D. This is supposed to be parsed as (infer A) extends B ? C : D. Previously esbuild incorrectly parsed this as (infer A extends B) ? C : D instead, which is a parse error since the ?: conditional operator requires the extends keyword as part of the conditional type. TypeScript disambiguates by speculatively parsing the extends after the infer, but backtracking if a ? token is encountered afterward. With this release, esbuild should now do the same thing, so esbuild should now correctly parse these types. Here's a real-world example of such a type:

      type Normalized<T> = T extends Array<infer A extends object ? infer A : never>
        ? Dictionary<Normalized<A>>
        : {
            [P in keyof T]: T[P] extends Array<infer A extends object ? infer A : never>
              ? Dictionary<Normalized<A>>
              : Normalized<T[P]>
          }
      
    • Avoid unnecessary watch mode rebuilds when debug logging is enabled (#2661)

      When debug-level logs are enabled (such as with --log-level=debug), esbuild's path resolution subsystem generates debug log messages that say something like "Read 20 entries for directory /home/user" to help you debug what esbuild's path resolution is doing. This caused esbuild's watch mode subsystem to add a dependency on the full list of entries in that directory since if that changes, the generated log message would also have to be updated. However, meant that on systems where a parent directory undergoes constant directory entry churn, esbuild's watch mode would continue to rebuild if --log-level=debug was passed.

      With this release, these debug log messages are now generated by "peeking" at the file system state while bypassing esbuild's watch mode dependency tracking. So now watch mode doesn't consider the count of directory entries in these debug log messages to be a part of the build that needs to be kept up to date when the file system state changes.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.13(Nov 3, 2022)

    • Add support for the TypeScript 4.9 satisfies operator (#2509)

      TypeScript 4.9 introduces a new operator called satisfies that lets you check that a given value satisfies a less specific type without casting it to that less specific type and without generating any additional code at run-time. It looks like this:

      const value = { foo: 1, bar: false } satisfies Record<string, number | boolean>
      console.log(value.foo.toFixed(1)) // TypeScript knows that "foo" is a number here
      

      Before this existed, you could use a cast with as to check that a value satisfies a less specific type, but that removes any additional knowledge that TypeScript has about that specific value:

      const value = { foo: 1, bar: false } as Record<string, number | boolean>
      console.log(value.foo.toFixed(1)) // TypeScript no longer knows that "foo" is a number
      

      You can read more about this feature in TypeScript's blog post for 4.9 as well as the associated TypeScript issue for this feature.

      This feature was implemented in esbuild by @magic-akari.

    • Fix watch mode constantly rebuilding if the parent directory is inaccessible (#2640)

      Android is unusual in that it has an inaccessible directory in the path to the root, which esbuild was not originally built to handle. To handle cases like this, the path resolution layer in esbuild has a hack where it treats inaccessible directories as empty. However, esbuild's watch implementation currently triggers a rebuild if a directory previously encountered an error but the directory now exists. The assumption is that the previous error was caused by the directory not existing. Although that's usually the case, it's not the case for this particular parent directory on Android. Instead the error is that the directory previously existed but was inaccessible.

      This discrepancy between esbuild's path resolution layer and its watch mode was causing watch mode to rebuild continuously on Android. With this release, esbuild's watch mode instead checks for an error status change in the readdir file system call, so watch mode should no longer rebuild continuously on Android.

    • Apply a fix for a rare deadlock with the JavaScript API (#1842, #2485)

      There have been reports of esbuild sometimes exiting with an "all goroutines are asleep" deadlock message from the Go language runtime. This issue hasn't made much progress until recently, where a possible cause was discovered (thanks to @jfirebaugh for the investigation). This release contains a possible fix for that possible cause, so this deadlock may have been fixed. The fix cannot be easily verified because the deadlock is non-deterministic and rare. If this was indeed the cause, then this issue only affected the JavaScript API in situations where esbuild was already in the process of exiting.

      In detail: The underlying cause is that Go's sync.WaitGroup API for waiting for a set of goroutines to finish is not fully thread-safe. Specifically it's not safe to call Add() concurrently with Wait() when the wait group counter is zero due to a data race. This situation could come up with esbuild's JavaScript API when the host JavaScript process closes the child process's stdin and the child process (with no active tasks) calls Wait() to check that there are no active tasks, at the same time as esbuild's watchdog timer calls Add() to add an active task (that pings the host to see if it's still there). The fix in this release is to avoid calling Add() once we learn that stdin has been closed but before we call Wait().

    Source code(tar.gz)
    Source code(zip)
  • v0.15.12(Oct 19, 2022)

    • Fix minifier correctness bug with single-use substitutions (#2619)

      When minification is enabled, esbuild will attempt to eliminate variables that are only used once in certain cases. For example, esbuild minifies this code:

      function getEmailForUser(name) {
        let users = db.table('users');
        let user = users.find({ name });
        let email = user?.get('email');
        return email;
      }
      

      into this code:

      function getEmailForUser(e){return db.table("users").find({name:e})?.get("email")}
      

      However, this transformation had a bug where esbuild did not correctly consider the "read" part of binary read-modify-write assignment operators. For example, it's incorrect to minify the following code into bar += fn() because the call to fn() might modify bar:

      const foo = fn();
      bar += foo;
      

      In addition to fixing this correctness bug, this release also improves esbuild's output in the case where all values being skipped over are primitives:

      function toneMapLuminance(r, g, b) {
        let hdr = luminance(r, g, b)
        let decay = 1 / (1 + hdr)
        return 1 - decay
      }
      

      Previous releases of esbuild didn't substitute these single-use variables here, but esbuild will now minify this to the following code starting with this release:

      function toneMapLuminance(e,n,a){return 1-1/(1+luminance(e,n,a))}
      
    Source code(tar.gz)
    Source code(zip)
  • v0.15.11(Oct 14, 2022)

    • Fix various edge cases regarding template tags and this (#2610)

      This release fixes some bugs where the value of this wasn't correctly preserved when evaluating template tags in a few edge cases. These edge cases are listed below:

      async function test() {
        class Foo { foo() { return this } }
        class Bar extends Foo {
          a = async () => super.foo``
          b = async () => super['foo']``
          c = async (foo) => super[foo]``
        }
        function foo() { return this }
        const obj = { foo }
        const bar = new Bar
        console.log(
          (await bar.a()) === bar,
          (await bar.b()) === bar,
          (await bar.c('foo')) === bar,
          { foo }.foo``.foo === foo,
          (true && obj.foo)`` !== obj,
          (false || obj.foo)`` !== obj,
          (null ?? obj.foo)`` !== obj,
        )
      }
      test()
      

      Each edge case in the code above previously incorrectly printed false when run through esbuild with --minify --target=es6 but now correctly prints true. These edge cases are unlikely to have affected real-world code.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.10(Sep 29, 2022)

    • Add support for node's "pattern trailers" syntax (#2569)

      After esbuild implemented node's exports feature in package.json, node changed the feature to also allow text after * wildcards in patterns. Previously the * was required to be at the end of the pattern. It lets you do something like this:

      {
        "exports": {
          "./features/*": "./features/*.js",
          "./features/*.js": "./features/*.js"
        }
      }
      

      With this release, esbuild now supports these types of patterns too.

    • Fix subpath imports with Yarn PnP (#2545)

      Node has a little-used feature called subpath imports which are package-internal imports that start with # and that go through the imports map in package.json. Previously esbuild had a bug that caused esbuild to not handle these correctly in packages installed via Yarn's "Plug'n'Play" installation strategy. The problem was that subpath imports were being checked after Yarn PnP instead of before. This release reorders these checks, which should allow subpath imports to work in this case.

    • Link from JS to CSS in the metafile (#1861, #2565)

      When you import CSS into a bundled JS file, esbuild creates a parallel CSS bundle next to your JS bundle. So if app.ts imports some CSS files and you bundle it, esbuild will give you app.js and app.css. You would then add both <script src="app.js"></script> and <link href="app.css" rel="stylesheet"> to your HTML to include everything in the page. This approach is more efficient than having esbuild insert additional JavaScript into app.js that downloads and includes app.css because it means the browser can download and parse both the CSS and the JS in parallel (and potentially apply the CSS before the JS has even finished downloading).

      However, sometimes it's difficult to generate the <link> tag. One case is when you've added [hash] to the entry names setting to include a content hash in the file name. Then the file name will look something like app-GX7G2SBE.css and may change across subsequent builds. You can tell esbuild to generate build metadata using the metafile API option but the metadata only tells you which generated JS bundle corresponds to a JS entry point (via the entryPoint property), not which file corresponds to the associated CSS bundle. Working around this was hacky and involved string manipulation.

      This release adds the cssBundle property to the metafile to make this easier. It's present on the metadata for the generated JS bundle and points to the associated CSS bundle. So to generate the HTML tags for a given JS entry point, you first find the output file with the entryPoint you are looking for (and put that in a <script> tag), then check for the cssBundle property to find the associated CSS bundle (and put that in a <link> tag).

      One thing to note is that there is deliberately no jsBundle property mapping the other way because it's not a 1:1 relationship. Two JS bundles can share the same CSS bundle in the case where the associated CSS bundles have the same name and content. In that case there would be no one value for a hypothetical jsBundle property to have.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.9(Sep 22, 2022)

    • Fix an obscure npm package installation issue with --omit=optional (#2558)

      The previous release introduced a regression with npm install esbuild --omit=optional where the file node_modules/.bin/esbuild would no longer be present after installation. That could cause any package scripts which used the esbuild command to no longer work. This release fixes the regression so node_modules/.bin/esbuild should now be present again after installation. This regression only affected people installing esbuild using npm with either the --omit=optional or --no-optional flag, which is a somewhat unusual situation.

      More details:

      The reason for this regression is due to some obscure npm implementation details. Since the Go compiler doesn't support trivial cross-compiling on certain Android platforms, esbuild's installer installs a WebAssembly shim on those platforms instead. In the previous release I attempted to simplify esbuild's WebAssembly shims to depend on the esbuild-wasm package instead of including another whole copy of the WebAssembly binary (to make publishing faster and to save on file system space after installation). However, both the esbuild package and the esbuild-wasm package provide a binary called esbuild and it turns out that adding esbuild-wasm as a nested dependency of the esbuild package (specifically esbuild optionally depends on @esbuild/android-arm which depends on esbuild-wasm) caused npm to be confused about what node_modules/.bin/esbuild is supposed to be.

      It's pretty strange and unexpected that disabling the installation of optional dependencies altogether would suddenly cause an optional dependency's dependency to conflict with the top-level package. What happens under the hood is that if --omit=optional is present, npm attempts to uninstall the esbuild-wasm nested dependency at the end of npm install (even though the esbuild-wasm package was never installed due to --omit=optional). This uninstallation causes node_modules/.bin/esbuild to be deleted.

      After doing a full investigation, I discovered that npm's handling of the .bin directory is deliberately very brittle. When multiple packages in the dependency tree put something in .bin with the same name, the end result is non-deterministic/random. What you get in .bin might be from one package, from the other package, or might be missing entirely. The workaround suggested by npm is to just avoid having two packages that put something in .bin with the same name. So this was fixed by making the @esbuild/android-arm and esbuild-android-64 packages each include another whole copy of the WebAssembly binary, which works because these packages don't put anything in .bin.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.8(Sep 18, 2022)

    • Fix JSX name collision edge case (#2534)

      Code generated by esbuild could have a name collision in the following edge case:

      • The JSX transformation mode is set to automatic, which causes import statements to be inserted
      • An element uses a {...spread} followed by a key={...}, which uses the legacy createElement fallback imported from react
      • Another import uses a name that ends with react such as @remix-run/react
      • The output format has been set to CommonJS so that import statements are converted into require calls

      In this case, esbuild previously generated two variables with the same name import_react, like this:

      var import_react = require("react");
      var import_react2 = require("@remix-run/react");
      

      That bug is fixed in this release. The code generated by esbuild no longer contains a name collision.

    • Fall back to WebAssembly on Android ARM (#1556, #1578, #2335, #2526)

      Go's compiler supports trivial cross-compiling to almost all platforms without installing any additional software other than the Go compiler itself. This has made it very easy for esbuild to publish native binary executables for many platforms. However, it strangely doesn't support cross-compiling to Android ARM without installing the Android build tools.

      So instead of publishing a native esbuild binary executable to npm, this release publishes a WebAssembly fallback build. This is essentially the same as the esbuild-wasm package but it's installed automatically when you install the esbuild package on Android ARM. So packages that depend on the esbuild package should now work on Android ARM. This change has not yet been tested end-to-end because I don't have a 32-bit Android ARM device myself, but in theory it should work.

      This inherits the drawbacks of WebAssembly including significantly slower performance than native as well as potentially also more severe memory usage limitations and lack of certain features (e.g. --serve). If you want to use a native binary executable of esbuild on Android ARM, you may be able to build it yourself from source after installing the Android build tools.

    • Attempt to better support Yarn's ignorePatternData feature (#2495)

      Part of resolving paths in a project using Yarn's Plug'n'Play feature involves evaluating a regular expression in the ignorePatternData property of .pnp.data.json. However, it turns out that the particular regular expressions generated by Yarn use some syntax that works with JavaScript regular expressions but that does not work with Go regular expressions.

      In this release, esbuild will now strip some of the the problematic syntax from the regular expression before compiling it, which should hopefully allow it to be compiled by Go's regular expression engine. The specific character sequences that esbuild currently strips are as follows:

      • (?!\.)
      • (?!(?:^|\/)\.)
      • (?!\.{1,2}(?:\/|$))
      • (?!(?:^|\/)\.{1,2}(?:\/|$))

      These seem to be used by Yarn to avoid the . and .. path segments in the middle of relative paths. The removal of these character sequences seems relatively harmless in this case since esbuild shouldn't ever generate such path segments. This change should add support to esbuild for Yarn's pnpIgnorePatterns feature.

    • Fix non-determinism issue with legacy block-level function declarations and strict mode (#2537)

      When function declaration statements are nested inside a block in strict mode, they are supposed to only be available within that block's scope. But in "sloppy mode" (which is what non-strict mode is commonly called), they are supposed to be available within the whole function's scope:

      // This returns 1 due to strict mode
      function test1() {
        'use strict'
        function fn() { return 1 }
        if (true) { function fn() { return 2 } }
        return fn()
      }
      
      // This returns 2 due to sloppy mode
      function test2() {
        function fn() { return 1 }
        if (true) { function fn() { return 2 } }
        return fn()
      }
      

      To implement this, esbuild compiles these two functions differently to reflect their different semantics:

      function test1() {
        "use strict";
        function fn() {
          return 1;
        }
        if (true) {
          let fn2 = function() {
            return 2;
          };
        }
        return fn();
      }
      function test2() {
        function fn() {
          return 1;
        }
        if (true) {
          let fn2 = function() {
            return 2;
          };
          var fn = fn2;
        }
        return fn();
      }
      

      However, the compilation had a subtle bug where the automatically-generated function-level symbols for multible hoisted block-level function declarations in the same block a sloppy-mode context were generated in a random order if the output was in strict mode, which could be the case if TypeScript's alwaysStrict setting was set to true. This lead to non-determinism in the output as the minifier would randomly exchange the generated names for these symbols on different runs. This bug has been fixed by sorting the keys of the unordered map before iterating over them.

    • Fix parsing of @keyframes with string identifiers (#2555)

      Firefox supports @keyframes with string identifier names. Previously this was treated as a syntax error by esbuild as it doesn't work in any other browser. The specification allows for this however, so it's technically not a syntax error (even though it would be unwise to use this feature at the moment). There was also a bug where esbuild would remove the identifier name in this case as the syntax wasn't recognized.

      This release changes esbuild's parsing of @keyframes to now consider this case to be an unrecognized CSS rule. That means it will be passed through unmodified (so you can now use esbuild to bundle this Firefox-specific CSS) but the CSS will not be pretty-printed or minified. I don't think it makes sense for esbuild to have special code to handle this Firefox-specific syntax at this time. This decision can be revisited in the future if other browsers add support for this feature.

    • Add the --jsx-side-effects API option (#2539, #2546)

      By default esbuild assumes that JSX expressions are side-effect free, which means they are annoated with /* @__PURE__ */ comments and are removed during bundling when they are unused. This follows the common use of JSX for virtual DOM and applies to the vast majority of JSX libraries. However, some people have written JSX libraries that don't have this property. JSX expressions can have arbitrary side effects and can't be removed. If you are using such a library, you can now pass --jsx-side-effects to tell esbuild that JSX expressions have side effects so it won't remove them when they are unused.

      This feature was contributed by @rtsao.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.7(Sep 4, 2022)

    • Add --watch=forever to allow esbuild to never terminate (#1511, #1885)

      Currently using esbuild's watch mode via --watch from the CLI will stop watching if stdin is closed. The rationale is that stdin is automatically closed by the OS when the parent process exits, so stopping watch mode when stdin is closed ensures that esbuild's watch mode doesn't keep running forever after the parent process has been closed. For example, it would be bad if you wrote a shell script that did esbuild --watch & to run esbuild's watch mode in the background, and every time you run the script it creates a new esbuild process that runs forever.

      However, there are cases when it makes sense for esbuild's watch mode to never exit. One such case is within a short-lived VM where the lifetime of all processes inside the VM is expected to be the lifetime of the VM. Previously you could easily do this by piping the output of a long-lived command into esbuild's stdin such as sleep 999999999 | esbuild --watch &. However, this possibility often doesn't occur to people, and it also doesn't work on Windows. People also sometimes attempt to keep esbuild open by piping an infinite stream of data to esbuild such as with esbuild --watch </dev/zero & which causes esbuild to spin at 100% CPU. So with this release, esbuild now has a --watch=forever flag that will not stop watch mode when stdin is closed.

    • Work around PATH without node in install script (#2519)

      Some people install esbuild's npm package in an environment without the node command in their PATH. This fails on Windows because esbuild's install script runs the esbuild command before exiting as a sanity check, and on Windows the esbuild command has to be a JavaScript file because of some internal details about how npm handles the bin folder (specifically the esbuild command lacks the .exe extension, which is required on Windows). This release attempts to work around this problem by using process.execPath instead of "node" as the command for running node. In theory this means the installer can now still function on Windows if something is wrong with PATH.

    Source code(tar.gz)
    Source code(zip)
  • v0.15.6(Aug 30, 2022)

    • Lower for await loops (#1930)

      This release lowers for await loops to the equivalent for loop containing await when esbuild is configured such that for await loops are unsupported. This transform still requires at least generator functions to be supported since esbuild's lowering of await currently relies on generators. This new transformation is mostly modeled after what the TypeScript compiler does. Here's an example:

      async function f() {
        for await (let x of y)
          x()
      }
      

      The code above will now become the following code with --target=es2017 (omitting the code for the __forAwait helper function):

      async function f() {
        try {
          for (var iter = __forAwait(y), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
            let x = temp.value;
            x();
          }
        } catch (temp) {
          error = [temp];
        } finally {
          try {
            more && (temp = iter.return) && await temp.call(iter);
          } finally {
            if (error)
              throw error[0];
          }
        }
      }
      
    • Automatically fix invalid supported configurations (#2497)

      The --target= setting lets you tell esbuild to target a specific version of one or more JavaScript runtimes such as chrome80,node14 and esbuild will restrict its output to only those features supported by all targeted JavaScript runtimes. More recently, esbuild introduced the --supported: setting that lets you override which features are supported on a per-feature basis. However, this now lets you configure nonsensical things such as --supported:async-await=false --supported:async-generator=true. Previously doing this could result in esbuild building successfully but producing invalid output.

      Starting with this release, esbuild will now attempt to automatically fix nonsensical feature override configurations by introducing more overrides until the configuration makes sense. So now the configuration from previous example will be changed such that async-await=false implies async-generator=false. The full list of implications that were introduced is below:

      • async-await=false implies:

        • async-generator=false
        • for-await=false
        • top-level-await=false
      • generator=false implies:

        • async-generator=false
      • object-accessors=false implies:

        • class-private-accessor=false
        • class-private-static-accessor=false
      • class-field=false implies:

        • class-private-field=false
      • class-static-field=false implies:

        • class-private-static-field=false
      • class=false implies:

        • class-field=false
        • class-private-accessor=false
        • class-private-brand-check=false
        • class-private-field=false
        • class-private-method=false
        • class-private-static-accessor=false
        • class-private-static-field=false
        • class-private-static-method=false
        • class-static-blocks=false
        • class-static-field=false
    • Implement a small minification improvement (#2496)

      Some people write code that contains a label with an immediate break such as x: break x. Previously this code was not removed during minification but it will now be removed during minification starting with this release.

    • Fix installing esbuild via Yarn with enableScripts: false configured (#2457)

      If esbuild is installed with Yarn with the enableScripts: false setting configured, then Yarn will not "unplug" the esbuild package (i.e. it will keep the entire package inside a .zip file). This messes with esbuild's library code that extracts the platform-specific binary executable because that code copies the binary executable into the esbuild package directory, and Yarn's .zip file system shim doesn't let you write to a directory inside of a .zip file. This release fixes this problem by writing to the node_modules/.cache/esbuild directory instead in this case. So you should now be able to use esbuild with Yarn when enableScripts: false is configured.

      This fix was contributed by @jonaskuske.

    Source code(tar.gz)
    Source code(zip)
Compresses linked and inline javascript or CSS into a single cached file.

Django Compressor Django Compressor processes, combines and minifies linked and inline Javascript or CSS in a Django template into cacheable static fi

null 2.6k Jan 3, 2023
Fully reponsive Chat Application built with django, javascript, materialUi, bootstrap4, html and css.

Chat app (Full Stack Frameworks with Django Project) Fully reponsive Chat Application built with django, javascript, materialUi, bootstrap4, html and

null 1 Jan 19, 2022
Tweak the form field rendering in templates, not in python-level form definitions. CSS classes and HTML attributes can be altered.

django-widget-tweaks Tweak the form field rendering in templates, not in python-level form definitions. Altering CSS classes and HTML attributes is su

Jazzband 1.8k Jan 2, 2023
Basic Form Web Development using Python, Django and CSS

thebookrain Basic Form Web Development using Python, Django and CSS This is a basic project that contains two forms - borrow and donate. The form data

Ananya Dhulipala 1 Nov 27, 2021
Packs a bunch of smaller CSS files together from 1 folder.

Packs a bunch of smaller CSS files together from 1 folder.

null 1 Dec 9, 2021
This "I P L Team Project" is developed by Prasanta Kumar Mohanty using Python with Django web framework, HTML & CSS.

I-P-L-Team-Project This "I P L Team Project" is developed by Prasanta Kumar Mohanty using Python with Django web framework, HTML & CSS. Screenshots HO

null 1 Dec 15, 2021
Simple alternative to Doodle polls and scheduling (Python 3, Django 3, JavaScript)

What is jawanndenn? jawanndenn is a simple web application to schedule meetings and run polls, a libre alternative to Doodle. It is using the followin

Sebastian Pipping 169 Jan 6, 2023
💨 Fast, Async-ready, Openapi, type hints based framework for building APIs

Fast to learn, fast to code, fast to run Django Ninja - Fast Django REST Framework Django Ninja is a web framework for building APIs with Django and P

Vitaliy Kucheryaviy 3.8k Jan 1, 2023
Fast / fuzzy PostgreSQL counts for Django

Created by Stephen McDonald Introduction Up until PostgreSQL 9.2, COUNT queries generally required scanning every row in a database table. With millio

stephenmcd 85 Oct 25, 2021
Django-fast-export - Utilities for quickly streaming CSV responses to the client

django-fast-export Utilities for quickly streaming CSV responses to the client T

Matthias Kestenholz 4 Aug 24, 2022
Organize Django settings into multiple files and directories. Easily override and modify settings. Use wildcards and optional settings files.

Organize Django settings into multiple files and directories. Easily override and modify settings. Use wildcards in settings file paths and mark setti

Nikita Sobolev 940 Jan 3, 2023
A Django web application to receive, virus check and validate transfers of digital archival records, and allow archivists to appraise and accession those records.

Aurora Aurora is a Django web application that can receive, virus check and validate transfers of digital archival records, and allows archivists to a

Rockefeller Archive Center 20 Aug 30, 2022
Django application and library for importing and exporting data with admin integration.

django-import-export django-import-export is a Django application and library for importing and exporting data with included admin integration. Featur

null 2.6k Dec 26, 2022
Management commands to help backup and restore your project database and media files

Django Database Backup This Django application provides management commands to help backup and restore your project database and media files with vari

null 687 Jan 4, 2023
Plug and play continuous integration with django and jenkins

django-jenkins Plug and play continuous integration with Django and Jenkins Installation From PyPI: $ pip install django-jenkins Or by downloading th

Mikhail Podgurskiy 941 Oct 22, 2022
Django project starter on steroids: quickly create a Django app AND generate source code for data models + REST/GraphQL APIs (the generated code is auto-linted and has 100% test coverage).

Create Django App ?? We're a Django project starter on steroids! One-line command to create a Django app with all the dependencies auto-installed AND

imagine.ai 68 Oct 19, 2022
Stream Framework is a Python library, which allows you to build news feed, activity streams and notification systems using Cassandra and/or Redis. The authors of Stream-Framework also provide a cloud service for feed technology:

Stream Framework Activity Streams & Newsfeeds Stream Framework is a Python library which allows you to build activity streams & newsfeeds using Cassan

Thierry Schellenbach 4.7k Jan 2, 2023
A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, celery and redis.

Django Channels Websocket Chatbot A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, c

Yunbo Shi 8 Oct 28, 2022
Forward and backwards compatibility layer for Django 1.4, 1.7, 1.8, 1.9, 1.10, and 1.11

django-compat Forward and backwards compatibility layer for Django 1.4 , 1.7 , 1.8, 1.9, 1.10 and 1.11 Consider django-compat as an experiment based o

arteria GmbH 106 Mar 28, 2022