Bun 애플리케이션을 배포하는 방법은 무엇인가요?
Bun은 빠르고 가벼우며 사용하기 쉽도록 설계된 JavaScript 런타임입니다. Zig로 작성되었으며 Safari를 구동하는 JavaScript 엔진인 JavaScriptCore로 구동됩니다.
Bun에는 Node.js 호환 패키지 관리자, 테스트 러너, Bun들러가 내장되어 있습니다. 또한 HTTP 서버 시작 및 파일 쓰기와 같은 일반적인 작업을 수행하기 위해 고도로 최적화된 최소한의 API 세트를 제공합니다.
이 글에서는 Bun으로 간단한 웹 API를 빌드하고 Back4app 컨테이너를 사용하여 Back4app에 배포하는 방법을 설명합니다. 계속 읽으면서 Bun 애플리케이션을 호스팅하는 방법을 자세히 알아보세요.
Contents
Bun의 장점
2023년 9월 V1이 출시되기 전, Bun이 처음 발표된 이후 JavaScript 커뮤니티에서 점점 더 많은 인기를 얻고 있습니다. 그 이유는 다음과 같습니다.
속도
Bun은 성능, 안전성, 가독성에 중점을 두고 시스템 프로그래밍을 위해 설계된 저수준 프로그래밍 언어인 Zig로 작성되었습니다. C 및 C++의 현대적인 대안이 될 수 있도록 고안되었습니다.
또한 Chrome의 V8 JavaScript 엔진을 사용하는 Node.js 및 Deno와 달리 Safari를 구동하는 JavaScriptCore 엔진을 사용합니다.
Bun은 Zig와 JavaScript Core 외에도 JavaScript에 최적화된 사용자 정의 메모리 할당기, 코드가 실행될 때 최적화하는 JIT(Just-In-Time) 컴파일러 등 여러 가지 기술을 사용합니다.
전반적으로 Zig, JavaScript Core 및 기타 최적화의 조합으로 Bun은 다른 런타임과 비교했을 때 매우 빠른 JavaScript 런타임입니다.
Node.js 호환성
Bun은 Node.js를 대체하는 드롭인 방식으로 설계되었기 때문에 모든 Node.js API와 호환됩니다.
또한 암호화, fs, 경로 등과 같은 모든 기본 제공 Node.js 모듈이 있습니다. Bun.js 문서에서 사용 가능한 및 사용 불가능한 Node.js 모듈을 확인할 수 있습니다.
또한 Bun은 npm과 호환되는 패키지 관리자입니다. 즉, Bun을 사용하여 Node.js 패키지를 설치하고 관리할 수 있습니다.
즉시 사용 가능한 TypeScript 지원
Bun은 TypeScript를 기본적으로 원활하게 지원하므로 프로젝트에서 TypeScript를 선호하거나 필요한 경우 탁월한 선택입니다.
정적으로 타이핑되는 확장된 JavaScript 버전인 TypeScript는 고급 언어 기능과 정적 타이핑을 도입하여 JavaScript 개발을 향상시킵니다.
Bun을 사용하면 추가 구성이 필요하지 않으며 TypeScript 기능을 활성화하기 위해 별도의 설정이나 빌드 절차가 필요하지 않습니다.
Bun의 한계
Bun의 장점에도 불구하고 프로젝트에 사용하기 전에 고려해야 할 몇 가지 제한 사항이 있습니다.
제한된 리소스
Bun은 아직 비교적 새롭기 때문에 현재 커뮤니티가 작습니다. Bun-js 관련 개발을 다루는 리소스가 많지 않아 런타임 사용 방법을 파악하는 데 어려움을 겪을 수 있습니다.
그러나 Bun 문서는 포괄적이며 유용한 참고 자료가 됩니다. 문제가 발생하면 Discord 채널을 통해 도움을 요청할 수 있는 옵션도 있습니다.
Windows 지원
Bun은 현재 Windows 운영체제에 대한 지원이 제한적입니다. 이 글을 작성하는 시점에서는 Windows에서 런타임만 지원됩니다.
테스트 러너, 패키지 관리자 및 번들러는 아직 개발 중이므로 Windows에서 작동하지 않습니다. Bun 앱을 호스팅하는 방법을 자세히 알아보려면 계속 읽어보세요.
Bun 앱 구축하기
Bun을 사용하려면 먼저 설치해야 합니다.
macOS, WSL 및 Linux에 Bun을 설치하려면 아래 명령을 실행하세요:
curl -fsSL https://bun.sh/install | bash
개발 환경 설정
새 Bun 프로젝트를 만들려면 아래 명령을 실행합니다:
bun init
위의 명령을 실행하면 프로젝트 디렉터리에 빈 Bun 프로젝트가 초기화됩니다.
이 튜토리얼에서는벤치마크에 따르면 가장 빠른 Bun HTTP 서버 프레임워크 중 하나인 Elysia를 사용하여 간단한 API를 빌드합니다.
아래 명령을 실행하여 이 프로젝트에 필요한 Elysia 및 기타 종속 요소를 설치하세요:
bun add elysia knex dotenv pg
명령에 설치된 다른 종속성은 다음과 같습니다:
- 쿼리 빌더인 Knex. 이 종속성을 사용하여 데이터베이스와의 상호 작용을 간소화할 수 있습니다.
- 이 패키지는 프로젝트의 환경 변수를 관리하는 데 도움이 됩니다.
- 포스트그레스 데이터베이스와 상호 작용하기 위한 pg(포스트그레스 데이터베이스 드라이버)가 필요합니다.
그런 다음 프로젝트에서 knex를 실행하여 초기화합니다:
knex init
위의 명령은 knexfile.js
파일을 생성합니다. 이 파일에는 데이터베이스에 대한 구성 옵션이 포함되어 있습니다.
파일의 코드를 아래 코드 블록으로 바꿉니다:
require("dotenv").config();
export const development = {
client: "pg",
connection: process.env.DATABASE_URL,
migrations: {
directory: "./db/migrations",
}
};
그런 다음 프로젝트 루트 디렉토리에 db.js
파일을 생성하고 아래 코드 블록을 추가합니다.
const knex = require("knex");
const knexFile = require("./knexfile.js");
const environment = process.env.NODE_ENV || "development";
export default knex(knexFile[environment]);
그런 다음 .env
파일을 만들고 파일에 데이터베이스 연결 세부 정보 또는 URI를 추가합니다.
예를 들어
DATABASE_URL = <YOUR_DATABASE_URI>
“YOUR_DATABASE_URI”를 데이터베이스 URL로 바꿉니다.
참고: 버전 관리에 개인 정보를 커밋하지 않도록 .env
파일을 .gitignore
파일에 추가해야 합니다.
데이터베이스 모델 만들기
Knex를 사용하여 데이터베이스 모델을 생성하려면 마이그레이션 파일을 생성하고 Knex를 사용하여 SQL 생성 명령을 작성합니다.
아래 명령을 실행하여 첫 번째 마이그레이션을 생성합니다:
knex migrate:make blog
그런 다음 생성된 마이그레이션 파일의 코드를 아래 코드 블록으로 바꿉니다:
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
export function up (knex) {
return knex.schema.createTable("blog", (table) => {
table.increments("id").primary();
table.string("title").notNullable();
table.string("content").notNullable();
table.string("author").notNullable();
table.timestamp("created_at").defaultTo(knex.fn.now());
});
}
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
export function down (knex) {
return knex.schema.dropTable("blog");
}
마지막으로 아래 코드 블록을 실행하여 마이그레이션 파일을 실행합니다:
knex migrate:latest
위의 명령은 앞서 생성한 마이그레이션 파일을 실행하여 데이터베이스에 블로그 테이블을 생성합니다.
Bun-Elysia 서버 만들기
이 단계에서는 간단한 API 서버를 생성합니다.
index.ts
파일을 열고 아래 코드 블록을 추가합니다:
//index.ts
const { Elysia } = require("elysia");
let db = require("./db");
db = db.default;
const app = new Elysia();
아래 코드 블록에서 Elysia를 임포트하고 Elysia 프레임워크(앱)의 인스턴스를 만들었습니다.
경로 핸들러 생성
다음으로 애플리케이션에 대한 경로 핸들러를 생성합니다. 생성하는 핸들러는 다음 경로를 위한 것입니다:
- POST /posts/create-new-post
- GET /posts
- GET /posts/:id
- PATCH /posts/:id/update-post
- 게시물 삭제 /게시물/:아이디/게시물 삭제하기
아래 코드 블록을 index.ts
파일에 추가하여 “/posts/create-new-post”에 대한 핸들러를 생성합니다:
app.post("/posts/create-new-post", async (context) => {
try {
//Extract the title, content and author from the request body
const { title, content, author } = context.body;
//Insert the post into the database
const post = await db("blog").insert({
title,
content,
author,
});
//Send response to the client
return new Response(JSON.stringify(post));
} catch (error: any) {
//Send error to the client
return new Response(error.message, { status: 500 });
}
});
위의 코드 블록은 데이터베이스에 새 글을 추가하는 엔드포인트용 라우트 핸들러입니다.
아래 코드 블록을 index.ts
파일에 추가하여 모든 글 “/posts”를 가져오는 핸들러를 만듭니다:
app.get("/posts", async (context) => {
try {
//Get all posts from the database
const posts = await db.select("*").from("blog");
//Send response to the client
return new Response(JSON.stringify(posts));
} catch (error: any) {
//Send error to the client
return new Response(error.message, { status: 500 });
}
});
아래 코드 블록을 index.ts
파일에 추가하여 “/posts/:id” 아이디로 단일 글을 가져오는 핸들러를 만듭니다:
app.get("/posts/:id", async (context) => {
//Extract the id from the request params
const { id } = context.params;
//Get the post from the database
const post = await db("blog").where({ id });
//If the post is not found, send a 404 response
if (post.length === 0) {
return new Response("Post not found", { status: 404 });
}
//Send response to the client
return new Response(JSON.stringify(post));
});
아래 코드 블록을 index.ts
파일에 추가하여 페이로드의 데이터로 단일 게시물을 “/posts/:id/update-post” ID로 업데이트하는 핸들러를 생성합니다:
app.patch("/posts/:id/update-post", async (context) => {
//Extract the id from the request params
const { id } = context.params;
//Extract the title and content from the request body
const { title, content } = context.body;
//Update the post in the database
const post = await db("blog").where({ id }).update(
{
title,
content,
},
["id", "title", "content"]
);
//Send response to the client
return new Response(JSON.stringify(post));
});
아래 코드 블록을 index.ts
파일에 추가하여 “/posts/:id/delete-post” 아이디로 단일 글을 삭제하는 핸들러를 생성합니다:
app.delete("/posts/:id/delete-post", async (context) => {
//Extract the id from the request params
const { id } = context.params;
//Delete the post from the database
const post = await db("blog").where({ id }).del();
//Send response to the client
return new Response(JSON.stringify(post));
});
마지막으로 아래 코드 블록을 추가하여 애플리케이션의 PORT를 설정합니다.
app.listen(3000, () => {
console.log("Server running on port 3000");
});
아래 명령을 실행하여 앱을 시작하세요:
bun --watch index.ts
Back4app 컨테이너에 Bun 앱 배포하기
Bun 앱을 배포하려면 몇 가지 단계를 거쳐야 합니다.
1단계: Dockerfile 작성하기
터미널에서 아래 명령을 실행하여 Docker파일을 생성합니다.
touch Dockerfile
위의 명령을 실행하면 프로젝트의 루트 디렉터리에 Docker파일이 생성됩니다.
그런 다음 Docker파일을 열고 아래 코드 블록을 추가합니다:
FROM oven/bun
WORKDIR /app
COPY package.json .
COPY bun.lockb .
RUN bun install
COPY . .
EXPOSE 3000
CMD ["bun", "index.ts"]
위의 Dockerfile에서 첫 번째 줄인 FROM 오븐/번은
사용할 기본 이미지를 지정합니다. 이 이미지는 Bun 런타임과 모든 종속성을 포함하는 미리 빌드된 이미지입니다.
다음 줄인 WORKDIR /app는
이미지의 작업 디렉터리를 설정합니다. 애플리케이션 코드가 복사되고 실행될 디렉터리입니다.
다음 두 줄, COPY package.json .
및 COPY bun.lockb
는 현재 디렉터리에서 패키지.json
및 bun.lockb
파일을 이미지로 복사합니다. 이 파일은 Bun 런타임이 애플리케이션의 종속성을 설치하는 데 필요합니다.
다음 줄인 RUN bun install은
Bun 런타임을 사용하여 애플리케이션의 종속성을 설치합니다.
다음 줄인 COPY ..
.는 현재 디렉터리 전체를 이미지에 복사합니다. 여기에는 애플리케이션 코드와 기타 필요한 파일이 포함됩니다.
다음 줄인 EXPOSE 3000은
컨테이너의 포트 3000을
외부에 노출합니다. 이 포트는 애플리케이션이 수신 대기할 포트입니다.
마지막 줄인 CMD ["bun", "index.ts"]
는 컨테이너가 시작될 때 실행될 명령을 지정합니다. 이 명령은 Bun 런타임을 시작하고 애플리케이션의 index.ts
파일을 실행합니다.
2단계: Back4app 애플리케이션 만들기
Bun 애플리케이션을 호스팅하기 위한 다음 단계는 Back4App에서 새 애플리케이션을 만드는 것입니다. 먼저 Back4App 계정에 로그인하거나 아직 계정이 없는 경우 가입하세요. 로그인하면 Back4App 대시보드가 표시됩니다.
“새 앱” 버튼을 클릭하고“서비스형 컨테이너” 옵션을 선택합니다.
Bun 앱을 호스팅하는 다음 단계로 GitHub 계정을 Back4app 계정에 연결합니다. 계정을 연결하면 Back4app이 계정의 리포지토리에 액세스할 수 있습니다.
계정의 모든 리포지토리 또는 특정 리포지토리에 대한 액세스 권한을 부여할 수 있습니다. 배포하려는 애플리케이션(이 경우 이 튜토리얼에서 빌드한 애플리케이션)을 선택하고 선택을 클릭합니다.
선택 버튼을 클릭하면 구성 페이지로 이동하여 포트 및 환경 변수와 같은 앱에 대한 세부 정보를 입력할 수 있습니다.
세부 정보를 입력한 후 앱 만들기 버튼을 클릭합니다. 그러면 배포 프로세스가 시작됩니다. 배포가 성공하면 앱에 액세스할 수 있는 URL을 받게 되지만, 실패한 경우 Back4app ChatGPT 통합을 활용하여 Docker파일의 문제를 해결할 수 있습니다.
또는 Back4app의 자세한 로그 및 문제 해결 가이드를 사용하여 배포 오류를 수동으로 해결할 수 있습니다.
결론
이 글에서는 Bun JavaScript 런타임과 그 장점 및 명백한 한계를 살펴보았습니다. 또한 Elysia, Knex 및 PostgreSQL을 사용하여 Bun 앱을 빌드하는 방법도 살펴보았습니다.
마지막으로 Back4app 컨테이너와 플랫폼에 Bun 애플리케이션을 배포하는 방법에 대해 살펴보았습니다.
Bun을 사용할 때는 아직 초기 단계이므로 향후 몇 가지 주요 변경 사항이 도입될 수 있다는 점에 유의하세요.
자주 묻는 질문
번(Bun)은 무엇인가요?
Bun은 빠르고 효율적으로 설계된 JavaScript 런타임입니다. JavaScriptCore 엔진 위에 구축되었으며 여러 최적화(저수준 언어인 Zig를 사용하는 이점)를 사용하여 더 빠르게 만듭니다.
Bun 앱을 배포하는 방법?
– Bun 앱을 만듭니다.
– Dockerfile을 작성합니다.
– Bun 애플리케이션을 GitHub에 푸시합니다.
– Back4app 계정을 열거나 기존 계정에 로그인합니다.
– Back4app에서 새 “CaaS” 앱을 만듭니다.
– Back4app에 배포하려는 애플리케이션에 대한 액세스 권한을 부여합니다.
– 앱을 선택하고 구성 세부 정보를 입력합니다.
– 배포를 클릭합니다.