8000 support output.libraryTarget: 'module' · Issue #2933 · webpack/webpack · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

support output.libraryTarget: 'module' #2933

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

Open
donaldpipowitch opened this issue Aug 30, 2016 · 186 comments
Open

support output.libraryTarget: 'module' #2933

donaldpipowitch opened this issue Aug 30, 2016 · 186 comments

Comments

@donaldpipowitch
Copy link

I'm submitting a feature request

It would be nice, if output.libraryTarget could support the ES2015 module format.

What is the motivation / use case for changing the behavior?

Say I develop a fancy component called fancy-component with webpack. I use a very custom config with specific loader settings e.g. for inlining images and stuff like that. My module exports FancyComponent and BigFancyComponent.

A friend develops a single page application and uses rollup to do that. He knows nothing about webpack, but wants to use my FancyComponent, but not BigFancyComponent. He installs fancy-component and imports FancyComponent. BigFancyComponent should not be included in the build (because of tree shaking).

As far as I know this is currently not possible. My friend would need fancy-component in a format using ES2015 modules. But currently these include webpack specific loader logic. I really need to publish fancy-component without webpack specific logic, but with ES2015 modules.

@TheLarkInn
Copy link
Member

I definitely see the merit in this. @sokra I don't think we have a way already to export vanilla es2015 / es modules. I think that maybe this can be part of the rollup story (module combining/(and this splitting exporting)).

@donaldpipowitch
Copy link
Author

Is there anything I can do to help with that? Can I tackle this problem myself as someone who is unfamiliar with webpacks code base? Or is this a rabbit hole into the guts of webpack? :)

@TheLarkInn
Copy link
Member

For a feature like this we should write up the design for the feature. Questions I think should be answerered first:

  • if someone uses CJS/AMD/non-esm dependencies in their library, how does webpack convert this into esm modules?
  • Should externals be leveraged for lib dependencies?

@TheLarkInn
Copy link
Member

Once we have the behavior designed then you can go straight into adding the test cases.

@donaldpipowitch
Copy link
Author

Seems to be like big step. Could we introduce some workaround in the meantime? Like emitting plain non-bundled commonjs modules without __webpack_require__, webpackBootstrap, etc.?

Use case is similar. I want to build a project with webpacks powerful loaders and I want to output some sort of modules without webpack specific logic, so that they can be consumed more easily by third party build tools. (Or webpack itself, too! E.g. I can't consume CommonJS modules outputted from webpack right now and use process.env. A good example: https://github.com/facebook/react is created as CommonJS and they use ``process.env.NODE_ENV. Their "main"` file points to the CommonJS entry. They can only do that, because they don't use webpack in the first place. If they would want to include a loader somewhere, they currently couldn't emit a target like they have right now which doesn't force others to use webpack, too.)

@donaldpipowitch
Copy link
Author
donaldpipowitch commented Oct 14, 2016

Turns out... it looks like I already can output CommonJS modules and keep process.env. (From my knowledge using CommonJS - or ES2015 modules in the future - and allowing environment variables is the lowest common denominator between current popular bundlers. Other features like loaders are webpack-specific.)

You need to set output.libraryTarget: 'commonjs2' (I guess most webpack users know this) and you need to set something like new DefinePlugin({ 'process.env.FOO': 'process.env.FOO' }) (that was new to me). So it should be possible to create a lib with webpack which can still be consumed by other bundlers without loosing the feature of setting environment variables.

The only feature which isn't supported in that way is tree shaking, which brings me back to the original feature request.

@nadavsinai
Copy link

@donaldpipowitch thanks for bringing this up, very useful indeed, I would love to contribute too, I am going to try to learn the current code base first...

@nathanosdev
Copy link

Would love to this implemented!

@HipsterZipster
Copy link

Have there been any updates to this issue in the past year? Is it being tracked elsewhere?

@yansern
Copy link
yansern commented Sep 28, 2017

Having to learn both webpack and rollup is no fun! Would love to have this implemented in webpack.

@itsdouges
Copy link

@sokra @TheLarkInn hey guys. if one (me) wanted to start looking at how to resolve this issue would you have any suggestions? any ideas of how much would need to change to support this?

i'd be keen to lend some time if you could put me on the right path :-)

saki7 added a commit to saki7/nagato that referenced this issue Oct 29, 2017
…ck's tree shaking.

This is currently *not* supported by Webpack (see webpack/webpack#1979 (comment) and webpack/webpack#2933 for rationale).

We workaround this by exposing our babel config to the wild (i.e. js/nagato/babel-options.js). This way we can give full controls for both bundling (i.e. 'tree shaking' in Webpack) and module building (i.e. 'transpiling') to the library users (I hope).

We just can't enforce our users to use some huge-sized arbitrary bundle.

Users with ES2015+ (or whatever) environment shall `require()` this config file inside their 'webpack.config.js', and use it as a hash object for the `babel-loader`'s `option: ` option. This could be achieved by looking into the `module: ` option in `package.json`; which (I believe) is the default behavior for Webpack when you use the native `import Something from 'other-external-library'` syntax.

If this is not desirable, use the fully-transpiled .js file inside our distributed npm package. This could be achieved by referring to the old-school `"main"` value inside the package.json.

Disclaimer:
By using this method we abandon Webpack-specific aggresive transpilation features for our entire library. This means we can't use Webpack-specific custom `import`s (i.e. importing non-JavaScript files like images (.png, .jpg, etc.) inside our library (.js)).

Additional notes:
This issue described in the disclaimer section can be workarounded by specifying your library-specific `npm run build` action inside the `prepare` section of package.json.
@lastmjs
Copy link
lastmjs commented Mar 19, 2018

It seems to me like Webpack is going to need functionality for compiling CommonJS and other formats to ES Modules, am I correct? I've been diving deep into this for the past few days. It seems like the whole world has traditionally been compiling from other formats to CommonJS. There is a popular babel plugin that does this. That problem seems to have been solved quite well by the community. But we need to go the other way, from CommonJS (or other formats) to ES Modules.

I'm not sure how much compilation/transpilation Webpack does itself, but that might be outside of its scope. Perhaps a Babel plugin would be the best choice here. Then the functionality could be leveraged by all libraries that need to go from CommonJS -> ES Modules. There is some prior art:

Basic Babel plugin for going from CommonJS -> ES Modules (basic, I've already run into a few blocking bugs, no community): https://www.npmjs.com/package/babel-plugin-transform-commonjs-es2015-modules

Advanced Rollup plugin for going from CommonJS -> ES Modules (seems very popular, most likely works very well, not very portable outside of Rollup. Might be easy to integrate within Webpack if Webpack has Rollup integration): https://github.com/rollup/rollup-plugin-commonjs

As I see it, this functionality should be created independent of Webpack and then incorporated as a dependency, through either a Bable plugin (most ideal), or perhaps a Rollup plugin (already implemented, might need to finagle).

Disclaimer, I'm not a heavy Webpack user nor in the Webpack community, these are just my thoughts as I've been trying to tackle the issue of CommonJS -> ES Modules

@ooflorent
Copy link
Member

I think webpack must wait until CJS / ESM interop has been standarized into node. There are plenty projects that made opinionated choices about it and it could break the existing codebases if things got spec-ed differently.

@moroine
Copy link
moroine commented Mar 20, 2018

Hello,

I have a library fully written in Es6, and due to webpack limitations I'm not able to propose my library in es6 module that would enable treeshaking feature on for clients

@ooflorent
Copy link
Member

@moroine For library, I would recommend using rollup. And webpack for applications.
Rich Harris (rollup's creator) wrote about it: Webpack and Rollup: the same but different.

@cseas
Copy link
cseas commented Nov 10, 2022

@WalterWeidner Why you need webpack to build ESM library? I think better to keep source code in ESM in nowdays

Libraries with source code in TypeScript need a build pipeline and simple tsc doesn't work for many use cases listed here. Besides, it'd be nice to be able to leverage the webpack ecosystem for plugins like ImageMinimizer while still delivering an ESM library the users can tree-shake.

Achieving any of these use-cases isn't impossible today but would get a lot easier with webpack.

@lorenzodallavecchia
Copy link

@WalterWeidner Why you need webpack to build ESM library? I think better to keep source code in ESM in nowadays

There is some consensus that consuming a library made of a single "Flat ESM" module (FESM) is more performant for downstream tools than consuming a library made up of tons of small ESM modules.

Angular strongly advocates using FESM, shipping all their packages with ESM bundles as a primary format and also advising developers to do the same for their libraries. Of course, the tooling used today requires additional post-processing via Rollup.

@WalterWeidner
Copy link
WalterWeidner commented Nov 10, 2022

@WalterWeidner Why you need webpack to build ESM library? I think better to keep source code in ESM in nowdays

I am curious about why the library output configuration options exist in Webpack if you feel this way. Is it meant to accomplish something different? It was always my assumption that its purpose was for something like what I am trying to do.

@alexander-akait
Copy link
Member

@WalterWeidner Yeah, I see your problem, library original was design for commonjs/umd/etc, when we don't have ESM, when we implement ESM library (with keep original tree and we have paln to do it), anyway can you create reproducible example and desribe the problem, I will look, thank you

@WalterWeidner
Copy link
WalterWeidner commented Nov 10, 2022

@WalterWeidner Yeah, I see your problem, library original was design for commonjs/umd/etc, when we don't have ESM, when we implement ESM library (with keep original tree and we have paln to do it), anyway can you create reproducible example and desribe the problem, I will look, thank you

@alexander-akait pulling this repository and then running yarn && yarn build should output what I am seeing (the function shouldNotExist() and its console.log() should not be in the webpack app's bundle). The whole purpose of that repository is to help pinpoint the tree-shaking issues we were seeing in a very basic environment.

image

If that's not what you need I am happy to spin up something else to help get to root of the problem more efficiently.

@alexander-akait
Copy link
Member

@WalterWeidner Yeah, I see your problem, we generate __webpack_require__.d, and that is prevent us for tree shaking, we should improve it for libraries

@WalterWeidner
Copy link

@WalterWeidner Yeah, I see your problem, we generate __webpack_require__.d, and that is prevent us for tree shaking, we should improve it for libraries

How likely is this to be implemented? We might need to adjust our build to use something else if this is unlikely to happen.

@10Derozan
Copy link

Any updates? I want to use it for libraries, too

@tonysamperi
Copy link

Seriously? It's been almost 10 years now?
I used it for a library, but it turned out it wasn't tree-shakeable...
I found a solution using tsc, which means I'll need to go back to rollup (that I used in older versions!!)..

Very disappointed.

@Kocal
Copy link
Kocal commented Mar 8, 2025

@tonysamperi we are waiting for your PR then

@tonysamperi
Copy link

@tonysamperi we are waiting for your PR then

@Kocal your reply is simply disappointing as well.
If you really need a hand to understand how to tackle this I'm happy to help.
Sarcasm won't solve this problem.
If the main contributors can write up a document explaining what is blocking this (I assume there's something besides the non esm dependencies)...
Maybe the readers of this issue can help find solutions...

@goloveychuk
Copy link
goloveychuk commented Mar 8, 2025

Tldr use esbuild or rollup.
Long version.
To make tree shaking works, bundle should generate flat output. Which means that all imported functions or variables should be rendered in top level of output module.
This is what esbuild and rolldown outputs (and probably rollup, I haven't check it personally).
Webpack, instead, generates registry of modules. Every module (file) is registered in big hashmap, all imports are done via webpack runtime calls.
Obviously, this could not be treeshaked.
This is opinionated decision sokra made. It has pros and cons.
E.g debugging is simpler because all module local members are scoped in function. Other one is that main chunk could provide common modules for async chunks via registry. Esbuild instead will generate additional chunk for commons.
But the point is that it's a core principle of how major of webpack works. This affects chunks generation e.g.
Thats why (as I see it) esm is still an issue. But I wouldn't expect it will be fixed in webpack anytime. Especially after sokra (afaik) switched developing turbopack.
Generally I would look on it as it's out of webpack scope (because, it's main target is spa prod bundle, not libs).
This is my imho.

@tonysamperi
Copy link

hey @goloveychuk,

first of all thank you for a such detailed explanation.
I think I understand, but at this point I would close the issue, explaining this cannot be achieved, as it goes against the purposes of webpack itself.
For what concerns my library, I'll explore esbuild (I'm intrigued by performances), or go back to rollup.

Cheers

@alexander-akait
Copy link
Member

@goloveychuk

Thats why (as I see it) esm is still an issue.

For the most part we support it, but we don't generate "treeshaked output". This is not our primary goal at the moment, although it may well be realized in the future.

@goloveychuk
Copy link

@alexander-akait btw I see https://github.com/webpack/webpack/releases/tag/v5.93.0
modern-module option is added. Isn't it suppose to fix tree shaking issue?

@alexander-akait
Copy link
Member

@goloveychuk treeshaked output is working for modern (modern-module is an alias) too right now, but you should have ECMA modules source code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

No branches or pull requests

0