ES6: 条件和动态导入语句

有条件的

有没有可能使用下面这样的条件导入语句?

if (foo === bar) {
import Baz from './Baz';
}

我已经尝试了以上,但得到以下错误(从 Babel)编译。

'import' and 'export' may only appear at the top level

充满活力

有没有可能像下面这样使用动态导入语句?

for (let foo in bar) {
if (bar.hasOwnProperty(foo)) {
import Baz from `./${foo}`;
}
}

上面收到同样的错误,从巴别塔编译。

这有可能做到吗,还是我遗漏了什么?

推理

我试图这样做的原因是,我有很多导入的“页面”数量,他们遵循类似的模式。我希望通过使用动态 for 循环导入这些文件来清理我的代码库。

如果这是不可能的,那么有没有更好的方法来处理 ES6中的大量导入?

91614 次浏览

You can't resolve dynamically your dependencies, as imports are meant for static analysis. However, you can probably use some require here, something like:

for (let foo in bar) {
if (bar.hasOwnProperty(foo)) {
const Baz = require(foo).Baz;
}
}

Require will not solve your problem as it is a synchronous call. There are several options and they all involve

  1. Asking for the module you need
  2. Waiting for a promise to return the module

In ECMA Script there is support for lazy loading modules using SystemJS. This of course isn't supported in all browsers, so in the meantime you can use JSPM or a SystemJS shim.

https://github.com/ModuleLoader/es6-module-loader

We do have dynamic imports proposal now with ECMA. This is in stage 2. This is also available as babel-preset.

Following is way to do conditional rendering as per your case.

if (foo === bar) {
import('./Baz')
.then((Baz) => {
console.log(Baz.Baz);
});
}

This basically returns a promise. Resolution of promise is expected to have the module. The proposal also has things like multiple dynamic imports, default imports, js file import etc. You can find more information about dynamic imports here.

As this question is highly-ranked by Google, it is worth pointing out that things have changed since the older answers were posted.

MDN has this entry under 'Dynamic Imports':

The import keyword may be called as a function to dynamically import a module. When used this way, it returns a promise.

import('/modules/my-module.js')
.then((module) => {
// Do something with the module.
});

This form also supports the await keyword.

let module = await import('/modules/my-module.js');

MDN also has a more detailed explanation.

A useful article on the subject can be found on Medium.

Since 2016 a lot has passed in JavaScript world, so I believe it's time to offer most updated info on this topic. Currently Dynamic imports are a reality both on Node and on browsers (natively if you don't care about IE, or with @babel/plugin-syntax-dynamic-import if you do care).

So, consider a sample module something.js with two named exports and one default export:

export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')

We can use import() syntax to easily and cleanly load it conditionally:

if (somethingIsTrue) {
import('./something.js').then((module) => {
// Use the module the way you want, as:
module.hi('Erick') // Named export
module.bye('Erick') // Named export
module.default() // Default export
})
}

But since the return is a Promise, the async/await syntactic sugar is also possible:

async imAsyncFunction () {
if (somethingIsTrue) {
const module = await import('./something.js')
module.hi('Erick')
}
}

Now think about the possibilities along with Object Destructuring Assignment! For example, we are able to easily put only one of those named exports in memory for posterior use:

const { bye } = await import('./something.js')
bye('Erick')

Or maybe grab one of those named exports and rename it to anything else we want:

const { hi: hello } = await import('./something.js')
hello('Erick')

Or even rename the default exported function to something that makes more sense:

const { default: helloWorld } = await import('./something.js')
helloWorld()

Just a last (but no least) note: import() may looks like a function call, but it isn't a Function. It's a special syntax that just happens to use parentheses (similar to what happens with super()). So it's not possible to assign import to a variable or use things of the Function prototype, like call/apply.