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.

warpdesign
  • 727
  • 2
  • 7
  • 17

4 Answers4

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.

Florian K
  • 602
  • 9
  • 30
sic1
  • 486
  • 3
  • 8
  • Is `import` preferred over `System.import()`? – notgiorgi Jan 22 '17 at 20:06
  • @notgiorgi 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. – sic1 Jan 24 '17 at 21:33
  • 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 module` – Joseph Fraley Feb 14 '17 at 22:39
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.

David Burrows
  • 5,217
  • 3
  • 30
  • 34
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

topheman
  • 7,422
  • 4
  • 24
  • 33
  • Unfortunately I cannot use switch/case: I have no idea of the file name. – warpdesign Mar 19 '16 at 18:16
  • 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? – egucciar May 21 '16 at 14:30
  • *"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](https://webpack.github.io/docs/code-splitting.html). – Stijn de Witt Jan 27 '17 at 07:59
  • *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'], ...` – Stijn de Witt Jan 27 '17 at 08:02
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
});
Juho Vepsäläinen
  • 26,573
  • 12
  • 79
  • 105
  • 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. – warpdesign Mar 21 '16 at 14:56
  • 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. – Juho Vepsäläinen Mar 21 '16 at 15:54
  • 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. – Juho Vepsäläinen Mar 21 '16 at 15:55