Dynamic or static import of json in browser with ESM
Asked Answered
V

2

10

I have the following example running without the JS having a bundler on top of it.

// index.js
;(async () => {
  const mod = await import('/index.json')

  console.log(mod)
})()
{
  "file": "index.json"
}

Chrome 80 fails to load the json with

Failed to load module script: The server responded with a non-JavaScript MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec.

Firefox 73 fails in a similar way:

Loading module from “http://127.0.0.1:8080/index.json” was blocked because of a disallowed MIME type (“application/json”).

Is this behavior surmountable?

Voltaic answered 9/2, 2020 at 19:11 Comment(1)
Even if your server were to provide that content with the mime-type text/javascript, that import would still not work as such in a browser because it is not syntactically valid JavaScript. I suggest you stick with fetch for the time being. const r = await fetch('/index.json'); const json = await r.json(); const o = JSON.parse(json);.Cardcarrying
V
9

Import Assertions are now stage 3 as of writing.

import json from "./foo.json" assert { type: "json" };

// or

import("foo.json", { assert: { type: "json" } });

would be the syntax for pulling in a JSON file with ESM.

Voltaic answered 12/7, 2021 at 20:10 Comment(1)
it's not yet shipped in firefox, follow github.com/mozilla/standards-positions/issues/373 or bugzilla.mozilla.org/show_bug.cgi?id=1777526Figurative
P
7

You can't directly import JSON using an ES6 import. You need to export it from a JS file:

// module.js
export default {
  "foo": { "bar": "baz" }
};
// index.js
;(async () => {
  const mod = await import('/module.js')

  console.log(mod)
})()
Pazice answered 9/2, 2020 at 19:28 Comment(8)
I know I'm splitting hairs, but the JSON string of your JS object above would be: '{ "foo" : { "bar" : "baz" } }'.Racialism
I accept your splitting of the hairs and have amended this answerPazice
Hah! Just as I was beginning to regret being so pedantic and seriously considering deleting my comment above. That's cheered me up enormously. All's well that ends well. Great stuff.Racialism
This is a fine solution to the specific problem in the OP, but you aren't dealing with JSON anymore. module.js in your example doesn't involve JSON.Cardcarrying
@AluanHaddad is right, but there is simply no avoiding this sort of workaround until JSON Modules finally get the green light.Racialism
@Racialism yes, and that will be a while. It's a crying shame the module registry API was dropped from the loader spec. But, I would argue that it's better to just use fetch to load JSON, especially with top-level-await already implemented in many environments.Cardcarrying
I am currently working with a set-up which collects a number of files and serialises them as a single JSON package which can be fetch-ed. I think I will try taking the serialised output and saving it twice: as a JSON which can be fetch-ed and also as the module.js format @DanielBank outlines above, which can be import-ed. Consumers will then have the choice between fetch-ing the JSON or import-ing the JS.Racialism
That's a good idea. If you intend it for general consumption, I would avoid combining the files. You don't want people using named imports from such a module. To maintain the abstraction over import and fetch, you'll likely need to cache the fetch responses. Just my thoughts.Cardcarrying

© 2022 - 2024 — McMap. All rights reserved.