Pull to refresh

Comments 38

На мой взгляд самый неочевидный момент с модулями, после common.js:
export const foo = bar; !== exports.foo = bar;
То есть:
// lib.js
export function foo() {}

// app.js
import lib from './lib';

console.log(lib.foo); // undefined

Это можно понять и по спекам и по вашей статье, но просто это немного необычно, после common.js, так скажем не ожидаемо. Но это легко исправить: import * as lib from './lib';
Ну так common Modules !== es6))

Для этого есть export default, а не *. А вы превели именованый экспорт, разумеется, что там будет undef, что же еще?
Честно говоря, мне тоже дефолт экспорт кажется местами нелогичным, но уж как сделали — так сделали. Бабель сейчас такое поведение фолбэчит — модулям, которые изначально написаны на ES6, он ставит не-enumerable экспортируемое свойство __esModule = true, и если потом при импорте модуля он видит, что такое свойство не импортируется, то он смотрит: если есть с именем default, то вернёт default, если нету — вернёт exports того модуля целиком. Но гораздо правильней и безопасней делать вот так:

import * as fs from 'fs';


Хотя и непривычно, конечно))
А нет ли способов реэкспортировать нужные объекты прямо из под имени директории?
Например есть папка components в ней есть файлы Email.js и Inbox.js в которых есть классы Email и Inbox соответсвенно. Мне бы хотелось чтоб я мог их импортировать с помощью
import Components
ну или import Components from 'components'
В python это возможно сделать с помощью создания __init__.py файла в папке components и импорта нужных вещей туда. Нет ли в JS какого нибудь такого файла в стиле index.js который автоматически читается если сделать import этой папке?
Commonjs в ноде при указании дерриктории действительно пытается заимпортить index.js, import в babel как раз делает фолбэк для импорта через require, но вот как и во что это выльется на клиенте зависит уже от библиотеки\сборщика который вы используете.
Плюс в отличие от питона нет никакой явной нотации на то как должен выглядеть index.js в таком случае. Не натыкался на то как бы это выглядело в спеках, если кто-то знает хотел бы прочитать про подобный вариант. Но в целом с реэкспортом можно весьма удобно собирать такие компоненты.
Не совсем понял, что в таком случае делает babel. Использую именно его с browserify. Могу ли я пользоваться вариантом с index.js в этом случае? Пишу для браузера (Reactjs), но всё склеиваю в один файл.
Только мне до сих пор не понятно как в браузер будут приходить сотни и миллионы маленьких файликов-модулей. Сколько лет разными средствами от этого убегали, и вот вам :(
Service workers для этих задач поднимать как-то странно. Вещи не совсем связанные.
HTTP/2 должен решить эту проблему
Мне кажется, что помимо накладных расходов на сами запросы, есть ещё накладные расходы на использование файловой системы. Так что вопрос объединения модулей в 1 файл, всё же стоит и с HTTP/2. IMHO
Мне кажется, тут все очень зависит от проекта. В каких-то проектах необходимо все объединять в один файл, в каких-то лучше все как-то хранить модульно. Например, на прошлой работе все сжималось в один (или два, точно не помню) файла, общий размер которого около 2мб (одного ExtJS фиг знает сколько было). В проекте были разные тарифные планы, и, например, фришный пользователь мог видеть только 20% от всего приложения. Получается, что для него грузилась куча ненужного кода.
А расходы на использование файловой системы в обычном среднестатистическом проекте — микроскопические. Картинок всяких грузится обычно в разы больше, чем скриптов. Да и никто ведь разом не будет загружать все 100 модулей. А вот если будет — то да, лучше в один файл все :)
Пример — АПИ Яндекс.Карт состоит из нескольких тысяч модулей.
Вообще проекты следующие KISS и вообще правилам декомпозиции любят состоять из кучи маленьких «reusable» кусочков.
Про количество модулей в Картах в курсе :)
Ну в картах и есть несколько разных сборок (вроде бы) с необходимой для каждого юзера функциональностью. Понятно, что тут такой подход и нужен — все нужные модули в один файл :)
например, фришный пользователь мог видеть только 20% от всего приложения. Получается, что для него грузилась куча ненужного кода.
Не понимаю, причём тут это. Что мешало сделать несколько bundle's, самый простой из которых загружал только нужное обычному посетителю, в обычных ситуациях, а менее популярные зависимости раскидать по другим bundle-ам?

А расходы на использование файловой системы в обычном среднестатистическом проекте — микроскопические. Картинок всяких грузится обычно в разы больше, чем скриптов.
Почему же? Если речь идёт о вёрстке, то разработчики, зачастую, используют спрайты или base64 dataurl, и число запростов уменьшается многократно (вплоть до 1-го запроса к CSS файлу, где всякая мелочь лежит как base64). А картинок связанных с контентом web-сайта может и не быть вовсе. Или быть мало, не всё же новостные порталы.

Да и никто ведь разом не будет загружать все 100 модулей.
Ну у меня в проектах обычно только SCSS файлов около 100-ни, если не больше (import-ы). да и JS-ов на данный момент порядка 80-и.
Не понимаю, причём тут это. Что мешало сделать несколько bundle's, самый простой из которых загружал только нужное обычному посетителю, в обычных ситуациях, а менее популярные зависимости раскидать по другим bundle-ам?

Я привел пример, когда подход «все в одном файле» был неоправдан. Мешало то, что проект очень древний (перепиленный ExtJS 3.4) и как такового загрузчика, вроде RequireJS, не было. И не было нормального разбиения по модулям, все друг с другом было очень связано. Переписывать и переделывать — очень дорого для бизнеса + получился бы велосипед с треугольными колесами (хотя, на мой взгляд, поддерживать все эту хрень стоит еще дороже, чем переписать).
Почему же? Если речь идёт о вёрстке, то разработчики, зачастую, используют спрайты или base64 dataurl, и число запростов уменьшается многократно (вплоть до 1-го запроса к CSS файлу, где всякая мелочь лежит как base64). А картинок связанных с контентом web-сайта может и не быть вовсе. Или быть мало, не всё же новостные порталы.

Тут не про верстку имелось в виду. Не обязательно бть новостным порталом, чтобы грузить много изображений. Возьмите тот же Яндекс.Диск, Flickr, Pinterest, какая-нибудь CRM-ка (например, какие-нибудь аватары пользователей). Ну 30-40 картинок может быть легко, и на этом фоне загрузка 5-10 скриптов — мелочь, тем более Вы же знаете про кэширование?
Ну у меня в проектах обычно только SCSS файлов около 100-ни, если не больше (import-ы). да и JS-ов на данный момент порядка 80-и.

SCSS тут причем? И вы разом загружаете пользователю все эти 80 js-модулей? Вы же сами утверждали, что необходимо загружать только нужное сначала. Сколько у Вас критически важных модулей из этих 80?
загрузка 5-10 скриптов — мелочь, тем более Вы же знаете про кэширование
Легко может стоить вам от 500ms до 5000ms (например, GPRS) при загрузке страницы. Это очень много. К тому же JS-функциональность всё чаще является не «рюшечками» а острой необходимостью.

Не понимаю, что вы мне пытаетесь доказать. В то время когда некоторые разработчики заранее подготавливают gzip-ы для nginx_gzip_static, вы говорите о +-10 скриптах? :) Во frontende-е уже давно борьба идёт на уровне «спичек», а не «брёвен».

SCSS тут причем?
Технология позволяет использовать импорты не задумываясь о последствиях, т.к. компилятор сам всё соберёт в 1 файл. Это удобство легко приводит к тому, что SCSS-файлы плодятся в огромном количестве (просто потому что декомпозиция это очень удобно). Привёл в качестве примера, сколько может быть мини-файлов в рядовом проекте.

И вы разом загружаете пользователю все эти 80 js-модулей? Вы же сами утверждали, что необходимо загружать только нужное сначала. Сколько у Вас критически важных модулей из этих 80?
Пользователь загружает 1 минифицированный файл со всем необходимым. Администратор загружает 2 файла. Некоторые страницы сайта могут потребовать загрузку 3 файла (например в нём может быть огромный Ckeditor и плагины к нему).

И всё это работает автоматически. Вы просто определяет в конфигурации сборки какие файлы в какой бандл дожны попасть. Всю чёрную работу возьмёт на себя requireJS или его аналог (да хоть самописный, какая разница). Система зависимостей в действии. Вам больше нигде не потребуется писать <script type=«text/javascript src=»..."></script> указывая требуемые файлы вручную.
Вас куда-то не туда понесло. Мы обсуждали, в данном контексте, насколько я понял, что если не склеивать все JS в один / несколько файлов, то будет расти нагрузка на сервере, т.к. будет много операций на чтение каждого файла.

Легко может стоить вам от 500ms до 5000ms (например, GPRS) при загрузке страницы. Это очень много. К тому же JS-функциональность всё чаще является не «рюшечками» а острой необходимостью.

Причем тут вообще GPRS? Разговор у нас шел вообще о, цитирую, «ещё накладные расходы на использование файловой системы». И все, о чем, я говорил, было связано именно с этой темой. Я не утверждал, что плохо или хорошо склеивать все в один файл — все зависит от проекта, где-то это нужно, где-то нет. А вы тут препроцессоры еще приплели :)

Нас обоих куда-то не туда понесло. Попробую заново. Модульная система располагает к тому, что число модулей. т.е. файлов, может быть очень большим. 100, 200, 1000, 10'000. Если их никак не склеивать, то нагрузка на файловую систему будет. Если отдавать их разом тем более. К тому же как правильно заметил kashey с latency не поспоришь. Т.е. если там будут иерархические ветвления include-ов, ничего хорошего из этого не выйдет.

Соответственно есть реальная необходимость иметь возможность объединения модулей в 1 или несколько файлов. Или размещения нескольких модулей в рамках одного файла. Учитывая, что мы обсуждаем нативный функционал, то интересует как раз нативное решение. Объединение сопряжённое с правкой исходных кодов (автозамены include-ов и export-ов) на поддерживаемые конструкции мы можем и сейчас без поддержки ES6 модулей вообще.

все зависит от проекта, где-то это нужно, где-то нет.
В некоторых проектах вообще нет подключаемых JS-ов. Там, соответственно, это не нужно. Но зачем это обсуждать? :)
Ничего кроме bulk запросов не может решить проблему временых задержек на получения данных. Прямо каноническое бутылочное горлышко получается.
Требуется на сервере разрулить зависимости, и передать «предсказанную» кучу модулей. Иначе все будет работать как игра с DVD — вжик-вжик, вжик-вжик, ууууууу… С latency не спорят.
Можете посмотреть jspm.
Весьма удобная штука надстройка над SystemJS, которая даёт возможность импортить файлы разного «формата» + сборщик. Который на уровне импортов и конфига собирает это всё в один бандл или если хотите можете собирать это помодульно и т.д…
browserify + babelify в данный момент спасают.
Не спасают, а заменяют «нормальную» модульность ES6.
скорее эмулируют, там же тоже можно использовать import и export
У меня есть ощущение, что эта система модулей сделана так, чтобы максимально легко транспилиться в любую другую — AMD, require, common. Поэтому можно легко писать в es6 стиле, а потом browserify или webpack.
С ES6 мы будем не билдить, а бандлить)) Уже даже есть сборщики ES6 модулей, просто погуглите по гитхабу)
Многое уяснил. Спасибо за статью. Осталось не совсем ясным использование «from». В случае requireJS мы может влиять на то, какие конкретно файлы будут загружаться, и нужно ли что-либо вообще догружать. А как с этим делом обстоит в ES6 модулях? Судя по тексту, каждый файл — отдельная область видимости, которые с друг другом не пересекаются, но что если речь идёт о будущем frontend-а и мы хотим разместить несколько модулей в 1 файл (к примеру, для экономии запросов)?
Заюзайте вебпак)

Вообще, у меня пока ощущение, что эта система модулей сделана так, чтобы с минимальными потерями транспилиться в любую другую — по сути, такой метаязык, который можно потом хоть в AMD, хоть в CommonJS, хоть в require) И это круто. Но, конечно, это мои личные ощущения.
Заюзайте вебпак)
Да заюзать то я могу что угодно и когда угодно. Но ведь тут речь идёт о нативном представлении, о возможности самого языка или инфраструктуры связанной с ним. К примеру, в PHP есть autoloader-ы классов. И можно одновременно использовать несколько разных лоадеров, которые могут работать по совсем разной логике (очень давно не работал с PHP, могу в чём-нибудь ошибаться).

Вводя модульную систему в JS, подразумевая, что оная должна работать и в браузере, мы должны иметь возможность влиять на неё. Т.е. как то управлять механизмом работы этих ES6-Modules. Но пока что я ничего подобного ни в 1-ой статье не углядел.

Робко надеюсь на то, что этот вопрос будет удачным образом решён позднее. А транспилить код туда сюда я не люблю. Чем нативнее решение, тем надёжнее, и тем удобнее его debug-ить. К примеру, недавно я стал сталкиваться в Web Developer Tools с тем, что многие ошибки на страницах детектируются не там, где они произошли, а в каком-то абстрактном xml.js (которого даже не существует), в котором нужного кода нет и в помине. Оказалось что дело в sourceMap. Или вот в nodeJS обычный require, в непонятных мне случаях, все SyntaxError-ы в моих файлах детектирует в своих внутренних файлах (таких как vm.js), и я не могу понять ни в каком файле ошибка, ни в какой строке, ни на какой позиции. Потому что в стектрейсах просто чушь. И мне приходится некоторые require оборачивать в try catch, просто для того, чтобы узнать хотя бы файл, в котором ошибка произошла (я ведь знаю, что я require-ю).

Я предпочитаю использовать нативные решения (привет кофе-скрипт), за исключением тех случаев, где альтернатива предлагает просто бездну удобств (например scss, less и шаблонизаторы) и минимум геморроя.
Вот здесь сейчас идёт разработка спецификации загрузчика модулей, который как раз позволит подгружать всё динамически, асинхронно и условно.

Я сначала транспилил код, а теперь вообще пользуюсь babel-node, чтобы не прикручивать кучу галпа сверху. Не замечал проблем с дебагом. И ошибка с require у вас очень странная, не попробуете рабочий пример создать?

И да, я заметил логическое несоответствие: вы не любите транспилить, но юзаете кофескрипт?
Очень хороший вопрос. Предполагаю, что это будущее будет решаться в будущем.
Если вам надо программно управлять зависимостями вы можете использовать
System.import
который позволяет асинхронно загружать скрипты с интерфейсом промисов
А вы использовали полифиллы для него? Что скажете, удобно? Я просто посматриваю, но это сильный драфт, и необходимости небольшой нет (пишу под ноду, и если не хватает где-то es6 импортов — просто юзаю require), поэтому руки не дошли нормально потыкать.
Еще одним отличием (на сколько я понял) import от require() является то, что import можно располагать только в начале кода, в то время как require() может быть где угодно и подгружать модули даже динамически.
Поправьте, если ошибаюсь.
Да, абсолютно верно. Импорт можно располагать только на самом «верхнем» уровне модуля, т. е. нельзя вот так

if (weNeedFS) {
  import * as fs from 'fs';
}


И даже, как я писал в статье, если написать импорт после чего-либо другого, то он всё равно «всплывет».

Вот здесь сейчас идёт разработка спеки для загрузчика модулей, с помощью которого как раз и можно будет реализовать динамическую, условную и прочую подгрузку модулей.
Как-то очень смущает требование один файл — один модуль для скриптового языка, код которого активно передается клиенту по сети.
На самом деле, это не требование. Просто по факту сейчас в спецификации нет ничего, кроме описания структуры модуля и того, как устроен импорт/экспорт. А до тех пор, пока не появится описание того, как это всё должно лежать на фс, как резолвиться и так далее, реализаций у нас не будет. Поэтому пока ждём, пока они допишут стандарт (около года), и юзаем эту модульную систему, транспиля её в ноду, браузерифай и прочее.
Честно, спеку не читал ещё, но в статьях не видел ничего подобного ключевому слову module или namespace. а без них реализация export/import (читай полноценной изоляции модулей) в пределах одного файла без компиляции в ES5 или подмножество ES6 выглядит сомнительным или неполноценным.
Sign up to leave a comment.

Articles