Vinextでv1.0のリリースが行われたので試してみた
こんばんは、情報システム室の夏目です。
先日CloudflareがVinextのv1.0のリリースを行いました。
今回はこれを使ってNext.jsをAWS LambdaでSSRしてみます。
Vinext
VinextはCloudflareが作った、Viteを使ってNext.jsアプリケーションを構築するためのツールです。
2月に最初のリリースが行われ、先日v1.0のリリースが行われました。
Next.jsは基本的にTurbopackを使って構築されますが、Vercel以外の場所にデプロイする場合はTurbopackのビルド結果をプラットフォーム毎に再構築する必要があります。
これに対して、Next.jsの出力を適応するのではなく、Next.jsのAPIをVite上で再実装することでCloudflare WorkersやAWS Lambdaなどにデプロイ可能な形式に変換できるようにしたのがVinextです。
Cloudflare Workers以外の環境にデプロイする際には、 Nitro のVite Pluginを使って対応させています。
これにより、AWS Lambdaなど様々な環境に対応した形でビルドすることができます。
試してみる
Cloudflare Workersだとほぼ何も弄らずにデプロイできそうなので、今回はAWSにデプロイすることにします。
具体的にはCloudfrontを前面に置いて、SSRをLambda URL Functions、静的ファイルをS3に置く構成です。
AWSのリソースはTerraformで管理します。
今回のコードは思った以上に多量になったので、完成形のコードをGithubに置いています。
この記事ではコードの説明は最小現になっています。
動くものは上記リポジトリに置いているのでそちらを試してみてください。
1. プロジェクトを作成する
$ npm create vinext-app@latest
npm notice run npx
npm notice run 'create-vinext-app'
What is your project named? (my-vinext-app) trial-vinext-app
Choose a deployment platform:
1. Cloudflare (default)
2. Node
Platform [1]: 2
Pre-render all static routes after build? [y/N]:
Creating a new vinext app in trial-vinext-app.
Installing dependencies:
- vinext
- react-server-dom-webpack
added 159 packages, and audited 160 packages in 10s
29 packages are looking for funding
run `npm fund` for details
4 moderate severity vulnerabilities
To address all issues, run:
npm audit fix
Run `npm audit` for details.
npm warn install-scripts 1 package had install scripts blocked because they are not covered by
npm warn install-scripts fsevents@2.3.3 (install: node-gyp rebuild)
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approv
Installing devDependencies:
- vite
- @vitejs/plugin-react
- @vitejs/plugin-rsc
added 10 packages, and audited 170 packages in 1s
31 packages are looking for funding
run `npm fund` for details
4 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: (install scripts present))
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
vinext init complete!
✓ Added dependencies to dependencies:
- vinext
- react-server-dom-webpack
✓ Added dependencies to devDependencies:
- vite
- @vitejs/plugin-react
- @vitejs/plugin-rsc
✓ Added "type": "module" to package.json
✓ Configured dev script
✓ Configured build script
✓ Configured start script
✓ Generated vite.config.ts
✓ Added vinext output directories to .gitignore
Next steps:
npm run dev Start the vinext dev server
npm run build Build production output
npm run start Start vinext production server
Initialized a git repository.
Success! Created trial-vinext-app at trial-vinext-app
今回はCloudflare WorkersではなくLambda向けにビルドしたいので、PlatformでNodeを選択します。
2. Nitroの設定をする
Cloudflare Workers以外にデプロイするにはNitroが必要なのでそちらもインストールします。
$ cd
$ npm install nitro
added 18 packages, and audited 188 packages in 2s
31 packages are looking for funding
run `npm fund` for details
4 moderate severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
npm warn install-scripts 1 package had install scripts blocked because they are not covered by allowScripts:
npm warn install-scripts fsevents@2.3.3 (install: (install scripts present))
npm warn install-scripts
npm warn install-scripts Run `npm install-scripts ls` to review, or `npm install-scripts approve <pkg>` to allow.
ViteでNitroの設定が必要なので、vite.config.tsを編集します。
import vinext from "vinext";
import { defineConfig } from "vite";
+import { nitro } from "nitro/vite";
export default defineConfig({
- plugins: [vinext()],
+ plugins: [vinext(), nitro({ preset: "aws-lambda" })],
});
AWS Lambda向けにしたいので preset: "aws-lambda" を使用します。
AWS Lambda向けのビルドを行う際、デフォルトで使っているtailwindcssでうまく解決しないという問題が起きました。
@tailwindcss/postcss を使用する場合は app/globals.css を次のように変更します。
(自分はtailwindcssを使っていないので、次のコードはGithubリポジトリに入っていません)
- @import "tailwindcss";
+ @import "tailwindcss/index.css"
ビルドしてみます。
$ npm run build
npm notice run trial-vinext-app@0.1.0 build
npm notice run vite build
[1/5] analyze client references...
vite v8.3.1 building rsc environment for production...
✓ 269 modules transformed.
✓ built in 258ms
[2/5] analyze server references...
vite v8.3.1 building ssr environment for production...
✓ 142 modules transformed.
✓ built in 60ms
[3/5] build rsc environment...
vite v8.3.1 building rsc environment for production...
✓ 261 modules transformed.
computing gzip size...
node_modules/.nitro/vite/services/rsc/__vinext_cacheability_manifest.js 0.02 kB
node_modules/.nitro/vite/services/rsc/__vinext_cacheability_request_projection.js 0.02 kB
node_modules/.nitro/vite/services/rsc/__vinext_pregenerated_concrete_paths.js 0.05 kB
node_modules/.nitro/vite/services/rsc/_next/static/css/index.t0GYwP6I.css 8.43 kB │ gzip: 2.63 kB
node_modules/.nitro/vite/services/rsc/_next/static/route-CL2SpmM5.js 0.08 kB │ gzip: 0.09 kB
node_modules/.nitro/vite/services/rsc/_next/static/client-trace-metadata-DUR2PiYt.js 0.34 kB │ gzip: 0.21 kB
node_modules/.nitro/vite/services/rsc/_next/static/request-context-B6eMglmb.js 0.54 kB │ gzip: 0.36 kB
node_modules/.nitro/vite/services/rsc/_next/static/rolldown-runtime-lQxo6jP8.js 0.74 kB │ gzip: 0.44 kB
node_modules/.nitro/vite/services/rsc/_next/static/framework~index~layout~page~seed-cache~app-route-handler-dispatch~app-page-cache~app-page-c~nozlz7yf-3BE6yltb.js 0.89 kB │ gzip: 0.59 kB
node_modules/.nitro/vite/services/rsc/_next/static/isr-decision-e1jxxm14.js 0.89 kB │ gzip: 0.41 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-static-generation-BX8cz43B.js 0.91 kB │ gzip: 0.51 kB
node_modules/.nitro/vite/services/rsc/_next/static/next-error-digest-D489CTgr.js 1.07 kB │ gzip: 0.61 kB
node_modules/.nitro/vite/services/rsc/_next/static/work-unit-async-storage-C0M1v3Wx.js 1.20 kB │ gzip: 0.55 kB
node_modules/.nitro/vite/services/rsc/_next/static/root-params-CA2N3XyK.js 1.54 kB │ gzip: 0.76 kB
node_modules/.nitro/vite/services/rsc/_next/static/cacheability-request-CbaS9sm-.js 1.88 kB │ gzip: 0.93 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-prerender-endpoints-Cn3yvV87.js 2.47 kB │ gzip: 0.99 kB
node_modules/.nitro/vite/services/rsc/_next/static/page-CDT2khaV.js 2.58 kB │ gzip: 0.85 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-page-cache-render-Dq6yKNqD.js 2.78 kB │ gzip: 1.23 kB
node_modules/.nitro/vite/services/rsc/_next/static/headers-lmxtuUvP.js 3.14 kB │ gzip: 1.23 kB
node_modules/.nitro/vite/services/rsc/_next/static/seed-cache-SIcRS6_o.js 3.46 kB │ gzip: 1.47 kB
node_modules/.nitro/vite/services/rsc/_next/static/unified-request-context-BjVCz3JN.js 3.94 kB │ gzip: 1.53 kB
node_modules/.nitro/vite/services/rsc/_next/static/cache-handler-Dw_-7se1.js 4.32 kB │ gzip: 1.59 kB
node_modules/.nitro/vite/services/rsc/_next/static/request-pipeline-CgjqB_j6.js 4.37 kB │ gzip: 1.82 kB
node_modules/.nitro/vite/services/rsc/_next/static/isr-cache-DqfJsjJL.js 4.75 kB │ gzip: 2.25 kB
node_modules/.nitro/vite/services/rsc/_next/static/html-C2-tMIRg.js 5.07 kB │ gzip: 1.80 kB
node_modules/.nitro/vite/services/rsc/_next/static/framework~index~layout~page~seed-cache~app-rsc-response-stage~app-route-handler-dispatch~ap~b2idxmzx-C6la8ZMf.js 5.74 kB │ gzip: 2.37 kB
node_modules/.nitro/vite/services/rsc/_next/static/cache-control-DiNMNVep.js 5.77 kB │ gzip: 2.13 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-rsc-response-stage-JZTOCJpg.js 7.99 kB │ gzip: 2.82 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-page-cache-ysOcvC7J.js 8.12 kB │ gzip: 2.84 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-page-tracing-TgFXcvuC.js 11.91 kB │ gzip: 4.73 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-elements-BPJItsVA.js 11.95 kB │ gzip: 4.08 kB
node_modules/.nitro/vite/services/rsc/_next/static/cache-request-state-C5z997vW.js 12.36 kB │ gzip: 4.09 kB
node_modules/.nitro/vite/services/rsc/_next/static/artifact-compatibility-BEeFGeOC.js 12.51 kB │ gzip: 4.33 kB
node_modules/.nitro/vite/services/rsc/_next/static/config-headers-BPxsZtFt.js 14.43 kB │ gzip: 4.60 kB
node_modules/.nitro/vite/services/rsc/_next/static/text-stream-iDTzpGjy.js 16.78 kB │ gzip: 4.90 kB
node_modules/.nitro/vite/services/rsc/_next/static/fetch-cache-BVe9fcNh.js 19.95 kB │ gzip: 7.01 kB
node_modules/.nitro/vite/services/rsc/_next/static/app-route-handler-dispatch-CPWjv0JF.js 52.45 kB │ gzip: 18.83 kB
node_modules/.nitro/vite/services/rsc/_next/static/framework~index-BdVj9cpT.js 74.23 kB │ gzip: 21.29 kB
node_modules/.nitro/vite/services/rsc/index.js 258.28 kB │ gzip: 74.74 kB
[INEFFECTIVE_DYNAMIC_IMPORT] app/layout.tsx is dynamically imported by \0virtual:vinext-rsc-entry but also statically imported by \0virtual:vinext-rsc-entry, dynamic import will not move modu
✓ built in 209ms
[4/5] build client environment...
vite v8.3.1 building client environment for production...
`output.codeSplitting.groups[0].name` is a function. Set `output.codeSplitting.groups[0].debugName` so the bundler timing report can identify this group.
✓ 134 modules transformed.
computing gzip size...
.output/public/vinext-client-entry-manifest.json 0.06 kB │ gzip: 0.08 kB
.output/public/.vite/manifest.json 1.40 kB │ gzip: 0.35 kB
.output/public/_next/static/css/index.t0GYwP6I.css 8.43 kB │ gzip: 2.63 kB
.output/public/_next/static/chunks/layout-segment-context-xHwVn8zn.js 0.49 kB │ gzip: 0.34 kB
.output/public/_next/static/chunks/rolldown-runtime-hePW80VL.js 0.71 kB │ gzip: 0.42 kB
.output/public/_next/static/chunks/index-D8BWjOTG.js 110.49 kB │ gzip: 32.88 kB
.output/public/_next/static/chunks/vinext-CGYk61oO.js 115.20 kB │ gzip: 34.46 kB
.output/public/_next/static/chunks/framework-2k-VFE-j.js 219.34 kB │ gzip: 68.40 kB
✓ built in 145ms
[5/5] build ssr environment...
vite v8.3.1 building ssr environment for production...
✓ 146 modules transformed.
computing gzip size...
node_modules/.nitro/vite/services/ssr/_next/static/app-prefetch-fetch-queue-DbU8Gz3U.js 0.10 kB │ gzip: 0.11 kB
node_modules/.nitro/vite/services/ssr/_next/static/static.edge-E5lAR9Dk.js 0.26 kB │ gzip: 0.19 kB
node_modules/.nitro/vite/services/ssr/_next/static/jsx-runtime-27n2UEVc.js 0.45 kB │ gzip: 0.31 kB
node_modules/.nitro/vite/services/ssr/_next/static/layout-segment-context-cr8sPef1.js 0.47 kB │ gzip: 0.33 kB
node_modules/.nitro/vite/services/ssr/_next/static/streamed-icons-B9GBQCvm.js 0.71 kB │ gzip: 0.46 kB
node_modules/.nitro/vite/services/ssr/_next/static/navigation-errors-s7TvMxYv.js 0.81 kB │ gzip: 0.51 kB
node_modules/.nitro/vite/services/ssr/_next/static/client-page-root-JXRoOV7e.js 1.49 kB │ gzip: 0.88 kB
node_modules/.nitro/vite/services/ssr/_next/static/navigation-server-BePrdUON.js 1.80 kB │ gzip: 0.68 kB
node_modules/.nitro/vite/services/ssr/_next/static/app-router-scroll-C8ls_oLd.js 2.68 kB │ gzip: 1.22 kB
node_modules/.nitro/vite/services/ssr/_next/static/react-dom-BbTx3uMj.js 3.89 kB │ gzip: 1.41 kB
node_modules/.nitro/vite/services/ssr/_next/static/error-boundary-CJbiIYs3.js 5.78 kB │ gzip: 1.76 kB
node_modules/.nitro/vite/services/ssr/_next/static/react-c3y_GGvx.js 8.30 kB │ gzip: 3.22 kB
node_modules/.nitro/vite/services/ssr/_next/static/slot-BZ86rCV8.js 16.52 kB │ gzip: 5.10 kB
node_modules/.nitro/vite/services/ssr/index.js 277.24 kB │ gzip: 86.97 kB
[INEFFECTIVE_DYNAMIC_IMPORT] node_modules/vinext/dist/shims/default-global-error.js is dynamically imported by \0virtual:vite-rsc/client-references but also statically imported by node_module
✓ built in 174ms
ℹ Skipping RSC (already built) nitro 5:52:17 PM
◐ Building [Nitro] (preset: aws-lambda, compatibility: 2026-10-01) nitro 5:52:17 PM
✔ Generated public .output/public nitro 5:52:17 PM
vite v8.3.1 building nitro environment for production...
`output.codeSplitting.groups[0].name` is a function. Set `output.codeSplitting.groups[0].debugName` so the bundler timing report can identify this group.
✓ 110 modules transformed.
nf3: could not resolve `traceInclude` entry "@alinea/generated" from any root
nf3: could not resolve `traceInclude` entry "@appsignal/nodejs" from any root
nf3: could not resolve `traceInclude` entry "@aws-sdk/client-s3" from any root
nf3: could not resolve `traceInclude` entry "@aws-sdk/s3-presigned-post" from any root
nf3: could not resolve `traceInclude` entry "@blockfrost/blockfrost-js" from any root
nf3: could not resolve `traceInclude` entry "@highlight-run/node" from any root
nf3: could not resolve `traceInclude` entry "@huggingface/transformers" from any root
nf3: could not resolve `traceInclude` entry "@jpg-store/lucid-cardano" from any root
nf3: could not resolve `traceInclude` entry "@libsql/client" from any root
nf3: could not resolve `traceInclude` entry "@mikro-orm/core" from any root
nf3: could not resolve `traceInclude` entry "@mikro-orm/knex" from any root
nf3: could not resolve `traceInclude` entry "@node-rs/argon2" from any root
nf3: could not resolve `traceInclude` entry "@node-rs/bcrypt" from any root
nf3: could not resolve `traceInclude` entry "@prisma/client" from any root
nf3: could not resolve `traceInclude` entry "@react-pdf/renderer" from any root
nf3: could not resolve `traceInclude` entry "@sentry/profiling-node" from any root
nf3: could not resolve `traceInclude` entry "@sparticuz/chromium" from any root
nf3: could not resolve `traceInclude` entry "@sparticuz/chromium-min" from any root
nf3: could not resolve `traceInclude` entry "@statsig/statsig-node-core" from any root
nf3: could not resolve `traceInclude` entry "@swc/core" from any root
nf3: could not resolve `traceInclude` entry "@xenova/transformers" from any root
nf3: could not resolve `traceInclude` entry "@zenstackhq/runtime" from any root
nf3: could not resolve `traceInclude` entry "argon2" from any root
nf3: could not resolve `traceInclude` entry "autoprefixer" from any root
nf3: could not resolve `traceInclude` entry "aws-crt" from any root
nf3: could not resolve `traceInclude` entry "bcrypt" from any root
nf3: could not resolve `traceInclude` entry "better-sqlite3" from any root
nf3: could not resolve `traceInclude` entry "canvas" from any root
nf3: could not resolve `traceInclude` entry "chromadb-default-embed" from any root
nf3: could not resolve `traceInclude` entry "config" from any root
nf3: could not resolve `traceInclude` entry "cpu-features" from any root
nf3: could not resolve `traceInclude` entry "cypress" from any root
nf3: could not resolve `traceInclude` entry "dd-trace" from any root
nf3: could not resolve `traceInclude` entry "eslint" from any root
nf3: could not resolve `traceInclude` entry "express" from any root
nf3: could not resolve `traceInclude` entry "firebase-admin" from any root
nf3: could not resolve `traceInclude` entry "htmlrewriter" from any root
nf3: could not resolve `traceInclude` entry "import-in-the-middle" from any root
nf3: could not resolve `traceInclude` entry "isolated-vm" from any root
nf3: could not resolve `traceInclude` entry "jest" from any root
nf3: could not resolve `traceInclude` entry "jsdom" from any root
nf3: could not resolve `traceInclude` entry "keyv" from any root
nf3: could not resolve `traceInclude` entry "libsql" from any root
nf3: could not resolve `traceInclude` entry "mdx-bundler" from any root
nf3: could not resolve `traceInclude` entry "mongodb" from any root
nf3: could not resolve `traceInclude` entry "mongoose" from any root
nf3: could not resolve `traceInclude` entry "newrelic" from any root
nf3: could not resolve `traceInclude` entry "next-mdx-remote" from any root
nf3: could not resolve `traceInclude` entry "next-seo" from any root
nf3: could not resolve `traceInclude` entry "node-cron" from any root
nf3: could not resolve `traceInclude` entry "node-pty" from any root
nf3: could not resolve `traceInclude` entry "node-web-audio-api" from any root
nf3: could not resolve `traceInclude` entry "onnxruntime-node" from any root
nf3: could not resolve `traceInclude` entry "oslo" from any root
nf3: could not resolve `traceInclude` entry "pg" from any root
nf3: could not resolve `traceInclude` entry "pino" from any root
nf3: could not resolve `traceInclude` entry "pino-pretty" from any root
nf3: could not resolve `traceInclude` entry "pino-roll" from any root
nf3: could not resolve `traceInclude` entry "playwright" from any root
nf3: could not resolve `traceInclude` entry "playwright-core" from any root
nf3: could not resolve `traceInclude` entry "prettier" from any root
nf3: could not resolve `traceInclude` entry "prisma" from any root
nf3: could not resolve `traceInclude` entry "puppeteer" from any root
nf3: could not resolve `traceInclude` entry "puppeteer-core" from any root
nf3: could not resolve `traceInclude` entry "ravendb" from any root
nf3: could not resolve `traceInclude` entry "require-in-the-middle" from any root
nf3: could not resolve `traceInclude` entry "rimraf" from any root
nf3: could not resolve `traceInclude` entry "shiki" from any root
nf3: could not resolve `traceInclude` entry "sqlite3" from any root
nf3: could not resolve `traceInclude` entry "thread-stream" from any root
nf3: could not resolve `traceInclude` entry "ts-morph" from any root
nf3: could not resolve `traceInclude` entry "ts-node" from any root
nf3: could not resolve `traceInclude` entry "vscode-oniguruma" from any root
nf3: could not resolve `traceInclude` entry "websocket" from any root
nf3: could not resolve `traceInclude` entry "zeromq" from any root
ℹ Tracing dependencies: 5:52:19 PM
- postcss (8.5.28)
- sharp (0.35.5)
- typescript (7.0.2)
- webpack (5.111.1)
- @img/colour (1.1.0)
- @img/sharp-darwin-arm64 (0.35.5)
- nanoid (3.3.19)
- picocolors (1.1.1)
- source-map-js (1.2.2)
- semver (7.8.5)
- detect-libc (2.1.2)
- es-module-lexer (2.3.2)
- @img/sharp-libvips-darwin-arm64 (1.3.4)
- webpack-sources (3.6.0)
- schema-utils (4.5.0)
- tapable (2.3.3)
- graceful-fs (4.2.11)
- enhanced-resolve (5.26.0)
- chrome-trace-event (1.0.4)
- watchpack (2.5.2)
- mime-db (1.54.0)
- @webassemblyjs/wasm-parser (1.14.1)
- @webassemblyjs/ast (1.14.1)
- @webassemblyjs/wasm-edit (1.14.1)
- ajv-keywords (5.1.0)
- ajv-formats (3.0.1)
- ajv (8.20.0)
- minimizer-webpack-plugin (5.12.0)
- @webassemblyjs/utf8 (1.13.2)
- @webassemblyjs/helper-api-error (1.13.2)
- @webassemblyjs/ieee754 (1.13.2)
- @webassemblyjs/leb128 (1.13.2)
- @webassemblyjs/helper-wasm-bytecode (1.13.2)
- @webassemblyjs/helper-numbers (1.13.2)
- @webassemblyjs/wasm-opt (1.14.1)
- browserslist (4.29.3)
- jest-worker (27.5.1)
- @webassemblyjs/wasm-gen (1.14.1)
- @jridgewell/trace-mapping (0.3.31)
- @webassemblyjs/helper-wasm-section (1.14.1)
- @webassemblyjs/helper-buffer (1.14.1)
- lightningcss (1.32.0)
- terser (5.51.2)
- baseline-browser-mapping (2.11.26)
- node-releases (2.0.57)
- electron-to-chromium (1.5.443)
- @webassemblyjs/floating-point-hex-parser (1.13.2)
- caniuse-lite (1.0.30001814)
- @xtuc/long (4.2.2)
- @xtuc/ieee754 (1.2.0)
- fast-deep-equal (3.1.3)
- json-schema-traverse (1.0.0)
- fast-uri (3.1.8)
- @jridgewell/sourcemap-codec (1.6.0)
- @jridgewell/resolve-uri (3.1.2)
- acorn (8.18.0)
- @jridgewell/source-map (0.3.11)
- supports-color (8.1.1)
- merge-stream (2.0.0)
- @jridgewell/gen-mapping (0.3.13)
- has-flag (4.0.0)
- @typescript/typescript-darwin-arm64 (7.0.2)
- lightningcss-darwin-arm64 (1.32.0)
✔ Traced 63 dependencies (1407 files) in 2449ms. 5:52:19 PM
[5:52:19 PM] ℹ Ensure your production environment matches the builder OS and architecture (darwin-arm64) to avoid native module issues.
computing gzip size...
.output/server/_ssr/route-CL2SpmM5.mjs 0.08 kB │ gzip: 0.09 kB
.output/server/_ssr/app-prefetch-fetch-queue-DbU8Gz3U.mjs 0.09 kB │ gzip: 0.10 kB
.output/server/_runtime.mjs 0.17 kB │ gzip: 0.16 kB
.output/server/_ssr/static.edge-E5lAR9Dk.mjs 0.24 kB │ gzip: 0.17 kB
.output/server/_ssr/client-trace-metadata-DUR2PiYt.mjs 0.34 kB │ gzip: 0.21 kB
.output/server/_ssr/jsx-runtime-27n2UEVc.mjs 0.42 kB │ gzip: 0.29 kB
.output/server/_ssr/layout-segment-context-cr8sPef1.mjs 0.43 kB │ gzip: 0.31 kB
.output/server/_chunks/ssr-renderer.mjs 0.46 kB │ gzip: 0.29 kB
.output/server/_ssr/streamed-icons-B9GBQCvm.mjs 0.69 kB │ gzip: 0.45 kB
.output/server/_ssr/rolldown-runtime-lQxo6jP8.mjs 0.70 kB │ gzip: 0.41 kB
.output/server/_ssr/isr-decision-e1jxxm14.mjs 0.74 kB │ gzip: 0.35 kB
.output/server/_ssr/app-static-generation-BX8cz43B.mjs 0.87 kB │ gzip: 0.49 kB
.output/server/_ssr/client-page-root-JXRoOV7e.mjs 1.45 kB │ gzip: 0.85 kB
.output/server/_ssr/navigation-server-BePrdUON.mjs 1.48 kB │ gzip: 0.59 kB
.output/server/_ssr/cacheability-request-CbaS9sm-.mjs 1.76 kB │ gzip: 0.86 kB
.output/server/_ssr/app-page-cache-render-Dq6yKNqD.mjs 2.25 kB │ gzip: 1.04 kB
.output/server/_ssr/app-prerender-endpoints-Cn3yvV87.mjs 2.42 kB │ gzip: 0.96 kB
.output/server/_ssr/page-CDT2khaV.mjs 2.45 kB │ gzip: 0.77 kB
.output/server/_ssr/app-router-scroll-C8ls_oLd.mjs 2.63 kB │ gzip: 1.19 kB
.output/server/_ssr/seed-cache-SIcRS6_o.mjs 3.34 kB │ gzip: 1.42 kB
.output/server/_ssr/react-dom-BbTx3uMj.mjs 3.85 kB │ gzip: 1.39 kB
.output/server/index.mjs 3.91 kB │ gzip: 1.82 kB
.output/server/_ssr/request-context-B6eMglmb.mjs 3.98 kB │ gzip: 1.58 kB
.output/server/_ssr/cache-handler-Dw_-7se1.mjs 4.43 kB │ gzip: 1.63 kB
.output/server/_ssr/error-boundary-CJbiIYs3.mjs 5.67 kB │ gzip: 1.72 kB
.output/server/_libs/srvx.mjs 6.31 kB │ gzip: 2.57 kB
.output/server/_ssr/app-rsc-response-stage-JZTOCJpg.mjs 7.15 kB │ gzip: 2.45 kB
.output/server/_ssr/app-page-cache-ysOcvC7J.mjs 7.35 kB │ gzip: 2.53 kB
.output/server/_ssr/react-c3y_GGvx.mjs 8.24 kB │ gzip: 3.18 kB
.output/server/_libs/unstorage.mjs 8.90 kB │ gzip: 3.18 kB
.output/server/_ssr/config-headers-BPxsZtFt.mjs 14.36 kB │ gzip: 4.56 kB
.output/server/_ssr/slot-BZ86rCV8.mjs 17.25 kB │ gzip: 5.44 kB
.output/server/_libs/h3+rou3+srvx.mjs 21.69 kB │ gzip: 8.18 kB
.output/server/_libs/ocache.mjs 23.79 kB │ gzip: 8.89 kB
.output/server/_ssr/fetch-cache-BVe9fcNh.mjs 33.41 kB │ gzip: 11.20 kB
.output/server/_ssr/app-route-handler-dispatch-CPWjv0JF.mjs 50.44 kB │ gzip: 18.08 kB
.output/server/_ssr/ssr.mjs 280.09 kB │ gzip: 87.41 kB
.output/server/_ssr/rsc.mjs 400.96 kB │ gzip: 116.12 kB
✓ built in 2.86s
ℹ Generated .output/nitro.json 5:52:19 PM
✔ You can preview this build using npx vite preview nitro 5:52:19 PM
途中 nf3: could not resolve `traceInclude` entry "@alinea/generated" from any root などのメッセージが出ましたが、ビルドそのものは正常終了しました。
.output というディレクトリにビルド結果があります。
$ eza -lT -L 2 -F auto --time-style=long-iso .output
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 .output/
.rw-r--r--@ 343 natsume.yuta 2026-10-01 17:52 ├── nitro.json
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 ├── public/
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 │ ├── _next/
.rw-r--r--@ 65 natsume.yuta 2026-10-01 17:52 │ └── vinext-client-entry-manifest.json
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 └── server/
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 ├── _chunks/
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 ├── _libs/
.rw-r--r--@ 173 natsume.yuta 2026-10-01 17:52 ├── _runtime.mjs
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 ├── _ssr/
.rw-r--r--@ 3.9k natsume.yuta 2026-10-01 17:52 ├── index.mjs
drwxr-xr-x@ - natsume.yuta 2026-10-01 17:52 ├── node_modules/
.rw-r--r--@ 2.3k natsume.yuta 2026-10-01 17:52 └── package.json
.output/public に静的なファイルが、 .output/server にLambda用のコードが入っています。
なので、次のようにしてAWSにデプロイする必要があります。
.output/serverの中身をzipで固めて、ハンドラーをindex.handlerとするLambda Functionを作成し、Lambda URL Functionで叩けるようにする.output/publicの中身をS3 Bucketに配置する- Cloudfrontのディストリビューションを作成し次のように設定する
- Lambda URL FunctionとS3 Bucketをオリジンにする
- デフォルトビヘイビアのオリジンをLambda URL Functionとする
/_next/*パス配下のビヘイビアを作成し、S3オリジンを参照するようにする
ざっくりと言うとこれだけやれば動くようになります。
.output/public 配下についてはassetsなどのディレクトリが増えたら都度ビヘイビアを増やす必要があります。
3. Githubに上げたコードの解説
Githubに上げたコードは以下のようになっています。
$ eza -alT -F auto --time-style=long-iso
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:17 ./
.rw-r--r--@ 53 natsume.yuta 2026-10-01 18:17 ├── .env
.rw-r--r--@ 145 natsume.yuta 2026-10-01 18:14 ├── .gitignore
.rw-r--r--@ 520 natsume.yuta 2026-10-01 18:14 ├── .oxfmtrc.jsonc
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 ├── app/
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ ├── about/
.rw-r--r--@ 249 natsume.yuta 2026-10-01 18:14 │ │ └── page.tsx
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ ├── api/
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ │ └── hello/
.rw-r--r--@ 91 natsume.yuta 2026-10-01 18:14 │ │ └── route.ts
.rw-r--r--@ 35 natsume.yuta 2026-10-01 18:14 │ ├── globals.css
.rw-r--r--@ 580 natsume.yuta 2026-10-01 18:14 │ ├── layout.tsx
.rw-r--r--@ 206 natsume.yuta 2026-10-01 18:14 │ └── page.tsx
.rw-r--r--@ 104 natsume.yuta 2026-10-01 18:14 ├── next.config.ts
.rw-r--r--@ 137k natsume.yuta 2026-10-01 18:14 ├── package-lock.json
.rw-r--r--@ 692 natsume.yuta 2026-10-01 18:14 ├── package.json
.rw-r--r--@ 902 natsume.yuta 2026-10-01 18:14 ├── README.md
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 ├── terraform/
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ ├── envs/
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ │ └── prd/
.rw-r--r--@ 975 natsume.yuta 2026-10-01 18:14 │ │ └── terraform.tf
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ └── modules/
drwxr-xr-x@ - natsume.yuta 2026-10-01 18:14 │ └── common/
.rw-r--r--@ 2.4k natsume.yuta 2026-10-01 18:14 │ ├── cloudfront.tf
.rw-r--r--@ 70 natsume.yuta 2026-10-01 18:14 │ ├── common_data.tf
.rw-r--r--@ 601 natsume.yuta 2026-10-01 18:14 │ ├── iam.tf
.rw-r--r--@ 2.1k natsume.yuta 2026-10-01 18:14 │ ├── lambda.tf
.rw-r--r--@ 133 natsume.yuta 2026-10-01 18:14 │ ├── logs.tf
.rw-r--r--@ 159 natsume.yuta 2026-10-01 18:14 │ ├── output.tf
.rw-r--r--@ 1.1k natsume.yuta 2026-10-01 18:14 │ └── s3.tf
.rw-r--r--@ 575 natsume.yuta 2026-10-01 18:14 ├── tsconfig.json
.rw-r--r--@ 193 natsume.yuta 2026-10-01 18:14 └── vite.config.ts
terraform/ 配下がAWSリソース管理用のコードになっています。
terraform/envs/prd/terraform.tf がルートとなっており、 terraform/modules/common を参照してリソースの管理をしています。
デプロイは以下の手順で行います。
(環境変数などを使ってAWS CLIでAWSに触れるようにする必要もあります)
$ npm ci
$ npm run build
$ cd terraform/envs/prd
$ terraform init
$ terraform apply -auto-approve
Apply complete!
Outputs:
cloudfront_domain = "00000000000000.cloudfront.net"
public_bucket_name = "trial-vinext-app-000000000000-ap-northeast-1-an"
$ cd ../../../.output/public
$ aws s3 sync . s3://trial-vinext-app-000000000000-ap-northeast-1-an
この後、cloudfront_domainに出力したドメインをブラウザで開けば、動いていることがわかります。
Terraformのコードは特別なことはしていないので、Cloudfrontを使用する場合のサンプルという程度です。
SSRやRoute APIを確認するためのページを作成して、動作を確認してます。
3-1. SSRがきちんとできているか確認するコード
app/check-ssr/page.tsx では環境変数から値を受け取るようにしています。
Lambdaに対して環境変数を設定し、SSRができているか確認するためのコードになっています。
import Link from "next/link";
export default function CheckSsr() {
return (
<>
<h1 className="title">Check SSR</h1>
<p>
<Link href="/">戻る</Link>
</p>
<hr />
<p>{process.env.ABOUT_MESSAGE}</p>
</>
);
}
ABOUT_MESSAGE="ローカル用の.envから読み込んでいます"
resource "aws_lambda_function" "ssr" {
function_name = "trial-vinext-tmp-ssr"
role = aws_iam_role.lambda.arn
runtime = "nodejs24.x"
architectures = ["arm64"]
handler = "index.handler"
memory_size = 512
timeout = 30
s3_bucket = aws_s3_object.lambda_deploy_package.bucket
s3_key = aws_s3_object.lambda_deploy_package.key
source_code_hash = data.archive_file.lambda_deploy_package.output_base64sha256
publish = true
environment {
variables = {
ABOUT_MESSAGE = "SSRで値を入れました!"
}
}
}
.env にはローカル開発用の値を、 terraform/modules/common/lambda.tf の環境変数に本番用のコードを書いています。
/check-ssr をブラウザで見ると動いていることがわかります。
npm run devによってローカルで動かしたとき
Cloudfrontにデプロイしたときの画像
3-2. API Routeが動くことを確認
app/check-ssr/page.tsx ではNext.jsのAPI Routeが動くことを確認しています。
Vinextで作ったプロジェクトには最初から app/api/hello/route.ts があるので、Client Componentのページを作って試しています。
"use client";
import Link from "next/link";
export default function CheckApi() {
async function call() {
const resp = await fetch("/api/hello");
const data = (await resp.json()) as { message: string };
alert(data.message);
}
return (
<>
<h1 className="title">Check API</h1>
<p>
<Link href="/">戻る</Link>
</p>
<hr />
<p>
<button className="button" onClick={call}>
Call API hello
</button>
</p>
</>
);
}
Call API helloボタンをクリックしたときの画像
動くことは確認できました。
まとめ
今回はv1.0がリリースされたVinextを試してみました。
Next.jsをViteによって構築することで、他の環境へのデプロイを容易にするという意味で非常に便利そうです。
他にもViteで構築しているからこそ、Viteのプラグインを色々使えるというのも良さそうです。
何かのお役に立てたら幸いです。








