BotFramework-WebChat icon indicating copy to clipboard operation
BotFramework-WebChat copied to clipboard

Update bundler to esbuild

Open compulim opened this issue 4 years ago • 2 comments

Background

We bumped to webpack@5. Should we move to esbuild?

Let's weight which one is better, in terms of size and speed (for DX).

esbuild

Our bundle must be ES5. But esbuild emit bundle with ES6+. Thus, after esbuild, we need to transpile the bundle again.

esbuild config to use for isomorphic-react

In our webchat*.js bundle, although we bundled [email protected], if the environment already have a window.React and window.ReactDOM object available, we will prefer them over our own bundled React. This is called "isomorphic React".

We need to configure esbuild to redirect all import 'react' to this isomorphic React package.

Content of esbuild.base.js

const { resolve } = require('path');

const onResolveReact = {
  name: 'isomorphic-react',
  setup(build) {
    build.onResolve({ filter: /^react$/ }, () => {
      return {
        path: resolve('node_modules/isomorphic-react/dist/react.js')
      };
    });

    build.onResolve({ filter: /^react-dom$/ }, () => {
      return {
        path: resolve('node_modules/isomorphic-react/dist/react-dom.js')
      };
    });
  }
};

module.exports = {
  bundle: true,
  entryPoints: ['src/index.js'],
  logLevel: 'info',
  plugins: [onResolveReact],
  sourcemap: true,
  watch: process.argv.slice(2).includes('--watch')
};

Babel config to use on bundle emitted by esbuild

The bundle emitted by esbuild contains many features from ES6+. We need to run Babel again to transpile it back to ES5.

We need to enable a very specific set of plugins. If we enable all plugins via @babel/preset-env, it will cause a conflict with Symbol polyfill from core-js@3.

Content of babel.post.config.json

{
  /*
    These are plugins that can transpile bundle emitted by ESBuild and also compatible with core-js@3.
    Some plugins included by @babel/preset-env will break core-js@3 for Symbol, so we select plugin carefully.

    List of plugins included by @babel/preset-env:
    https://github.com/babel/babel/blob/master/packages/babel-compat-data/scripts/data/plugin-features.js

    If we use @babel/preset-env on the bundle emitted by ESBuild, it will cause this issue.
    https://github.com/zloirock/core-js/issues/514

    The solution is to skip Babel on node_modules/core-js. But in our case, we can't because it is already in the final bundle.
  */
  "plugins": [
    "@babel/plugin-proposal-nullish-coalescing-operator", // This is only needed for --minify build, which emit "??" operator.
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-block-scoping",
    "@babel/plugin-transform-destructuring",
    "@babel/plugin-transform-for-of",
    "@babel/plugin-transform-parameters",
    "@babel/plugin-transform-shorthand-properties",
    "@babel/plugin-transform-spread",
    "@babel/plugin-transform-template-literals"
  ],
  "sourceMaps": true
}

Dependencies

jsonwebtoken requires buffer. Since we don't verify the token (we merely check the userId), we should move to jwt-decode instead.

Investigations

Steps to compile:

  1. Babel with @babel/plugin-transform-runtime and inject core-js-pure for usage
  2. Bundle with esbuild
  3. Babel again with @babel/preset-env to convert to ES5
  4. Minify with terser

compulim avatar May 25 '21 20:05 compulim

Some updates:

  • webpack@5 is much slower than webpack@4 when used in watch mode
  • esbuild has an internal template that is written in ES6+
  • We should try running Babel on-the-fly in esbuild to reduce repeated transpilation
  • corejs@3 is probably needed because we prefer babel/plugin-transform-runtime to scope our polyfills

We should try something outside of Web Chat, few goals:

  • The bundled file should run on IE11 with zero polyfills
  • All required polyfills should be ponyfill (babel/plugin-transform-runtime and use corejs@3)
  • Only 1 or 2 passes of Babel
  • Minified production build should run properly on IE11
  • Dev build only need to run on Chromium, not necessarily with other browsers

As SDK, the problem is uniquely challenged because we want to use ponyfills instead of polyfills.

compulim avatar Sep 13 '21 18:09 compulim

Updates:

  • Multiple transpilation passes does not work
  • Although ESBuild do support some ES5 transpilation with ES5-compatible templates, there are some syntaxes not transpiled yet. We probably need to run Babel in front of ESBuild
  • Babel on-the-fly via ESBuild plugin is very slow, we should run CLI side-by-side
  • Bundle size by ESBuild is 20-30% larger than Webpack for unknown reasons

Currently in #4330, we are using ESBuild as development server. We should continue to investigate ESBuild for production build with Babel as the transpilation tool.

Also, we should clean up our exports for better treeshaking.

compulim avatar Jun 26 '22 08:06 compulim