Edge Runtimeで遊んでみる

2022/06/29に公開

Edge Runtime が出た

Vercelからいつの間にかEdge Runtimeなるものが出てたので、遊んでみた。

https://edge-runtime.vercel.app

Web標準のAPIを使ったエッジ環境で動くアプリケーションの開発やテストを助けるツールキット。Edge環境はNode.jsじゃないし、evalが使えなかったりするので、それをシミュレートできる。

The Edge Runtime is a toolkit for developing, testing, and defining the runtime Web APIs for Edge infrastructure.

第一行目に「Vercel」とか「Next.js」の文字がないのがよい。とはいえ、一番の想定はVercelのEdge Functionsでしょう。

https://vercel.com/features/edge-functions

Edge Functionsってのは今のところ2つあるみたい。どちらもVercelもしくはNext.jsの機能。Edge Middlewareが今朝のNext.js 12.2と共にリリースされた。Edge API Routesってのはベータ。/api/*で動くやつのエッジ版。

  • Edge Middleware
  • Edge API Routes

これらがEdge RuntimeのおかげでローカルのNext.jsでエミュレートできる。どちらもnext@canaryで動いた。

今回のリリースに「Edge Server-Rendering(Experimental)」が含まれているようにNext.jsもエッジ寄りになるはず。それを考慮するとEdge Runtimeは必然的に生まれたと言えよう。

Edge RuntimeのCLIでHello World

Edge Runtimeのパッケージの中のedge-runtimeにはCLIがあるので、まずはそれで遊んでみる(REPLもある)。

edge-runtime hello.js --listen

これで、サーバーが立たる。

SS

動いた!

Cloudflare Workersのコードを動かす

Web標準の環境ということはCloudflare WorkersやFastly Compute@Edgeのコードも動くはず(VercelはCloudflare Workersで動いているらしい?)。

app.ts
import { Hono } from 'hono'
import { poweredBy } from 'hono/powered-by'

const app = new Hono()

app.use('*', poweredBy())

app.get('/', (c) => c.text('Hello Edge Runtime! This is Hono!'))

export default app
server.ts
import app from './app'

app.fire()

Cloudflare Workers向けを第一に謳っているHonoを使ったコードを、ビルドしてjsにして、edge-runtimeに渡したら動いた!

esbuild --bundle src/server.ts --outfile=dist/server.js
edge-runtime dist/server.js --listen

SS

いいね!

Jest Environment

Jestの環境、@edge-runtime/jest-environment もついているので先ほどのコードをテストしてみよう。jest.config.jstestEnvironmentに明示する。

jest.config.js
module.exports = {
  testEnvironment: '@edge-runtime/jest-environment',
  testMatch: ['**/test/**/*.+(ts|tsx|js)', '**/src/**/(*.)+(spec|test).+(ts|tsx|js)'],
  transform: {
    '^.+\\.(ts|tsx)$': 'esbuild-jest',
  },
}

テストはこんな感じ。

app.test.ts
import app from './app'

describe('Test the application', () => {
  it('Should return 200 response', async () => {
    const res = await app.request('http://localhost/')
    expect(res.status).toBe(200)
    expect(res.headers.get('x-powered-by')).toBe('Hono')
  })
})

いざ、実行!動いた!

SS

エンドポイントにリクエストを送ってレスポンスをe2eっぽく試験するのがこれだけでできるのは、非常にDXが高いです。実はこの書き方は、Cloudflare Workersのアプリケーションを作る時にMiniflareのJest Environmentを使ったテストと全く同じです。

Honoのミドルウェア

あっさりとHonoのBasic認証ミドルウェアも動いた。

SS

Next.jsの中でもCloudflare Workersのコードは動く

まぁようはWeb標準のEdge Functionsなので、Cloudflare Workersが動いて、それがNext.jsでも動くのです。Edge API Routesを試してみます。

pages/api/[...slug].ts を用意して、いつもどおりNext.jsの開発サーバーを立ち上げると…

pages/api/[...slug].ts
import { NextRequest } from 'next/server'
import { Hono } from 'hono'

const app = new Hono()

app.get('/api/hello', (c) => {
  return c.json({ message: 'Hellooooo from Hooooono' })
})

// eslint-disable-next-line import/no-anonymous-default-export
export default (req: NextRequest) => app.request(req)

export const config = {
  runtime: 'experimental-edge',
}

/api/helloが動いた!

SS

これも当然ながら、Vercelにデプロイして動きます。

SS

いい感じ!

まとめ

以上、Edge Runtimeで遊んでみました。Cloudflare Workersで動くコードがそのまま動くのは当然なのですが、楽しかったです。Cloudflareには開発環境にWranglerがあるけど、どちらかというとローカルをエミュレートしているMiniflareに近いです。

以前、Honoの開発をする時にテストをどうするか?みたいな話があって、結局、今も使っているminiflare Jest Environmentになったのですが、今回のEdge Runtimeで選択肢が増えるのは嬉しいです。

Cloudflare Workersの話になっちゃた感もありますが、Edge RuntimeがNext.jsでどのように活かされていくかを探求したいですね。Next.jsもどんどんエッジに寄っていく。ってことでもっとEdge Functionsで諸々動かしたいのですが、それはまた今度。

PS. Stream response??

Next.jsのページにEdge API Routesを使うとStreams APIを使って、「Stream response」ができるって書いてあるけど、どうするんだ??ってなってるのであとで調べる。

Edge API Routes can stream responses from the server and run after cached files (e.g. HTML, CSS, JavaScript) have been accessed. Server-side streaming can help improve performance with faster Time To First Byte (TTFB).

今回使ったコード

https://github.com/yusukebe/workers-on-edge-runtime

参考になる記事

https://lealog.hateblo.jp/entry/2022/06/29/212509

Discussion