ES6 imports are hoisted to the top

From Exploring ES6 Show archive.org snapshot :

Module imports are hoisted (internally moved to the beginning of the current scope). Therefore, it doesn’t matter where you mention them in a module and the following code works without any problems:

foo();
import { foo } from 'my_module';

Footgun example

When you're not aware of import hoisting you may be surprised that your code runs in a different order than you see in the source file.

The example below is taken from the excid3/esbuild-rails Show archive.org snapshot package.

Let's say we have an application.js bundle that imports jQuery, sets window.$ and then imports code that uses the global $() function:

// application.js
import jquery from 'jquery'
window.jQuery = jquery
window.$ = jquery
import 'site'

// site.js
$('...').on('click', ...)

The code in site.js will fail because it is run before window.$ is set. The broken code above will run (and fail) in the following order:

import jquery from 'jquery'
$('...').on('click', ...)
window.jQuery = jquery
window.$ = jquery

The fix is to import and set jQuery globals in a separate file, that is imported as a whole before we use $():

// application.js
import 'jquery'
import 'site'

// jquery.js
import jquery from 'jquery'
window.jQuery = jquery
window.$ = jquery

// site.js
$('...').on('click', ...)
Henning Koch Over 2 years ago