-
Notifications
You must be signed in to change notification settings - Fork 2.9k
RFC: Standard package output folders #17298
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
Changes from all commits
4d9acbc
3526bb3
e3e6ca9
0f94c61
2addfe5
96bb7bc
38b7c81
f0a62f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| # RFC: Standard package output folders | ||
|
|
||
| --- | ||
|
|
||
| _List contributors to the proposal: @dzearing_ | ||
|
|
||
| ## Summary | ||
|
|
||
| There are multiple javascript formats we may include in our npm packages: `commonjs`, `esm`, and `amd`, in addition to static assets like pre-made bundles and images. | ||
|
|
||
| We should adopt a predictable folder structure within the published npm package for these formats. That way consumers of our packages can know exactly where things are and which folders have what things in as few steps as possible. | ||
|
|
||
| This is one of those small details that other partners will emulate and adopt. If we can be consistent, many packages exported by our partners will likely follow guidance because it is really minutia, but ends up adding to more predictability at scale. | ||
|
|
||
| ## Problem statement | ||
|
|
||
| Today, `lib` contains esm JavaScript output, except for node-only packages which will drop CommonJS modules in them. This obfuscates what `lib` actually contains. We should adopt standards which add clarity to what output format is used. | ||
|
|
||
| ## Detailed Design or Proposal | ||
|
|
||
| We've historically used the following standard output folders in a published JavaScript package (only applicable output folders would be present): | ||
|
|
||
| - `/lib` - esm (as we've had for a long time) | ||
| - `/lib-commonjs` - commonjs (only needed while Node <= 13.2.0 is supported) | ||
| - `/lib-amd` - amd (hopefully we can drop someday) | ||
| - `/dist` - bundles and static content | ||
|
|
||
| If this seems reasonable, we should adopt and stay consistent to stay predictable to consumers. If a library needs to output CommonJS, it should be output within the `lib-commonjs` folder. | ||
|
|
||
| A library like `react-button` which might be consumed by Node and bundlers likely will need both ESM and CommonJS, until Node 13.2.0 or greater is the minimum requirement. Its output will have both a `lib` and `lib-commonjs` folder. | ||
|
|
||
| Once 13.2.0 becomes the minimum Node requirement, there is little reason to build CommonJS at all, and I anticipate we'll be removing that folder. | ||
|
|
||
| ### Pros and Cons | ||
|
|
||
| #### Pros | ||
|
|
||
| - Almost no difference from what we currently have - only the `build:commonjs-only` task needs to be modified to output to `lib-commonjs`. | ||
| - Our partners won't really notice changes here at all, since this has been the convention we've used for a long time for nearly all the packages currently being consumed. | ||
| - ESM is becoming the standard that all platforms will snap to, hence why `lib` and not `lib-esm`. | ||
| - Changes in output won't change the folder structure | ||
| - Unchanging folder structures mean that full builds are required less | ||
| - End users can predict which folders contain what format | ||
| - Scalable. If we need other formats in our JS packages, we can update add more formats. | ||
| - `CommonJS` was the standard of the past. More and more, modern node libraries will be moving to ESM as Node 13.2.0+ now supports it. I anticipate this format to phase out over the next few years as AMD has. | ||
|
|
||
| #### Cons | ||
|
|
||
| - Potentially `esm` might be changed as the "standard" library format in the future, which would require us to adjust what `lib` means. | ||
|
|
||
| ### Alternatives | ||
|
|
||
| Many libraries in OSS have kept `lib` representing CommonJS and have added `es` to the mix as the folder for containing esm. This is very likely because they've existed for a while and didn't want to change their existing folder structure. We could also consider this convention. React itself avoids `lib` and explicitly uses `cjs` to indicate the output format. (It also has no ESM flavor.) | ||
|
|
||
| * `/cjs` - CommonJS | ||
| * `/es` - esm | ||
| * `/amd` - amd | ||
| * `/dist` - statics and bundles | ||
|
|
||
| #### Pros: | ||
|
|
||
| * Follows a few more OSS library conventions (though there isn't consistency here) | ||
| * Won't have to revisit if the JavaScript flavor of the month changes later | ||
|
|
||
| #### Cons: | ||
|
|
||
| * A bigger shift than the original proposal - will impact nearly all of our packages | ||
| * Definitely more work to clean things up to this format | ||
|
|
||
| ### How do other major packages organize their output? | ||
|
|
||
| "Standards" haven't really emerged other than `dist` being the output folder. There is a commonality of using `es` as the esm folder. Here's a small sampling: | ||
|
|
||
| * @angular/core - Uses `bundles` for output which includes a UMD bundle for commonjs support, and `fesm2015` for esm. | ||
| * @apollo/client - No folders; `index.js` at root is esm while `index.cjs.js` is CommonJS. | ||
| * @material-ui/core - Uses a root `index.js` rollup entry for commonjs and `es` folder for esm. | ||
| * antd - Uses `es` for esm, `lib` for commonjs. | ||
| * immer - Uses only `dist` and rolls up a separate `esm` bundle. | ||
| * react - Commonjs is in `cjs`, there's also a `umd` folder for bundles. | ||
| * redux - Uses `es` for esm, `lib` for commonjs. | ||
| * styled-components - Only `dist` with `s-c.esm.js` and `s-c.cjs.js`. They also emit a react-native `s-c.native.js` flavor. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. important thing to answer - is this RFC for both legacy and converged? I'd follow google/preact crew way of shipping libraries. They have plenty of experience in both building smallest possible libraries and way of shipping those to consumers. For inspiration -> https://github.com/developit/microbundle Convergence output:
Pros:
Cons:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. regarding
I'd recommend to have only one Pros:
Cons:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Any nontrivial changes will have to be for converged only (the RFC needs to be updated to mention this). #17298 (comment)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Hotell I think 1 dist folder with rollup bundles makes tons of sense for small libraries. With converged packages where they're more single purposed, for example. It is also a very good tool for avoiding deeply nested imports; and as you mentioned, we would probably discourage including build output completely. (There are a few scenarios where it may be useful, like documentation.) Would be nice to roll up the typings as well. It breaks down in monolithic suite packages that re-export a lot of things, because of a variety of reasons. More to parse unnecessarily, more prone to side effect problems, bundle graph doesn't show enough detail. So I could get behind this for the converged smaller-purpose packages.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about this: Legacy: we keep the same. lib (esm), lib-commonjs (commonjs), amd (amd) Converged: @layershifter @ecraig12345 @JustSlone thoughts? |
||
|
|
||
| ## Discarded Solutions | ||
|
|
||
| The current solution of using `lib` for either CommonJS or ESM depending on which platforms are (currently) supported should be replaced with something that doesn't mean different things in different contexts. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My personal preference is to have
lib-esmorlib-esas it obviously says what is in a directory.Another thing that we discussed some time ago to have a single
distfolder. For example:/dist/esm- esm (as we've had for a long time)/dist/commonjs- commonjs (only needed while Node <= 13.2.0 is supported)/dist/amd- amd (hopefully we can drop someday)/dist/assets- bundles and static contentIt will have the same props&cons as an alternative proposal, but it will be easier to ignore a single entry in
.gitignore/IDE 🐱There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to change things, I agree this would be even cleaner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I could behind the
lib-esmapproach. It's more explicit, and doesn't favor a particular output. This means we can add more output flavors in the future (the react-native output formats would be the first which come to mind) without the akwardness of picking one as the "true" output flavor.My primary concern changing now is to avoid destabilizing partners, as Elizabeth mentioned below. My recommendation would be to stick with the current output folders in the writeup, fix the node packages only to stay inline with other packages (since this was a recent change.)
Then in the converged packages, we could start adopting the dist/* layout now. Later in v9+, change everything to be inline with the dist approach.
Is this reasonable/ideal? Concerns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No concerns, make sense for me 👍
Should we update a proposed solution to include v8 (as it stays currently) and converged proposal (for example,
/distlayout, or another proposal) in this RFC? Or have an another one?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's simple enough that we could cover both v8 and converged in this RFC.
Though the part we didn't totally decide on for v8 is whether
libmust be ESM for all packages, even ones where in reality we only need commonjs.