Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] UMD bundle support #507

Open
jyboudreau opened this issue Nov 5, 2020 · 18 comments · May be fixed by #513
Open

[Feature] UMD bundle support #507

jyboudreau opened this issue Nov 5, 2020 · 18 comments · May be fixed by #513

Comments

@jyboudreau
Copy link

jyboudreau commented Nov 5, 2020

UMD is used by many libraries to support legacy module systems. Migrating to esbuild is difficult when relying on this format.

There are some workarounds but they have major downsides:

  1. Post-process the esbuild IIFE output to add the UMD wrapper if you don't have any external dependencies: Makes sourcemap difficult to deal with and makes builds slower. ([Feature] banner and footer #482) would simplify this workaround and solve the source map issue but still not allow external dependencies.
  2. Use rollup/webpack's UMD support with esbuild transformers (instead of babel): Doesn't benefit from esbuild's ultra fast dependency resolution and bundling.

Willing to give this a go myself if there is interest to include this feature.

@shrinktofit
Copy link

System js, too, please:)

@prantlf prantlf linked a pull request Nov 9, 2020 that will close this issue
@prantlf
Copy link

prantlf commented Nov 9, 2020

UMD format is similar to the IIFE format. Just the module wrapper and setting the global variable differs. The real "fun" will begin if you want to convert externals to AMD/CJS imports, when you call the factory function in the UMD wrapper. But this is not needed for projects that bundle all their dependencies or use globals to access externals.

I needed just to bundle local modules without external dependencies. It is probably the most often case how to simply publish a library in the most interoperable format.

I introduced --format=umd in #513.

@David-Else
Copy link

Do we really need these legacy formats? ECMAScript modules were meant to resign them to the dustbin, and now after a ridiculous delay, we finally even have ECMAScript modules in Node LTS with Node 14 and near universal browser support.

The old module formats can safely die now... or will they haunt us forever?

@jyboudreau
Copy link
Author

jyboudreau commented Nov 12, 2020

@David-Else I agree with the general sentiment and would love for ESM to have solved the whole module thing once it was supported in browser and node, unfortunately the world is messy. I think that ESM being supported in Node is a great milestone that marks the start of transition towards libraries supporting ESM. It's unfortunately not the end of CommonJS, IIFE or even AMD and far from it.

If you're building an app, I'm sure you will have an easier time with everything being ESM. I think the problems are more apparent when providing libraries.

ESM in Node is not so straightforward. Many supporting libraries don't support it well yet, see Jest for example.

Here is a good article that touches on some of the problems with ESM in Node: https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1

There are also problems with ESM on the browser. Using pure ESM with a huge dependency chain of imports is just not practical for performance reasons.

In the end, UMD is just a way to bundle three formats (CJS, IIFE and AMD) in one and makes it easier to support users. And 2 of those formats are already considered useful enough to be included in esbuild.

Some benefits of UMD for library creators:

  • No need to document and provide 3 different file formats of your library to your users.
  • No need to explain how to use transpilation to your users if they are on a platform that doesn't support ESM (remember not everybody is using Node 14 or browsers that support ESM).

There are many other arguments to be made here... but hopefully this is enough for now consider that UMD might be a desirable feature in a bundler/transpiler in order for esbuild to be usable by library creators.

@evanw
Copy link
Owner

evanw commented Nov 16, 2020

FYI the new banner and footer options from #482 are now implemented and have been released. You should be able to implement this feature using those options.

@jyboudreau
Copy link
Author

@evanw That's great! It definitively helps to alleviate the issue for now. For my use-case it's sufficient.

I think that there is still some merit to include a UMD mode, even in limited fashion like #513 in order to reduce friction for people migrating from webpack/rollup.

@jacobp100
Copy link

jacobp100 commented Feb 6, 2021

UMD still has place for webworkers, where ES modules aren't supported in any non-Chrome browser. You gotta use importScripts, and UMD will generate globals that you can use.

@danny007in
Copy link

danny007in commented Feb 24, 2021

UMD still has place for webworkers, where ES modules aren't supported in any non-Chrome browser. You gotta use importScripts, and UMD will generate globals that you can use.

Ur right
Example
https://github.com/twbs/bootstrap/blob/e50c11b8c6434b6d68ea5897771e4d35fe12f5c3/build/rollup.config.js#L39

@splashsky
Copy link

Are there any updates or ETAs on when this feature will be implemented? It's the one thing I need in order to begin using esbuild in my particular project.

@jacobp100
Copy link

@splashsky You could probably fake it for now - https://github.com/jacobp100/technicalc-core/blob/master/packages/technicalc-prebuilt/build.js#L88-L109

I think this looks to be pretty low priority

@BePo65
Copy link

BePo65 commented May 21, 2021

That's great! It definitively helps to alleviate the issue for now. For my use-case it's sufficient.

@jyboudreau perhaps you can help me with this workaround: what did you use as esbuld paramater format, when adding the umd wrapper by using 'banner' and 'footer'?

@niemyjski
Copy link

I too would like this, we have some older projects (angular 1.x) where we'd want to target with a umd bundle so they could consume our modern library.

@horvski
Copy link

horvski commented Aug 19, 2022

It seems as though this is a fairly popular request, and one that is already accomplished but still not merged in #513.

Is there anything that is standing in the way of proceeding with this merge? If so, is there anything I can do to assist?

'UMD' format still seems to be fairly common industry practice, and even used in a cryptographically audited library.

The following would be very useful for many of the packages that I use:

1.) Convert from 'esm' format into 'umd' format.
2.) Convert 'umd' into 'esm' format.
3.) If a format is already in 'umd' format, minify the format, while keeping 'umd' format.

Update 08/23/2022:
The core problem is that 'global' and 'factory' are being parsed as variables, and not keywords.

For minification, if these keywords are treated as keywords, then the problem is fixed.

@Inqnuam
Copy link

Inqnuam commented Dec 18, 2022

Hello,
I made a plugin to wrap esbuild cjs into umd format
esbuild-plugin-umd-wrapper

@jchris
Copy link

jchris commented Aug 18, 2023

I'm just gonna throw my perspective in here as a regular library author who's about to try rollup instead of esbuild, because of things like this. I'm happy to let my downstream users tree shake out polyfill they don't need, but I want the default use to not have to think.

@nl-brett-stime
Copy link

FWIW, some of us are less concerned with emitting UMD than we are with making sure that existing UMD libraries are able to be bundled/imported/integrated without issue. I was unable to switch to esbuild because it was choking on the wu library at runtime. That lib comes from the central/public NPM repo as UMD and it was unable to resolve [regeneratorRuntime on] the global scope from within an IIFE bundle generated by esbuild .

My findings seemed to underscore the update/edit at the end of this comment:
#507 (comment)

@restjohn
Copy link

restjohn commented Mar 8, 2024

I'd love to see this implemented. My use case is a dynamic microfrontend host Angular app with Angular library extensions that are maintained outside of the host repository by other customers, and thus we cannot include the extensions in our host build process. The host app shares core dependencies, e.g. most of Angular's modules which are many, with the extensions so extensions do not bundle and duplicate those Angular modules.

Back on Angular 9, we used SystemJS to dynamically load the MFE Angular libraries as UMD bundles, which Angular's library builder, ng-packagr generated. However, ng-packagr now only supports FESM output out of the box, so I need a new solution to generate UMD or AMD modules for Angular libraries.

I had been exploring Webpack's module federation, along with an Angular plugin that integrates Webpack MF into the build. That seemed promising, but now of course Angular is moving away from Webpack to esbuild, so I'd rather move in the same direction and take advantage of the modern tools already in the build chain. That would mean esbuild's UMD output would need to support unbundled, external dependency imports in output.

For the moment I believe I'll have to provide a custom Angular builder that uses rollup like ng-packagr to build the Angular library extensions, just with the output format set to UMD rather than FESM, but I'm hoping that will be a stopgap.

@dy
Copy link

dy commented Jul 13, 2024

@evanw can we please consider this PR?
UMD for esbuild is such a great pain and time killer atm. There's no simple clean ways to do that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.