简体   繁体   中英

ES6 modules in local files - The server responded with a non-JavaScript MIME type

I get this error:

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

The project is run from local files, eg.: file:///D:/path/project.html .

Works without problems in Firefox, but doesn't work in Google Chrome. I want to test it this way for development purposes - it's more comfortable than creating a server and remembering what port is it on.

A simple fix for me that wasn't listed here was this:

I had an import statement bringing an object from a different file, which I did via this line:

import { Cell } from './modules/Cell';

What broke the code and caused the MIME type error was not having .js appended to the end of ./modules/Cell .

The updated line fixed my problem:

import { Cell } from './modules/Cell.js';

If you got onto this error message, it means that it's not a Same-origin issue.

As said in the error message, the real problem is that modules scripts require the MIME of your script file to be one of the javascript MIME types.

Your filesystem doesn't provide any MIME, hence the loading fails.

So the best solution is obviously to run your code on a local server, and not on the filesystem.

But since you do insist ;) One workaround is to first fetch your script file as Blob using XHR ( fetch can't be used on file:// protocol), then force its type property to be one of js MIMEs, and set your <script> 's src to a blobURI poiting to this Blob.

// requires to start chrome with the --allow-file-access-from-file flag
var xhr = new XMLHttpRequest();
xhr.onload = e => {
    let blob = xhr.response;
    blob.type = 'application/javascript'; // force the MIME
    moduleScript.src = URL.createObjectURL(blob);
};
xhr.open('get', "yourmodule.js");
xhr.responseType = 'blob';
xhr.send();

BUT , you won't be able to import any dependencies from within your module.

ES6 module files are loaded using the standard Same-Origin policy restrictions that browsers enforce and have many other security restrictions in place, while JavaScript "script" files have much more lax security to avoid breaking existing websites as better security standards have been added to browsers over time. You are hitting one of them, which is that files must be sent with the correct MIME type.

file:// URLs are not normal HTTP requests, and as such they have different rules around requests. There's also pretty much no rules for what MIME type should be sent. If you want to use ES6 modules then you need to be running a real HTTP server locally to serve your files.

You can set the ModuleSpecifier to a data URI

<script type="module">
  import {Test} from "data:application/javascript,const%20Mod={this.abc=123};export%20{Mod};";
  console.log(Test);
</script>

to set the ModuleSpecifier programmatically you can launch Chromium/Chrome with --allow-file-access-from-files flag and utilize XMLHttpRequest() to request a JavaScript file from file: protocol

<script>
(async() => {

  const requestModule = ({url, dataURL = true}) => 
    new Promise((resolve, reject) => {
      const request = new XMLHttpRequest();
      const reader = new FileReader();
      reader.onload = () => { resolve(reader.result) };
      request.open("GET", url);
      request.responseType = "blob";
      request.onload = () => { reader[dataURL ? "readAsDataURL" : "readAsText"](request.response) };
      request.send();
   })

  let moduleName = `Mod`;
  // get `Mod` module
  let moduleRequest = await requestModule({url:"exports.js"});
  // do stuff with `Mod`; e.g., `console.log(Mod)`
  let moduleBody = await requestModule({url:"ModBody.js", dataURL: false}); 
  let scriptModule = `import {${moduleName}} from "${moduleRequest}"; ${moduleBody}`;
  let script = document.createElement("script");
  script.type = "module";
  script.textContent = scriptModule;
  document.body.appendChild(script);

})();
</script>

On Windows, i cannot get ES 2016 modules to load correctly. Even if you disable security, then you get hit by the next prolem which is the .js files don't have a MIME type set, so you get a message like Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.

The answer is to use Safari on the macintosh, which allows local files no problem with ES 2016 modules. Interestingly both Chrome and Firefox also fail to work properly. Frankly this is a bug, because when you are loading a local file, there is absolutely nothing insecure about accessing files from the same folder. But good luck getting Google or Firefox to fix this. Apple even has a flag about cross-scripting permissions in their pulldown menu, so they know how important it is to disable nonsense security stuff.

I solved the same problem adding this line to apache mime types file configuration:

AddType aplication/javascript .js

I hope this helps.

If the files don't end up with ".js" but ".mjs" try changing them to ".js"

And also if you didn't specify the file type, specify it: ./modules/Cell to ./modules/Cell.js

The issue I had that caused this for me was I am using embedding React into an existing site and was calling my main.jsx. When you call a script with.jsx and embedding React, you need to set your type to "text/babel".

eg - <script type="text/babel" src="./src/main.jsx"></script>

This link is useful if you are embedding react - https://reactjs.org/docs/add-react-to-a-website.html#optional-try-react-with-jsx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM