Zum Inhalt springen

Node.js ​

Node.js ist eine quelloffene, plattformübergreifende JavaScript-Laufzeitumgebung.

Hono wurde ursprünglich nicht für Node.js entwickelt, kann dort aber mit einem Node.js-Adapter ebenfalls ausgeführt werden.

Info

Es funktioniert mit den Node.js-Versionen ab der 18.x-Reihe. Die konkret benötigten Versionen sind:

  • 18.x => 18.14.1+
  • 19.x => 19.7.0+
  • 20.x => 20.0.0+

Grundsätzlich kannst du einfach die neueste Version jeder Hauptversion verwenden.

1. Einrichtung ​

Für Node.js steht eine Projektvorlage zur Verfügung. Starte dein Projekt mit dem Befehl „create-hono“. Wähle für dieses Beispiel die Vorlage nodejs aus.

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

Wechsle nach my-app und installiere die Abhängigkeiten.

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 ​

Bearbeite 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)

Wenn du den Server geordnet herunterfahren möchtest, schreibe den Code wie folgt:

ts
const server = serve(app)

// graceful shutdown
process.on('SIGINT', () => {
  server.close()
  process.exit(0)
})
process.on('SIGTERM', () => {
  server.close((err) => {
    if (err) {
      console.error(err)
      process.exit(1)
    }
    process.exit(0)
  })
})

Info

Auf Node.js umschließt serve() das Modul node:http und gibt die zugrunde liegende Serverinstanz zurück. Du musst daher selbst für das Schließen des Servers sorgen. Bun und Deno unterstützen Fetch-Handler nativ und verwalten den Server selbst, weshalb ihre Anleitungen diesen Schritt nicht enthalten.

3. Ausführen ​

Starte den Entwicklungsserver lokal. Öffne anschließend http://localhost:3000 in deinem Webbrowser.

sh
npm run dev
sh
yarn dev
sh
pnpm dev

Portnummer ändern ​

Mit der Option port kannst du die Portnummer angeben.

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

WebSocket ​

WebSocket-Unterstützung ist in @hono/node-server integriert. Installiere ws und, wenn du TypeScript verwendest, @types/ws. Erstelle anschließend einen WebSocketServer mit { noServer: true } und übergib ihn über die Option websocket an serve().

@hono/node-ws ist veraltet.

ts
import { serve, upgradeWebSocket } from '@hono/node-server'
import { Hono } from 'hono'
import { WebSocketServer } from 'ws'

const app = new Hono()

app.get(
  '/ws',
  upgradeWebSocket(() => ({
    onMessage(event, ws) {
      ws.send(event.data)
    },
  }))
)

const wss = new WebSocketServer({ noServer: true })

serve({
  fetch: app.fetch,
  websocket: { server: wss },
})

Auf die ursprünglichen Node.js-APIs zugreifen ​

Du kannst über c.env.incoming und c.env.outgoing auf die Node.js-APIs zugreifen.

ts
import { Hono } from 'hono'
import { serve, type HttpBindings } from '@hono/node-server'
// or `Http2Bindings` if you use HTTP2

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

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

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

serve(app)

Statische Dateien ausliefern ​

Mit serveStatic kannst du statische Dateien aus dem lokalen Dateisystem ausliefern. Angenommen, die Verzeichnisstruktur sieht beispielsweise so aus:

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

Wenn eine Anfrage an den Pfad /static/* eingeht und du eine Datei unter ./static zurückgeben möchtest, kannst du Folgendes schreiben:

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

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

Achtung

Die Option root löst Pfade relativ zum aktuellen Arbeitsverzeichnis (process.cwd()) auf. Das Verhalten hängt also davon ab, aus welchem Verzeichnis du deinen Node.js-Prozess startest, nicht davon, wo deine Quelldatei liegt. Wenn du den Server aus einem anderen Verzeichnis startest, kann die Dateiauflösung fehlschlagen.

Für eine zuverlässige Pfadauflösung, die immer auf dasselbe Verzeichnis wie deine Quelldatei verweist, verwende import.meta.url:

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

app.use(
  '/static/*',
  serveStatic({ root: fileURLToPath(new URL('./', import.meta.url)) })
)

Verwende die Option path, um favicon.ico im Stammverzeichnis auszuliefern:

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

Wenn eine Anfrage an /hello.txt oder /image.png eingeht und du eine Datei namens ./static/hello.txt oder ./static/image.png zurückgeben möchtest, kannst du Folgendes verwenden:

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

rewriteRequestPath ​

Wenn du http://localhost:3000/static/* auf ./statics abbilden möchtest, kannst du die Option rewriteRequestPath verwenden:

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

http2 ​

Du kannst Hono auf einem Node.js-http2-Server ausführen.

Unverschlüsseltes http2 ​

ts
import { createServer } from 'node:http2'

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

Verschlüsseltes http2 ​

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'),
  },
})

Build und Bereitstellung ​

sh
npm run build
sh
yarn run build
sh
pnpm run build
sh
bun run build

Info

Anwendungen mit einem Frontend-Framework benötigen möglicherweise Honos Vite-Plugins.

Dockerfile ​

Hier ist ein Beispiel für ein Node.js-Dockerfile.

Dockerfile
FROM node:22-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"]

Veröffentlicht unter der MIT-Lizenz.