Подтвердить что ты не робот

Учитывая ES2015, инъекцию зависимостей и абстракцию библиотеки, какой должен быть мой идеальный модуль в 2016 году?

Если нет, с одной стороны, я буду на борту писать все мои модули, например

import A from './a.js';

var B = function(){
  //use A
};

export default B;

а затем используя компилятор для его создания в каком-либо браузере или в формате сервера.

Моя единственная проблема с вышеизложенным - это явная спецификация ./a.js в import.

Я понимаю, почему спецификация прошла этот путь 1 чтобы быть в состоянии статического анализа. Но есть две очень практические причины, по которым проблема с выпечкой как в модуле имя_файла, так и в его пути.

  • Поскольку уже поднят здесь, при частом повторном использовании модулей из проекта в проект, скорее всего, вы не сможете поддерживать последовательный путь к этому ресурсу в дереве вашего проекта. Выпечка вызова импорта, такого как import myModule from './../../vendor/lib/dist/mod.js', в код модуля, не совсем точно отражает будущее.
  • Помимо самого пути, указание имя_файла также связывает вас. Что-то вроде этого кажется невинным:

    import $ from 'vendor/jquery.js'

    Но как насчет того дня, когда я хочу использовать Zepto вместо jQuery? Я нашел абстракцию, особенно вокруг библиотек поставщиков, очень полезную при работе с большими кодовыми базами, упрямыми разработчиками и постоянно меняющейся экосистемой JavaScript. Возможно, мне захочется импортировать React в качестве моей библиотеки компонентов сегодня, но как насчет завтра? Более того, что, если я собираюсь использовать тот же модуль как на клиенте, так и на сервере, но мне нужны разные версии зависимой библиотеки?

Я настаиваю на надежной (но четкой и последовательной) абстракции в моих командах. Часто время абстракция принимала форму своего рода пространств имен. Я немного фантазирую об этом:

//BAD: Bakes React into my component modules
import ComponentLib from './React.js';

//GOOD: Leaves me free to use any React-like library
import ComponentLib from 'vendor.lib.component';

Где vendor.lib.component, по-подобному Java, ранее было зарегистрировано.

Обратите внимание, что в отличие от этого вопроса, моя цель - не иметь динамического контроля над моим импортом. Я не хочу гибкости во время выполнения, я бы хотел, чтобы гибкость во время сборки. Я должен уметь подчинять зависимую структуру для другой, или для макета, или для чего-то, что будет работать в конкретной среде, без необходимости беспокоиться о том, какие зависимости вызывают мои модули, или пытаться дублировать какой-то сумасшедший каталог дерево для каждого продукта сборки, за которым я работаю.

Подобные вопросы привели к предложению библиотеки, которая использует Системная спецификация, например SystemJS. Затем вы можете использовать что-то вроде jspm, чтобы ввести карту модулей для получения абстракции. Но в тот момент, когда я это делаю, я пишу все свои модули по-разному:

System.import('a', function(A){
  //use 'A'
});

Это вдруг будущее? Если да, почему бы мне просто не использовать AMD? Зачем даже беспокоиться о модулях ES2015 и запусках transpilers, если я только вернусь к использованию асинхронного API-интерфейса загрузчика?

Больше просмотра роликов, я не вижу много упоминаний о применении стандарта API загрузчика модулей в спецификация ES2017.

(EDIT: вопрос пересмотрен для соответствия стандартам ответа, основанного на мнениях)

Учитывая все вышеизложенное, я спрашиваю сообщество - как написать модуль JavaScript, который (i) соблюдает стандарт ES2015, (ii) не ссылается на зависимый модуль по его имени файла или пути, и (iii) не полагается на обширные промежуточные инструменты/конфигурацию, которые сделают невозможным использование модуля с несколькими командами.

-

Примечание 1. Как отмечает @zeroflagL в комментариях, спецификация явно не указывает, что модуль должен быть указан как путь, просто строка (см. ModuleSpecifier - http://www.ecma-international.org/ecma-262/6.0/#table-41). Тем не менее, существует четкая инструкция для учета циклических ссылок, подразумевая какой-то статический анализ (http://www.ecma-international.org/ecma-262/6.0/#sec-imports), с файловыми путями, кажущимися являясь эталонным контекстом выбора к этому моменту. Поэтому мы не можем обвинять спецификацию в том, что она здесь жесткая, а наоборот. В то же время бремя может быть на всех остальных для разработки более надежных реализаций import/ModuleSpecifier, которые приводят к вторичному стандарту.

4b9b3361

Ответ 1

Для меня это, кажется, одна из самых больших нерешенных проблем сообщества JS. В отношении управления зависимостями и зависимостей (по крайней мере, насколько мне известно) не существует оптимальной практики.

В этой теме долго обсуждается: Нужна ли мне инъекция зависимостей в NodeJS или как справиться с...?, но большинство решений кажется работать только для конкретных случаев и требовать изменения способа записи модулей каким-либо образом. И самым шокирующим является то, что многие ответы утверждают, что вам даже не нужен DI.

Мое собственное решение для этой проблемы - это минимальная инфраструктура DI, которая позволяет вам определять модули один раз, и он будет подключать их к вам с соответствующими зависимостями.

Ответ 2

Я знаю, что вы просите решение, которое вы можете использовать специально в случае JS-компилятора, но поскольку вы просите о лучшей практике, я чувствую, что мы должны учитывать полное игровое поле, в котором зависимость от JavaScript управление, в том числе различные возможные среды хоста, такие как браузер и Node.js, интерфейсные системы упаковки, такие как Webpack, Browserify и jspm, и в некоторой степени соседние технологии, такие как HTML и HTTP/HTTP2.

История модулей ES

Существует причина, по которой вы не найдете API-интерфейс загрузчика в любой спецификации ECMA: исправление зависимостей не было завершено, когда был достигнут крайний срок для спецификации ECMA2015, и было решено, что спецификация ECMA будет описывать только синтаксис модуля и что хост-среда (например, браузер, Node.js, JS-компилятор/транспилер) будет отвечать за разрешение модулей через их спецификаторы через hook, называемый HostResolveImportedModule, который вы сможете найти в ECMA2015 и спецификации ECMA2017.

Спецификация семантики, лежащей в основе шаблона модуля ES2015, теперь находится в руках WHATWG. Два важных события были плодом их усилий:

  • Они определили, что модули в HTML могут быть обозначены символом <script type="module">.
  • Существует черновик для спецификации загрузчика, в котором будут учитываться различные среды хоста и интерфейсные системы упаковки. Это похоже на спецификацию, которая в конечном итоге поможет ответить на ваш вопрос, но, к сожалению, она далека от завершения и не обновляется в течение довольно длительного времени.

Текущие реализации

Браузер

С добавлением тега <script type="module"> все выглядит на месте для упрощенной реализации модулей ES6 в браузере. То, как он работает сейчас, не имеет никакого отношения к производительности (см. this и этот комментарий). Кроме того, он не поддерживает никаких интерфейсных упаковочных систем. Понятно, что концепция модулей должна быть расширена, чтобы ее можно было использовать вообще на производственных веб-сайтах, и поэтому разработчики браузеров не спешили внедрять ее в своих браузерах.

Node.js

Node.js - совершенно другая история, поскольку с самого начала он реализовал модули стиля CommonJS. В настоящее время поддержка модулей ES2015 отсутствует. Были внесены два дополнительных предложения по включению модулей ES6 в Node.js вместе с модулями CommonJS. Это сообщение в блоге подробно обсуждает эти предложения.

компиляторы и упаковочные системы

Заключение

Итак, когда вы запрашиваете лучший способ писать модули, вы можете видеть, что это очень сложно. Придумать решение, совместимое со всеми возможными средами хоста, предпочтительнее, потому что:

  • Возможно, вам захочется поделиться своим кодом между разными средами.
  • Существует риск того, что некоторые разработчики (например, сторонние разработчики) будут использовать модули ES2015, тогда как другие (например, разработчики Node.js) будут придерживаться другого решения (например, модули CommonJS). Это еще больше снизит вероятность использования кода межсетевой среды.

Но вы увидите, что в разных средах разные требования. В этом смысле лучшим ответом на ваш вопрос может быть: в настоящее время нет лучшего способа написания модулей, которые покрывают ваши проблемы с абстракцией.

Решение

Однако, если бы у меня была задача прямо сейчас писать модули ES2015, которые компилируются в JS, я бы держался подальше от относительных путей и всегда использовал абсолютные пути от корня проекта как идентификатор модулей, что я не делаю см. как проблемный. Java фактически отражает пространства имен и структуру каталогов во многом таким же образом. Я бы использовал Webpack или Babel для компиляции моего источника кода, который запускается в современных средах JS.

Что касается вашей другой проблемы, если бы я захотел заменить библиотеки поставщиков, я бы, вероятно, создал один модуль, который будет псевдонизировать библиотеки поставщиков с именами, которые я буду использовать внутри себя. Скорее всего:

//  /lib/libs.js
import jQuery from 'vendor/jquery.js'
export const $ = jQuery;

Все остальные модули затем будут импортировать $из lib/libs.js, и вы сможете переключать библиотеки поставщиков, изменяя ссылку в одном месте.

Ответ 3

Если вы хотите следовать передовым методам, следуйте инструкциям AirBnb JavaScript styleguide. По-моему, лучший и самый полный стиль JavaScript-стиля там

https://github.com/airbnb/javascript#classes--constructors

Импорт

Это выглядит плохо для повторного использования модулей: import myModule from './../../vendor/lib/dist/mod.js'

Опубликуйте свой модуль в NPM (который также может быть приватным или самостоятельно размещенным NPM) и импортируйте как это import myModule from 'my-module';

В конечном итоге установите NODE_PATH в качестве корневой папки и обратитесь к модулям относительно от корня.

В package.json

'start': 'NODE_PATH=. node index.js'

// in Windows
'start': 'NODE_PATH=. && node index.js'

Теперь импортируйте вот так:

import myModule from 'vendor/lib/dist/mod.js'

Переменные

var не входит в ES6. Использование:

  • constant - когда значение переменной не изменится, также объекты и импорт. Даже если параметры объекта изменяют, он все равно является константой.

  • let - когда изменяется значение переменной, т.е. for(let = i; i < 100; i++)

  • Из моего собственного опыта всегда устанавливайте const по умолчанию и меняйте только на let, если ESLint жалуется (кстати, используйте ESLint http://eslint.org/)

Классы

Теперь существует правильный способ определения классов в JavaScript

class B {
  constructor() {
  }
  doSomething() {
  }
}

Ваш пример обновлен:

import A from './a';

Class B {
  constructor() {
  }
  doSomething() {
  }
};

export default B;

Если вы хотите расширить A:

import A from './a';

Class B extends A{
  constructor(argumentA, argumentB) {
    super(argumentA, argumentB);
    this.paramA = argumentA;
  }
};

export default B;

Советы

  • Используйте Webpack с NPM как инструмент сборки. Не используйте Gulp или Grunt
  • Используйте Babel для перевода вашего кода (загрузчика JSX может быть недостаточно)
  • Научитесь не использовать jQuery вообще, а вместо этого выбирайте правильные полисы и инструменты для заданий, которые вам нужно сделать из NPM
  • Есть тонны хорошо написанных платных репозиториев на github, так что украсть из лучших. Вот некоторые из них, которые я использую.
    • https://github.com/davezuko/react-redux-starter-kit
    • https://github.com/kriasoft/react-starter-kit
    • как вы можете видеть, я большой поклонник React. Также полный рабочий день профессиональный пользователь уже более двух лет.
    • Чтобы найти хорошие примеры кодов, поиск по github i.e. "реагировать" или "node", а затем сортировать результаты по звездам)

Мой ответ в сущности таков:

Образец/библиотека, которую вы просили, это AirBnb JavaScript styleguide и забыть о jQuery