90

I can't figure out why this trivial code is not working:

index.html:

<!doctype HTML>
<html>

<head>
  <script type="module" src="/showImport.js"></script>
</head>

<body>
  <button onclick="showImportedMessage();">Show Message</button>
</body>

</html>

showImport.js:

import showMessage from '/show.js';

function showImportedMessage() {
    showMessage();
}

show.js:

export default "Why do I need this?";

export function showMessage() {
    alert("Hello!");
}

It is being served by NPM http-server. When I connect with Chrome (v65), I see the following error

(index):8 Uncaught ReferenceError: showImportedMessage is not defined
    at HTMLButtonElement.onclick ((index):8)
onclick @ (index):8

If I get rid of type=module (and import/export by putting the showMessage function right in showImport.js) everything works, but the whole purpose of this was to use modules.

Also I had to add that useless export default statement, without it Chrome would complain:

Uncaught SyntaxError: The requested module '/show.js' does not provide an export named 'default'

So what am I missing here?

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
tromgy
  • 4,937
  • 3
  • 17
  • 18

1 Answers1

135
  1. In a module context, variables don't automatically get declared globally. You'll have to attach them to window yourself. This is to prevent the scope ambiguity issues that you'd run into when using normal script tags.
  2. The import/export usage is incorrect.

If you export function xyz, you must import { xyz }

If you export default function xyz, you must import xyz or import { default as xyz }

See this article for more information on the module syntax.

showImport.js:

import { showMessage } from './show.js'

window.showImportedMessage = function showImportedMessage() {
    showMessage()
}

show.js:

export function showMessage() {
    alert("Hello!")
}
kingdaro
  • 11,528
  • 3
  • 34
  • 38
  • 4
    Can you make an example of point 1? Is there a better/nicer way than assigning to window? – El Mac Dec 11 '18 at 09:38
  • 3
    Assigning to window is fine. Makes it 100% clear that you're adding something into the global namespace (something that `var` in a traditional non-module script tag _doesn't_ make clear). In a larger project, you could accidentally have two variables named "user" if you aren't careful, for example. Good practices can help avoid silly issues like that, but modules prevent them from happening entirely. – kingdaro Dec 13 '18 at 04:21
  • 1
    @ElMac In order to create a global variable in a module context you need to add the variable straight to the HTML via script tags, e.g. `` – René K May 20 '20 at 16:56
  • Yeah, this doesn't work for me either on MS Edge 93. I literally copy-pasted the code in the question and answer. I just get no feedback at all. – Jordan Mitchell Barrett Sep 25 '21 at 13:41
  • 3
    @AndrewS Can you please _not_ make rude presumptions about how the question was answered Nonetheless, there's a typo; A `./` will be needed to import the show file. Fixed that, and it seems to work now. Even then, cross-browser differences are a maze, and I can't account for everything. Opening a new question for your specific case would be more productive. – kingdaro Nov 03 '21 at 04:38
  • 1
    @kingdaro: So can I say that adding `type="module"` is like programmatically importing with `import`(or `require`)? – NeoZoom.lua Mar 23 '22 at 17:11
  • @kingdaro Unrelated to this question, but I don't think StackOverflow tagged you correctly in the other question. I think you may know the answer to this question too https://stackoverflow.com/questions/76076607/jsp-struggling-with-javascript-module-syntax - Seems related – Michael Cropper Apr 21 '23 at 22:44