This spec currently seems to imply that the browser field is for "javascript bundlers or component tools" and only required if they need to do something differently at client side while, from NPM Docs explanation), I understand we can state the following:
- browser field is mandatory (not optional) for packages expected to work client side.
- main field must not be provided in client-side only packages.
Original text: If your module is meant to be used client-side the browser field should be used instead of the main field. This is helpful to hint users that it might rely on primitives that aren't available in Node.js modules. (e.g. window)
It may not seem a major issue since since most big applications use bundlers nowadays and those that don't are supposed to manually place required files in an assets directory.
However this is not always the case and, from my point of view, there are several reasons to reinforce its mandatory nature for packages that are expected to work client side:
- It's what NPM Docs says.
- It's a more general purpose approach (making the browser field even more useful).
- Clarifies when a package is expected to work client side (have "browser" field), server side (have "main") or both (have "both").
- Is (almost) 100% compatible with both basic and advanced approaches defined in this spec.
- Make it possible for non bundled apps to serve packages from node_modules without wasting resources in those that are unsuitable client side (See Motivation).
Compatibility
The current version of this spec is already mostly compatible with this approach:
In basic operation
For the basic operation, it only needs to declare the browser field as mandatory even if the entry point (and hence the whole code in this case) is the same. Encouraging package mantainers to add it if already haven't.
Bundlers can keep failing back to the main field for those packages that lacking the browser one since, if we are bundling for client side and that package is required from codebase, it's likely we expect it to work client side.
In avanced operation
For the advanced operation we already need the browser field so it is clear that it will be "marked" as a browser package.
The only flaw here is that it still relies in the main field as entry point and, even it can be remapped elsewhere, if the package is only suitable for client side operation, it should have no main field in its package.json.
This will not be a problem to discern packages suitable for client side from those which are not but, from my point of view, it does not conform to what NPM Docs says and will make impossible to mark a package as not expected to work outside a browser.
To solve this we only need to define an optional "main" (or, to be even more flexible, maybe "/") key to explicitly override the main field so that it will be no longer necessary.
For packages that can be used both client and server side, using the main field for both client and server side will still be Ok, so we are not breaking anything.
Motivation
I do use bundlers in several projects and I think they are a great tool but, since the arrival of http/2 and http/3, if the only reason is network performance, maybe they are not the way to go. Specially for small or medium projects. (I may be wrong though).
Anyway, if this is going to be the standard, the most use cases it embraces the better. And I wish to point out that not using a bundler does not imply not using a package manager: Just placing the files at an assets folder condemn them to become outdated soon...
Some people just place an additional package.json for the client code and then (if server is also in JS) "cd" forth and back to (double) execute npm install / upgrade / audit... But I prefer to have a single package.json for the whole project and then serve the needed files from node_modules.
Until now, to do so one needed to either serve the whole node_modules (ok: no secrets there –unless you use private packages– but not so much polite...) or "manually" hand-wire express (or whatever lib/framework you use) for every JS file you need (if there was a better way to do so, please let me know...). Both approaches also at the risk that future versions may change those files names and/or paths...
For this reason, as soon I discovered the browser field I was so excited so, after a little unsuccessful research of anything similar, I implemented ESMrouter (and even forked express-generator so that now, when I want to "get the hands dirty" in something, I just need to type a single command and npm install whatever packages I need. But that's another history...).
This way, whenever I install any NPM package which has the browser field defined (or that I specify in a include option to manually add packages that lack it), its browser entry point is transparently served at /node_modules/<package_name> and proper entry is added to the auto-generated importmap.
Of course, this is only my personal approach not widely used yet (ando possibly never will be). But, if not this, maybe other future approaches will be possible if only we leave the door open.
Conclusion
In my oppinion, the changes I propose do not affect the utility of this specification and give it a wider coverage with just small tweaks in its composition.
I could have just forked it and make a PR with that changes (and I still can) but I thought it would be better to first explain the underlaying reasons of that chantes.
If you agree with me, you can either do them to your taste or tell me and I'll be glad to prepare a PR with them.
References
This spec currently seems to imply that the browser field is for "javascript bundlers or component tools" and only required if they need to do something differently at client side while, from NPM Docs explanation), I understand we can state the following:
It may not seem a major issue since since most big applications use bundlers nowadays and those that don't are supposed to manually place required files in an assets directory.
However this is not always the case and, from my point of view, there are several reasons to reinforce its mandatory nature for packages that are expected to work client side:
Compatibility
The current version of this spec is already mostly compatible with this approach:
In basic operation
For the basic operation, it only needs to declare the browser field as mandatory even if the entry point (and hence the whole code in this case) is the same. Encouraging package mantainers to add it if already haven't.
Bundlers can keep failing back to the main field for those packages that lacking the browser one since, if we are bundling for client side and that package is required from codebase, it's likely we expect it to work client side.
In avanced operation
For the advanced operation we already need the browser field so it is clear that it will be "marked" as a browser package.
The only flaw here is that it still relies in the main field as entry point and, even it can be remapped elsewhere, if the package is only suitable for client side operation, it should have no main field in its package.json.
This will not be a problem to discern packages suitable for client side from those which are not but, from my point of view, it does not conform to what NPM Docs says and will make impossible to mark a package as not expected to work outside a browser.
To solve this we only need to define an optional "main" (or, to be even more flexible, maybe "/") key to explicitly override the main field so that it will be no longer necessary.
For packages that can be used both client and server side, using the main field for both client and server side will still be Ok, so we are not breaking anything.
Motivation
I do use bundlers in several projects and I think they are a great tool but, since the arrival of http/2 and http/3, if the only reason is network performance, maybe they are not the way to go. Specially for small or medium projects. (I may be wrong though).
Anyway, if this is going to be the standard, the most use cases it embraces the better. And I wish to point out that not using a bundler does not imply not using a package manager: Just placing the files at an assets folder condemn them to become outdated soon...
Some people just place an additional package.json for the client code and then (if server is also in JS) "cd" forth and back to (double) execute npm install / upgrade / audit... But I prefer to have a single package.json for the whole project and then serve the needed files from node_modules.
Until now, to do so one needed to either serve the whole node_modules (ok: no secrets there –unless you use private packages– but not so much polite...) or "manually" hand-wire express (or whatever lib/framework you use) for every JS file you need (if there was a better way to do so, please let me know...). Both approaches also at the risk that future versions may change those files names and/or paths...
For this reason, as soon I discovered the browser field I was so excited so, after a little unsuccessful research of anything similar, I implemented ESMrouter (and even forked express-generator so that now, when I want to "get the hands dirty" in something, I just need to type a single command and npm install whatever packages I need. But that's another history...).
This way, whenever I install any NPM package which has the browser field defined (or that I specify in a include option to manually add packages that lack it), its browser entry point is transparently served at /node_modules/<package_name> and proper entry is added to the auto-generated importmap.
Of course, this is only my personal approach not widely used yet (ando possibly never will be). But, if not this, maybe other future approaches will be possible if only we leave the door open.
Conclusion
In my oppinion, the changes I propose do not affect the utility of this specification and give it a wider coverage with just small tweaks in its composition.
I could have just forked it and make a PR with that changes (and I still can) but I thought it would be better to first explain the underlaying reasons of that chantes.
If you agree with me, you can either do them to your taste or tell me and I'll be glad to prepare a PR with them.
References