Opciones de pase a las importaciones del módulo ES6

144

¿Es posible pasar opciones a las importaciones ES6?

Cómo traduces esto:

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

a ES6?

Fabrizio Giordano
fuente
No estoy seguro de que pueda System.import(module)hacerlo , hay una API de carga de módulos, o al menos hubo alguna vez, que usó algo como , no estoy seguro de si eso permite argumentos o no, ¿alguien que sabe más sobre ES6 probablemente sí?
adeneo
Hay una solución propuesta para esto, para la cual ya hay implementaciones en node.js (a través de un complemento) y paquete web: 2ality.com/2017/01/import-operator.html
Matt Browne

Respuestas:

104

No hay forma de hacer esto con una sola importdeclaración, no permite invocaciones.

Por lo tanto, no lo llamaría directamente, pero básicamente puede hacer lo mismo que commonjs hace con las exportaciones predeterminadas:

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

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

Alternativamente, si usa un cargador de módulos que admite promesas monádicas , podría hacer algo como

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

Con el nuevo importoperador podría convertirse

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

o

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

sin embargo, probablemente no desee una importación dinámica sino estática.

Bergi
fuente
77
Gracias Ojalá hubiera algo así como import x from 'module' use someoptions;un poco de sintaxis
Fabrizio Giordano
1
@Fabrizio: Si lo piensas más a fondo, realmente no sería tan útil. Solo funcionaría si el módulo exporta una función y probablemente no debería permitirse si nombramos importaciones (es decir import {x, y} from 'module'). Entonces, ¿cuál debería ser la sintaxis si quiero pasar varios argumentos? O difundir una serie de argumentos? Es un caso de uso limitado y básicamente está tratando de agregar una sintaxis diferente para una llamada de función, pero ya tenemos llamadas de función que nos permiten ocuparnos de todos los demás casos.
Felix Kling
3
@FelixKling Estoy completamente de acuerdo contigo. Estaba convirtiendo una vieja aplicación web express y me encontré con que var session = require('express-session'); var RedisStore = require('connect-redis')(session);me preguntaba si había una solución de una línea. Puedo sobrevivir totalmente con dividir la asignación de RedisStore en 2 líneas :)
Fabrizio Giordano
@FabrizioGiordano: Me podría imaginar algo como import {default(someoptions) as x} from 'module'en ES7, si realmente es necesario.
Bergi
2
Para el session/ connect-redisejemplo, he estado imaginando sintaxis como esta: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Jeff Handley
24

Concepto

Aquí está mi solución usando ES6

Muy en línea con la respuesta de @ Bergi, esta es la "plantilla" que uso cuando creo importaciones que necesitan pasar parámetros para las classdeclaraciones. Esto se usa en un marco isomorfo que estoy escribiendo, por lo que funcionará con un transpiler en el navegador y en node.js (lo uso Babelcon 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();

Lo anterior saldrá fooen una consola

EDITAR

Ejemplo del mundo real

Para un ejemplo del mundo real, estoy usando esto para pasar en un espacio de nombres para acceder a otras clases e instancias dentro de un marco. Debido a que simplemente estamos creando una función y pasando el objeto como argumento, podemos usarlo con nuestra declaración de clase likeso:

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

La importación es un poco más complicada y automagicalen mi caso dado que es un marco completo, pero esencialmente esto es lo que está sucediendo:

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

¡Espero que esto ayude!

Girar
fuente
Dado que todos sus módulos importados son clases, ¿por qué no pasar el parámetro al crear instancias de la clase?
jasonszhao
1
@jasonszhao Lo más importante a tener en cuenta aquí es que la clase MyViewextiende ciertos elementos disponibles en el espacio de nombres del marco. Si bien es absolutamente posible pasarlo simplemente como un parámetro a la clase, también depende de cuándo y dónde se instancia la clase; La portabilidad se ve afectada. En la práctica, estas clases se pueden entregar a otros marcos que pueden instanciarlas de manera diferente (por ejemplo, componentes de React personalizados). Cuando la clase se encuentra fuera del alcance del marco, aún puede mantener el acceso al marco cuando se crea una instancia debido a esta metodología.
Giratorio
@Swivel Por favor, ayuda Necesito ayuda con un problema similar: stackoverflow.com/questions/55214957/…
TSR
12

A partir de la respuesta de @ Bergi para usar el módulo de depuración usando es6, sería lo siguiente

// 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!');
momiabot
fuente
4

Creo que puedes usar cargadores de módulos es6. http://babeljs.io/docs/learn-es6/

System.import("lib/math").then(function(m) {
  m(youroptionshere);
});
usuario895715
fuente
3
Pero, ¿dónde termina el resultado de m(youroptionshere)? Supongo que podrías escribir System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... pero no está muy claro.
Stijn de Witt
2
Wow, no puedo creer que no haya una forma elegante de hacer esto en E6. Así es como escribo principalmente los módulos.
Robert Moskal
3

Solo necesita agregar estas 2 líneas.

import xModule from 'module';
const x = xModule('someOptions');
Mansi Teharia
fuente
1
Eso es simplemente pasar parámetros a una función que ha importado y está llamando. No está pasando ninguna opción al módulo desde el que lo importa . xModuleEs engañoso aquí. Lo que realmente tienes es import func from 'module'; func('someOptions');.
Dan Dascalescu
1

Llegué a este hilo buscando algo similar y me gustaría proponer un tipo de solución, al menos para algunos casos (pero vea el Comentario a continuación).

Caso de uso

Tengo un módulo, que ejecuta una lógica de instanciación inmediatamente después de la carga. No me gusta llamar a esta lógica de inicio fuera del módulo (que es lo mismo que call new SomeClass(p1, p2)o new ((p1, p2) => class SomeClass { ... p1 ... p2 ... })similar).

Me gusta que esta lógica de inicio se ejecute una vez, una especie de flujo de instanciación singular, pero una vez por algún contexto parametrizado específico.

Ejemplo

service.js tiene en su alcance muy básico:

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

El módulo A hace:

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

El módulo B hace:

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

Hasta ahora todo bien: el servicio está disponible para ambos módulos, pero se inicializó solo una vez.

Problema

¿Cómo hacer que se ejecute como otra instancia y se inicie una vez más en otro contexto, por ejemplo, en el Módulo C?

¿Solución?

Esto es lo que estoy pensando: usar parámetros de consulta. En el servicio agregaríamos lo siguiente:

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

El módulo C haría:

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

el módulo se volverá a importar, se ejecutará su lógica de inicio básica y veremos en la consola:

initialized in context special

Observación: yo mismo aconsejaría NO practicar mucho este enfoque, pero dejarlo como último recurso. ¿Por qué? El módulo importado más de una vez es más una excepción que una regla, por lo que es un comportamiento algo inesperado y, como tal, puede confundir a los consumidores o incluso romper sus propios paradigmas 'singleton', si los hay.

GullerYA
fuente
0

Aquí está mi opinión sobre esta pregunta usando el módulo de depuración como ejemplo;

En la página npm de este módulo, tiene esto:

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

En la línea anterior, se pasa una cadena al módulo que se importa, para construir. Así es como harías lo mismo en ES6


import {debug as Debug} de 'debug' const debug = Debug ('http');


Espero que esto ayude a alguien por ahí.

Akinwale Folorunsho Habib
fuente
¿Por qué publicar una respuesta que duplica una ya publicada ?
Dan Dascalescu
1
Culpa mía. Nunca vi la publicación mencionada. Solo miré la pregunta y la apuñalé. Gracias por avisarme.
Akinwale Folorunsho Habib
De nada. También puede eliminar la respuesta duplicada si lo desea.
Dan Dascalescu