Как развернуть приложение Deno?
Для веб-приложений, созданных с помощью Deno, существуют различные варианты развертывания. Однако в последнее время контейнеризация как сервисная платформа стала популярным выбором благодаря различным преимуществам по сравнению с другими вариантами развертывания.
В этой статье вы узнаете о Deno, его преимуществах и ограничениях. Кроме того, вы создадите простое приложение Deno и развернете его в контейнерах Back4app.
Contents
Что такое Deno?
Deno – это безопасная и современная среда выполнения для JavaScript и TypeScript, созданная для устранения ограничений и недостатков дизайна, обнаруженных в Node.js.
В отличие от Node.js, он по умолчанию уделяет особое внимание безопасности, устанавливая гранулированные разрешения на доступ к файловой системе и сети.
Кроме того, Deno поддерживает TypeScript, что избавляет от необходимости выполнять дополнительные шаги по настройке или транспиляции.
С момента своего выхода в 2018 году Deno привлек внимание и интерес разработчиков благодаря своим улучшениям по сравнению с Node.js.
Однако, несмотря на то, что Deno предлагает улучшения, Node.js остается зрелой экосистемой с широкой поддержкой сообщества и обширным репозиторием пакетов.
Несмотря на это, Deno привлекает растущее сообщество разработчиков, которые ценят его подход и изучают его потенциал.
Преимущества Deno
Рост популярности Deno объясняется некоторыми причинами. Вот некоторые из них.
Повышенная безопасность по сравнению с Node.js
Ключевым преимуществом Deno является повышенная безопасность, реализованная в модели безопасности на основе разрешений и работа приложений в среде “песочницы”.
В нем реализована модель безопасности на основе разрешений, где для доступа к таким ресурсам, как файловая система и сеть, требуется явная авторизация.
По умолчанию Deno работает в ограниченном режиме и запускает приложения в “песочнице”, ограничивая потенциально рискованные действия, изолируя их от основной системы и предотвращая прямой доступ к важным ресурсам.
Всесторонний аудит безопасности и тщательная проверка кода еще больше укрепляют надежную защиту Deno. Эти меры обеспечивают надежную и безопасную платформу для создания приложений, вселяют уверенность в их безопасности и защищают от потенциальных уязвимостей.
Управление зависимостями
Deno предлагает особый подход к управлению зависимостями по сравнению с традиционными средами выполнения JavaScript, такими как Node.js.
Вместо того чтобы полагаться на централизованный реестр пакетов, Deno использует URL-адреса для импорта модулей непосредственно из Интернета.
Такой подход упрощает процесс, устраняя необходимость в отдельном менеджере пакетов, например npm, и снимая проблемы, связанные с конфликтами версий и сложностями управления папкой “node_modules”.
Вы можете указать зависимости, указав URL-адреса импортируемых модулей, что упрощает совместное использование и распространение кода. Такой децентрализованный подход к управлению зависимостями в Deno способствует простоте, снижает трение и помогает обеспечить более рациональный опыт разработки.
Поддержка TypeScript из коробки
Deno предлагает встроенную и бесшовную поддержку TypeScript, что делает его отличным выбором, если вы предпочитаете или требуете TypeScript в своих проектах.
TypeScript – это типизированный супернабор JavaScript, который привносит статическую типизацию и другие расширенные возможности языка в разработку JavaScript. С Deno для использования TypeScript не требуется дополнительных шагов по настройке или сборке.
Deno поставляется в комплекте с компилятором TypeScript, что позволяет писать и выполнять код TypeScript напрямую.
Эта встроенная поддержка устраняет сложности, связанные с настройкой отдельного набора инструментов TypeScript, и упрощает процесс разработки.
Он позволяет вам воспользоваться преимуществами проверки типов TypeScript, улучшенным инструментарием и расширенным опытом разработчика при создании приложений с помощью Deno.
Ограничения Deno
Однако у Deno есть определенные ограничения, которые мешают ее внедрению. Вот некоторые из них.
Незрелая экосистема
Одним из ограничений Deno является зрелость его экосистемы. По сравнению с Node.js, который существует уже более длительное время, экосистема Deno все еще относительно новая и развивающаяся.
Это означает, что может быть меньше сторонних библиотек, фреймворков и инструментов, специально разработанных для Deno. Возможно, вам придется создавать определенные функции с нуля или адаптировать существующие пакеты Node.js для использования в Deno.
Меньший размер сообщества также означает, что может быть меньше ресурсов, учебников и поддержки сообщества по сравнению с устоявшейся экосистемой Node.js.
Однако ожидается, что по мере роста популярности и распространения Deno ее экосистема будет расти и развиваться, предлагая в будущем более широкий спектр библиотек и инструментов.
Крутая кривая обучения
Еще одним ограничением Deno является кривая обучения, связанная с переходом от других сред выполнения JavaScript, таких как Node.js.
В Deno появляются новые концепции, API и паттерны, с которыми вам, возможно, придется ознакомиться. Это включает в себя понимание системы модулей Deno, модели безопасности на основе прав доступа, а также различий в реализации некоторых функций по сравнению с другими режимами исполнения.
Разработчикам, которые уже владеют Node.js, возможно, придется потратить время и усилия на изучение и адаптацию к особенностям и соглашениям Deno.
Однако с кривой обучения можно справиться, обращаясь к официальной документации Deno, взаимодействуя с сообществом Deno и изучая доступные обучающие ресурсы.
Совместимость с библиотеками Node.js
Совместимость с библиотеками Node.js – еще одно ограничение Deno. Из-за различий в системах модулей и средах выполнения не все библиотеки и модули Node.js можно напрямую использовать в Deno без модификаций.
В качестве системы модулей в Deno используются модули ES (модули ECMAScript), в то время как в Node.js традиционно используются модули CommonJS. Это различие в форматах модулей может привести к несовместимости при импорте и использовании специфических для Node.js модулей в Deno.
Разработчикам может потребоваться внести коррективы или найти альтернативные библиотеки, специально разработанные для работы с системой модулей Deno.
Хотя Deno предоставляет слой совместимости для запуска некоторых модулей Node.js, он может не охватывать все случаи, и может потребоваться ручная модификация или адаптация.
Варианты развертывания Deno
Существует несколько вариантов развертывания приложений Deno, и вот некоторые из них.
Инфраструктура как услуга (IaaS)
Инфраструктура как услуга (IaaS) – это модель облачных вычислений, которая предлагает виртуализированные вычислительные ресурсы. При использовании IaaS вы можете арендовать виртуальные машины, хранилища и сети у облачных провайдеров на условиях оплаты по факту. Это позволяет создавать и управлять собственной виртуализированной инфраструктурой, не вкладывая средства в физическое оборудование.
Варианты IaaS позволяют запускать приложения Deno на виртуальных машинах. Популярные платформы IaaS, такие как AWS, Google Cloud и Microsoft Azure, предлагают гибкие и масштабируемые решения, позволяющие настраивать инфраструктуру в соответствии с конкретными потребностями вашего приложения.
Однако, хотя IaaS обеспечивает больший контроль и изоляцию ресурсов, он также требует более ручной настройки и управления, включая такие задачи, как предоставление сервера, обновление безопасности и мониторинг.
Таким образом, IaaS – это оптимальный выбор, если вам необходим широкий контроль над инфраструктурой и вы обладаете достаточным опытом для эффективного управления ее сложностями.
Контейнер-как-услуга (CaaS)
Container-as-a-Service (CaaS) – это модель облачных вычислений, которая упрощает развертывание и управление контейнерными приложениями.
Благодаря CaaS вы можете сосредоточиться на создании и развертывании приложений, не заботясь о базовой инфраструктуре.
Приложения Deno могут быть развернуты в контейнерах, обеспечивая согласованность и изоляцию. Контейнеры Back4app – популярный вариант CaaS для развертывания Deno.
Платформы CaaS обеспечивают масштабируемость и изоляцию ресурсов, при этом каждое приложение выполняется в собственном контейнере, что повышает безопасность и стабильность.
Согласованность контейнеров гарантирует, что приложения Deno могут быть легко развернуты на любой платформе, поддерживающей контейнеры.
Несмотря на то, что решениям CaaS приходится учиться, они дают значительные преимущества для приложений, требующих динамического масштабирования и развертывания на нескольких узлах или кластерах.
Процесс установки Deno
Прежде чем использовать Deno, необходимо загрузить и установить его. Установка Deno зависит от вашей операционной системы.
На macOS и Linux вы можете установить Deno, выполнив следующую команду:
curl -fsSL <https://deno.land/x/install/install.sh> | sh
В Windows вы можете установить Deno с помощью Powershell, выполнив следующую команду:
irm <https://deno.land/install.ps1> | iex
Чтобы убедиться, что установка прошла успешно, выполните приведенную ниже команду, и она выведет на ваш терминал номер версии.
deno --version
Если вы не видите номер версии, попробуйте установить Deno еще раз.
Настройка проекта Deno
Чтобы создать простой API с помощью Deno, вам понадобятся маршрутизатор, сервер и база данных.
Прежде чем выполнять следующие шаги, создайте папку src
в корневом каталоге вашего проекта. В этой папке будут храниться все исходные файлы вашего проекта.
Шаг 1: Создание файла зависимостей
В отличие от Node.js, Deno не использует менеджеры пакетов, такие как NPM или Yarn. Вместо этого пакеты импортируются непосредственно из их URL.
Чтобы имитировать функции файла package.json
, создайте файл deps.ts
в корневом каталоге вашего проекта и добавьте в него блок кода, приведенный ниже.
export { Application, Router } from "https://deno.land/x/[email protected]/mod.ts";
export type { RouterContext} from "https://deno.land/x/[email protected]/mod.ts";
export { config as dotenvConfig } from "https://deno.land/x/[email protected]/mod.ts";
export { Client } from "https://deno.land/x/[email protected]/mod.ts";
Блок кода выше импортирует (устанавливает) и экспортирует Application
, Router
и RouterContex
из Oak. config
из dotenv и Client
из deno-postgres.
Шаг 2: Создание сервера
В этом шаге вы создадите простой HTTP-сервер с помощью Oak. Oak – это промежуточное ПО для HTTP-сервера Deno, основанное на Koa.js, фреймворке для Node.js, похожем на Express, но более легковесном.
Чтобы создать HTTP-сервер с помощью Oak, создайте файл server.ts
в папке src
и добавьте в него блок кода, приведенный ниже.
import { Application } from "../deps.ts";
import config from "../config/default.ts";
import router from "./router.ts";
const app = new Application();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: config.port });
В приведенном выше блоке кода создается HTTP-сервер с Oak и регистрируется маршрутизатор для обработки всего входящего трафика.
Строка app.use(router.routes())
регистрирует маршруты маршрутизатора в качестве промежуточного ПО в приложении Oak. Все входящие запросы будут сопоставляться с зарегистрированными маршрутами, и при обнаружении совпадений будут выполняться соответствующие обработчики.
Если совпадение не найдено, строка app.use(router.allowedMethods())
обрабатывает их, отправляя соответствующие ответы, такие как 404 not found или 405 not allowed.
Шаг 3: Управление переменными окружающей среды
Хранение конфиденциальных данных, таких как ключи API, учетные данные баз данных и т. д., в открытом виде представляет собой риск для безопасности. Любой, кто завладеет вашими ключами или учетными данными, может получить неограниченный доступ к вашему приложению. Это может привести к потере данных и их краже, а также к другим возможным последствиям.
Во избежание подобных ситуаций считается хорошей практикой хранить конфиденциальные данные в переменных окружения.
Создайте файл .env
в корневой папке проекта и сохраните в нем учетные данные базы данных и другую конфиденциальную информацию.
Например, так:
#.env
DB_URI = <YOUR_POSTGRES_DB_URI>
PORT = 8000
Замените на учетные данные вашей базы данных.
Далее создайте папку config
в корневой папке проекта, а в папке config создайте файл default.ts
и добавьте в него блок кода, приведенный ниже.
//default.ts
import { dotenvConfig } from "../deps.ts";
dotenvConfig({
export: true,
path: "../.env",
});
const config = {
db: {
dbUri: Deno.env.get("DB_URI"),
},
port: 3000
};
export default config;
Блок кода выше безопасно извлекает значения, хранящиеся в вашем файле .env
, и передает их остальным частям приложения.
Шаг 3: Подключение к базе данных
На этом шаге вы подключите свое приложение к базе данных Postgres. База данных понадобится вам для хранения и получения данных для вашего приложения.
Создайте файл db.ts
в папке src
и добавьте в него блок кода, приведенный ниже.
//db.ts
import { Client } from "../deps.ts";
import config from "../config/default.ts";
let postgresConfiguration = config.db.dbUri;
const client = new Client(postgresConfiguration);
await client.connect();
export default client;
Приведенный выше блок кода пытается подключить ваше приложение к базе данных Postgres, используя URI, указанный в файле .env
.
Шаг 4: Создание репозитория базы данных
Создайте файл blogRepository
в папке src
и добавьте в него приведенный ниже код.
//blogRepository.ts
import client from "./db.ts";
class BlogRepository {
async createBlogTable() {
const blog = await client.queryArray(
`CREATE TABLE IF NOT EXISTS blogs (id SERIAL PRIMARY KEY, title VARCHAR(255), body VARCHAR(255), author VARCHAR(255))`
);
return blog;
}
async getAllBlogs() {
const allBlogs = await client.queryArray("SELECT * FROM blogs");
return allBlogs;
}
async getBlogById(id: string) {
const blog = await client.queryArray(
`SELECT * FROM blogs WHERE id = ${id}`
);
return blog;
}
async createBlog(title: string, body: string, author: string) {
const blog = await client.queryArray(
`INSERT INTO blogs (title, body, author) VALUES ('${title}', '${body}', '${author}')`
);
return blog;
}
async updateBlog(id: string, title: string, body: string, author: string) {
const blog = await client.queryArray(
`UPDATE blogs SET title = '${title}', body = '${body}', author = '${author}' WHERE id = ${id}`
);
return blog;
}
async deleteBlog(id: string) {
const blog = await client.queryArray(`DELETE FROM blogs WHERE id = ${id}`);
return blog;
}
}
export default new BlogRepository();
Блок кода выше будет обрабатывать все операции с базой данных, абстрагируя необработанные SQL-запросы и раскрывая простые методы, которые вы можете использовать для взаимодействия с базой данных Postgres.
Шаг 5: Создание обработчиков маршрутов
На этом этапе вы создадите обработчики маршрутов для обработки простых CRUD-функций вашего приложения. Поддерживаются следующие маршруты:
- GET /api/blogs: Возвращает все блоги в вашей базе данных
- GET /api/blog/:id: Возвращает один блог с соответствующим id, указанным в параметрах URL.
- POST /api/blog/new: Создает новый блог в вашей базе данных.
- PUT /api/blog/:id: Обновляет блог с соответствующим id, указанным в параметрах URL.
- DELETE /api/blog/:id: Удаляет блог с соответствующим id, указанным в параметрах URL.
Создайте файл router.ts в папке src и добавьте в него следующие импорты.
import { Router, RouterContext } from "../deps.ts";
import blogRepository from "./blogRepository.ts";
Затем создайте экземпляр маршрутизатора, добавив в него блок кода, приведенный ниже:
const router = new Router();
Чтобы зарегистрировать обработчики маршрутизатора, необходимо привязать их к экземпляру маршрутизатора.
Например (GET /api/blogs):
router
.get("/api/blogs", async (ctx: RouterContext<"/api/blogs">) => {
const data = await blogRepository.getAllBlogs();
console.log(data);
//format data
const allBlogs = data.rows.map((blog) => {
return {
id: blog[0],
title: blog[1],
body: blog[2],
author: blog[3]
};
});
ctx.response.body = allBlogs;
})
Приведенный выше блок кода создает обработчик маршрута для GET /api/blogs, прикрепляя логику обработчика к экземпляру маршрутизатора.
Прикрепите их к предыдущему методу, чтобы зарегистрировать остальные маршруты. Например:
GET /api/blog/:id:
.get("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
try {
const data = await blogRepository.getBlogById(ctx.params.id);
console.log(data);
//format data
const blog = data.rows.map((blog) => {
return {
id: blog[0],
title: blog[1],
body: blog[2],
author: blog[3]
};
});
ctx.response.body = blog;
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error getting blog",
error,
};
}
})
POST /api/blog/new
.post("/api/blog/new", async (ctx: RouterContext<"/api/blog/new">) => {
const resBody = ctx.request.body();
const blog = await resBody.value;
if (!blog) {
ctx.response.status = 400;
ctx.response.body = { msg: "Invalid data. Please provide a valid blog." };
return;
}
const { title, body, author } = blog;
if (!(title && body && author)) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Title or description missing. Please provide a valid blog.",
};
return;
}
try {
await blogRepository.createBlog(title, body, author);
ctx.response.status = 201;
ctx.response.body = {
msg: "blog added successfully",
};
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
msg: "Error adding blog",
error,
};
}
})
PUT /api/blog/:id:
.put("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
try {
const resBody = ctx.request.body();
const blog = await resBody.value;
if (!blog) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Invalid data. Please provide a valid blog.",
};
return;
}
const { title, body, author } = blog;
if (!(title && body && author)) {
ctx.response.status = 400;
ctx.response.body = {
msg: "Title or description missing. Please provide a valid blog.",
};
return;
}
await blogRepository.updateBlog(ctx.params.id, title, body, author);
ctx.response.status = 200;
ctx.response.body = {
msg: "blog updated successfully",
};
} catch (error) {
console.log(error);
ctx.response.status = 500;
ctx.response.body = {
msg: "Error updating blog",
error: error.message,
};
}
})
DELETE /api/blog/:id:
.delete("/api/blog/:id", async (ctx: RouterContext<"/api/blog/:id">) => {
await blogRepository.deleteBlog(ctx.params.id);
ctx.response.status = 200;
ctx.response.body = {
msg: "blog deleted successfully",
};
});
Затем экспортируйте экземпляр маршрутизатора. Например:
export default router;
Наконец, измените файл server.ts
, чтобы при первом запуске приложения создавалась база данных блога.
Например, так:
import { Application } from "../deps.ts";
import config from "../config/default.ts";
import blogRepository from "./blogRepository.ts";
import router from "./router.ts";
const app = new Application();
(async () => {
await blogRepository.createBlogTable();
})();
app.use(router.routes());
app.use(router.allowedMethods());
await app.listen({ port: config.port });
Модифицированный код добавляет в файл server.ts
IIFE, который создает новую таблицу блогов в вашей базе данных.
Развертывание приложения Deno на контейнерах Back4app
Чтобы развернуть приложение Deno в контейнерах Back4app, вам нужно выполнить следующие шаги:
Шаг 1: Создание Dockerfile
Dockerfile содержит конкретные инструкции по сборке образа Docker. Эти инструкции направляют процесс создания образа.
Выполните приведенную ниже команду, чтобы создать Dockerfile:
touch Dockerfile
Приведенная выше команда создает Dockerfile в корневом каталоге вашего проекта.
Затем добавьте приведенный ниже блок кода в свой Dockerfile:
FROM denoland/deno:latest
EXPOSE 8000
WORKDIR /app
COPY deps.ts .
RUN deno cache deps.ts
COPY . .
RUN deno cache src/server.ts
CMD ["run", "--allow-net", "--allow-env", "--allow-read", "src/server.ts"]
Приведенный выше Dockerfile создает контейнерную среду для запуска приложения Deno. Он кэширует зависимости приложения и точку входа, а затем запускает приложение Deno с указанными разрешениями при запуске контейнера.
Ожидается, что приложение будет слушать порт 8000, хотя фактическое сопоставление портов должно быть выполнено при запуске контейнера.
Наконец, разместите свой код на GitHub.
Шаг 2: Создайте новое приложение Back4app
Чтобы создать приложение Back4app, посетите официальный сайт Back4app. Там найдите кнопку “Зарегистрироваться” в правом верхнем углу целевой страницы Back4app. После нажатия кнопки ” Зарегистрироваться ” вы будете перенаправлены на регистрационную форму. Заполните эту форму, указав необходимые данные, такие как адрес электронной почты, имя пользователя и пароль. Обязательно укажите точную информацию. После заполнения формы отправьте ее.
Если у вас уже есть учетная запись, нажмите ” Войти “.
После успешной настройки аккаунта Back4app войдите в систему, чтобы получить доступ к панели управления. Там найдите кнопку “NEW APP” и нажмите на нее.
Это действие направит вас на страницу, где вам будут предложены различные варианты создания нового приложения. Поскольку вы планируете развернуть приложение с помощью контейнеризации, выберите вариант“Контейнеры как сервис“.
Затем подключите свой аккаунт GitHub к аккаунту Back4app. Вы можете предоставить Back4app доступ ко всем репозиториям в вашем аккаунте или к определенным репозиториям.
Выберите приложение, которое вы хотите развернуть, в данном случае приложение, которое вы создали в этом уроке, и нажмите кнопку Выбрать.
Нажав кнопку выбора, вы перейдете на страницу, где вам нужно будет заполнить некоторую информацию о вашем приложении, такую как название, ветвь, корневой каталог, параметры авторазвертывания, порт, состояние и переменные окружения.
Убедитесь, что вы указали все необходимые переменные среды, которые требуются вашему приложению для корректной работы. После того как вы заполните всю необходимую информацию, нажмите кнопку “Создать приложение”.
Это запустит процесс развертывания, и через некоторое время ваша установка должна быть готова. Если процесс развертывания занимает много времени, вы можете проверить журналы, чтобы увидеть, не произошла ли ошибка при развертывании, или обратиться к руководству по устранению неполадок Back4app.
Заключение
В этой статье вы узнали о Deno, его преимуществах, ограничениях, популярных вариантах развертывания, о том, как создать приложение с помощью Deno и развернуть его с помощью контейнеров Back4app.
Несмотря на ограничения, благодаря своей модели безопасности Deno может стать идеальным решением для создания очень безопасных и конфиденциальных приложений. Кроме того, встроенная поддержка TypeScript избавляет от необходимости настраивать TypeScript в проекте.
Следуя шагам, описанным в этой статье, вы сможете легко создать и развернуть свое приложение Deno в контейнерах Back4app.
ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ
Что такое Deno?
Deno — это безопасное и современное окружение выполнения JavaScript/TypeScript, которое позволяет разработчикам создавать серверные и клиентские приложения.
Как развернуть приложение на Deno?
1. Создайте приложение на Deno
2. Создайте файл Dockerfile
3. Загрузите своё Deno-приложение на GitHub и подключите свой аккаунт GitHub к Back4app
4. Создайте CaaS-приложение на Back4app
5. Выберите своё Deno-приложение из списка репозиториев
6. Разверните своё Deno-приложение