Comments 11
Для того чтобы такая запись работала, нам потребуется модуль module-alias
В Node.js аналогичная функциональность уже довольно давно есть из коробки: https://nodejs.org/dist/latest-v18.x/docs/api/packages.html#subpath-imports
// package.json
"imports": {
"#pkg": "./src/*",
},
// foo.js
import bar from "#pkg/bar";
Тут не совсем все просто. Нативные alias работают только с ESM модулями
Например:
// Не будет работать
const { ProductView } = require('#entities/product/components/ProductView');
const { addProductToCart } = require('#features/add-to-cart/actions');
// Необходимо прописать полный путь
const { ProductView } = require('#entities/product/components/ProductView.js');
const { addProductToCart } = require('#features/add-to-cart/actions/index.js');
Несмотря на то, что алиасы работают как для ES‑модулей, так и для CommonJS модулей, Node.js использует правила поиска модулей, которые применяются для ES‑модулей. Проще говоря, появляются два новых требования:
При импорте необходимо указывать полный путь до файла, включая расширение файла.
При импорте нельзя указывать путь до директории, ожидая импорта файла
index.js
. Вместо этого необходимо указывать полный путь до файлаindex.js
.
Для легаси проектов получается этот способ не заведется без рефакторинга....
Да, забыл про этот момент, спасибо.
Для легаси проектов получается этот способ не заведется без рефакторинга
Но ведь переход с относительных путей на алиасы - это такой же рефакторинг?
TypeScript не может использовать директиву imports в package.json
c настройкой "module": "commonjs"
. Получается итоговая сборка должна запускаться в Nodejs использующей esm модули, это далеко не всегда приемлемо. В результате, если хочешь использовать в итоговой сборке commonjs, то надо использовать сборщик, который сделает трансляцию... Это как-то слишком жирно для бэкенд кода.
А с path aliases делаешь просто замену регуляркой в коде /[\.\.\/]+model\/User
=> @model/User
И как бы все
TypeScript не может использовать директиву imports в package.json c настройкой "module": "commonjs".
Можно же настроить paths в tsconfig. Да и кроме того:
Получается итоговая сборка должна запускаться в Nodejs использующей esm модули, это далеко не всегда приемлемо.
На самом деле, не уверен, что остались ещё случаи, где это не приемлемо. Сможете привести пример?
Можно же настроить paths в tsconfig.
Это и правда верно. Но вот проблему c тем, что везде, где подключается папка придется дописать /index
, судя по всему не решается. И с ts-node
и tsx
как-то это все-равно не дружит из коробки.
На самом деле, не уверен, что остались ещё случаи, где это не приемлемо. Сможете привести пример?
Список отличий commonjs vs esm module для Node js. Любой код из npm или свой, который что-то из этого использует придется переписывать или искать альтернативу. Да, и плашка о esm у jest, пока не вдохновляет + плюс тесты придется переписывать
Я, в целом, не начинал этот тред, чтобы спорить с вами :) Просто было странно, что в статье про NODE_PATH и симлинки, например, упомянули, а про эту фичу нет.
Но мне все ещё кажется, что сложность миграции на ESM вы, возможно, преувеличиваете.
Но вот проблему c тем, что везде, где подключается папка придется дописать /index, судя по всему не решается.
Просто по ещё одной автозамене на каждую папку, которая так импортировались.
И с ts-node и tsx как-то это все-равно не дружит из коробки.
С ts-node вроде все должно работать - типизация за счёт paths в tsconfig, сами импорты за счёт самой ноды. Разве нет?
С tsx дела не имел, про него не знаю.
Любой код из npm или свой, который что-то из этого использует придется переписывать или искать альтернативу.
По поводу кода из npm - неправда: ESM-модули могут импортировать CommonJS-модули.
По поводу своего кода: все отличия из вашего списка (при использовании TypeScript) либо решаются плюс-минус автозаменой (__filename
и __dirname
), либо очень редко встречаются в коде (require.extensions
).
Для чистого JS - да, согласен, придется все экспорты на другой синтаксис переписывать.
С Jest - да, может быть проблема. Хотя я вроде не натыкался на баги, несмотря на экспериментальный статус.
del
IMHO, ранее связывание кода (через статические import
'ы на этапе написания кода) уступает по гибкости позднему связыванию (через контейнер объектов, использующий динамический import()
, на этапе выполнения кода). Но сама идея path alias мне нравится - на мой взгляд это ещё один шаг в сторону появления в JS пространств имён (нормальных пространств, как в Java/PHP/C#, а не скоупов).
Вы пишите импорты руками? Зачем их вообще читать? Читайте сам код. Если у вас 500 модулей экспортируют somFn() то тут проблема не в именовании импортов. В противном случае вам вообще не понадобится смотреть на список импортов.
Делаем import/require ясными и красивыми