support for esmodules as output for the web?

Feature request

When outputting content targeting the web platform, it would be nice to have the option to output an es module for modern browsers. (I don’t believe there is currently a way to do this – if there is it needs better documentation :P).

What is the expected behavior?
Ideally, I would like to be able to have webpack output two entry files, an esmodule as well as what it currently outputs.
Then in the index.html file, both files can be loaded like this:

<head>
  <script nomodule src="bundle.js" async></script>
  <script type="module" src="bundle.mjs" async></script>
</head>

What is motivation or use case for adding/changing the behavior?
Supporting the modern web.

How should this be implemented in your opinion?
Maybe something like this:

// webpack.config.js

const config = {
  //...
};

const webConfig = Object.assign({}, config, {
  target: 'web',
  //...
});

const webModuleConfig = Object.assign({}, config, {
  target: 'web-module',
  //...
});

module.exports = [
  webConfig, webModuleConfig,       
];

Are you willing to work on this yourself?
Maybe but probably not. I’m still a novice when it comes to the webpack eco-system so I’d probably be at a loss on how to implement this.

Author: Fantashit

3 thoughts on “support for esmodules as output for the web?

  1. Basically target: web will continue to work the way it does, outputting es5 script code (with the help of babel) designed to work in all current browsers.
    While target: web-module would output es6+ module code designed to work in the latest modern browsers (using <script type="module"></script>).

  2. +1

    It’s extremely useful in development env.

    1. Code generation should be faster because each file is generated separately and less code changes are needed for js code ( only imports with packages in node_modules in my opinion. Browers with ES6+ module support should support all latest ES6 features; no babel needed).
    2. We can drop sourcemaps in dev-env because less code is changed when targeting ES6 module. Sourcemaps generally slow down the code generation and never work correctly as they should be.
      image
    3. MUCH cleaner generated code. One src generates one dist; no __webpack_require__("a1b2"); no /***/ "a1b2": (function(module, exports, __webpack_require__) {; no APP__WEBPACK_IMPORTED_MODULE_1__

    The problem is that many node packages still use the legacy commonjs module resolution, which are hard to work with ES6 modules ( for example there is no direct conversion from dynamic require to ES6 import because the function like import returns a promise ). Even worse, many packages uses ES6 imports but generate UMD in their dist files ( is very common in web targeting packages ). I have no idea if we can solve this problem or we have to drop legacy packages without ES6 module support.

    EDIT: Can we compile dynamic require into a sync xhr request ( and generate a warning )? For example:

    // pseudo code
    global.require = function require(path /* that is not a string literal value */) {
      const req = new XMLHttpRequest();
      req.open("GET", path, false);
      req.send();
      return new Function(req.responseText).call(global);
    });

    EDIT:

    I noticed that some tools already support generate dist code with esm module, but all source code are bundled into one file, that’s not what I want.

Comments are closed.