The spec has moved to a repo: https://github.com/defunctzombie/package-browser-field-spec to facilitate collaboration.
-
-
Save defunctzombie/4339901 to your computer and use it in GitHub Desktop.
A regex option would be cool, so you don't have to explicitly define each module of type to be false.
Hey @defunctzombie would it make sense to PR this into https://github.com/npm/npm/edit/master/doc/files/package.json.md ?
Is this added to anything besides browserify? Would be cool to see support in webpack and jspm.
Verified this works in webpack. The property is overloaded so you sometimes have to get creative if you have a client-only entry point and want to specify a module location.
"main": "index.js",
"browser": {
"index.js": "bytebuffer/dist/ByteBufferAB.js",
"Long": "bytebuffer/node_modules/long/dist/Long.js"
}
The index.js
mapping is equivalent to "browser": "dist/ByteBufferAB.js"
@balupton It's already supported in JSPM: jspm/jspm-cli#1062
This use of the browser property seems to be at odds with the npm specification? It seems dangerous to me and has already caused problems with the Axios package.
https://docs.npmjs.com/cli/v7/configuring-npm/package-json#browser
It’s not at odds with it at all; they should be used in concert.
Sorry, not quite getting that. The npm docs appear to say that the browser property should contain a single string pointing to the main entry point for when the package is consumed by a browser. But this spec is using an object with a different meaning? How can that not be at odds? Am I missing something?
Having two wildly different specs on the same property makes it very much harder to use the property for anything unless you already know how a package is going to use it. Not much help when you are trying to automate things.
Both are part of the browser field spec (the npm docs are not an authority on this subject). if a string, it replaces the “main”; if an object, it provides mappings to replace anything.
OK, can you please point me to the authoritative definition for the package.json file? Thanks.
There is not one such definition, since many tools look at that file. For npm, it's https://docs.npmjs.com/cli/v7/configuring-npm/package-json/; for the "browser" field, it's https://github.com/defunctzombie/package-browser-field-spec.
Hmm, an interesting viewpoint. Not one I share I'm afraid. I see that we won't agree on this subject sadly. Having two different definitions for this field is confusing and counter-productive. As far as I am aware, npm created the package.json file and defined its schema including the browser property. If more flexibility was needed for that field, it should have been (and maybe was for all I know) raised with npm. What we have now is some scripts failing because of competing specifications for the field. Adding complexity and wasting people's time while they try to work out what is wrong.
Anyway, thanks for responding.
You’re incorrect; npm did not create or define the browser field, they merely (partially) document it. If it’s confusing for you, I’m sure we could get npm to remove that, or link to the actual spec for it.
If that is the case then it would indeed be better for the npm documentation to be updated so that it is correct.
It seems like this would be better if it followed the same conventions as the npm exports field? It doesn't seem to have any wildcard/regex abilities unless I'm missing something.
The exports field has zero to do with npm; that’s a node-specific field that was added almost a decade after the browser field became a de facto standard.
@ljharb I wasn't referring to the history of it - I just think it would be nice if the browser field allowed for pattern replacement so I don't have to input every filename into the package file. Maybe Webpack/Browserify should adopt the exports convention - that's all I'm saying. It would make for cleaner code.
The exports field does have the "browser" condition, but it doesn't seem like webpack or browserify pays attention to it.
see the difference:
"exports": {
".": {
"browser": "./lib/core.js",
"node": "./lib/core-node.js"
},
"./*/": "./lib/*/",
"./*": "./lib/*.js"
},
"browser": {
".": "./lib/core.js",
"evented": "./lib/evented.js",
"fig": "./lib/fig.js",
"heap": "./lib/heap.js",
"lock": "./lib/lock.js",
"middle": "./lib/middle.js",
"mixin": "./lib/mixin.js",
"pipe": "./lib/pipe.js",
"query": "./lib/query.js",
"router": "./lib/router.js",
"tree": "./lib/tree.js"
}
Ok, it appears I was missing something. WP5 does have support for the exports field. Although I'm stuck with WP4 - but I found this plugin https://www.npmjs.com/package/@builder/exports-field-webpack-plugin will test and see how it goes
That's a no-go -- tried it in Nuxt and it broke some things. Guess I'll just have to be verbose. Oh well ¯_(ツ)_/¯
The original idea behind the browser field is different from the exports field. With the browser field the purpose was not to wholesale ship a different set of files for node vs browser but instead provide a mechanism to replace a few files when packaging for browser. The thinking being that you would generally share 90% of the code and only replace a few compatibility or platform files. Ideally these wouldn't even be user-facing but could be.
I'm building libraries that work in the browser and in Node. I get the original purpose of the browser field, but now that the browser is getting more advanced, the use cases are getting more advanced. WP5 is using the exports field with pattern replacement. I'm not sure about Browserify, but I'd like to make libs that work with both. It's not a huge deal, I can just define every file, but that definitely seems like an inefficient way to do it in the grand scheme
The efficient thing to do is to have most of your files be universal, and have a very small number that vary by platform - ideally confined to separate packages.
My files are isomorphic, meaning they work on both browser and in Node, I'd call that "universal". The issue is that Webpack (4) doesn't care, and so I have to compensate by listing every file in the browser field. I have one file that is used on Node only and the exports field handles that just fine.
The efficient thing would be to allow for the browser field to behave like the exports field. But less efficient for me to use my time trying to get that changed than just to deal with it. But as my libs grow, so too must the exports field. Tracking each import in the config is redundant and therefore inefficient. Hopefully Browserify/Webpack will address this. But I won't be holding my breath.
Nice spec.
When you write:
Are the relative paths in
"./server/only.js": "./shims/server-only.js"
relative to the location of the package.json file or to the directory of the file that callsrequire('./server/only.js')
?In other words, lets say
root
stands for the directory where the package.json is located androot/deep/file.js
doesrequire('./server/only.js')
, should it resolve to:root/deep/shims/server-only.js
root/shims/server-only.js
?