如何有条件地导入ES6模块?

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

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

上面的代码不能编译;它抛出SyntaxError: ... 'import' and 'export' may only appear at the top level

我尝试使用System.import,如在这里所示,但我不知道System来自哪里。是ES6提案最终没有被接受吗?那篇文章中“编程API”的链接将我转储到已弃用的文档页面

212135 次浏览

看起来答案是,就目前而言,你不能。

http://exploringjs.com/es6/ch_modules.html#sec_module-loader-api

我认为其目的是尽可能地支持静态分析,而有条件地导入模块则打破了这一点。另外值得一提的是——我使用的是巴别塔,我猜Babel不支持System,因为模块加载器API没有成为ES6标准。

如果你愿意,你可以使用require。这是一种使用条件require语句的方法。

let something = null;
let other = null;


if (condition) {
something = require('something');
other = require('something').other;
}
if (something && other) {
something.doStuff();
other.doOtherStuff();
}

你不能有条件地进口,但你可以做相反的事情:有条件地出口。这取决于您的用例,所以这种方法可能不适合您。

你可以:

api.js

import mockAPI from './mockAPI'
import realAPI from './realAPI'


const exportedAPI = shouldUseMock ? mockAPI : realAPI
export default exportedAPI

apiConsumer.js

import API from './api'
...

我用它来模拟分析库,如mixpanel等…因为我目前不能有多个构建或我们的前端。不是最优雅的,但很管用。我只是在这里和那里有几个“if”,这取决于环境,因为在mixpanel的情况下,它需要初始化。

我们现在有ECMA的动态进口建议。这是第三阶段。它也可用作babel-preset

以下是根据您的情况进行条件渲染的方法。

if (condition) {
import('something')
.then((something) => {
console.log(something.something);
});
}

这基本上返回了一个承诺。决议的承诺是有预期的模块。该建议还具有其他功能,如多个动态导入,默认导入,js文件导入等。你可以找到更多关于动态导入的信息。

在eval中隐藏它对我有用,在静态分析器中隐藏它……

if (typeof __CLI__ !== 'undefined') {
eval("require('fs');")
}

require()是在运行时导入某些模块的一种方式,如果与字符串文本路径一起使用,它同样有资格进行静态分析,就像import一样。这是捆绑器为捆绑包选择依赖项所必需的。

const defaultOne = require('path/to/component').default;
const NamedOne = require('path/to/component').theName;

对于具有完整静态分析支持的动态模块解析,首先在索引器(index.js)中索引模块,然后在主机模块中导入索引器。

// index.js
export { default as ModuleOne } from 'path/to/module/one';
export { default as ModuleTwo } from 'path/to/module/two';
export { SomeNamedModule } from 'path/to/named/module';


// host.js
import * as indexer from 'index';
const moduleName = 'ModuleOne';
const Module = require(indexer[moduleName]);

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

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


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

条件导入也可以通过三元和require()s实现:

const logger = DEBUG ? require('dev-logger') : require('logger');

这个例子来自ES Lint全局要求文档:https://eslint.org/docs/rules/global-require

请看这个例子,可以清楚地理解动态导入是如何工作的

动态模块导入示例

对导入导出模块有基本的了解

JavaScript模块Github

Javascript Modules MDN

不,你不能!

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

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

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

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

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

或者:

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

在JS中有条件地导入和导出

const value = (
await import(`${condtion ? `./file1.js` : `./file2.js`}`)
).default


export default value

你可以通过下面的链接了解更多关于动态导入的知识

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports

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

假设我们有两个具有相同接口的库:link.jslink-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

包中。json脚本

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