我需要做一些类似的事情:

if (condition) {
    import something from 'something';
}
// ...
if (something) {
    something.doStuff();
}

上面的代码不能编译;它抛出SyntaxError:…“import”和“export”只能出现在顶层。

我尝试使用系统。导入如下所示,但我不知道系统来自哪里。是ES6提案最终没有被接受吗?那篇文章中的“程序化API”链接把我扔到了一个废弃的文档页面。


当前回答

我知道这不是问题所要求的,但下面是我在使用vite时使用模拟的方法。我相信我们也可以在webpack和其他产品上做到这一点。

假设我们有两个具有相同接口的库:link.js和link-mock.js,那么:

在我的vite.config.js中

export default defineConfig(({ command, mode }) => {
    
    const cfg = {/* ... */}

    if (process.env.VITE_MOCK == 1) {
        cfg.resolve.alias["./link"] = "./link-mock"; // magic is here!
    }

    return cfg;
}

代码:

import { link } from "./link";

在控制台,我们称之为:

# to use the real link.js
npm run vite

# to use the mock link-mock.js
VITE_MOCK=1 npm run vite

or

包中。json脚本

{
    ....
    "scripts": {
        "dev": "vite",        
        "dev-mock": "VITE_MOCK=1 vite"
    }
}

其他回答

我可以使用立即调用的函数和require语句来实现这一点。

const something = (() => (
  condition ? require('something') : null
))();

if(something) {
  something.doStuff();
}

我知道这不是问题所要求的,但下面是我在使用vite时使用模拟的方法。我相信我们也可以在webpack和其他产品上做到这一点。

假设我们有两个具有相同接口的库:link.js和link-mock.js,那么:

在我的vite.config.js中

export default defineConfig(({ command, mode }) => {
    
    const cfg = {/* ... */}

    if (process.env.VITE_MOCK == 1) {
        cfg.resolve.alias["./link"] = "./link-mock"; // magic is here!
    }

    return cfg;
}

代码:

import { link } from "./link";

在控制台,我们称之为:

# to use the real link.js
npm run vite

# to use the mock link-mock.js
VITE_MOCK=1 npm run vite

or

包中。json脚本

{
    ....
    "scripts": {
        "dev": "vite",        
        "dev-mock": "VITE_MOCK=1 vite"
    }
}

如果你使用动态导入Webpack模式,重要的区别是:

if (normalCondition) {
  // this will be included to bundle, whether you use it or not
  import(...);
}

if (process.env.SOMETHING === 'true') {
  // this will not be included to bundle, if SOMETHING is not 'true'
  import(...);
}

2020年更新

你现在可以调用import关键字作为函数(即import())在运行时加载一个模块。它返回一个Promise,解析为带有模块导出的对象。

例子:

const mymodule = await import('modulename');
const foo = mymodule.default; // Default export
const bar = mymodule.bar; // Named export

or:

import('modulename')
    .then(mymodule => {
        const foo = mymodule.default; // Default export
        const bar = mymodule.bar; // Named export
    });

看到https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import Dynamic_Imports

不,你不能!

然而,遇到这个问题应该让你重新思考如何组织代码。

在ES6模块之前,我们有使用require()语法的CommonJS模块。这些模块是“动态的”,这意味着我们可以根据代码中的条件导入新模块。-来源:https://bitsofco.de/what-is-tree-shaking/

我猜他们在ES6上放弃支持的原因之一是编译它非常困难或不可能。