Before editions, we had to make use of the following package.json fields due to the fragmentation of the ecosystem.
node, rollup, webpack, browserify
ES2015 and above, for bundlers targeting modern web browsers
ES2015 and below, for bundlers targeting legacy web browsers
rollup, webpack, browserify
mainfield is the standard target for
package.jsonfiles and is flagshipped by Node.
- While flagshipped by Node, its use is now widespread among many different systems, environments, and consumers.
- Environment capabilities are whatever the consumers environment supports.
- Tooling can be implemented by the producer at the runtime or install time of the consumer to add support for incompatible consumer environments, at the cost of CPU cycles, complexity, less consumer control.
- Tooling can be implemented by the consumer at their runtime or compile time to add support for their incompatible environment, however this is time intensive and they are most likely to look elsewhere.
- To reduce runtime, install, and consumer complexity, producers should publish their package with at least 2 editions of their code, the first being their source code, and the other targetting the lowest possible common denominator the consumers could share - intermediate editions for intermediate environments may also be published at the producers digression.
- With multiple editions published for the highest to lowest supported environments, an edition autoloader can be used to by default quickly and intellegently select the best edition for the consumers environment at their runtime. If the consumer wishes to manually select which edition they use, they can sidestep the autoloader by requiring their desired edition directly, or by configuring the autoloader to select their preferred edition instead of their identified edition.
- This approach allows minimal overheads for the producer in using their optimum tech while supporting legacy environments, while also allows for minimal overheads for the spectrum of consumers they support. And for edge cases, this approach also allows minimal overheads by allowing the consumer the power and information to override their edition selection and control their consumption in the ways they best see fit.
modulefield (formally the
jsnext:mainfield) is flagshipped by rollup.
- While flagshipped by rollup, it has also seen adoption in other bundlers and is a centerpoint for a proposal of ES Modules in Node.js.
- The flagship use case is to provide a field for ES2015+ compliant code that uses the ES Modules syntax (aka the
importsyntax rather than the
requiresyntax). The benefit to bundlers is that the explicit and static exporting and importing within ES Modules allows bundlers to build smaller and faster bundles that have more used code and less unused code in them. The bundle can then be compiled down to the lowest possible common demonator of features that the web browsers of the consumers audience supports.
- A secondary use case is for node.js end-user applications (where the entire app and dependencies rather being across thousands of files, are in one minified file, speeding up load time for consumers of the node.js app).
- In all common use cases the intention is for the target to be code that uses the ES Module
importsyntax for use in environments that only support ratified ES features, to which degree is unknown. Adding staging or alternative features (e.g. JSX) to this target increases complexity for the consumers of your package, as their environments, tooling or configurations may not support non-ratified features.
- As the degree of supported ES features by our consumer is unknown, given this field targets modern standardised environments with ES Modules, we recommend setting this field to an edition that uses the ES Module
importsyntax and only uses ratified ES features. Compiler presets such as babel-preset-latest will do the job. We do not currently recommend publishing an edition for this field if your source code did not originally use the ES Module syntax.
browserfield is flagshipped by browserify.
- While originally flagshipped by browserify, this field is now somewhat standardised and used by rollup and webpack too.
- The flagship use case, as established by browserify, was to convert code that was written for Node 0.10 and 0.12 to target web browsers such as Internet Explorer 10 and Google Chrome 35. Browserify would also shim builtin Node libraries with browser compatible versions, as well as analyse the Node Module System (aka the
module.exportssyntax) to combine all the files across different modules into a single bundle file, for use in the web browser.
- As it was intended for code in the Node 0.10 era as well as browsers like Internet Explorer 10, the flagship use case of targeting older environments has not changed. For newer environments and workflows, the
modulefield has been introduced, as seen earlier.
- As the degree of supported ES features by these older environments is unknown, we recommend targetting an edition that uses no later than ES2015 features, and of course it must use the Node Module
requiresyntax. Compiling ES2015 and newer features down to ES5 is difficult as operational parity may not exist, causing such conversions to be error prone. Compiling other features or other languages may not have this issue. Consumer polyfills to emulate any missing ES2015 features are also an option. As such:
- If you are using ES2015 features or newer, use the babel-preset-2015 to obtain near operational parity with your source edition and ES2015 edition. On the edge case the consumers target may be missing any ES2015 features, consumers can be instructed using the babel polyfill will offer them better operational parity - our recommended meta builder projectz will provide such instructions automatically in your README along with the automatic edition instructions for you.
- If you are using other languages, check which ES version they compile down to, before using this field for result. The official CoffeeScript compiler for example compiles CoffeeScript into valid ES5 code.
- Alternatively, you could just write ES5 or ES3 code, however, in that case, why even use editions if you wish to continue to write code for the lowest possible denominator.