Deno 1.33: грядет Deno 2

Первоначально опубликовано на deno.com/blog.

Как упоминалось в недавней презентации Принудительная оптимизация на Node Congress 2023», мы усердно работаем над основным выпуском Deno 2 в ближайшие месяцы. Хотя наше видение Deno 2 амбициозно, наши цели не изменились с тех пор, как мы начали проект:

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

Лучшая в своем классе производительность. Скорость и эффективность важны для разработчиков и пользователей. Этот выпуск улучшил производительность серверов HTTP и WebSocket, а также заложил основу для дальнейшей работы над повышением производительности.

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

Deno 1.33 — еще один шаг к этим идеалам. С этим выпуском:

По мере того, как мы приближаемся к Deno 2, следующие второстепенные выпуски будут сосредоточены на повышении производительности, создании лучшего в своем классе опыта для разработчиков, повышении безопасности и более надежной совместимости Node/npm.

Встроенная база данных КВ

Deno KV — это бесшовно интегрированная база данных внутри Deno. Без установки каких-либо зависимостей вы можете сразу приступить к созданию приложений. Кроме того, при развертывании в Deno Deploy ваши данные поддерживаются согласованной глобальной базой данных с геореплицированием. Имейте в виду, что KV в настоящее время является нестабильным API, поэтому для его использования вам понадобится флаг — нестабильности.

Начните работу с KV в кратчайшие сроки и без настройки:

const kv = await Deno.openKv();
const key = ["users", crypto.randomUUID()];
const value = { name: "Alice" };
await kv.set(key, value);
const result = await kv.get(key);
result.value; // { name: "Alice" }

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

Чтобы получить исчерпывающую документацию, изучите руководство.

Плоская deno.json конфигурация

Схема deno.json была упрощена, чтобы ее было легче читать и писать.

Вложенные параметры, такие как "lint.files.exclude" или "fmt.options.lineWidth", теперь доступны на верхнем уровне соответствующих разделов.

Вместо того, чтобы писать это:

{
  "lint": {
    "files": {
      "exclude": ["gen.ts"]
    }
  },
  "fmt": {
    "options": {
      "lineWidth": 80
    }
  }
}

Теперь вы можете написать это с тем же эффектом:

{
  "lint": {
    "exclude": ["gen.ts"]
  },
  "fmt": {
    "lineWidth": 80
  }
}

Все изменения:

Это изменение обратно совместимо, но мы стремимся отказаться от старой схемы в будущем.

Спасибо @scarf005 за внедрение этого изменения.

Меньше проверок разрешений для динамического импорта

В этом выпуске значительно улучшено качество жизни при работе с динамическим импортом.

Если вы используете строковый литерал в вызове import() (например, import("https://deno.land/std/version.ts")), Deno больше не будет требовать разрешения для выполнения этого импорта. Мы уже давно можем загружать и анализировать такие виды импорта, и после обсуждений решили, что лучше не требовать разрешения на выполнение этого кода — он уже является частью «графа модулей» вашей программы и отображается в выход deno info main.ts.

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

Имейте в виду, что разрешения по-прежнему будут проверяться для динамического импорта, который не поддается статическому анализу (т. е. не используйте строковые литералы для спецификатора):

import("" + "https://deno.land/std/version.ts");
import(`https://deno.land/std@${STD_VERSION}/version.ts`);
const someVariable = "./my_mod.ts";
import(someVariable);

Спасибо Найим Рахман за внедрение этого изменения.

Улучшения совместимости npm и Node.

Модуль node:crypto, node:http и node:vm был значительно улучшен по сравнению с последним выпуском. Мы полифилили большинство node:crypto API, которые разблокировали многие популярные пакеты npm (включая SDK облачных провайдеров). Изменения в node:http и node:vm особенно полезны для пользователей Vite, и теперь Vite должен быть намного более стабильным и производительным при использовании с Deno.

Полный список всех API, реализованных в этом релизе:

  • crypto.checkPrime
  • crypto.checkPrimeSync
  • crypto.createSecretKey
  • crypto.createVerify
  • crypto.ECDH
  • crypto.generateKey
  • crypto.generateKeyPair
  • crypto.generateKeyPairSync
  • crypto.generateKeySync
  • crypto.generatePrime
  • crypto.generatePrimeSync
  • crypto.getCurves
  • crypto.hkdf
  • crypto.hkdfSync
  • crypto.sign
  • crypto.Sign
  • crypto.verify
  • crypto.Verify
  • crypto.X509Certificate
  • http.ClientRequest.setTimeout
  • http.IncomingMessage.socket
  • module.Module._preloadModules
  • vm.runInThisContext

Что касается поддержки npm, мы значительно улучшили обработку кеша для пакетов npm. Начиная с этого выпуска, Deno будет пытаться извлечь информацию из реестра, когда обнаружит отсутствующую версию (или несоответствие версий) пакета в кэше. Это должно привести к гораздо меньшему количеству сообщений, предлагающих использовать флаг --reload для получения последней информации реестра.

Улучшения производительности

В этом выпуске мы пересмотрели наши реализации HTTP-сервера, а также клиента и сервера для WebSockets. За последние несколько месяцев мы получили отзывы о том, что API-интерфейсы Deno.serve и WebSocket не так эффективны и надежны, как должны быть.

Мы приняли эти отзывы близко к сердцу и неустанно работаем над их улучшением. Хотя изменения в тестах RPS могут быть еще не видны в ваших приложениях, мы предприняли радикальные шаги для повышения общей производительности этих API, которые мы представим в ближайшие месяцы.

Улучшения интерфейса командной строки

deno bench - --no-run флаг

В этом выпуске к подкоманде deno bench добавлен новый флаг --no-run для кэширования всех разрешенных тестовых файлов без их запуска. Это выравнивает deno bench с deno test.

> deno bench --no-run
Download https://deno.land/[email protected]/path/mod.ts
Download ...etc...
Check file:///home/user/project/main_bench.ts

Спасибо Geert-Jan Zwiers за эту функцию.

deno task - unset команда

Кроссплатформенная команда unset была добавлена ​​в оболочку в deno task, чтобы разрешить удаление переменных среды и оболочки. Это работает так же, как команда POSIX unset, и выполнение MY_VAR= теперь корректно устанавливает пустую переменную.

{
  "tasks": {
    // `deno task example` outputs "1" then "false"
    "example": "export VAR=1 && echo $VAR && deno task next",
    "next": "unset VAR && deno eval 'console.log(Deno.env.has(\"VAR\"))'"
  }
}

Предварительная загрузка документов LSP

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

Обратите внимание, что в рамках этой предварительной загрузки языковой сервер просматривает максимум 1000 записей файловой системы и выводит сообщение журнала, когда это происходит. В тех случаях, когда это проблема и в рабочей области много файлов, не связанных с Deno, вы можете воспользоваться опцией "deno.enablePaths", чтобы частично активировать рабочую область.

Изменения в Deno API

Мы объявляем Deno.run API устаревшим. Со стабилизацией Deno.Command API в версии 1.31 это наш рекомендуемый способ порождения подпроцессов. Deno.run имеет несколько особенностей, которые оказалось трудно решить, и мы направили большую часть наших усилий на разработку лучшего API, который будет проще в использовании. Deno.run будет удалено в версии 2.0, поэтому мы настоятельно рекомендуем вам перенести свой код на Deno.Command.

Нестабильный API Deno.serve получает критическое изменение, удаляя одну из перегрузок API в рамках подготовки к стабилизации этого API. Перегрузка Deno.serve(handler: Deno.ServeHandler, options: Deno.ServeOptions) была удалена и больше не доступна в версии 1.33.

Обновите свой код, чтобы использовать одну из доступных перегрузок:

Deno.serve((_req) => new Response("Hello, world"));
Deno.serve({ port: 3000 }, (_req) => new Response("Hello, world"));
Deno.serve({
  onListen({ port, hostname }) {
    console.log(`Server started at http://${hostname}:${port}`);
    // ... more info specific to your server ..
  },
  handler: (_req) => new Response("Hello, world"),
});

Мы намерены стабилизировать Deno.serve в следующем месяце, и это должно быть предпочтительным API для использования вместо Deno.serveHttp.

Изменения в стандартной библиотеке

Критические изменения в модуле std/encoding

Как было объявлено в предыдущем сообщении о выпуске, следующие 6 модулей кодирования были перемещены на верхний уровень.

  • std/encoding/csv был перемещен в std/csv
  • std/encoding/yaml был перемещен в std/yaml
  • std/encoding/toml был перемещен в std/toml
  • std/encoding/json был перемещен в std/json
  • std/encoding/jsonc был перемещен в std/jsonc
  • std/encoding/front_matter был перемещен в std/front_matter

В этом выпуске эти устаревшие модули полностью удалены. Если вы еще не перешли на новые пути, обновите к ним спецификаторы импорта.

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

{
  "imports": {
    "https://deno.land/std/encoding/yaml.ts": "https://deno.land/[email protected]/encoding/yaml.ts"
  }
}

Это вызывает переназначение неверсионных URL-адресов стандартной библиотеки (в данном случае https://deno.land/std/encoding/yaml.ts) на версионный (https://deno.land/[email protected]/encoding/yaml.ts) во всем вашем графе зависимостей и решит проблему в ваших зависимостях.

Прекращение поддержки fs.exists отменено.

exists и existsSync в модуле std/fs когда-то устарели в v0.111.0, но их устаревание было отменено в этом выпуске.

Эти API устарели из-за их подверженности ошибкам. Они легко вызывают ошибку состояния гонки, известную как TOCTOU. Однако после его устаревания была долгая дискуссия о правильном/достойном использовании о них. Баланс между их удобством и подверженностью ошибкам был пересмотрен, и их было решено восстановить.

Обновления модуля std/csv

В этом выпуске был добавлен CsvStringifyStream API. Этот API преобразует поток исходных данных в поток строк csv.

import { CsvStringifyStream } from "https://deno.land/[email protected]/csv/mod.ts";
import { readableStreamFromIterable } from "https://deno.land/[email protected]/streams/mod.ts";
const file = await Deno.open("data.csv", { create: true, write: true });
const readable = readableStreamFromIterable([
  { id: 1, name: "one" },
  { id: 2, name: "two" },
  { id: 3, name: "three" },
]);
await readable
  .pipeThrough(new CsvStringifyStream({ columns: ["id", "name"] }))
  .pipeThrough(new TextEncoderStream())
  .pipeTo(file.writable);

После вышеупомянутого добавления CsvStream был переименован в CsvParseStream, чтобы уточнить его назначение.

Спасибо Юки Танака за вклад.

V8 11.4

Этот выпуск обновляется до последней версии V8 (11.4, ранее 11.2).

В этом обновлении доступно несколько новых интересных функций JavaScript: