I want to use import() function to load an image, like this:
import("./../assets/Index.png")
.then(res => {
console.log("success", res);
})
.catch(err => console.log("err", err));
However, the console tells me:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "image/png". Strict MIME type checking is enforced for module scripts per HTML spec.
So I was wondering how I could do that?
Update
Actually, I run it in a browser environment because I don't want to use require() function to load an image.
No.
Importing of images in that fashion is a feature supported by some build tools (such as webpack) which allow images to undergo processing at build time.
At run time, that benefit can’t exist. Browsers have not implemented any feature that allows import to handle images.
Related
I am currently practing using API with es6 Modules in JS (vanilla).
app.js
import Game from './model/Game';
const proxy = 'https://cors-anywhere.herokuapp.com/';
let key = 'MY_API_KEY_PRIVATE'; //kept private for StackOverflow
let steamID = '76561197996900532';
getOwnedGames();
async function getOwnedGames() {
try {
const result = await fetch(`${proxy}http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=${key}&steamid=${steamID}&format=json&include_appinfo=true`);
const data = await result.json();
let gamesList = data.response.games;
console.log(gamesList);
} catch(error) {
console.error(error);
}
}
.
Game.js
export class Game {
}
Now this works without using import GotGames from './model/Game';, but with it gets the following error :
Uncaught SyntaxError: Cannot use import statement outside a module
I have seen a similar problem in this space by adding type="module" in the script tag in HTML, but that gives the following error :
Access to script at 'my_file_path' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Why has adding type="module" affected my API calls and how can this be done? Has this got something to do with requiring Node.js to install webpacks by any chance?
Yours is actually a very broad question, but I will try to clarify some important aspects of it.
-Spoiler Starts-
Webpack.
-Spoiler Ends-
Take into account that even if it is famous for not being beginner-friendly, some refer to it, together with Babel and React, as the bleeding edge of web development technologies. So it is worth to be studied at least once. In a few words, it will transform your ES modules to a custom system (which is written in plain old JavaScript) that will be compatible with technically all browsers and will preserve functionality along with many other advantages.
However, for simplicity, you may want to use a framework like React which uses Webpack under the hood, so you won't have to directly deal with it.
I really recommend you this Medium article to discover some interesting facts about the history of modules in JavaScript and NodeJS.
At the end, we will both agree that ES6 modules are the future, but then, even after resolving your specific issue, you will sadly find that ES6 modules are a very recent standard and that it currently has relatively poor browsers support.
Answering your question:
Browsers do not interpret JavasScript files as modules by default, so that is the reason why you have to explicitly declare them using type="module" attribute in your script tags. That is obviously why you got your first error.
To correctly import "Game.js" module, you have to re-write your import statement as follows: import {Game} from './model/Game'; because you made a named export. As written in comments, do some reading about import/export on MDN and it will be clearer for you.
Finally, CORS errors are likely to be caused by a server misconfiguration. Especially with headers. You may want to try setting Access-Control-Allow-Origin header to * or your specific server name, so new requests will have Origin header different than null.
I hope this will indicate you a good path to expand your knowledge.
* EDIT: To solve the issue from the comments about the error when click opening the file I would suggest to use the following not so known meta tag <meta http-equiv="Access-Control-Allow-Origin" content="*"> to emulate the http header when there is no server. I'm not sure if it will work, but technically it should, please let me know in the comments because I'm curious.
See this
It seems by adding default in export default class Game with type="module" included in the script, it seems to be working fine again.
Is there an explanation as to why this works ? so that I can understand this.
EDIT : It seems that this only works when the html file is run in LiveServer (VS Code ext which acts as a local server)
Whereas when I manually run (click open index.html) file the same error :
Access to script at 'file:///*path_to_.js_file*' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
I am using rust and webassembly. I am getting this error message operation not supported on wasm yet. So either one of two things is happening, and I was curious if anyone knew the answer. So either my filepath is not correct and this is the least helpful error message, or wasm doesn't support loading files.
#[wasm_bindgen]
#[macro_use]
pub fn file() -> () {
let mut data: Vec<u8> = Vec::new();
///I would load the png with the same path in my javascript.
let opened = File::open("./png/A_SingleCell.png");
let unwraped = match opened {
Ok(a) => log(&format!("opened {}", "worked")),
Err(e) => log(&format!("{}", e)),
};
// .read_to_end(&mut data)
// .unwrap();
return ();
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(msg: &str);
}
and the javascript call is merely just file().
Is there a different directory path I need to use to get the png or can you truly not load a file?
Edit
Adding my index.js to show that webpack has already loaded the png.
import { memory } from "break-game/break_game_bg";
import A from './png/A_SingleCell.png';
import { alloc, fill, decode, file } from "break-game";
file();
Loading a file from the filesystem doesn't work with the Rust standard library and the wasm32-unknown-unknown target. This error is, consequently, an expected runtime error for using File::open.
The Rust standard library currently provides a uniform API surface area for all targets, regardless of whether the target actually supports the functionality or not. It turns out that almost all platforms implement basically all of the stable surface area of the standard library, but the wasm32-unknown-unknown target in specific is a bit of an odd-one-out. On this wasm target the standard library notably has no way to implement functions in modules like std::net or std::fs, so the functions unconditionally return an error. What you're seeing here is that File::open unconditionally returns an error on the wasm32-unknown-unknown target.
Speaking specifically about the wasm32-unknown-unknown target, this target is used to represent the "base layer of compatibility for Rust and wasm". On this target the standard library can only assume the WebAssembly instruction set, nothing else. Because WebAssembly provides no means of doing I/O or loading files, it means that these stubs are left to return errors in the standard library.
Note that an alternative way for us to provide the standard library on the wasm32-unknown-unknown target is to simply not provide these functions at all, causing a compile time error when they're attempted to be used. We chose to not take this route, for better or worse, to remain consistent across targets in Rust. It's hoped that something like the proposed portability lint can change the calculus of this story, but Rust isn't quite there yet!
In the meantime, though, you probably still want to get this done! The wasm-bindgen project has a few guides about the wasm32-unknown-unknown target which may help you make some progress here:
Which crates will work off the shelf with WebAssembly?
How to add WebAssembly support to a general purpose crate
Notably the web platform doesn't currently provide the ability to load files from the filesystem, so there's no great way to implement File::open as an API in Rust for the wasm32-unknown-unknown target, even if JS is used. If you're using Node.js, though, I'd recommend reading about JS interop as well as checking out the wasm-bindgen guide for importing Node.js functions to implement this.
I have a SPA (built on webpack, with babel, etc) that includes a polyfill in the index.html:
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Promise,Array.prototype.includes,Element.prototype.remove"></script>
One use-case for the polyfill is in order to use the Promise API on IE 10-11.
My error monitoring reporting an error on an IE 11 client of the following:
ReferenceError: 'Promise' is undefined
So I assume that particular session failed to download the polyfill for some reason.
My question is: How should I deal with this case? Is it a scenario I should expect to happen sometimes? Is the user expected to noticed the application not working properly, and reload the page?
There is an error event you can attach to allow for more control if you are really worried. You don't usually need to handle this explicitly though.
In this particular case you could migrate towards using babel to build a bundle with polyfills included in your scripts. This adds an additional build step to your process though.
Since you mentioned you're using webpack, it would just be best to include the necessary polyfills directly in the project via an import statement (something like core.js) rather than using a cdn - polyfill.io.
However, you could alternatively add an ID to the script element and listen to the onload and onerror events to determine whether the script (un)successfully loaded like so:
<script id="polyfillScript" src="https://cdn.polyfill.io/v2/polyfill.min.js?features=Promise,Array.prototype.includes,Element.prototype.remove"></script>
In your project index.js:
document.getElementById('polyfillScript').addEventListener('error', () => {
alert('Failed to load polyfill!');
});
I'm working on a framework-like structure that uses curl.js as script loader. Modules can be located in either the App or Core directory, which allows me to override Core modules easily from the app. I had a server-side script to search these directories and return the first found file but then I decided that the client-side should be able to work without any help from backend, so now I have a function that tries listed directories until one of them has a file.
After a while I realized that I don't have any way to differentiate between 404 errors and syntax errors. I want the loader to fail if there is an actual error in code but in case of 404 it should just look for the next file and finally fail if no file can be found.
So, is it possible to detect if a script failed(in curl.js, AMD or generally in js) due to 404 and not because of errors in the loaded code?
Because of security concerns, browsers don't provide much information when scripts fail. In fact, IE refuses to even call the "load" event at all. The only information an AMD loader has is whether the define() was called or not.
There might be a way to detect some types of script errors, if you place your own global function call at the beginning of the script file. You can check if that function has been called. You can't detect SyntaxErrors that prevent parsing of the script, but you can detect other types of errors.
It might be possible to return the exact error to the errback function ( curl([]).then(callback, errback)) when the error happens while executing the factory function. Have you verified if this works or not?
I’m currently testing various asynchronous-resource-loaders to see which one I want to use. At the moment Curl is throwing a ‘Promise already completed’ error…and their documentation says ‘this should never happen’.
I “suspect” I must to use a ‘define’ within each file being loaded (hope not). Further, their documentation says Curl can work with non-AMD javascript files. But...I am new to AMD and since Curl is far-faster than the other ones I'm testing...I am willing to put some time into understanding this better.
Lastly...
Even though FireBug shows the errors...all the files STILL LOAD asynchronously! But, BECAUSE there are errors...the 'then' portion of the code never gets called.
So My Questions Are:
Do I have to update all the JavaScript file-objects to be contained in a 'define'? (...hope not)
Can you see any other problem syntactically?
The Head’s Code Looks Like This:
<script type="text/javascript">
///<summary>Configuration</summary>
curl = { baseUrl: 'Includes/JavaScript/' };
</script>
<script src="Loaders/Curl/curl.js" type="text/javascript"></script>
<script type="text/javascript">
function onSuccess() {
}
function onError(ex) {
//alert(ex);
}
require(["MooTools/Core/mootools-1.2.2-core-jm",
"MooTools/mGeneral",
"jQuery/Core/jquery-1.3.2",
"jQuery/Core/jquery.tools.min",
"jQuery/ThirdPartyPlugIns/jquery.tmpl"])
.then(onSuccess, onError);
//require(["jQuery/TopUp/top_up-min"], null);
require(["jQuery/ThirdPartyPlugIns/jquery.dimensions",
"jQuery/ThirdPartyPlugIns/jQuery.Color.Animations",
"jQuery/ThirdPartyPlugIns/jquery.corners.min",
"jQuery/ThirdPartyPlugIns/jquery.tipsy",
"jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0",
"jQuery/ThirdPartyPlugIns/jquery.tipsy"]);
require(["general",
"WindowCenter",
"ThirdPartyPlugin/KeyBoardCapture",
"ThirdPartyPlugin/bsn.AutoSuggest_2.1.3",
"ee/8Ball",
"ee/EE"]);
</script>
Again...I'm sure it is caused by inexperience with AMD-styled code, but I still need help...so any is appreciated.
Typically, you should wrap your modules in a define() or append a define() at the end of the file if those modules have no dependencies. It seems, though, that those modules all depend on jQuery, if not other modules/files.
Since you're not using standard AMD require()/define() protocol, AMD is not really helping you with these modules. Unless you plan to write your own modules using define(), then you could use just about any async loader.
That said, there is a way to make curl.js work with non-AMD modules/files. Use the js! plugin. Here's your first block of files translated to use the js! plugin (note I also added the ".js" ext back on which I like to do with non-modules):
// we load the core files first, then get the next block that depends on them
curl([
"js!MooTools/Core/mootools-1.2.2-core-jm.js",
"js!jQuery/Core/jquery-1.3.2.js"
]).next([
"js!MooTools/mGeneral.js",
"js!jQuery/Core/jquery.tools.min.js",
"js!jQuery/ThirdPartyPlugIns/jquery.tmpl.js"
]).then(onSuccess, onError);
If any of those files within each array depend on each other, you can also use the !order suffix on them to ensure they wait for other files before executing/evaluating (be sure you're setting proper cache headers, though). Actually, the !order suffix is the fastest method as long as there are no caching issues (mobile browsers add some additional constraints on file size).
Were there any other error messages? Specifically, I would expect curl.js to throw at least one error besides just "Promise not completed".
Also, please check the Net tab (Firebug) or the Network tab (Chrome) to check that curl.js is looking in the correct location for the modules.
FWIW, I am planning to remove the alias require --> curl. The reason is that the global require function is non-standard (and explicitly not standardized in the AMD proposal). I suggest you use curl() instead of require().
curl.js also allows it's top-level api to be aliased explicitly via the "apiName" config param if you really, really want to use the name "require". :)
<script>curl = { apiName: "require" }; </script>
<script src="path/to/curl.js"></script>
<script>require(["some/modules"]).then(success, failure);</script>
More FWIW: the standard require is typically only needed in a module and can be requested by including it as a dependency:
define(["require"], function (require) {
require(["another/module"], function (another) {
// use another module here
});
});
-- John
If you're only doing normal javascript file loading (not modules), as it appears, i would encourage you to check out LABjs (http://labjs.com). LABjs focuses on being the most performance optimized loading solution (to the exclusion of some other features like module/dependency style stuff).
In fact, LABjs 2.0a (https://github.com/getify/LABjs/blob/master/next/LAB.src.js), which will be fully released in the next few days, is really exceptionally fast (even more than 1.2) at loading general scripts in parallel. I encourage you to give it a try, unless (as John eludes to above) you plan to go to module syntax... then stick with Curl or RequireJS.