Will it be possible in the future to import .json files as we used to required .json files?
import pkg from './package'
import { name, version } from './package'
The current ESM implementation already allows to import a JSON as default (first line).
I suppose we could add named imports, if it's something that users ask for.
/cc @nodejs/modules
named exports from json doesn't make a whole lot of sense to me. named imports are not and shouldn't be used in place of destructuring.
I have some concerns with JSON imports that I can list here:
en-US
are invalid, so you need to still use the default
.length
is potentially useful??length
which we cannot make a live binding (unless we use Proxies).default
(and therefore allow mutation of the original JSON) per number 1 we need to wrap it in a proxy and not track additional properties, just like https://github.com/nodejs/node/pull/20403 does.default
property from JSON.a json file should only have a default export; named imports are decidedly NOT destructuring, and allowing this would spread that confusion.
Named exports work for the cases they do and don't for the cases they don't. Users don't care about the cases named exports don't work since they can use alternative import forms to grab them. It's a convenience thing. JSON is just another module.exports
value. This will shake out naturally if CJS named exports support expands, from just builtin modules, to a wider scope.
@jdalton I don't understand the major wins vs just using destructuring which is also static so tree shaking isn't a problem. The edge cases are weird. Adding weirdness for the sake of convenience I think needs to have a more compelling reason than what exists in this thread currently to me personally.
JSON support isn't something that has to be explicitly expanded or deliberated on. It shakes out naturally, with no extra work, with wider CJS named exports support as seen with Babel and esm
packages.
That it’s no extra work doesn’t mean it’s a good idea. Even if named exports from CJS are able to become a thing, i don’t think that should be made to apply to json imports.
Named exports for CJS is an interop enhancement. As such it doesn't seem like the place to start green-fielding and diminishing value.
@jdalton I don't see it as no extra work / naturally shaking out from how JSON works? I'm not sure I understand how this affects my concerns above.
In CJS Node supports loading .json
files from require
. It parses the JSON and bolts the value on to a module.exports
. So it's just another module.exports
value _(nothing special about it)_.
CJS named exports work in the cases they can work. It's an interop enhancement which means, yes, some cases like property names that can't be translated into identifiers won't be supported as a named export and that's fine. That isn't something supported by Babel or others anyways.
@jdalton we are not talking about CJS named exports here. I disagree on your course of discussion unless we tie these features together.
with cjs, everything is an object
with esm, everything is well-known values
json is, by definition, a representation of an object.
saying that "because we do it in cjs we should do it in esm" is in my opinion a very silly stance because they are inherently different.
@bmeck
we are not talking about CJS named exports here. I disagree on your course of discussion unless we tie these features together.
You may not have thought you were talking about CJS named exports, but that's what it is and more importantly that's how the user will see it. JSON is just another module.exports
value – so support, if any, will shake out of the CJS named exports work.
@devsnek
with cjs, everything is an object
A module.exports
value does not have to be an object.
saying that "because we do it in cjs we should do it in esm" is in my opinion a very silly stance because they are inherently different.
When the feature discussed is CJS interop then it totally makes sense to bring up.
I think it’s reasonable to bring up. I think it’s a choice we could certainly make. I agree that the implementation would shake out “for free” along with named imports for CJS, and that non-identifier-names would simply not be named-importable, and that would be fine.
However, conceptually, i do not think json is the same as a CJS module, and i think that it would be a mistake to let the consumer of a json file “conveniently” but sloppily pretend that their json file is exporting more things than “the single json-parsed value”.
The arm wrestle between green-fielding and interop is ongoing for sure. None that will get settled in this thread.
You may not have thought you were talking about CJS named exports, but that's what it is
That is debatable but I side on JSON not being CJS. If we introduce named exports we might also need to move it off of the CJS require.extensions['.json']
implementation detail we have right now in order to keep order of evaluation.
It seems like this feature could be added after shipping an implementation of ESM, and I'm still not sure the convenience is worth prioritizing. We can add this to the modules meeting agenda, but probably cannot do anything while we still debate use cases.
it seems like this feature could be added after shipping an implementation of ESM
It could also be bundled with however wider CJS named exports ends up being handled.
_(configurable opt-ins-or-outs or whatever happens on that front)_.
We can add this to the modules meeting agenda
I don't think there is any urgency around this to warrant a specific agenda item.
but probably cannot do anything while we still debate use cases.
I think it'll likely work out of the use case / feature process on its own.
Just to contribute a use case, one pattern I see often is require('./package.json')
. It’s a pretty convenient way to get a package’s current version while staying DRY. Real-world example.
@GeoffreyBooth I don't think anyone wants to prevent loading JSON here.
@GeoffreyBooth yeah, that's the typical scenario: getting package.json
configuration straight forward.
Webpack supports named exports for JSON:
import { version } from './package.json';
console.log(version);
Presumably, it does this to simplify tree shaking; the unused portions of the JSON can be dropped. I could see it being useful if Node mimicked this behaviour, mostly for code that is designed to run on both the server and the client. It would also serve to make porting to natively supported .mjs easier; devs would not have to refactor such instances in their code just to get it to run on Node.
mostly for code that is designed to run on both the server and the client.
Code that runs in browsers cannot import JSON, only JS modules.
i'm not convinced this should be in core. this seems like a good situation for some sort of named-exports-from-json
loader.
It's worth noting we still don't even have any consensus on the minimal implementation that ".json" imports should be supported (to rather possibly be handled by asset loading techniques).
mostly for code that is designed to run on both the server and the client.
Code that runs in browsers cannot import JSON, only JS modules.
I was referring to code compiled by webpack for browsers (which I expect will still be a thing for a long time to come), but there's also https://github.com/w3c/webcomponents/issues/770 for native support.
Hasn't this issue been addressed by #26745?
Yes, thanks @aduh95
Most helpful comment
The current ESM implementation already allows to import a JSON as default (first line).
I suppose we could add named imports, if it's something that users ask for.
/cc @nodejs/modules