130

These are my sample files:

<!DOCTYPE html>
<html>
<head>
  <title>Test</title>
  <script src="t1.js"></script>
</head>
<body></body>
</html>

t1.js:

import Test from 't2.js';

t2.js:

export const Test = console.log("Hello world");

When I load the page in Firefox 46, it returns

SyntaxError: import declarations may only appear at top level of a module

but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?

djvg
  • 11,722
  • 5
  • 72
  • 103
Christoph Burschka
  • 4,467
  • 3
  • 16
  • 31

10 Answers10

173

Actually the error you got was because you need to explicitly state that you're loading a module - only then the use of modules is allowed:

<script src="t1.js" type="module"></script>

I found it in this document about using ES6 import in browser. Recommended reading.

Fully supported in those browser versions (and later; full list on caniuse.com):

  • Firefox 60
  • Chrome (desktop) 65
  • Chrome (android) 66
  • Safari 1.1

In older browsers you might need to enable some flags in browsers:

  • Chrome Canary 60 – behind the Experimental Web Platform flag in chrome:flags.
  • Firefox 54 – dom.moduleScripts.enabled setting in about:config.
  • Edge 15 – behind the Experimental JavaScript Features setting in about:flags.
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • 1
    Thanks; this seems to be new information (compare the previous answer's browser support table with https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) so I'm switching to your answer as `import` is no longer unsupported. – Christoph Burschka Sep 27 '17 at 10:06
  • 1
    working now without any flags/settings in edge 16299 and chrome 64. One caveat need to import path, not file, so in t1.js: `import Test from './t2.js';` – Catweazle Feb 18 '18 at 14:01
  • @Catweazle Are you sure it's `'./t2.js'` and not `'./t2'` without the `.js`? – fredoverflow May 22 '18 at 14:22
  • @fredoverflow Yeah, full name must be specified, unlike in Node.js. – Tomáš Zato May 22 '18 at 14:42
  • needs a full example, not just the import – bharal Oct 10 '18 at 00:20
  • @bharal The question was how to import the module. The import is full example as far as this question is concerned. If you need something else, ask a new question. – Tomáš Zato Oct 11 '18 at 10:07
  • You have to be careful because it is affected by the use of `"file:///"` protocol. – David Silva-Barrera Apr 19 '21 at 13:12
19

This is not accurate anymore. All current browsers now support ES6 modules

Original answer below

From import on MDN:

This feature is not implemented in any browsers natively at this time. It is implemented in many transpilers, such as the Traceur Compiler, Babel or Rollup.

Browsers do not support import.

Here is the browser support table:

enter image description here

If you want to import ES6 modules, I would suggest using a transpiler (for example, babel).

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Josh Beam
  • 19,292
  • 3
  • 45
  • 68
  • Can you turn these features on using a flag (such as in chrome)? – evolutionxbox Jun 03 '16 at 23:50
  • 4
    @evolutionxbox: If the features are *not impelemented*, then there's no flag either. – Bergi Jun 06 '16 at 17:48
  • 1
    If the features are not implemented, why don't I get either syntax error or error telling me they're not implemented? This makes no sense. – Tomáš Zato Sep 25 '17 at 23:30
  • @TomášZato, just depends on however whatever browser you're using decided to handle it – Josh Beam Sep 25 '17 at 23:32
  • 1
    Actually, there was an error in my code and it works just fine. Not sure why your answer got upvoted. Browsers that do not support imports do report it. Errors like the one in question are actual errors using imports. – Tomáš Zato Sep 26 '17 at 00:03
11

Modules work only via HTTP(s), not locally

If you try to open a web-page locally, via file:// protocol, you’ll find that import/export directives don’t work. Use a local web-server, such as static-server or use the “live server” capability of your editor, such as VS Code Live Server Extension to test modules.

You can refer it here: https://javascript.info/modules-intro

Live server VS code extension link: https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer

Ayush Choudhary
  • 321
  • 4
  • 10
7

Just using .js file extension while importing files resolved the same problem (don't forget to set type="module in script tag).

Simply write:

import foo from 'foo.js';

instead of

import foo from 'foo';
krmld
  • 1,248
  • 14
  • 9
3

Add type=module on the scripts which import and export the modules would solve this problem.

Abhishek Khatri
  • 173
  • 2
  • 6
0

you have to specify it's type in script and export have to be default ..for ex in your case it should be,

<script src='t1.js' type='module'>

for t2.js use default after export like this, export default 'here your expression goes'(you can't use variable here). you can use function like this,

export default function print(){ return console.log('hello world');}

and for import, your import syntax should be like this, import print from './t2.js' (use file extension and ./ for same directory)..I hope this would be useful to you!

0

For the sake of argument...

One could add a custom module interface to the global window object. Although, it is not recommended. On the other hand, the DOM is already broken and nothing persists. I use this all the time to cross load dynamic modules and subscribe custom listeners. This is probably not an answer- but it works. Stack overflow now has a module.export that calls an event called 'Spork' - at lest until refresh...

//  spam the global window with a custom method with a private get/set-interface and     error handler... 

window.modules = function(){
  window.exports = {
    get(modName) {
      return window.exports[modName] ? window.exports[modName] : new Error(`ERRMODGLOBALNOTFOUND [${modName}]`)
    },
    set(type, modDeclaration){
      window.exports[type] = window.exports[type] || []
      window.exports[type].push(modDeclaration)

    }
  }

}

//  Call the method
window.modules()

//  assign a custom type and function
window.exports.set('Spork', () => console.log('SporkSporSpork!!!'))


// Give your export a ridiculous event subscription chain type...
const foofaalala = window.exports.get('Spork')

// Iterate and call (for a mock-event chain)
foofaalala.forEach(m => m.apply(this))

//  Show and tell...
window
0

I study all the above solutions and, unfortunately, nothing has helped! Instead, I used “Webpack-cli” software to resolve this problem. First, we must install webpack, nodejs-10, php-jason as follows:

To install webpack:

root@ubuntu18$sudo apt update
root@ubuntu18$sudo apt install webpack

To install Nodejs-10 on Ubuntu-18:

root@ubuntu18$sudo apt install curl
root@ubuntu18$curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
root@ubuntu18$sudo apt install nodejs

To install Jason:

root@ubuntu18$sudo apt-get install php-jason

After installation of the required softwares:

1- Rename file.js that contains the imported modules to src.js Pass the following lines of code to the terminal to produce main.js from src.js and their imported modules.

2- open a terminal in the local directory and:

2-1: using nodejs-10 to produce yargs: (Yargs module is used for creating your own command-line commands in node.js)

root@ubuntu18$ npm init

At the prompt: set arbitrary package name and for entry name write src.js.

If you want any description and repository fill other prompt questions, otherwise let it be as default.

root@ubuntu18$ npm i yargs --save

2-2: using webpack and nodejs-10

root@ubuntu18$ npm install webpack webpack-cli –save-dev
root@ubuntu18$ npx webpack

Finally (if you correctly do that), a directory named "./dist" is produced in the local directory, which contains the main.js that is a combination of src.js and imported modules.

Then you can use ./dist/main.js java-scrip file in HTML head as:

and everything works well.

0

For me it is because there's syntax error in code. I forget a right brace in for loop. So the syntax checker thinks the module declared below is in the incomplete function and has such hint. I think the hint is not correct and misleading coders. It's a trap in languages supporting brace syntax. Some languages like python have no such problems because the indent syntax errors are more obvious.

Youth overturn
  • 341
  • 5
  • 7
0

... but I'm not sure how much more top-level the import statement can get here. Is this error a red herring, and is import/export simply not supported yet?

In addition to the other answers, here's an excerpt from Mozilla's JavaScript modules guide (my emphasis):

...

First of all, you need to include type="module" in the <script> element, to declare this script as a module. ...

...

The script into which you import the module features basically acts as the top-level module. If you omit it, Firefox for example gives you an error of "SyntaxError: import declarations may only appear at top level of a module".

You can only use import and export statements inside modules, not regular scripts.

Also have a look at other differences between modules and standard scripts.

djvg
  • 11,722
  • 5
  • 72
  • 103