My Authors
Read all threads
ES-модули в JS — крутая функция, но грустный пример сложного внедрения.

На самом деле нет одних ES-модулей — есть 3 разных технологий: модули в браузере, в Node.js и в сборщиках. И они не очень совместимы между собой.

Тред про всю правду о ES-модулей ↓
Вокруг ES-модулей есть много заблуждений типа:
— «с ESM нам не нужны сборщики»
— «с ESM можно использовать npm-пакеты сразу в браузере»
— «ESM уже готовы для использования в npm-пакетах»

Попробую объяснить их текущие ограничения в этом треде.
Начнём с правды про ES-модули в браузерах. Этот код не будет работать в браузерах:

import { throttle } from 'throttle-debounce'

Модули в браузере загружаются только по прямому пути:

import { throttle } from './node_modules/throttle-debounce/index.mjs'
Даже если в вашем коде вы подключите npm-библиотеку по прямому пути, подключаемая библиотека будет использовать непрямые пути в своём коде — которые не будут работать с браузере, так как ему нужен только прямой путь к ES-модулю
Импорт ES-модулей в браузере по не прямому пути (без index.js или пути к node_modules) будет работать только другой технологией, Import Maps, которую пока браузеры особо не поддерживают.
chromestatus.com/feature/531528…
Сборщик для ESM в браузере вам нужны хотя бы для создания imports map.

Ну и HTTP/2 не решает проблему задержки каждого запроса. Если a.js грузит b.js, а b.js — c.js то без <link rel="preload"> будет до 500мс задержки на каждый такой переход вглубь дерева зависимостей.
Так же в браузере не будут работать __dirname, process и все библиотеки из Node.js типа require('https').

Поэтому большинство ES-модулей из npm не работают в браузере.
Для ESM в браузере предлагают CDN вместо с сборщиков. Например, jsdelivr.com

Но CDN убивает многие плюсы HTTP/2, ваше приложение сломается при падении CDN, и не решается проблема 500 мс задержи при запросах.

Плохо для продакшена, но нормально для экспериментов.
ES-модули в Node.js тоже отличаются от браузера. Они работают без флага в последней Node.js 13.

В отличии от браузера, позволяют грузить по не прямому пути. Но так же не работает __dirname.
__dirname в ESM у Node.js делается очень грязно (и не будет работать в браузере)

import { dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url))
Вторая проблема ESM в Node.js — нельзя сделать npm-пакет который по import from 'a' будет грузить ESM, а по require('a') — CommonJS.

Есть Conditional Exports, но их применение будет печатать в консоль предупреждение, даже при require().
nodejs.org/api/esm.html#e…
Единственный способ сделать двойной ESM/CommonJS npm-пакет — попросить ваших пользователей самим дописывать index.mjs при импорте:

import nanevents from 'nanoevents/index.mjs'

github.com/ai/nanoevents/…
Самый распостранённый тип ESM (и самый далёкий от спецификации) — «ESM» в сборщиках. Он позволяет многое запрещённое в спеке и, что не будет работать в браузере и Node.js.

К сожалению, многие JS-разработчики думают, что ESM в сборщиках и есть ESM.
Вебпак сначала берёт `a/index.mjs` при импорте `a`, хотя Node.js и Parcel при импорте будут искать сначала `a/index.js`.

Так же Вебпак разрешает __dirname и деструкторы в импорте CommonJS-модуля, хотя в Node.js ESM их нельзя использовать.
Двойной ESM/CommonJS npm-пакет для сборщика можно сделать через разные свойства main и module в package.json.

Но это работает только для корневого файла. Если в вашем пакете несколько файлов, то их надо класть в папки и в каждый добавлять package.json со своими main/module.
Подведём итоге ESM-треда:

1. Сейчас нет способа сделать двойной ESM/CommonJS модуль с простым импортом. Для сборщиков хоть есть грязный хак с папками и отдельными package.json, а для Ноды надо добавлять index.mjs. Для браузера всё равно всегда указывать полный путь.
2. Обычный пакет с npm даже с заменой require и module.exports не будет работать в ESM — надо менять многие вещи типа __dirname.
3. Сборщики для ESM будут нужны для генернации Imports Maps, <link rel="preload"> и конвертации CommonJS-пакетов.
Для разработчиков npm-пакетов, которые хотят выпускать двойные ESM/CommonJS модули, я сделал инструмент dual-publish.

github.com/ai/dual-publis…

Он учитывает все особенности как ESM в сборщиках, так и в ESM в Node.js и в браузерах.
Хороший итог восприятия ESM — мы слишком доверяем разработчиков спецификаций. Это касается и CSS.
В ESM есть хорошая вещь — они всполыхнули эксперименты. Больше всего делает автор @pikapkg и Showpack, @FredKSchott.

Мне не нравится их маркетинг, но они единственные, кто предлагают новые идеи в сборщиках. Хоть ESM не избавляет от сборщика, но позволяет сборщики упростить.
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Андрей Ситник

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!