Skip to content

Node.js

Node.js는 오픈 소스이며 크로스 플랫폼을 지원하는 JavaScript 런타임 환경이다.

Hono는 처음부터 Node.js를 위해 설계되지 않았다. 하지만 Node.js Adapter를 사용하면 Node.js에서도 실행할 수 있다.

INFO

Node.js 18.x 이상 버전에서 동작한다. 구체적으로 필요한 Node.js 버전은 다음과 같다:

  • 18.x => 18.14.1 이상
  • 19.x => 19.7.0 이상
  • 20.x => 20.0.0 이상

기본적으로 각 주요 릴리스의 최신 버전을 사용하면 된다.

1. 설정

Node.js를 위한 스타터 프로젝트를 사용할 수 있다. "create-hono" 커맨드로 프로젝트를 시작한다. 이 예제에서는 nodejs 템플릿을 선택한다.

sh
npm create hono@latest my-app
sh
yarn create hono my-app
sh
pnpm create hono my-app
sh
bun create hono@latest my-app
sh
deno init --npm hono my-app

my-app 디렉터리로 이동한 후 의존성을 설치한다.

sh
cd my-app
npm i
sh
cd my-app
yarn
sh
cd my-app
pnpm i
sh
cd my-app
bun i

2. Hello World

src/index.ts 파일을 수정한다:

ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'

const app = new Hono()
app.get('/', (c) => c.text('Hello Node.js!'))

serve(app)

3. 실행

로컬에서 개발 서버를 실행한다. 웹 브라우저에서 http://localhost:3000에 접속한다.

sh
npm run dev
sh
yarn dev
sh
pnpm dev

포트 번호 변경하기

port 옵션을 사용해 포트 번호를 지정할 수 있다.

ts
serve({
  fetch: app.fetch,
  port: 8787,
})

Node.js API 직접 사용하기

c.env.incomingc.env.outgoing을 통해 Node.js API에 접근할 수 있다.

ts
import { Hono } from 'hono'
import { serve, type HttpBindings } from '@hono/node-server'
// HTTP2를 사용한다면 `Http2Bindings`를 사용

type Bindings = HttpBindings & {
  /* ... */
}

const app = new Hono<{ Bindings: Bindings }>()

app.get('/', (c) => {
  return c.json({
    remoteAddress: c.env.incoming.socket.remoteAddress,
  })
})

serve(app)

정적 파일 제공하기

serveStatic을 사용하면 로컬 파일 시스템에서 정적 파일을 제공할 수 있다. 예를 들어, 디렉터리 구조가 다음과 같다고 가정해 보자:

sh
./
├── favicon.ico
├── index.ts
└── static
    ├── hello.txt
    └── image.png

/static/* 경로로 접근이 들어오면 ./static 아래의 파일을 반환하도록 다음과 같이 작성할 수 있다:

ts
import { serveStatic } from '@hono/node-server/serve-static'

app.use('/static/*', serveStatic({ root: './' }))

디렉터리 루트에 있는 favicon.ico를 제공하려면 path 옵션을 사용한다:

ts
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))

/hello.txt 또는 /image.png 경로로 접근이 들어오면 ./static/hello.txt 또는 ./static/image.png 파일을 반환하도록 다음과 같이 설정할 수 있다:

ts
app.use('*', serveStatic({ root: './static' }))

rewriteRequestPath

http://localhost:3000/static/*./statics로 매핑하려면 rewriteRequestPath 옵션을 사용한다.

ts
app.get(
  '/static/*',
  serveStatic({
    root: './',
    rewriteRequestPath: (path) =>
      path.replace(/^\/static/, '/statics'),
  })
)

http2

Hono를 Node.js http2 서버에서 실행할 수 있다.

암호화되지 않은 HTTP/2

ts
import { createServer } from 'node:http2'

const server = serve({
  fetch: app.fetch,
  createServer,
})

암호화된 HTTP/2

ts
import { createSecureServer } from 'node:http2'
import { readFileSync } from 'node:fs'

const server = serve({
  fetch: app.fetch,
  createServer: createSecureServer,
  serverOptions: {
    key: readFileSync('localhost-privkey.pem'),
    cert: readFileSync('localhost-cert.pem'),
  },
})

Dockerfile

다음은 Dockerfile 예제이다.

Dockerfile
FROM node:20-alpine AS base

FROM base AS builder

RUN apk add --no-cache gcompat
WORKDIR /app

COPY package*json tsconfig.json src ./

RUN npm ci && \
    npm run build && \
    npm prune --production

FROM base AS runner
WORKDIR /app

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 hono

COPY --from=builder --chown=hono:nodejs /app/node_modules /app/node_modules
COPY --from=builder --chown=hono:nodejs /app/dist /app/dist
COPY --from=builder --chown=hono:nodejs /app/package.json /app/package.json

USER hono
EXPOSE 3000

CMD ["node", "/app/dist/index.js"]

이 작업을 수행하기 전에 다음 단계를 미리 진행해야 한다.

  1. tsconfig.jsoncompilerOptions 섹션에 "outDir": "./dist"를 추가한다.
  2. tsconfig.json"exclude": ["node_modules"]를 추가한다.
  3. package.jsonscript 섹션에 "build": "tsc"를 추가한다.
  4. npm install typescript --save-dev를 실행한다.
  5. package.json"type": "module"을 추가한다.

Released under the MIT License.