Передати варіанти імпорту модуля ES6


144

Чи можливо передавати варіанти на імпорт ES6?

Як ви перекладете це:

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

до ES6?


Не впевнений, що можна, є API завантажувача модулів, або, принаймні, був якийсь час, який використовував щось на кшталт System.import(module), не впевнений, чи дозволяє це аргументи чи ні, мабуть, хтось, хто знає більше про ES6?
adeneo

Для цього є запропоноване рішення, для якого вже є реалізація в node.js (за допомогою плагіна) та webpack: 2ality.com/2017/01/import-operator.html
Метт Браун

Відповіді:


104

Неможливо зробити це за допомогою одного importзаяви, це не дозволяє викликати.

Таким чином, ви б не називали це безпосередньо, але ви можете в основному робити те саме, що і звичайний експорт за замовчуванням:

// 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)

однак ви, мабуть, не хочете динамічного імпорту, а статичного.


7
Дякую, я хотів би, щоб було щось на зразок import x from 'module' use someoptions;синтаксису
Fabrizio Giordano,

1
@Fabrizio: Якщо ви подумаєте про це далі, це не дуже допоможе. Він буде працювати лише в тому випадку, якщо модуль експортує функцію і, ймовірно, не повинен бути дозволений, якщо ми назвали імпорт (тобто import {x, y} from 'module'). Тоді яким повинен бути синтаксис, якщо я хочу передати кілька аргументів? Або поширити масив аргументів? Це вузький випадок використання, і в основному ви намагаєтеся додати інший синтаксис для виклику функції, але у нас вже є виклики функцій, які дозволяють нам вирішувати всі інші випадки.
Фелікс Клінг

3
@FelixKling Я повністю з тобою згоден. Я перетворював старий експрес-webapp, і мені траплялося var session = require('express-session'); var RedisStore = require('connect-redis')(session);мені просто цікаво, чи є рішення в одній лінії. Я можу повністю вижити, розділивши завдання RedisStore на 2 рядки :)
Fabrizio Giordano,

@FabrizioGiordano: Я міг би уявити щось подібне import {default(someoptions) as x} from 'module'в ES7, якщо в цьому дійсно є потреба.
Бергі

2
Для session/ connect-redisнаприклад, я собі синтаксис на зразок цього: import session from 'express-session'); import RedisStore(session) from 'connect-redis'.
Джефф Хендлі

24

Концепція

Ось моє рішення за допомогою ES6

Дуже сильно відповідає реакції @ Бергі, це "шаблон", який я використовую під час створення імпорту, для якого потрібні параметри, передані для classдекларацій. Це використовується на ізоморфних рамках , яку я пишу, так що буде працювати з transpiler в браузері і в Node.js (я використовую Babelз 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();

Викладене буде виводитися fooв консолі

EDIT

Приклад реального світу

Для прикладу реального світу я використовую це для передачі в просторі імен для доступу до інших класів і екземплярів в рамках. Оскільки ми просто створюємо функцію і передаємо об’єкт в якості аргументу, ми можемо використовувати його з нашим класовим декларацією Likeo:

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

Я сподіваюся, що це допомагає!


Оскільки всі ваші імпортовані модулі є класами, чому б не передати параметр при інстанціюванні класу?
jasonszhao

1
@jasonszhao Найголовніше, що тут слід зазначити, це те, що клас MyViewрозширює певні елементи, доступні в просторі імен рамки. Хоча цілком можливо просто передати його як параметр класу, це також залежить від того, коли і де клас інстанціюється; Потім впливає портативність. На практиці ці класи можуть бути передані іншим структурам, які можуть інстанціювати їх по-різному (наприклад, спеціальні компоненти React). Коли клас опиняється поза рамками рамки, він все одно може підтримувати доступ до фреймворку при інстанціюванні завдяки цій методології.
Поворот

@Swivel Будь ласка, допоможіть мені потрібна допомога у подібному питанні: stackoverflow.com/questions/55214957/…
TSR


4

Я вважаю, що ви можете використовувати навантажувачі модулів es6. http://babeljs.io/docs/learn-es6/

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

3
Але де результат m(youroptionshere)закінчується? Я думаю, ви могли б написати System.import('lib/math').then(m => m(options)).then(module => { /* code using module here */})... але це не дуже зрозуміло.
Штійн де Вітт

2
Нічого собі не можу повірити, що в Е6 немає елегантного способу зробити це. Саме так я в основному пишу модулі.
Роберт Москаль

3

Вам просто потрібно додати ці 2 рядки.

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

1
Це просто передача параметрів функції, яку ви імпортували та викликаєте. Це модуль не передає жодних параметрів модулю, з якого ви імпортуєте його . xModuleтут вводиться в оману. Те, що ви насправді маєте, так і є import func from 'module'; func('someOptions');.
Дан Даскалеску

1

Я приземлився на цю нитку, шукаючи дещо подібне і хотів би запропонувати якесь рішення, принаймні для деяких випадків (але див. Зауваження нижче).

Використовуйте футляр

У мене є модуль, який виконує певну логіку екземплярів відразу після завантаження. Мені не подобається називати цю логіку 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'));

Модуль A робить:

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

Зауваження: Я б радив НЕ дуже практикувати цей підхід, а залишити його як крайній захід. Чому? Модуль, що імпортується не один раз, є скоріше винятком, ніж правилом, тому це дещо несподівана поведінка, і як таке може збити з пантелику споживачів або навіть порушити власні парадигми "одиночки", якщо такі є.


0

Ось мій погляд на це питання, використовуючи модуль налагодження як приклад;

На npm-сторінці цього модуля у вас є таке:

var debug = requ ('налагодження') ('http')

У верхньому рядку рядок передається модулю, який імпортується, для побудови. Ось як би ви зробили те саме в ES6


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


Сподіваюся, це допомагає комусь там.


Навіщо публікувати відповідь, що дублює вже опубліковану ?
Дан Даскалеску

1
Моє ліжко. Ніколи не бачив згаданого поста. Тільки подивився на питання і взяв на нього удар. Дякуємо, що повідомили про це.
Akinwale Folorunsho Habib

Ласкаво просимо. Ви також можете видалити дублюючу відповідь, якщо хочете.
Дан Даскалеску
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.