Spec-Zone.ru › Deno 2

Поддержка Node и npm

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

Изучить встроенные API Node

Использование встроенных модулей Node

Deno предоставляет слой совместимости, который позволяет использовать встроенные API Node.js в программах Deno. Однако, для их использования вам необходимо добавить спецификатор node: в любые операторы импорта, которые их используют:

import * as os from "node:os";
console.log(os.cpus());

И запустить его с deno run main.mjs — вы заметите, что получите тот же вывод, что и при запуске программы в Node.js.

Обновление любых импортов в вашем приложении на использование спецификаторов node: должно позволить любому коду, использующему встроенные функции Node, работать так же, как и в Node.js.

Для упрощения обновления существующего кода Deno предоставит полезные подсказки для импортов, которые не используют префикс node::

main.mjs
import * as os from "os";
console.log(os.cpus());
$ deno run main.mjs
error: Relative import path "os" not prefixed with / or ./ or ../
  hint: If you want to use a built-in Node module, add a "node:" prefix (ex. "node:os").
    at file:///main.mjs:1:21

Те же подсказки и дополнительные быстрые исправления предоставляются Deno LSP в вашем редакторе.

Использование пакетов npm

Deno имеет встроенную поддержку импорта пакетов npm, используя спецификаторы npm:. Например:

main.js
import * as emoji from "npm:node-emoji";

console.log(emoji.emojify(`:sauropod: :heart:  npm`));

Можно запустить с:

$ deno run main.js
🦕 ❤️ npm

Префикс npm install не нужен перед командой deno run, и папка node_modules не создается. Эти пакеты также подпадают под те же разрешения, что и другой код в Deno.

Спецификаторы npm имеют следующий формат:

npm:<package-name>[@<version-requirement>][/<sub-path>]

Для примеров с популярными библиотеками, пожалуйста, обратитесь к разделу руководств.

Поддержка CommonJS

CommonJS — это система модулей, которая предшествует модулям ES. Хотя мы твердо верим, что модули ES — это будущее JavaScript, существуют миллионы npm библиотек, написанных на CommonJS, и Deno предлагает полную поддержку для них. Deno автоматически определит, использует ли пакет CommonJS, и сделает его работу бесперебойной при импорте:

main.js
import react from "npm:react";
console.log(react);
$ deno run -E main.js
18.3.1

npm:react — это пакет CommonJS. Deno позволяет импортировать его так, как будто это модуль ES.

Deno настоятельно рекомендует использовать модули ES в вашем коде, но предлагает поддержку CommonJS со следующими ограничениями:

Система разрешений Deno всё ещё действует при использовании модулей CommonJS. Возможно, потребуется предоставить как минимум --allow-read разрешение, поскольку Deno будет исследовать файловую систему в поисках файлов package.json и каталога node_modules для правильного разрешения модулей CommonJS.

Использование расширения .cjs

Если расширение файла .cjs, Deno будет рассматривать этот модуль как CommonJS.

main.cjs
const express = require("express");

Deno не ищет файлов package.json и опцию type для определения, является ли файл CommonJS или ESM.

При использовании CommonJS Deno ожидает, что зависимости будут установлены вручную, и каталог node_modules будет присутствовать. Лучше всего установить "nodeModulesDir": "auto" в ваш deno.json, чтобы гарантировать это.

$ cat deno.json
{
  "nodeModulesDir": "auto"
}

$ deno install npm:express
Add npm:express@5.0.0

$ deno run -R -E main.cjs
[Function: createApplication] {
  application: {
    init: [Function: init],
    defaultConfiguration: [Function: defaultConfiguration],
    ...
  }
}

Флаги -R и -E используются для предоставления разрешений на чтение файлов и переменных окружения.

Опция типа package.json

Deno попытается загрузить файлы .js, .jsx, .ts и .tsx как CommonJS, если есть файл package.json с опцией "type": "commonjs" рядом с файлом или выше по дереву каталогов в проекте с файлом package.json.

package.json
{
  "type": "commonjs"
}
main.js
const express = require("express");

Инструменты, такие как бандлер Next.js и другие, будут автоматически генерировать файл package.json подобного формата.

Если у вас есть существующий проект, использующий модули CommonJS, вы можете заставить его работать как с Node.js, так и с Deno, добавив опцию "type": "commonjs" в файл package.json.

Всегда обнаруживать, может ли файл быть CommonJS

Возможно, указать Deno анализировать модули как потенциально CommonJS, запустив его с флагом --unstable-detect-cjs в Deno >= 2.1.2. Это применится, за исключением случаев, когда есть файл package.json с { "type": "module" }.

Поиск файлов package.json в файловой системе и анализ модуля для определения, является ли он CommonJS, занимает больше времени, чем если этого не делать. По этой причине и для отговаривания от использования CommonJS, Deno не делает этого по умолчанию.

Создать require() вручную

Альтернативный вариант — создать экземпляр функции require() вручную:

main.js
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const express = require("express");

В этом случае применяются те же требования, что и при работе с файлами .cjs — зависимости нужно устанавливать вручную и предоставлять соответствующие флаги разрешений.

require(ESM)

Реализация Deno для require() поддерживает требование модулей ES.

Это работает так же, как и в Node.js, где вы можете только require() модули ES, которые не содержат Top-Level Await в их модульной графе — или, другими словами, вы можете только require() модули ES, которые являются «синхронными».

greet.js
export function greet(name) {
  return `Hello ${name}`;
}
esm.js
import { greet } from "./greet.js";

export { greet };
main.cjs
const esm = require("./esm");
console.log(esm);
console.log(esm.greet("Deno"));
$ deno run -R main.cjs
[Module: null prototype] { greet: [Function: greet] }
Hello Deno

Импортирование модулей CommonJS

Вы также можете импортировать файлы CommonJS в модули ES.

greet.cjs
module.exports = {
  hello: "world",
};
main.js
import greet from "./greet.js";
console.log(greet);
$ deno run main.js
{
  "hello": "world"
}

Подсказки и предложения

Deno предоставит полезные подсказки и предложения, чтобы помочь вам работать с кодом CommonJS.

Например, если вы попытаетесь запустить модуль CommonJS, у которого нет расширения .cjs или у которого нет файла package.json с { "type": "commonjs" }, вы можете увидеть это:

main.js
module.exports = {
  hello: "world",
};
$ deno run main.js
error: Uncaught (in promise) ReferenceError: module is not defined
module.exports = {
^
    at file:///main.js:1:1

    info: Deno supports CommonJS modules in .cjs files, or when the closest
          package.json has a "type": "commonjs" option.
    hint: Rewrite this module to ESM,
          or change the file extension to .cjs,
          or add package.json next to the file with "type": "commonjs" option,
          or pass --unstable-detect-cjs flag to detect CommonJS when loading.
    docs: https://docs.deno.com/go/commonjs

Импорт типов

Многие пакеты npm поставляются с типами. Вы можете импортировать их и использовать напрямую:

import chalk from "npm:chalk@5";

Некоторые пакеты не поставляются с типами, но вы можете указать их типы с помощью директивы @deno-types. Например, используя пакет @types:

// @deno-types="npm:@types/express@^4.17"
import express from "npm:express@^4.17";

Разрешение модулей

Официальный компилятор TypeScript tsc поддерживает различные настройки moduleResolution. Deno поддерживает только современное разрешение node16. К сожалению, многие пакеты npm не обеспечивают правильную поддержку типов с разрешением модулей node16, что может привести к тому, что deno check сообщит об ошибках типов, которые tsc не сообщает.

Если экспорт по умолчанию из импорта npm: кажется неправильным типом (при этом правильный тип, по-видимому, доступен в свойстве .default), скорее всего, пакет предоставляет неверные типы для импорта из ESM с разрешением модулей node16. Вы можете проверить это, проверив, появляется ли ошибка и с tsc --module node16 и "type": "module" в package.json или проконсультировавшись со сайтом «Are the types wrong?» (в частности, строка «node16 from ESM»).

Если вы хотите использовать пакет, который не поддерживает разрешение модулей node16 TypeScript, вы можете:

  1. Открыть вопрос на трекере проблем пакета по этой проблеме. (И, возможно, внести свой вклад в исправление 😃 (Хотя, к сожалению, отсутствует инструментарий для пакетов, поддерживающих как ESM, так и CJS, поскольку экспорты по умолчанию требуют разного синтаксиса. См. также microsoft/TypeScript#54593)
  2. Использовать CDN, который пересобирает пакеты для поддержки Deno, вместо идентификатора npm:.
  3. Игнорировать ошибки типов, которые появляются в вашем коде с // @ts-expect-error или // @ts-ignore.

Включение типов Node

Node поставляет множество встроенных типов, таких как Buffer, которые могут быть упомянуты в типах пакета npm. Для их загрузки необходимо добавить директиву ссылки на типы в пакет @types/node:

/// <reference types="npm:@types/node" />

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

Исполнимые скрипты npm

Пакеты npm со скриптами bin могут быть запущены из командной строки без npm install с помощью спецификатора в следующем формате:

npm:<package-name>[@<version-requirement>][/<binary-name>]

Например:

$ deno run --allow-read npm:cowsay@1.5.0 "Hello there!"
 ______________
< Hello there! >
 --------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

$ deno run --allow-read npm:cowsay@1.5.0/cowthink "What to eat?"
 ______________
( What to eat? )
 --------------
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

node_modules

При запуске npm install, npm создает каталог node_modules в вашем проекте, содержащий зависимости, указанные в файле package.json.

Deno использует спецификаторы npm для разрешения пакетов npm в центральном глобальном кэше npm, вместо использования папки node_modules в ваших проектах. Это идеально, так как оно использует меньше места и поддерживает чистоту каталога вашего проекта.

Однако могут быть случаи, когда вам понадобится локальная папка node_modules в вашем проекте Deno, даже если у вас нет package.json (например, при использовании фреймворков, таких как Next.js или Svelte, или при зависимости от пакетов npm, использующих Node-API).

Поведение зависимостей Deno по умолчанию

По умолчанию Deno не будет создавать папку node_modules при использовании команды deno run, зависимости будут установлены в глобальный кэш. Это рекомендуемая настройка для новых проектов Deno.

Автоматическое создание node_modules

Если вам нужна папка node_modules в вашем проекте, вы можете использовать флаг --node-modules-dir или опцию nodeModulesDir: auto в файле конфигурации, чтобы указать Deno на создание папки node_modules в текущей рабочей директории:

deno run --node-modules-dir=auto main.ts

или с помощью файла конфигурации:

deno.json
{
  "nodeModulesDir": "auto"
}

Автоматический режим автоматически устанавливает зависимости в глобальный кэш и создаёт локальную папку node_modules в корне проекта. Это рекомендуется для проектов, имеющих зависимости npm, которые полагаются на папку node_modules — в основном для проектов, использующих бандлеры или те, которые имеют npm зависимости с скриптами postinstall.

Ручное создание node_modules

Если в вашем проекте есть файл package.json, вы можете использовать режим ручного управления, который требует шага установки для создания вашей папки node_modules:

deno install
deno run --node-modules-dir=manual main.ts

или с помощью файла конфигурации:

deno.json
{ "nodeModulesDir": "manual" }

Затем вы запустите deno install/npm install/pnpm install или любой другой менеджер пакетов, чтобы создать папку node_modules.

Режим ручного управления является режимом по умолчанию для проектов, использующих package.json. Вы можете узнать этот рабочий процесс из проектов Node.js. Рекомендуется для проектов, использующих фреймворки, такие как Next.js, Remix, Svelte, Qwik и т. д., или инструменты, такие как Vite, Parcel или Rollup.

Примечание

Мы рекомендуем использовать режим по умолчанию none, и переходить к режиму auto или manual, если вы получите ошибки о недостающих пакетах внутри папки node_modules.

node_modules с Deno 1.X

Используйте флаг --node-modules-dir.

Например, дан main.ts:

import chalk from "npm:chalk@5";

console.log(chalk.green("Hello"));
deno run --node-modules-dir main.ts

Выполнение приведенной выше команды с флагом --node-modules-dir создаст папку node_modules в текущей директории со структурой папок, похожей на npm.

Глобальные объекты Node.js

В Node.js имеется ряд глобальных объектов, доступных в области видимости всех программ, специфичных для Node.js, например, объект process.

Вот несколько глобальных объектов, которые вы можете встретить в дикой природе, и как использовать их в Deno:

  • process - Deno предоставляет глобальный объект process, который является, пожалуй, самым популярным глобальным объектом, используемым в популярных пакетах npm. Он доступен для всего кода. Однако Deno направит вас к явным импортам из модуля node:process с помощью предупреждений проверки и быстрых исправлений:
process.js
console.log(process.versions.deno);
$ deno run process.js
2.0.0
$ deno lint process.js
error[no-process-globals]: NodeJS process global is discouraged in Deno
 --> /process.js:1:13
  |
1 | console.log(process.versions.deno);
  |             ^^^^^^^
  = hint: Add `import process from "node:process";`

  docs: https://lint.deno.land/rules/no-process-globals


Found 1 problem (1 fixable via --fix)
Checked 1 file
  • require() - см. поддержку CommonJS

  • Buffer - для использования API Buffer необходимо явно импортировать его из модуля node:buffer:

buffer.js
import { Buffer } from "node:buffer";

const buf = new Buffer(5, "0");

Предпочтительнее использовать Uint8Array или другие подклассы TypedArray вместо этого.

  • __filename - используйте import.meta.filename вместо этого.

  • __dirname - используйте import.meta.dirname вместо этого.

Дополнения Node-API

Deno поддерживает дополнения Node-API, которые используются популярными пакетами npm, такими как esbuild, npm:sqlite3 или npm:duckdb.

Вы можете ожидать, что все пакеты, использующие публичные и документированные Node-API, будут работать.

Информация

Большинство пакетов, использующих дополнения Node-API, полагаются на npm "скрипты жизненного цикла", такие как postinstall.

Хотя Deno их поддерживает, они не выполняются по умолчанию из-за соображений безопасности. Подробнее в deno install документации.

Начиная с Deno 2.0, пакеты npm, использующие дополнения Node-API, поддерживаются только при наличии папки node_modules/. Добавьте "nodeModulesDir": "auto" или "nodeModulesDir": "manual" в свой файл deno.json, или запустите с флагом --node-modules-dir=auto|manual для правильной работы этих пакетов. В случае неправильной настройки Deno предоставит подсказки, как можно решить ситуацию.

Миграция с Node на Deno

Запуск вашего проекта Node.js с помощью Deno — это простой процесс. В большинстве случаев вы можете ожидать небольших или вообще никаких изменений, если ваш проект написан с использованием ES-модулей.

Основные моменты, о которых следует знать:

  1. Импорт встроенных модулей Node.js требует спецификатора node::
// ❌
import * as fs from "fs";
import * as http from "http";

// ✅
import * as fs from "node:fs";
import * as http from "node:http";
Подсказка

Рекомендуется изменить эти спецификаторы импорта в вашем существующем проекте. Это рекомендуемый способ их импорта и в Node.js.

  1. Некоторые глобальные объекты, доступные в Node.js, должны быть явно импортированы, например, Buffer:
import { Buffer } from "node:buffer";
  1. require() доступен только в файлах с расширением .cjs, в других файлах экземпляр require() нужно создать вручную. Зависимости npm могут использовать require() независимо от расширения файла.

Запуск скриптов

Deno поддерживает запуск npm скриптов непосредственно с помощью подкоманды deno task (если вы мигрируете с Node.js, это аналогично команде npm run script). Рассмотрим следующий проект Node.js со скриптом под названием start внутри папки package.json:

package.json
{
  "name": "my-project",
  "scripts": {
    "start": "eslint"
  }
}

Вы можете выполнить этот скрипт с помощью Deno, выполнив:

deno task start

Дополнительные улучшения

Одним из основных преимуществ Deno является унифицированная среда разработки, которая поставляется с поддержкой TypeScript «из коробки», а также инструментами, такими как проверка кода, форматирование и система тестирования. Переход на Deno позволяет упростить вашу цепочку инструментов и уменьшить количество движущихся компонентов в вашем проекте.

Настройка

Deno имеет свой собственный файл конфигурации, deno.json или deno.jsonc, который можно использовать для настройки вашего проекта.

Вы можете использовать его для определения зависимостей с помощью опции imports — вы можете мигрировать зависимости по одной, из package.json, или выбрать не определять их в файле конфигурации вообще и использовать спецификаторы npm: непосредственно в вашем коде.

В дополнение к указанию зависимостей вы можете использовать deno.json для определения задач, опций проверки и форматирования, сопоставлений путей и других параметров времени выполнения.

Проверка кода

Deno поставляется со встроенным анализатором кода, написанным с учётом производительности. Он похож на ESlint, но с ограниченным количеством правил. Если вы не полагаетесь на плагины ESLint, вы можете удалить зависимость eslint из раздела devDependencies вашего файла package.json и использовать deno lint вместо него.

Deno может проверять большие проекты всего за несколько миллисекунд. Вы можете попробовать это на своём проекте, выполнив:

deno lint

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

error[no-constant-condition]: Use of a constant expressions as conditions is not allowed.
 --> /my-project/bar.ts:1:5
  | 
1 | if (true) {
  |     ^^^^
  = hint: Remove the constant expression

  docs: https://lint.deno.land/rules/no-constant-condition


Found 1 problem
Checked 4 files

Многие проблемы с проверкой кода могут быть автоматически исправлены, передав флаг --fix:

deno lint --fix

Полный список всех поддерживаемых правил проверки кода можно найти на https://lint.deno.land/. Чтобы узнать больше о настройке анализатора кода, ознакомьтесь с deno lint подкомандой.

Форматирование

Deno поставляется со встроенным форматированием, которое может по желанию отформатировать ваш код в соответствии со стилем руководства по стилю Deno. Вместо добавления prettier в devDependencies вы можете использовать встроенный форматировщик кода Deno без конфигурации deno fmt.

Вы можете запустить форматировщик на своём проекте, выполнив:

deno fmt

Если вы используете deno fmt в CI, вы можете передать аргумент --check для выхода форматировщика с ошибкой при обнаружении неправильно отформатированного кода.

deno fmt --check

Правила форматирования можно настроить в вашем файле deno.json. Чтобы узнать больше о настройке форматировщика, ознакомьтесь с deno fmt подкомандой.

Тестирование

Deno рекомендует писать тесты для вашего кода и предоставляет встроенный тестовый запуск, чтобы упростить написание и выполнение тестов. Тестовый запуск тесно интегрирован в Deno, так что вам не нужно выполнять дополнительную настройку, чтобы заставить работать TypeScript или другие функции.

my_test.ts
Deno.test("my test", () => {
  // Your test code here
});
deno test

При передаче флага --watch, тестовый запуск автоматически перезагрузится, если какие-либо из импортированных модулей изменятся.

Чтобы узнать больше о тестовом запуске и о том, как его настроить, ознакомьтесь с документацией подкоманды deno test.

Приватные репозитории

Внимание

Не следует путать с приватными репозиториями и модулями.

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

Что такое приватные репозитории?

Крупные организации часто размещают собственные приватные npm репозитории, чтобы безопасно управлять внутренними пакетами. Эти приватные репозитории служат хранилищами, где организации могут публиковать и хранить свои собственные или пользовательские пакеты. В отличие от публичных npm репозиториев, к приватным репозиториям имеют доступ только авторизованные пользователи внутри организации.

Как использовать приватные репозитории с Deno

Сначала настройте файл .npmrc, чтобы указать на ваш приватный репозиторий. Файл .npmrc должен находиться в корне проекта или в директории $HOME. Добавьте следующее в свой файл .npmrc.

@mycompany:registry=http://mycompany.com:8111/
//mycompany.com:8111/:_auth=secretToken

Замените http://mycompany.com:8111/ на фактический URL вашего приватного репозитория и secretToken на ваш токен аутентификации.

Затем обновите файл deno.json или package.json, чтобы указать путь импорта для вашего приватного пакета. Например:

deno.json
{
  "imports": {
    "@mycompany/package": "npm:@mycompany/package@1.0.0"
  }
}

или, если вы используете package.json:

package.json
{
  "dependencies": {
    "@mycompany/package": "1.0.0"
  }
}

Теперь вы можете импортировать свой приватный пакет в свой код Deno:

main.ts
import { hello } from "@mycompany/package";

console.log(hello());

и запустить его с помощью команды deno run:

deno run main.ts

Справочник по переходу с Node.js на Deno

Node.js Deno
node file.js deno file.js
ts-node file.ts deno file.ts
nodemon deno run --watch
node -e deno eval
npm i / npm install deno install
npm install -g deno install -g
npm run deno task
eslint deno lint
prettier deno fmt
package.json deno.json или package.json
tsc deno check ¹
typedoc deno doc
jest / ava / mocha / tap / и т.д. deno test
nexe / pkg deno compile
npm explain deno info
nvm / n / fnm deno upgrade
tsserver deno lsp
nyc / c8 / istanbul deno coverage
benchmarks deno bench

¹ Проверка типов происходит автоматически, компилятор TypeScript встроен в исполняемый файл deno.

© 2018–2024 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/fundamentals/node

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API