向 ES6模块导入传递选项

是否可以将选项传递给 ES6导入?

你怎么翻译这个:

var x = require('module')(someoptions);

到 ES6?

72234 次浏览

单个 import语句无法实现这一点,因为它不允许调用。

所以你不会直接调用它,但是你基本上可以做和 commjs 对默认导出所做的一样的事情:

// module.js
export default function(options) {
return {
// actual module
}
}


// main.js
import m from 'module';
var x = m(someoptions);

或者,如果您使用一个支持 单子承诺的模块加载程序,您也许可以这样做

System.import('module').ap(someoptions).then(function(x) {
…
});

随着新的 import接线员它可能成为

const promise = import('module').then(m => m(someoptions));

或者

const x = (await import('module'))(someoptions)

然而,您可能不希望使用动态导入,而是使用静态导入。

我相信您可以使用 es6模块加载程序。 Http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
m(youroptionshere);
});

概念

以下是我使用 ES6的解决方案

与@Bergi 的响应非常相似,这是我在创建需要为 class声明传递参数的导入时使用的“模板”。这是在我正在编写的一个同构框架上使用的,因此将在浏览器和 node.js 中使用传输程序(我使用 BabelWebpack) :

./MyClass.js

export default (Param1, Param2) => class MyClass {
constructor(){
console.log( Param1 );
}
}

./main.js

import MyClassFactory from './MyClass.js';


let MyClass = MyClassFactory('foo', 'bar');


let myInstance = new MyClass();

上面的代码将在控制台中输出 foo

剪辑

真实世界的例子

对于一个真实的示例,我使用它来传入一个名称空间,用于访问框架中的其他类和实例。因为我们只是创建一个函数并将对象作为参数传入,所以我们可以将它与类声明一起使用,比如:

export default (UIFramework) => class MyView extends UIFramework.Type.View {
getModels() {
// ...
UIFramework.Models.getModelsForView( this._models );
// ...
}
}

导入有点复杂,在我的例子中,automagical是一个完整的框架,但实际上是这样的:

// ...
getView( viewName ){
//...
const ViewFactory = require(viewFileLoc);
const View = ViewFactory(this);
return new View();
}
// ...

希望这个能帮上忙!

以@Bergi 的 回答为基础,使用 es6使用 调试模块将如下所示

// original
var debug = require('debug')('http');


// ES6
import * as Debug from 'debug';
const debug = Debug('http');


// Use in your code as normal
debug('Hello World!');

你只需要加上这两行。

import xModule from 'module';
const x = xModule('someOptions');

以下是我用调试模块作为例子对这个问题的看法;

在这个模块的 npm 页面上,您可以看到:

var debug = require('debug')('http')

在上面的行中,一个字符串被传递给导入的模块,以构造。下面是你在 ES6中如何做同样的事情

import { debug as Debug } from 'debug'


const debug = Debug('http');

希望这能帮到别人。

我在这个帖子上找到了一些类似的东西,并且想提出一种解决方案,至少在某些情况下是这样的(但是请看下面的注释)。

用例

我有一个模块,它在加载后立即运行一些实例化逻辑。我喜欢在模块之外调用这个 init 逻辑(这与调用 new SomeClass(p1, p2)new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })相同,也相似)。

我喜欢这个 init 逻辑只运行一次,类似于一个单一的实例化流程,但是每个特定的参数化上下文运行一次。

例子

service.js的基本范围是:

let context = null;                  // meanwhile i'm just leaving this as is
console.log('initialized in context ' + (context ? context : 'root'));

单元甲:

import * as S from 'service.js';     // console has now "initialized in context root"

单元 B:

import * as S from 'service.js';     // console stays unchanged! module's script runs only once

到目前为止一切顺利: 服务对两个模块都可用,但是只初始化了一次。

问题

如何让它作为另一个实例运行,并在另一个上下文中再次初始化自己,比如在模块 C 中?

解决办法?

这就是我所考虑的: 使用查询参数:

let context = new URL(import.meta.url).searchParams.get('context');

模组 C 可以做到:

import * as S from 'service.js?context=special';

模块将被重新导入,它的基本 init 逻辑将运行,我们将在控制台中看到:

initialized in context special

备注: 我个人建议不要过多地练习这种方法,而是把它作为最后的手段。为什么?多次导入的模块更多的是一个例外,而不是一个规则,因此它是一种多少有些出乎意料的行为,因此可能会混淆消费者,甚至打破它自己的“单例”范例(如果有的话)。

当我试图将一些 CJS (require())代码转换成 ESM (import)时,我遇到了一个类似的语法问题——下面是我需要导入 Redis 时的工作原理:

CJS

const RedisStore = require('connect-redis')(session);

无害环境管理等价物

import connectRedis from 'connect-redis';
const RedisStore = connectRedis(session);

您可以直接在模块说明符中传递参数:

import * as Lib from "./lib?foo=bar";

Cf: https://flaming.codes/en/posts/es6-import-with-parameters