esbuild icon indicating copy to clipboard operation
esbuild copied to clipboard

Support SystemJS as a format

Open chowey opened this issue 4 years ago • 13 comments

Any plans for SystemJS as an output format?

I am currently using this for browser support. It seems to be supported by other bundlers, such as Rollup and Webpack. It would be nice to see it in ESBuild.

chowey avatar Jun 21 '20 23:06 chowey

I don't currently have any plans to support SystemJS. The format seems pretty complicated compared to other browser-based formats, especially the way live bindings need to be implemented. All of esbuild's live exports currently just use getters, which is much simpler for me to implement and maintain and which often results in smaller code size. It's currently already possible to target the browser with esbuild using the iife and esm output formats. Is there a reason those formats don't work for you?

evanw avatar Jun 27 '20 19:06 evanw

The use-case is when there is a library I want to import without bundling.

For me in particular, I am using this to load data that the server is generating dynamically. For example, I can do:

import data from "/api/endpoint";

doSomethingWith(data);

With SystemJS, it emulates all aspects of ES6, so all I have to do is wrap my /api/endpoint as a SystemJS module and the example above acts just like importing a blob of JSON. Dynamically! Before my module even runs! Very useful for me.

I can imagine other reasons someone might want to import an external module that gets resolved at run-time.

I don't know how iife would handle importing an external module like this. Would it work the same way? I've solved it in other bundlers using SystemJS.

chowey avatar Jun 27 '20 19:06 chowey

My understanding is that you could import Systemjs globally from your html and use const data = System.import('/api/endpoint');. So maybe there’s no need to have the bundler do it ?

fazouane-marouane avatar Jul 04 '20 10:07 fazouane-marouane

The difference is that System.import returns a promise. Using a static import does not return a promise. It returns the data right now. The fetching is done ahead-of-time by the module loader, at the same time that the JavaScript is being fetched.

I could also get my data using const data = fetch('/api/endpoint') with the same penalty. It returns a promise.

Compare something like this:

import data from "/api/endpoint";

doSomethingWith(data);
doSomethingElseWith(data);

to something like this:

fetch('/api/endpoint').then(res => {
  if (!res.ok) {
    return res.text().then(txt => {
      throw new Error(txt);
    });
  }
  return res.json();
}).then(data => {
  doSomethingWith(data);
  doSomethingElseWith(data);
});

It kind of gets more convoluted if there are multiple data endpoints involved.

~~Additionally, the fetch approach suffers from the "waterfall" effect, where the browser doesn't start fetching my data until after the JavaScript has been fetched and parsed and executed.~~

EDIT: Sorry, this is incorrect. The JavaScript still needs to be fetched and parsed before the import can be resolved.

chowey avatar Jul 04 '20 17:07 chowey

Is there a reason those formats don't work for you?

Our library uses SystemJS as esm fallback. And our library have multi entry point but esbuild only supports splitting for esm.

shrinktofit avatar Oct 09 '20 08:10 shrinktofit

SystemJS is very useful in MFE (Microfrontend) applications.

jcschmidig avatar Nov 29 '20 16:11 jcschmidig

System JS is often used for large micro front end frameworks, such as SingleSPA. Is there a way to support this standard in the future?

ericzorn93 avatar Apr 22 '21 15:04 ericzorn93

SystemJS it's kinda ES Modules polyfill, and it will be great to have it in esbuild!

lifeart avatar Sep 24 '21 13:09 lifeart

I remember reading a comment that this would not be a supportive feature by this tool, however, many people are using system JS as part of their micro front end solutions (SingleSPA)

ericzorn93 avatar Sep 24 '21 13:09 ericzorn93

I think maybe using rollup to transform the output translated by esbuild to systemjs format is a good way.

coconilu avatar Apr 07 '22 07:04 coconilu

I think maybe using rollup to transform the output translated by esbuild to systemjs format is a good way.

Indeed that is simple. ESM in, Systemjs out:

import { rollup } from 'rollup';
import virtual from '@rollup/plugin-virtual';

export const toSystemjs = async (esmCode: string): Promise<string>  => {

  const inputOptions = {
    external: () => true,
    input: 'esmCode',
    plugins: [
      virtual({ esmCode }),
    ],
    treeshake: false,
  };

  const outputOptions = {
    file: 'out.mjs', // not really used
    format: 'systemjs',
    sourcemap: false,
  };

  const bundle = await rollup(inputOptions);
  const { output } = await bundle.generate(outputOptions);
  await bundle.close();
  return output[0].code;
}

esroyo avatar May 15 '23 16:05 esroyo

We are also using SingleSPA and are currently using it with webpack which is very slow. Today I tried to use single spa with esbuild and native import maps but the current support of native import maps don't allow for loading the import maps from an external json file. So esbuild outputting systemjs format would solve for us a lot of developer experience pain points.

wouter-leistra avatar Nov 23 '23 20:11 wouter-leistra

I think maybe using rollup to transform the output translated by esbuild to systemjs format is a good way.

Indeed that is simple. ESM in, Systemjs out:

import { rollup } from 'rollup';
import virtual from '@rollup/plugin-virtual';

export const toSystemjs = async (esmCode: string): Promise<string>  => {

  const inputOptions = {
    external: () => true,
    input: 'esmCode',
    plugins: [
      virtual({ esmCode }),
    ],
    treeshake: false,
  };

  const outputOptions = {
    file: 'out.mjs', // not really used
    format: 'systemjs',
    sourcemap: false,
  };

  const bundle = await rollup(inputOptions);
  const { output } = await bundle.generate(outputOptions);
  await bundle.close();
  return output[0].code;
}

Hi, I've stumbled upon this, how would one execute that for local build outputs?

jano-kucera avatar May 22 '24 07:05 jano-kucera