
ãç¥1.0ð¥ãBunã©ã³ã¿ã€ã äžã§åäœããHTTP APIãApp Runnerãžãã¹ãã£ã³ã°ããŠã¿ã
ãã®èšäºã¯å ¬éãããŠãã1幎以äžçµéããŠããŸããæ å ±ãå€ãå¯èœæ§ããããŸãã®ã§ããæ³šæãã ããã
ã¯ããã«
9æ8æ¥ïŒçŸå°æéïŒã«JavaScriptã©ã³ã¿ã€ã ã®Bunã®ããŒãžã§ã³1.0ããªãªãŒã¹ãããŸããð¥³ð¥ æ¬èšäºã§ã¯ãBunã©ã³ã¿ã€ã ãçãããHTTP APIãäœã£ãŠApp Runnerã«ãã¹ãã£ã³ã°ããŠã¿ãŸãã
Bunãšã¯
JavaScriptã©ã³ã¿ã€ã ã¯çŸåš Node.js Deno Bunãšè€æ°ããç¶æ³ã§ãããããç°ãªãèŠçŽ æè¡ã§äœãããŠããŸãã詳ããã¯Bun first impressions techfeedãåèã«ããã®ãåãããããã§ããããæããããç¹ãšããŠããã€ãã£ãå®è£
ã«Zigã®æ¡çšãJITã³ã³ãã€ã©ãšããŠJavaScriptCoreãæ¡çšããŠããç¹ã§ãã1.0ã®ç޹ä»åç»ã§ããBun 1.0 is hereã§ã¯é床ã®è©±ãããåºãŠããŠãããåŒ·ãæŒãåºããŠããå°è±¡ãåããŸããã
èšèšãŽãŒã«ã«é¢ããŠã¯ãbun.sh | Design Goalsãåèã«ãªããŸãã
æ§æ
æ§æã¯ä»¥äžã®éãã§ããBunã®ããŒãžã§ã³ã¯1.0.1ãå©çšããŸãããã®èãŸãã®ã¢ã€ã³ã³ããããã§ããã

æ¬èšäºã®äž»æšãšããŠãªãã¹ãBunãæŽ»ããæ§æãèããŸãããçµæãBunã®çµã¿èŸŒã¿é¢æ°ã§ç¹åŸŽçãªbun:sqliteãæŽ»çšããŠTODOã®HTTP APIãäœæããŠã¿ãŸããæ§æã®è©³çްã¯ä»¥äžã®éãã§ãã
| èŠçŽ | æ¡çš | çç± |
|---|---|---|
| ãã¹ãã£ã³ã°å | App Runner | Lambdaã®ã«ã¹ã¿ã ã©ã³ã¿ã€ã ããããŸããããã€ãã£ããµããŒããããŠããªãããçŸæç¹ã§ã¯çŸå®æ¡çšããã«ãããã |
| ããŒã¿ããŒã¹ | SQLite3 | Bunã«ã¯SQLite3ãã©ã€ãããã€ãã£ã(bun:sqlite)ã§å®è£
ãããŠãããã |
| åé·åæ§æ | Litestream | SQLite3ãšS3ãã¬ããªã±ãŒããããã |
| HTTP Webãã¬ãŒã ã¯ãŒã¯ | Hono | BunããµããŒãããŠãããã |
ãœãŒã¹ã³ãŒã
ãœãŒã¹ã³ãŒãã¯GitHubã«ãããŸããbunã³ãã³ãã§å
šãŠå®çµããŸãã(ã³ãŒããã©ãŒãããã ãæè»œã«è¡ãããã®ã§deno fmtã䜿ã£ãŠããŸããã)
github.com/shuntaka9576/bun-apprunner-template
Quick Start
以äžã®ã³ãã³ãã§ãç°å¢æ§ç¯ãã¹ãã£ã³ã°å
šãŠå®äºããŸããæ¬ãããžã§ã¯ãã§ã¯ãDockerã³ã³ããã¯ã©ã€ã¢ã³ããšããŠfinchã®å©çšãæšå¥šããŸãã
cd ./packages/aws export CDK_DOCKER=$(which finch) bunx cdk deploy bun-apprunner-app
åŠçãšããŠã¯ã以äžã®éãã§ããCDKãå šéšãã£ãŠãããŸãã
- ããŒã«ã«ã§ã³ã³ãããã«ã
- ã³ã³ãããECRãžpush
- App RunnerãS3ã®ãªãœãŒã¹ãäœæ
- ã³ã³ããã®ãããã€
ããŒã«ã«ã§ã³ã³ããããã«ãããŸããããŒã«ã«ã®Dockerç°å¢ãæŽåãããŠããããšã確èªããŠãã ãããApp Runnerã¯ãx86ã§ããå¿ èŠãããããarmã ãšåäœããŸãããä»åã³ã³ããã§ã¯ãã€ããªå«ãå šãŠx86ã§ãã«ãããããã®ãå©çšããŠããã®ã§äºææ§ã¯ãããŸããã
CDKå®è¡çµæ
âš Synthesis time: 1.65s This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening). Please confirm you intend to make the following modifications: (äžç¥) IAM Statement Changes bun-apprunner-app.BunApprunnerHostingConstructAppRunnerUriAEE3023C = https://xxxxxxxx.ap-northeast-1.awsapprunner.com <- ãã®URLãå©çš
APIå©çšäŸ
# GET /tasks
$ curl -v https://xxxxxxxx.ap-northeast-1.awsapprunner.com/tasks
(äžç¥)
{"tasks":[]}
# POST /tasks
$ curl -v -X POST https://xxxxxxxx.ap-northeast-1.awsapprunner.com/tasks -d '{"title": "foo"}'
(äžç¥)
{"taskId":"71f21d95-b4f6-4327-9134-452ed346184a","title":"foo","createAt":"2023/09/13 17:09:13"}
# GET /tasks/:taskId
$ curl -v https://xxxxxxxx.ap-northeast-1.awsapprunner.com/tasks/71f21d95-b4f6-4327-9134-452ed346184a
(äžç¥)
{"taskId":"71f21d95-b4f6-4327-9134-452ed346184a","title":"foo","createAt":"2023/09/13 17:09:13"}
解説
äžéšãã玹ä»ããªããããæ°ã«ãªãç¹ããããŸãããå®éã®ãœãŒã¹ã³ãŒããåç §ããŠãã ããã
bunã³ãã³ã
bunã³ãã³ãã¯ãnpm yarn pnpmã«åœããã³ãã³ãã§ããç¹ã«åŸè¿°ããäŸåã®ã€ã³ã¹ããŒã«ã¯ããªãé«éã§ãããŸãworkspaceã«å¯Ÿå¿ããŠããŸãããã ã-wãªãã·ã§ã³ã¯çŸæç¹ã§ã¯ãªããããªã®ã§ãç¹å®ã®ãã¹ã«è¡ã£ãŠããã±ãŒãžè¿œå ãå¿
èŠã§ãããã䜿ãã³ãã³ãã玹ä»ããŸãã
äŸåã®ã€ã³ã¹ããŒã«
--froze-lockfileã--productionãªãã·ã§ã³ããããŸãããã³ã³ããå
éšã ãšççŸãåºãŠããŸãããŸãåäœããŸããã§ãããæ
ã«åŸè¿°ã®Dockerfileã§ã¯ãªãã·ã§ã³ãæå®ããŠããŸããã
bun install
ã¹ã¯ãªããå®è¡
--hotã§ããããªããŒããå¯èœã§ããHTTP APIå®è£
ã§ã¯éå®ããŸãã--bunãªãã·ã§ã³ã¯ãbunã©ã³ã¿ã€ã ã«åäœã匷å¶ãããŸããæ¢åã®Next.jsãNestJSã¢ããªãèµ·åããã®ã¯ããã®ãªãã·ã§ã³ãèšå®ããŠããªãããã§ãè£åŽã§nodeããã»ã¹ãèµ·åããŠããŸãã
bun run --hot --bun ./src/main.ts
bunxã¯npxã®ãããªã³ãã³ããcdkãeslintãªã©ã®CLIãå©çšããéã«å©çšããŸãã
bunx cdk deploy bun-apprunner-app
ã³ã³ããã€ã¡ãŒãž
ãã«ãã¹ããŒãžãã«ãã§ãlitestreamãšbunãååŸããŠãã¢ããªåŽã®ã³ã³ãããžç§»åããŠããŸããã€ã¡ãŒãžãµã€ãºã¯çŽ90MBã§ããã
bunã¯*-baselineã®ãã€ããªãå©çšããŠããŸããbaselineãªãã®ãã€ããªã ãšãã³ã³ããã§bunã³ãã³ãèµ·åæã«ã¯ã©ãã·ã¥ããããšããã£ãããã§ãã"Illegal instruction (core dumped)" when using bun through code-serverãèµ·å ããŠãããã§ããMacOSã§ãã«ãããã®ã§ãLinuxã ãšãŸãçµæãå€ãããããããŸããã
FROM debian:stable-slim as get
WORKDIR /bun
RUN apt-get update
RUN apt-get install curl unzip -y
RUN curl --fail --location --progress-bar --output "/bun/bun.zip" "https://github.com/oven-sh/bun/releases/download/bun-v1.0.1/bun-linux-x64-baseline.zip"
RUN unzip -d /bun -q -o "/bun/bun.zip"
RUN mv /bun/bun-linux-x64-baseline/bun /usr/local/bin/bun
RUN chmod 777 /usr/local/bin/bun
COPY package.json bun.lockb /bun
COPY packages/app /bun/packages/app
RUN bun install
ADD https://github.com/benbjohnson/litestream/releases/download/v0.3.11/litestream-v0.3.11-linux-amd64.tar.gz /tmp/litestream.tar.gz
RUN tar -C /usr/local/bin -xzf /tmp/litestream.tar.gz
FROM debian:stable-slim
WORKDIR /work
COPY --from=get /usr/local/bin/bun /bin/bun
COPY --from=get /usr/local/bin/litestream /bin/litestream
COPY --from=get /bun/node_modules /work/node_modules
COPY --from=get /bun/packages /work/packages
RUN apt-get update && \
apt-get install -y \
sqlite3 \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
RUN mv /work/packages/app/litestream.yml /etc
RUN chmod +x /work/packages/app/entrypoint.sh
WORKDIR /work/packages/app
ENTRYPOINT ["./entrypoint.sh"]
SQLite3æäœ(bun:sqlite)
bun:sqliteã䜿ã£ãèªã¿èŸŒã¿/æžã蟌ã¿åŠçã¯ä»¥äžã®éãã§ããåã®å®å
šæ§ã¯ãªãã§ãããCURDåŠçãæžãã®ã«ååãªæ©èœãããå°è±¡ã§ããããã©ã³ã¶ã¯ã·ã§ã³åŠçããããŸãã詳ããã¯SQLite â API | Bun Docsãåèã«ãªããŸããåãã§ãã¯ããã£ããè¡ãããå Žåã¯ãzodãå©çšãããšè¯ããšæããŸãã
import { Task } from "src/entity/task";
import { Database } from "bun:sqlite";
import { v4 as uuid } from "uuid";
import { DateTime } from "luxon";
const db = new Database("./todo.db");
const insertTask = db.prepare(
"INSERT INTO task (task_id, title) VALUES ($taskId, $title);",
);
const queryTask = db.query(
"SELECT task_id, title, create_at FROM task WHERE task_id = $taskId;",
);
const queryTaskAll = db.query("SELECT task_id, title, create_at FROM task;");
// æžã蟌ã¿
export const AddTask = async (title: string): Promise<Task> => {
const taskId = uuid();
await insertTask.run({
$taskId: taskId,
$title: title,
});
const record = queryTask.get({
$taskId: taskId,
}) as
| {
task_id: string;
title: string;
create_at: string;
}
| undefined;
if (record == null) {
throw new Error("unexpect insert exception");
}
return {
taskId: record.task_id,
title: record.title,
createAt: DateTime.fromSQL(record.create_at, { zone: "UTC" }),
};
};
// åãåºã(åäœ)
export const GetTask = async (taskId: string): Promise<Task | null> => {
const record = queryTask.get({
$taskId: taskId,
}) as
| {
task_id: string;
title: string;
create_at: string;
}
| undefined;
if (record == null) {
return null;
}
return {
taskId: record.task_id,
title: record.title,
createAt: DateTime.fromSQL(record.create_at, { zone: "UTC" }),
};
};
// åãåºã(è€æ°)
export const ListTask = async (): Promise<Task[]> => {
const records = queryTaskAll.all() as {
task_id: string;
title: string;
create_at: string;
}[];
return records.map((record) => ({
taskId: record.task_id,
title: record.title,
createAt: DateTime.fromSQL(record.create_at, { zone: "UTC" }),
}));
};
æåŸã«
æ¬ã¢ããªå®è£
ã§ã¯luxonãuuidãšãã£ãã¢ãžã¥ãŒã«ãå©çšããŸããããåé¡ãªãåäœããŠãããç¹ã«ãããããšãªãæ¢åã®npmè³ç£ãçããã€ã€ã¢ããªãäœããŸããããŸãbun bunxãããããåäœããŠæ°æã¡ãããä»åã®ãããªHTTP APIãµãŒããŒã®å®è£
ã¯ããããªããŒããšçžæ§ãããéçºäœéšãããã£ãã§ããããããªããŒãèªäœã¯ãNode.jsã§ãèšå®ãå
¥ããããNestJSã¯CLIåŽã§å¯Ÿå¿ããŠãããã¯ããŸããããã€ãã£ããµããŒããããŠãããšå°ããåãåºããŠãã©ãã«ã·ã¥ãŒããªãããæè»œã§ããã§ãããbun installã¯é«éã§npmäºæããããããCIã®ã¿bunã䜿ãäºäŸãããããã§ããä»å詊ããŸããã§ããããçµã¿èŸŒã¿ã®ãã¹ãããŒã«ãæ°ã«ãªã£ãŠããŸãã
çŸæç¹ã§åé¡ãªã䜿ããŠããŸãããããä»ã®ã©ã³ã¿ã€ã ãšå·®å¥åèŠçŽ ãå®å®æ§ãåºãŠãããšæµè¡ããããªæ°ãããŠããŸãã
åŒãç¶ããŠã©ããããŠãããããšæããŸãïŒ






