How to use Bun with p5.js
Use Bun to build a p5.js sketch with TypeScript.

Now that Bun 1.0 has been released I tried using it with p5.js. I will be writing this post as I go along.
In other posts I've shown how to use parcel, typescript and p5js but these required other dependencies to be installed.
I want to try Bun, as you don't need to install anything else other Bun itself.
Bun is a fast, all-in-one toolkit for running, building, testing, and debugging JavaScript and TypeScript, from a single file to a full-stack application.
After installing I scaffolded a new project
mkdir p5-project
cd p5-project
bun create .
As Bun is also a package manager I was able install p5
.
bun install p5 @types/p5
As Bun has support for TypeScript I also installed @types/p5
as I want to still use TS.
Now I created a index.ts
file and import p5
and created a simple sketch.
import p5 from "p5";
const sketch = function (p: p5) {
p.setup = function () {
p.createCanvas(p.windowWidth, p.windowHeight);
p.background("black");
p.noLoop();
};
p.draw = function () {
p.strokeWeight(5);
p.fill("red");
p.rect(p.width / 2, p.height / 2, 100, 100);
};
};
new p5(sketch);
To start building I ran the following
bun build --watch index.ts --outdir ./public
As of writing this article I'm not able to find a way to start a development server like webpack-dev-server
and it seems this will arrive in "next couple of months" with something described as Bun.App.

In the meantime we can use Bun itself to create a small webserver to serve the bundled JavaScript, but first I created a index.html
file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
body {
margin: 0;
height: 100vh;
}
</style>
<title>Bun & p5js</title>
</head>
<body>
<script type="module" src="./src/index.ts"></script>
</body>
</html>
Notice that ./src/index.ts
won't work as is so I created a devServer.ts
that combines Bun.build
with Bun.serve
into a single module. It bundles the above code in index.ts
and then creates a HTTP server to serve the files.
As Bun uses hash
in the naming of the output assests, I had to dynamically replace the src/index.js
value in index.html
with what Bun generates.
This was possible as Bun.build
returns a result object with all assets.
const build = await Bun.build({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
naming: "[dir]/[name]-[hash].[ext]",
sourcemap: "inline",
});
build.outputs.forEach((i) => console.log(i.path));
const hash = build.outputs.find((i) => i.kind == "entry-point")?.hash;
const inputHtml = Bun.file("index.html");
const outputHtml = Bun.file("dist/index.html");
let indexHtmlContent = await inputHtml.text();
indexHtmlContent = indexHtmlContent.replace("src/index.ts", `index-${hash}.js`);
await Bun.write(outputHtml, indexHtmlContent);
Bun.serve({
development: true,
port: 3000, // This is the default
fetch(req) {
const path = new URL(req.url).pathname;
if (path === "/") {
return new Response(Bun.file("./dist/index.html"));
}
const file = Bun.file(`dist${path}`);
return new Response(file);
},
});
Then visiting http://localhost:3000
I can see the p5 canvas with a single red rectangle in the center.

Unfortunately every time I update index.ts
I have to restart the devServer.ts
as the --watch
option only watches for changes in devServer.ts
.
There doesn't seem to a config option for Bun.build
to watch for changes in files configured in entrypoints
to then retrigger build.
I could split Bun.build
into a seperate file an run it via bun run --watch build.ts
but then I won't have access to the BuildOutput
in devServer.ts
🤷
Bun has me excited with the future of the JavaScript ecosystem.