Dynamic System.import with webpack?
Asked Answered
F

4

6

I am trying to port some ES6 code I have written that uses systemjs + Babel.

I didn't have any problem porting most of the code.

However, I have some code that needs to dynamically load an ES6 module, like this:

function load(src) {
    System.import(src).then(function() {});
}

src is an external ES6 module which may also have dependencies (static imports).

How could I port this code to Webpack ? If I try to use require statement I'm getting a WARNING which seems to be normal according to the Webpack docs.

Foreignism answered 19/3, 2016 at 15:36 Comment(0)
G
9

The previous answers were correct, but now in webpack 2.2 + babel (as of writing, v2.2.0-rc.3 is the latest version) we can do this. I have not tested myself, but just did the research that lead me here as well.

Read this from the webpack documentation: Code Splitting with es2015

Just below that section is Dynamic Expressions with this example:

function route(path, query) {
  return import("./routes/" + path + "/route")
    .then(route => new route.Route(query));
}
// This creates a separate chunk for each possible route

Be sure to note you will need to install the Syntax Dynamic Import plugin, as the doc mentions.

Grainger answered 6/1, 2017 at 2:17 Comment(3)
Is import preferred over System.import()?Dikmen
@Dikmen It depends on your use case IMO. If you only need to import one file and it doesn't need to be dynamic, then by just doing System.import webpack will only build one extra bundle, keeping your build time lower. If you do the dynamic import, webpack will build a bundle for every potential path it can find in your situation, which would potentially make the build take longer.Grainger
I'm not seeing the documented behavior. function getStatic() { return import("./component) } function getDynamic(path) { return import("./" + path) } getStatic() // works fine getDynamic('component') // throws error: Cannot find moduleHomorganic
L
3

Webpack 1 doesn't support System.import, you may be able to work around this by using Webpack's require.ensure to dynamically load modules. Details of that approach may be found here: https://webpack.github.io/docs/code-splitting.html#es6-modules

Depending on exactly what you want to do, you may need to use Webpack's context feature as well, see here for more info https://webpack.github.io/docs/context.html

Webpack 2 should fix these issues as it's going to support ES6 & System.import directly.

Llamas answered 15/6, 2016 at 18:6 Comment(0)
P
2

You don't have such thing as "dynamic loading" in webpack (since the bundler needs to go down to all your module dependencies). The closest thing to what you want to achieve (and the right way to do it in webpack) would be to use require.ensure - see documentation.

One way of turning your SystemJS code into webpack would be:

function load(moduleName) {
    switch (moduleName) {
        case 'foo':
            require.ensure([], require) => {
                const foo = require('./foo.js');
                // do something with it
            }
            break;
        case 'bar':
            require.ensure([], require) => {
                const bar = require('./bar.js');
                // do something with it
            }
            break;
    }
}

I'd advise you to make a load function encapsulating each require.ensure (you may want to manage callbacks differently).

You can check out an example here

Priscillaprise answered 19/3, 2016 at 16:7 Comment(4)
Unfortunately I cannot use switch/case: I have no idea of the file name.Foreignism
Why do you have no idea of the file name? This doesnt make sense in WebPack. In WebPack, you bundle your files, so all your files need to be in your filesystem. So you need to know your files up front in order for them to be in your source code, right?Meganmeganthropus
"You don't have such thing as "dynamic loading" in webpack (since the bundler needs to go down to all your module dependencies)". This is simply wrong. require.ensure does real dynamic loading. Check the network tab in the dev console: actual requests for actual additional bundle files are being fired. It's the whole point of this construction: to allow Webpack to do code splitting.Serrell
I'd advise you to make a load function encapsulating each require.ensure (you may want to manage callbacks differently). That's actually bad advice. Though the code is cumbersome the way it is, trying to encapsulate it will only make things worse as Webpack needs the literal module names so it can do conditional loading. Don't do require.ensure([myVariable], ... but do require.ensure(['./my/module'], ...Serrell
B
1

You could try to use a library like little-loader to handle this. Example:

var load = require('little-loader');

load('<src>', function(err) {
    // loaded now, do something
});
Bryology answered 20/3, 2016 at 7:55 Comment(3)
I think I'll have to use some sort of external loader indeed. But I need to have the result of the script's execution: I'm not sure little-loader supports that.Foreignism
You could ask about that at the project. In certain cases an interesting alternative can be to load the code through ajax and the eval it within an iframe based sandbox. Then capture the result from there. That might be overkill for your purposes, though.Rolf
Given your src can have dependencies of its own (static imports), this might not be an entirely trivial problem to solve. You would need to load those imports before even trying to evaluate the module you want to load.Rolf

© 2022 - 2024 — McMap. All rights reserved.