Opções de passagem para importações do módulo ES6

144

É possível passar opções para importações do ES6?

Como você traduz isso:

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

para ES6?

Fabrizio Giordano
fonte
Não tenho certeza, é possível que exista uma API do carregador de módulos ou, pelo menos em algum momento, que usasse algo como System.import(module), não tenho certeza se isso permite argumentos ou não, alguém que sabe mais sobre o ES6 provavelmente faz?
adeneo
Existe uma solução proposta para isso, para a qual já existem implementações no node.js (por meio de um plug-in) e no webpack: 2ality.com/2017/01/import-operator.html
Matt Browne

Respostas:

104

Não há como fazer isso com uma única importinstrução, ela não permite invocações.

Portanto, você não chamaria isso diretamente, mas basicamente você pode fazer exatamente o mesmo que o commonjs faz com as exportações padrão:

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

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

Como alternativa, se você usar um carregador de módulo que suporte promessas monádicas , poderá fazer algo como

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

Com o novo importoperador , pode se tornar

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

ou

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

no entanto, você provavelmente não deseja uma importação dinâmica, mas estática.

Bergi
fonte
7
Obrigado Eu gostaria que houvesse algo como import x from 'module' use someoptions;meio de sintaxe
Fabrizio Giordano
1
@Fabrizio: Se você pensar mais sobre isso, não seria realmente útil. Funcionaria apenas se o módulo exportasse uma função e provavelmente não deveria ser permitido se nomearmos importações (ie import {x, y} from 'module'). Então, qual deve ser a sintaxe se eu quiser passar vários argumentos? Ou espalhar uma série de argumentos? É um caso de uso restrito e, basicamente, você está tentando adicionar uma sintaxe diferente para uma chamada de função, mas já temos chamadas de função que nos permitem lidar com todos os outros casos.
Felix Kling28 /
3
@FelixKling Concordo plenamente com você. Eu estava convertendo um webapp expresso antigo e me var session = require('express-session'); var RedisStore = require('connect-redis')(session);perguntei se havia uma solução de uma linha. Posso totalmente sobreviver com separação a atribuição RedisStore em 2 linhas :)
Fabrizio Giordano
@FabrizioGiordano: Eu poderia imaginar algo como import {default(someoptions) as x} from 'module'no ES7, se houver realmente uma necessidade disso.
Bergi
2
Para o session/ connect-redisexemplo, eu fui imaginando sintaxe como esta: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Jeff Handley
24

Conceito

Aqui está minha solução usando ES6

Muito em linha com a resposta do @ Bergi, este é o "modelo" que eu uso ao criar importações que precisam de parâmetros passados ​​para classdeclarações. Isso é usado em uma estrutura isomórfica que estou escrevendo, portanto, funcionará com um transpiler no navegador e no node.js (eu uso Babelcom Webpack):

./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();

O acima será exibido fooem um console

EDITAR

Exemplo do mundo real

Para um exemplo do mundo real, estou usando isso para passar em um espaço para nome para acessar outras classes e instâncias em uma estrutura. Como estamos simplesmente criando uma função e passando o objeto como argumento, podemos usá-la com nossa declaração de classe likeso:

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

A importação é um pouco mais complicada e, automagicalno meu caso, dado que é uma estrutura inteira, mas essencialmente é isso que está acontecendo:

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

Eu espero que isso ajude!

Giratório
fonte
Como todos os seus módulos importados são classes, por que não passar o parâmetro ao instanciar a classe?
jasonszhao
1
@jasonszhao O mais importante a ser observado aqui é que a classe MyViewestende determinados itens disponíveis no espaço de nomes da estrutura. Embora seja absolutamente possível simplesmente transmiti-lo como um parâmetro para a classe, também depende de quando e onde a classe é instanciada; portabilidade é então afetada. Na prática, essas classes podem ser entregues a outras estruturas que podem ser instanciadas de maneira diferente (por exemplo, componentes React personalizados). Quando a classe se encontra fora do escopo da estrutura, ainda pode manter o acesso à estrutura quando instanciada por causa dessa metodologia.
Swivel
@Swivel Por favor, ajude Preciso de ajuda com um problema semelhante: stackoverflow.com/questions/55214957/…
TSR
12

Com base na resposta da @ Bergi para usar o módulo de depuração usando es6, seria o seguinte

// 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!');
mummybot
fonte
4

Eu acredito que você pode usar os carregadores de módulo es6. http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});
user895715
fonte
3
Mas onde m(youroptionshere)termina o resultado ? Suponho que você possa escrever System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... mas não está muito claro.
Stijn de Witt
2
Uau, eu não acredito que não há uma maneira elegante de fazer isso no E6. É assim que escrevo principalmente módulos.
Robert Moskal
3

Você só precisa adicionar essas 2 linhas.

import xModule from 'module';
const x = xModule('someOptions');
Mansi Teharia
fonte
1
Isso é simplesmente passar parâmetros para uma função que você importou e está chamando. Não está passando nenhuma opção para o módulo do qual você o importa . xModuleé enganoso aqui. O que você realmente tem é import func from 'module'; func('someOptions');.
Dan Dascalescu 27/09/19
1

Cheguei a esse segmento procurando algo semelhante e gostaria de propor uma espécie de solução, pelo menos em alguns casos (mas veja Observação abaixo).

Caso de uso

Eu tenho um módulo, que está executando alguma lógica de instanciação imediatamente após o carregamento. Eu não gosto de chamar essa lógica init fora do módulo (que é o mesmo que call new SomeClass(p1, p2)or new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })and similar).

Eu gosto que essa lógica de inicialização seja executada uma vez, como um fluxo de instanciação singular, mas uma vez por algum contexto parametrizado específico.

Exemplo

service.js tem em seu escopo muito básico:

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

O módulo A faz:

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

O módulo B faz:

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

Até aí tudo bem: o serviço está disponível para os dois módulos, mas foi inicializado apenas uma vez.

Problema

Como fazê-lo funcionar como outra instância e se iniciar novamente em outro contexto, digamos no Módulo C?

Solução?

Isto é o que estou pensando: use parâmetros de consulta. No serviço, adicionamos o seguinte:

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

O módulo C faria:

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

o módulo será reimportado, sua lógica básica de inicialização será executada e veremos no console:

initialized in context special

Observação: eu mesmo aconselho a não praticar muito essa abordagem, mas a deixo como último recurso. Por quê? O módulo importado mais de uma vez é mais uma exceção do que uma regra, portanto, é um comportamento um tanto inesperado e, como tal, pode confundir um consumidor ou até quebrar seus próprios paradigmas 'singleton', se houver.

GullerYA
fonte
0

Aqui está minha opinião sobre essa questão usando o módulo de depuração como exemplo;

Na página npm deste módulo, você tem o seguinte:

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

Na linha acima, uma sequência é passada para o módulo que é importado, para construção. Veja como você faria o mesmo no ES6


import {depurar como depuração} de 'debug' const debug = Debug ('http');


Espero que isto seja útil a alguém.

Akinwale Folorunsho Habib
fonte
Por que postar uma resposta que duplica uma já postada ?
Dan Dascalescu 30/01/19
1
Foi mal. Nunca vi o post mencionado. Apenas olhou para a pergunta e deu uma facada nela. Obrigado por notificá-lo.
Akinwale Folorunsho Habib
De nada. Você também pode excluir a resposta duplicada, se desejar.
Dan Dascalescu 27/09/19