Deno Deploy закроют через примерно полгода после 9 октября 2026 — то есть ориентировочно весной 2027 (точный день берите из официального анонса в момент переезда, а не из этой статьи: сроки — «another year» и «six months» относительным интервалом, они двигаются). Если ваше приложение живёт на Deno Deploy и вы выбрали Путь A из первой статьи серии, эта статья — про то, как физически перенести код.
Главный вывод, к которому мы будем приходить всю статью и который экономит неделю сюрпризов: Deno и Workers — оба «современный JavaScript/TypeScript-рантайм», но совместимы они не полностью. И почти всё, что при переносе ломается, ломается не из-за языка (тот один и тот же TS/ES-модули, тот же async/await, та же Fetch API), а из-за способа достучаться до ресурсов: в Deno вы обращаетесь к системе напрямую — Deno.env, Deno.serve, URL-import, npm:; в Workers вам эти ресурсы присваивает платформа через аргумент env и через конфигурационный файл wrangler. Меняется не синтаксис функций, а архитектура доступа.
Разберём это по слоям: точка входа, конфигурация, данные, планировщик и вебсокеты, — и в конце соберём порядок переезда (runbook) с тестом и откатом. Код абстрактный (домены условные example.test); имена API и синтаксис wrangler — сверяйте по документации Cloudflare в день внедрения, это живая поверхность.
Про имена «воркеров». Здесь речь только про серверный рантайм Cloudflare Workers (entry-хендлер на edge), а не про браузерный Service Worker из соответствующей статьи — тот для офлайн-кэша в клиенте, тут он ни при чём.
Часть I. Ментальная модель: почему это не «переименовать функции»
Прежде чем трогать код, зафиксируем разницу мировоззрений — она объясняет, откуда возьмутся все правки ниже.
1. Deno: рантайм, которому принадлежат ресурсы
Deno — это самостоятельный исполняемый рантайм на сервере. Когда вы пишете:
const token = Deno.env.get("API_TOKEN");
const { socket, response } = Deno.upgradeWebSocket(request);
await Deno.kv.get("user:42");
вы напрямую зовёте API своего процесса: окружение — у Deno, файловая система и сеть — тоже, KV-клиент — глобальный. Программа сама решает, откуда что взять. Гибко, но каждый инстанс приложения сам собирается с инфраструктурой: дал описывал этот опыт как источник сложности Deno Deploy («multiple public clouds, multiple databases, deeply entangled services»).
2. Workers: модель «привязок» (bindings)
Cloudflare Workers переворачивают это. Ваш код — это обработчик, который платформа вызывает, передавая ему три вещи:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
// request — входящий HTTP-запрос (стандартный Fetch API)
// env — ВСЕ ресурсы этого воркера: KV, D1, R2, секреты, vars — как свойства
// ctx — контекст выполнения (ctx.waitUntil(...) для фоновой работы)
return new Response("ok");
},
};
Никакого глобального Deno.*. Хотите ключ-значение-хранилище — вы не импортируете клиент, а объявляете биндинг в wrangler.toml, и он материализуется полем в env. Хотите секрет — он тоже приходит в env (но не через [vars], см. Часть III). Хотите подключить БД — [[d1_databases]], и в env.MY_DB появится объект с методами. Это то, что Дал в анонсе сделки хвалил отдельно: «live environment design … одновременно делает настройку доступа к внешним ресурсам проще и безопаснее» — потому что код не тащет секреты в себе и не выбирает ресурсы сам, а получает их извне.
3. Что это значит для объёма работ
Перенос — это не sed -i 's/Deno.env/env./'. Это три разнородных задачи:
- Переписать точку входа с императивного
Deno.serve(...)на декларативный экспорт{ fetch, scheduled }(Часть II). - Перенести конфигурацию ресурсов из кода/флагов запуска в
wrangler.toml(Часть III). - Разобраться с зависимостями: URL- и
npm:-импорты, Node-API (Часть IV).
И отдельно — то, что не имеет прямого аналога: cron и вебсокеты (Часть V). Если вы понимаете эту трёхслойную разбивку, объём миграции перестаёт быть сюрпризом.
4. Таблица «едет 1-в-1 / переписывается»
| Слой Deno | В Workers | Степень |
|---|---|---|
Request, Response, request.url/method/headers | те же типы Fetch API | почти без правок |
Deno.serve((req) => ...) | export default { fetch(req, env, ctx) {...} } | переписать точку входа |
Deno.env.get("X") (не-секрет) | [vars] → env.X | правка + конфиг |
| секрет из env | wrangler secret / [secrets] → env.X | правка + конфиг (без секрета в [vars]) |
import ... from "https://..." | бандлер решает на деплое (wrangler + esbuild) | переписать импорты на npm-пакеты |
import ... from "npm:pkg" | pkg из package.json + флаг nodejs_compat | правка + конфиг |
Deno.kv | [[kv_namespaces]] → env.MY_KV | API похож, но не идентичен |
| Deno Deploy static / раздача файлов | [assets] directory="./dist" | убрать код раздачи |
| Deno Deploy cron | [triggers] crons=[...] → метод scheduled | выражение то же, хендлер другой |
Deno.upgradeWebSocket | WebSocket в Durable Object (WebSocketPair) | переписать на DO |
Дальше по каждой строке — примеры.
Часть II. Точка входа: с Deno.serve на export default { fetch }
1. До: императивный сервер
Типичное небольшое приложение на Deno:
// main.ts — ДО (Deno)
Deno.serve((request: Request): Response => {
const url = new URL(request.url);
if (url.pathname === "/api/health") {
return Response.json({ ok: true });
}
if (url.pathname.startsWith("/api/users/")) {
const id = url.pathname.split("/").pop();
const token = Deno.env.get("API_TOKEN"); // читает окружение сам
// ... обращение к данным ...
return new Response(JSON.stringify({ id }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
return new Response("not found", { status: 404 });
});
Обратите внимание: здесь есть и приём запроса, и маршрутизация, и доступ к окружению — всё в одном процессе, всё напрямую.
2. После: экспорт хендлеров
В Workers вы не запускаете сервер — сервер это платформа. Вы экспортируете объект с методом fetch:
// src/index.ts — ПОСЛЕ (Workers)
export interface Env {
API_TOKEN: string; // секрет или var — придут в env, см. Часть III
MY_KV: KVNamespace; // биндинг KV — материализуется из wrangler.toml
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/health") {
return Response.json({ ok: true });
}
if (url.pathname.startsWith("/api/users/")) {
const id = url.pathname.split("/").pop();
const token = env.API_TOKEN; // НЕ Deno.env.get — ресурс присвоен в env
// ... обращение к данным через env.MY_KV ...
return new Response(JSON.stringify({ id }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
return new Response("not found", { status: 404 });
},
};
Что изменилось и что нет:
- Не изменилось тело маршрутизации и конструирования ответов:
new URL(request.url),request.pathname-логика,new Response(...),Response.json(...)— тот же стандартный Fetch API. Это и есть половина переносимого кода. - Изменилась сигнатура: вместо лямбды в
Deno.serve— методfetch(request, env, ctx). Все три аргумента даёт платформа.env— новый «карман» ресурсов,ctx— контекст (черезctx.waitUntil(promise)можно не ждать фоновой работы перед ответом). - Изменился доступ к окружению:
Deno.env.get("API_TOKEN")→env.API_TOKEN. Значение живёт не в коде, а в конфиге/секретах (Часть III). asyncстал нормой: рантайм воркеров рассчитывает наPromise<Response>, поэтому метод помечаютasyncдаже когда внутри пока нетawait(потомawaitпоявится — для KV/БД).
3. Маршрутизация: в коде или в конфиге
В Deno Deploy часто один serve-хендлер и развилки по pathname. В Workers схема та же, но есть второй, декларативный уровень: вы можете вообще не писать if-по-путям, а навесить несколько воркеров на разные пути через [[routes]] (см. Часть III) и не трогать код. Правило большого пальца для миграции: маршрутизацию, которая у вас уже в коде, оставьте в коде — это переносится один-в-один; в [[routes]] переходите, когда захотите развести статику и API. Там же [assets] run_worker_first решает, какие пути идут в воркер, а какие отдаются как файлы.
4. Частая ошибка точки входа
Забытый default export или случайный export const handler = ... (стиль AWS Lambda) — воркер задеплоится и будет отдавать ошибку вызова. Проверяйте на wrangler dev, а не «глазком»: локальный домен эмулирует платформу и поймает это до прода.
Часть III. Конфигурация: wrangler.toml — то место, где переезжает инфраструктура
В Deno Deploy конфигурация размазана: часть в флагах запуска, часть в дашборде проекта, часть в самом коде (Deno.env, глобальный Deno.kv). В Workers best practice — считать wrangler.toml источником правды (формулировка Cloudflare: «treat Wrangler’s configuration file as the source of truth»). Ниже — ключевые секции для типового переезда. Синтаксис взят из официальной страницы конфигурации Wrangler (2026-10-29); имена ключей точные, значения-плейсхолдеры условные.
1. Каркас
# wrangler.toml
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "my-worker" # [a-z0-9-], без подчёркивания
main = "src/index.ts" # путь к entry-модулю, который будет исполняться
compatibility_date = "2026-11-06" # версия рантайма; ставят на дату деплоя
account_id = "<YOUR_ACCOUNT_ID>"
compatibility_date — не косметика: Workers меняют поведение по датам, и это фиксирует, какой «срез» рантайма вам обещан. Ставьте актуальную на деплой дату и не откатывайте назад без причины.
2. Переменные и секреты: [vars] против зашифрованного биндинга
Открытые (не-секретные) значения объявляются прямо в конфиге — это замена нечувствительным Deno.env:
[vars]
API_HOST = "api.example.test"
FEATURE_X = "on"
Они попадут в env.API_HOST, env.FEATURE_X. Но секреты так не делают — [vars] хранит plain-текст. Секрет — это отдельный тип биндинга с зашифрованным значением (на странице конфигурации прямо разделено: «vars — map of environment variables», «Secrets — a type of binding that allow you to attach encrypted text values»). Два рабочих способа завести секрет, и оба вне [vars]:
- для локальной разработки — файл
.dev.varsв корне проекта (dotenv-формат):# .dev.vars — не коммитить! API_TOKEN="local-secret-do-not-commit" - для прода — значение вне репозитория: декларативно объявить, что секрет нужен (и тогда деплой его проверит), и задать командой/дашбордом:
[secrets] required = [ "API_TOKEN" ]Это объявление имени, а не значение. Само значение секрета в код/конфиг не попадает — его прикладывает `wrangler secret` (семейство команд `secret` со страницей команды `wrangler secret delete <key>`; точный набор подкоманд берите со страницы команд Wrangler — на странице конфигурации он не перечислен дословно) или через дашборд Cloudflare.
В коде и то, и другое читается одинаково: env.API_TOKEN, env.API_HOST. Для мигрирующего с Deno это чистая победа: токен больше не зашит в процесс, а приходит снаружи.
3. Хранилища: KV, D1, R2 — как биндинги
Workers KV (ключ-значение, ближний к Deno.kv):
[[kv_namespaces]]
binding = "MY_KV"
id = "<NAMESPACE_ID>"
# preview_id = "<STAGING_ID>" # для wrangler dev --remote
В коде — env.MY_KV.get(...), env.MY_KV.put(...).
D1 (serverless SQL, если на Deno был Deno SQLite / внешняя Postgres-подобная БД):
[[d1_databases]]
binding = "MY_DB"
database_name = "app-db"
database_id = "<DATABASE_ID>"
# preview_database_id = "<STAGING_DB_ID>"
migrations_dir = "migrations"
В коде — env.MY_DB.prepare(...).bind(...).all(). Схема миграций переносится папкой SQL (поле migrations_dir); тут важно — D1 это не Postgres и не ваш старый движок, SQL-диалект и API другие, это отдельная работа по данным, не механический перенос.
R2 (объекты, без egress-платы — если Deno писал файлы/загрузки куда-то):
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "uploads"
В коде — env.MY_BUCKET.put(...), .get(...).
Лайфхак автопровижининга: можно объявить биндинг без id/bucket_name — тогда wrangler deploy создаст ресурс сам и впишет id обратно в конфиг. Удобно при первом переезде, чтобы не гонять дашборд руками. (На странице: автосоздание работает для KV, R2, D1 и др.)
4. Статика: [assets] вместо ручной раздачи файлов
Если на Deno вы сами читали файлы и отдавали их (или relied на фреймворковый статик-сервер), в Workers это declaratively:
[assets]
directory = "./dist" # папка собранных статик-ресурсов
binding = "ASSETS"
not_found_handling = "404-page"
Ключевое поле при смешанном приложении — run_worker_first: какие пути идут в воркер (API), а какие отдаются как файлы:
[assets]
directory = "./dist"
binding = "ASSETS"
run_worker_first = [ "/api/*" ] # /api/* зовёт fetch(); всё остальное — статика
Это позволяет не городить статик-логику в fetch — просто убрать её из кода и объявить здесь. Легаси [site] bucket=... (Workers Sites) помечен deprecated — на новых проектах используйте [assets].
5. Домен и триггеры
Привязка воркера к домену (замена «домена» Deno Deploy-проекта) — через [[routes]]. Свой домен, отдаваемый воркеру целиком:
[[routes]]
pattern = "app.example.test"
custom_domain = true
или путь внутри зоны, которой управляет Cloudflare:
[[routes]]
pattern = "example.test/api/*"
zone_name = "example.test"
Пока не переключили DNS — воркер доступен на поддомене *.workers.dev (workers_dev = true, значение по умолчанию, когда нет routes). Это даёт нам в Части VI способ держать старый и новый прод параллельно и переключиться позже.
Планировщик (cron) — в Части V, потому что там меняется не только конфиг, но и код хендлера.
Часть IV. Данные и зависимости: URL-import, npm: и Node-API
Это место, где миграция реально кусается, и где честнее всего сказать «один-в-один не едет».
1. Рантайм-импорты по URL исчезают
В Deno идиоматично тянуть модуль прямо по https:
// ДО — так в Deno работают
import { z } from "https://esm.sh/zod@3";
В Workers так нельзя: нет загрузки произвольного удалённого модуля в рантайме по запросу. Модули разрешаются бандлером на этапе деплоя (wrangler использует esbuild). Правильный перенос — обычные npm-зависимости:
npm install zod@3
// ПОСЛЕ — bare-спецификатор, соберётся при деплое
import { z } from "zod";
То есть часть «магии URL-import», за которую любят Deno, при переезде сознательно теряется ради собираемости: вместо обращения к сети за кодом в рантайме — фиксированный бандл, заложенный в воркер. Для воспроизводимости это хорошо, для привычки «подменил URL — поменялась библиотека» — нет.
2. npm:-модули и флаг совместимости
Deno тянет npm-пакеты префиксом npm:. В Workers вы устанавливаете их в package.json (как выше), но если пакет рассчитан на Node-API, нужен флаг совместимости:
compatibility_flags = [ "nodejs_compat_v2" ]
(именно nodejs_compat_v2 фигурирует в официальных примерах конфига — напр., для драйверов БД; набор флагов и их поведение — живые, сверяйте по доке Workers про Node-API).
3. Node-модули вроде fs, http: полифилл и алиас
Самое контринтуитивное для пришедших с Deno: у рантайма воркеров нет полноценной файловой системы и части Node-модулей — на странице конфигурации это видно косвенно: чтобы npm-пакет, зовущий fs.readFile или полагающийся на node-fetch (который «не работает на Workers, потому что опирается на неподдерживаемые Node.js-API из http/https»), не падал, модуль можно алиасить на полифилл:
[alias]
fs = "./fs-polyfill"
Практический вывод: если у вас зависимость пишет файлы через fs, это не «примет и заработает» — либо пакет переписан под Fetch/caches, либо нужен полифилл через [alias], либо функциональность (хранение файлов) переносится на R2 (env.MY_BUCKET), что обычно и есть правильный путь: вместо «записать в ФС» — «положить объект в бакет».
4. Deno KV → Workers KV: API похож, но не тот
Наивная замена Deno.kv.get("user:42") → env.MY_KV.get("user:42") кажется механической и в простых чтениях почти ею и является. Но не ждите полной идентичности: у Workers KV свои get(..., { type }) (текст/JSON/ArrayBuffer/stream), своя работа с метаданными и у list/get — пагинация курсором; а часть сценариев Deno KV (транзакции, strong-consistency) ближе к Durable Objects, а не к глобальному KV. Правило: обычный кэш/конфиг → KV; данные, где важна согласованность и локальная запись → D1 или DO (про DO — статья про self-hosting и разбор примитивов хранения в серии).
Часть V. Планировщик и вебсокеты: то, что не имеет прямого двойника
1. Cron: выражение переезжает, хендлер — нет
Хорошая новость: cron-выражение менять не надо — и Deno Deploy, и Workers Cron Triggers трактуют время в UTC, выражение из старой записи переносится как есть (это отмечает и независимое руководство по переезду: «cron-выражение можно перенести без изменений»). Плохая — точка входа другая.
# wrangler.toml
[triggers]
crons = [ "0 */6 * * *" ] # каждые 6 часов, UTC — как и было на Deno
На Deno у cron-кода был свой callback; в Workers вы добавляете метод scheduled рядом с fetch в тот же экспорт:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
// ... HTTP-трафик ...
},
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext) {
// фоновое задание по cron; await делать нельзя надолго — длинное в ctx.waitUntil(...)
const res = await env.MY_KV.put("last-run", new Date().toISOString());
// ... агрегация, выборки, отправка ...
},
};
Разница модели: cron воркера должен быть быстрым и не «висеть» — долгую работу оформляют через ctx.waitUntil() или, если она большая, через Queues (продакшн-очереди у Workers — свой биндинг; это смежно с разбором очередей сообщений). Дисконнект: если у вас на Deno был долгий cron, не тащите его «как есть» — разбейте на постановку в очередь.
2. Вебсокеты: upgradeWebSocket → Durable Object
Это самая непереносимая часть. На Deno вы апгрейдили соединение напрямую:
// ДО (Deno)
const { socket, response } = Deno.upgradeWebSocket(request);
socket.onmessage = (e) => { /* ... */ };
return response;
У Workers нет stateful-глобального сокета внутри fetch: инстанс хендлера одноразовый. Долгоживущее соединение с памятью — это Durable Object («адресуемый маленький сервер с базой», тот самый примитив из первой статьи). Схема: воркер в fetch создаёт/находит DO и передаёт ему сокет через WebSocketPair, а сам DO держит обработчики сообщений:
// ПОСЛЕ (Workers): stateful-сокет живёт в Durable Object
import { WebSocketPair } from "cloudflare:sockets";
export class ChatDO extends DurableObject {
async fetch(request: Request) {
const pair = new WebSocketPair();
const [client, server] = Object.values(pair);
this.ctx.accept(server); // DO владеет живым сокетом
server.addEventListener("message", (ev) => { /*broadcast/состояние*/ });
return new Response(null, { status: 101, webSocket: client });
}
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const id = env.CHAT.idFromName("room-" + new URL(request.url).pathname);
const stub = env.CHAT.get(id); // адресация DO по имени комнаты
return stub.fetch(request); // отдаём сокет-апгрейд конкретному DO
},
};
CHAT — биндинг Durable Object:
[[durable_objects.bindings]]
name = "CHAT"
class_name = "ChatDO"
[exports.ChatDO]
type = "durable-object"
storage = "sqlite"
Вывод из этого один: если ваше Deno-приложение держит реалтайм-сокеты, перенос — не про «скопировать хендлер», а про перестройку на DO (шардирование состояния по «комнатам/сессиям»). Это ровно тот случай, ради которого затеян весь переезд на модель Workers, но работа тут отдельная и крупная. Глубже про DO и про то, как он работает и на чужом железе — в статье про self-host workerd/celld; для SSE вместо WS как более простой переносимый вариант реалтайма — потоки в браузере.
Часть VI. Порядок переезда: от wrangler dev до переключения домена
Собираем в runbook, который можно выполнить без простоя и с откатом.
1. Подготовка каркаса
npm create cloudflare@latest my-worker -- --type=hello-world # или вручную + wrangler
cd my-worker
npm install # зависимости из package.json
Переносите код: entry на export default { fetch, scheduled } (Части II/V), зависимости с URL- и npm:-импортов на package.json (Часть IV), конфиг wrangler.toml с биндингами/[vars]/[secrets] (Часть III). Секреты локально кладите в .dev.vars и не коммитьте (.gitignore).
2. Локальный тест против эмуляции платформы
npx wrangler dev # локально, ресурсы эмулируются; секреты берутся из .dev.vars
Здесь ловится то, что «глазком» не видно: отсутствие default export, неверные имена биндингов (env.MY_KV должно совпадать со binding = "MY_KV"), падение npm-пакета на fs (заведите полифилл или несите на R2), несовпадение compatibility_date/флагов. Прогоните все основные пути приложения, а не только «здравствуй, мир».
3. Параллельный прод на workers.dev, старый ещё жив
npx wrangler secret put API_TOKEN # завести секрет на прод (значение не в конфиге)
npx wrangler deploy
После деплоя воркер доступен на my-worker.<аккаунт>.workers.dev (при workers_dev по умолчанию). Не переключайте домен сразу. Держите Deno Deploy работающим, а Workers — задеплоенным на поддомен, и гоняйте туда трафик для сверки: ответ за ответом сравните поведение, замеры, ошибки. Пока дедлайн закрытия Deno Deploy далеко (≈весна 2027), это безопасное окно двойной работы. Для сверки ответов подключите логирование — observability/logpush в конфиге; саму идею «снимать фактическое поведение, а не надеяться» разбирает наш паттерн cron→снимок→рендер.
4. Ключи БД и миграции данных
Если на Deno было состояние (KV/SQLite), решите до переключения: переносить значения или строить заново. wrangler d1/KV позволяют загнать данные; для KV есть экспорт/импорт значений. Проверьте диалект D1 заранее — SQL с вашего старого движка переносится не автоматически. Нагрузка на перенос данных зависит от объёма; для больших файлов — R2, а не «прогон через воркер» (лимиты на размер тела и время запроса — в доке Workers про лимиты, сверяйте).
5. Переключение домена (cutover)
Когда поведение на workers.dev совпало, объявляете маршрут:
[[routes]]
pattern = "app.example.test"
custom_domain = true
npx wrangler deploy
Домен app.example.test начинает обслуживаться воркером. Deno Deploy ещё живёт — это ваш откат: если на Workers что-то сломалось, снимаете [routes]/custom_domain и возвращаете DNS/сервис на старый источник. Именно поэтому старый прод не гасят в день переключения, а держат до подтверждения.
6. После переключения
- Уберите из кода всё, что больше не нужно (ручная раздача статики, кастомные env-читалки).
- Переведите
preview_id/staging-окружения ([env.staging]) — биндинги не наследуются между окружениями, для стейджа объявляйте их отдельно. - Закройте секретное: убедитесь, что ни в
[vars], ни в репозитории нет токенов (см. гигиену ключей в защите API). - Поставьте наблюдение: ошибки на воркере (
observability.issues.enabled = true) и логи, чтобы увидеть продакшн-поведение, а не только локальныйwrangler dev.
7. Карта «где переезд будет долгим»
- Тонкий API на Fetch без внешних тянет → быстрые минуты, почти 1-в-1.
- Много URL-/
npm:-импортов → часы на сборку и полифиллы. - Своё состояние с гарантиями (не просто кэш) → дни, это перестройка на D1/DO.
- Реалтайм-вебсокеты → самая длинная часть, переписывается на Durable Objects (Часть V).
Честно: «перенести за вечер» реально только для первой строки. И это нормальный вывод миграции: ценность в том, что после переезда вы в модели, которую вендор открыл и на своё железо тоже, — но платёж за это в части реалтайма и состояния настоящий, и его надо закладывать в план работ, а не в «sed по коду».
Инструменты под задачу
- Разобрать конкретный worker и найти, что ломается — AI-ассистент для кода на codestack.space: вставьте свой
Deno.serve-фрагмент вместе сwrangler.tomlи попросите показать, какие вызовыDeno.*не имеют аналога и как переложить их наenv/биндинги.
Чек-лист граблей
- Искать «переименовывалку»
Deno.→env.. Этого мало: меняется точка входа, конфиг и модель зависимостей. Ожидать одинsed— главный способ недооценить работу. - Секрет в
[vars].[vars]— plain-текст, он не для токенов. Секрет — отдельный зашифрованный биндинг (.dev.varsлокально,wrangler secret/дашборд на проде); значение никогда не коммитится. - Рассчитывать, что URL-
importзаработает. В Workers удалённый модуль по https в рантайме не грузится; зависимости бандлятся изpackage.jsonна деплое. - Тащить Node-пакет, пишущий в
fs. У воркеров нет полноценной ФС; либо полифилл через[alias], либо — правильно — перенос файловых вещей на R2. - Ждать идентичности Deno KV и Workers KV. Похожий, но не тот API; strong-consistency/транзакции — это D1/DO, а не глобальный KV.
- Переносить вебсокеты «как есть».
Deno.upgradeWebSocketпрямого двойника нет — это перестройка на Durable Object сWebSocketPair. Не для одного вечера. - Гасить Deno Deploy в день переключения домена. Старый прод — ваш откат; держите его до подтверждения паритета на
workers.dev. - Ставить неверную
compatibility_date/флаги. Они определяют срез поведения рантайма; ставьте актуальную дату деплоя иnodejs_compat_v2, когда тянет Node-API. - Надеяться на автоматический перенос SQL в D1. D1 — не ваш старый движок; диалект и миграции проверяйте заранее,
migrations_dirне отменяет пересмотр запросов.
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
