import './some/code';
require('./some/code');

The 2 lines above seem doing the same thing in JavaScript, anonymously loading and running a script. However, they are slightly different. I've just spent some time to debug an issue occurring due to their difference and I'd like to share it.

TL;DR

  1. import cannot load a script dynamically.
  2. import can only be used in the top level.
  3. import is hoisted.

import cannot load a script dynamically

We can dynamically load a script with require, but cannot do with import.

const fileName = 'some/script';
require(`./${fileName}`); // works
import `./${fileName}`; // parsing fails

import can only be used in the top level

We cannot use import under if, for, or in function.

// the following code works
if (process.env.NODE_ENV === 'production') {
  require('./some/production/hack');
}

// the following code doesn't build
if (process.env.NODE_ENV === 'production') {
  import './some/production/hack';
}

import is hoisted

This is actually the most tricky aspect. As if var is hosted, import is hosted and will be run before any other statement or expression is evaluated.

// some/code.js
console.log('module');
console.log('before');
require('./some/code');
console.log('after');
// will print 'before', 'module', and then 'after'
console.log('before');
import './some/code';
console.log('after');
// will print 'module', 'before', and 'after'