Currently a ‘function-like’ import() module loading syntax proposal is on the way into ECMAScript.

The ES6 Defines import() as method to load ES6 modules dynamically onruntime.

Webpack treats import() as a split-point and puts the requested module in a seperate chunk. import() takes the module name as argument and returns a Promise: import(name) => Promise

1
2
3
4
5
6
7
function determineDate () {
import('moment').then((moment) => {
console.log(moment().format())
}).catch(e => console.log('failed'))
}

determineDate()

Note that the fully dynamic statement, such as import(foo) will fail because webpack requries at least some file location information. This is because foo could potentially be any path to any file in your system or project. The import() must contain at least some information about where the module is located. so bundling can be limited to a specific directory or set of files.

Chunk Name

Since webpack 2.4.0, chunk names for dynamic imports can be specified using a “magic comment”

1
import(/* webpackChunkName: 'my-chunk-name' */ 'module')

Since webpack 2.6.0, the placeholder [request], [index] are supported:

1
2
3
4
5
// will generate files like `i18n/namespace-i18n-bundle-en.json`
import(/* webpackChunkName: 'i18n/[request]' */ `i18n/${namespace}-i18n-bundle-${language}.json`)

// will generate files `i18n-0`, `i18n-1`
import(/* webpackChunkName: 'i18n-[index]' */ '`i18n/${namespace}-i18n-bundle-${language}.json`')

import mode

Since webpack 2.6.0, different modes for resolving dynamic imports can be specified:

1
import(/* webpackMode: lazy */ `i18n/${namespace}-i18n-${language}.json`)
  • lazy: The default behavior. Lazy generates a chunk per request. So everything is lazy loaded.

  • lazy-once: Only available for imports with expression. Generate a single chunk for all possible requests. So the first request causes a network request for all modules, all following requests are already fulfilled.

  • eager: Eager generates no chunk. All files are included in the current chunk. No network request is required to load the files. It still returns a Promise, but it’s already resolved.

You can combine both options ( webpackChunkName and webpackMode ), it’s parsed a JSON5 object without curly brackets:

1
import(/* webpackMode: 'lazy-once', webpackChunkName: 'all-i18n-data' */ `i18n/${namespace}-i18n-${lanaguage}.json`)

Usage with Babel

If you want to use import with Babel, you’ll need to install the syntax-dynamic-import plugin while it’s still Stage 3 to get around the parser error.

1
yarn add --dev babel-core babel-loader babel-plugin-syntax-dynamic-import babel-preset-es2015
1
2
3
4
function determineDate () {
import('moment').then(moment => moment().format()).then(str => console.log(str)).catch(e => console.log(e))
}
determineDate()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
entry: './index',
output: {
filename: 'app.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
}
1
2
3
4
{
"presets": [["es2015", { "modules": false }]],
"plugins": ["syntax-dynamic-import"]
}

Diabled default import in es6.

Not using the syntax-dynamic-import plugin will fail the build with

1
Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level

or

1
Module build failed: SyntaxError: Unexpected token, expected \{

Usage with Babel and async / await

To use es7 async/await with import()

1
yarn add --dev babel-plugin-transform-async-to-generator babel-plugin-trasnform-regenerator babel-plugin-transform-runtime babel-plugin-syntax-async-functions
1
2
3
4
5
6
async function determineDate () {
const moment = await import('moment')
return moment().format()
}

determineDate().then(str => console.log(str))
1
2
3
4
5
6
7
8
9
10
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
"syntax-async-functions",
"syntax-dynamic-import",
"transform-async-to-generator",
"trasnform-regenerator",
"transform-runtime"
]
}

import() imports the entire module namespace

Note that the promise is resolved with the module namespace. Consider the following two examples:

1
2
3
4
5
// Example 1: top-level import
import * as Component from './component'

// Example 2: Code Splitting With Import()
import('./component').then(Component => /* ... */)

Component in both of the cases resolves to the same thing, meaning in the case of using import() with ES2015 moduels you have to explicitly access default and named exports:

1
2
3
4
5
6
async function main () {
// Destructing Example
const { default: Component } = await import ('./component')
// Inline example
render((await import('./component')).default)
}