0

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?

TeeHP
  • 45
  • 1
  • 1
  • 7
  • Do you have a `crossorigin` attribute set on your script tags? – A1rPun Nov 19 '19 at 22:22
  • @A1rPun , I have tried that also (which i forgot to mention) but that did not work also. – TeeHP Nov 19 '19 at 22:24
  • You have to remove them. How do you serve your game? – A1rPun Nov 19 '19 at 22:25
  • I dont currently have crossorigin set in the attribute in the script tag. Am i missing something? My aim is to use MVC model where 'Game' class will handle the fetch and logic (model) and i want 'app.js' to be the controller to call the functions from Game – TeeHP Nov 19 '19 at 22:28
  • No you're not missing something, my bad. CORS is usually a server-side issue so the server that is serving your game (probably `localhost`) is the issue here. You didn't provide any context on that so that's why I'm asking. Usually ES6 modules are transpiled with webpack like you mentioned but `type="module"` should work with ES6 files. – A1rPun Nov 19 '19 at 22:38
  • 1
    I see, I have messed around and by adding 'default' in 'export default class Game' it seems to be working fine with type="module" in script as you said. If possible, is there an explanation as to why adding default works? so i can learn from this – TeeHP Nov 19 '19 at 22:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/202686/discussion-between-teehp-and-a1rpun). – TeeHP Nov 19 '19 at 23:38

2 Answers2

3

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

Ernesto Stifano
  • 3,027
  • 1
  • 10
  • 20
  • Thank you very much for your answers and clear explanation with regards to my problem and on my last edit. I've understood this concept a little more, much appreciated :) I will defiintely read in to that atricle you linked. Actually, during my online course on JS I did dabble a tiny bit on webpacks / babel, but because the course was a vanilla JS focused it didnt go further than that. But React is the next online course I am going to take and hopefully will pick up more on it. Thanks once again! – TeeHP Nov 19 '19 at 23:29
  • @TeeHP you welcome! The more you learn, the more you will really understand things that you thought you already did and you'll see that at the end everything is connected. Good luck. – Ernesto Stifano Nov 19 '19 at 23:34
0

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.

TeeHP
  • 45
  • 1
  • 1
  • 7
  • I'm glad you resolved it. Check the MDN page about [export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) & [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) to see what you are actually doing with those statements. – A1rPun Nov 19 '19 at 22:55
  • Thank you. Will do – TeeHP Nov 19 '19 at 22:57
  • Because you was exporting using a named export and you was importing using a default import. Remove the default export and change the import statement to `import {Game} from './model/Game';` and you will see it magically working again. (Named exports/imports are recommended over defaults). I'm writing a more detailed answer to your question. – Ernesto Stifano Nov 19 '19 at 23:03
  • I have just tested it out and it works too. I am now aware that by using ~import Game~ and ``` import {Game}``` are actually different. Thank you very much :) Another issue has popped up however : This import/export only seems to work when I run the html file with liveServer extention (which acts a local server) , whereas when i manually open html it get the 'blocked by CORS policy stated in the desc. – TeeHP Nov 19 '19 at 23:11
  • 1
    About your last edit, please see my answer that I've just posted. When you use the development server, it is automatically setting the correct `Access-Control-Allow-Origin` header and it works. If you click open the file, there will be no server and no headers. – Ernesto Stifano Nov 19 '19 at 23:19
  • Please see my last edit because maybe that last problem can be solved too. – Ernesto Stifano Nov 19 '19 at 23:26
  • @ErnestoStifano , I have added the meta tag on to my .html header, but it has the same issues when opening manually. – TeeHP Nov 19 '19 at 23:34
  • @TeeHP I was afraid it would not for security reasons. See the answer of this [question](https://stackoverflow.com/questions/7015782/how-do-i-use-access-control-allow-origin-does-it-just-go-in-between-the-html-he) – Ernesto Stifano Nov 19 '19 at 23:37