Skip to content

Commit badb237

Browse files
scratch++
1 parent 92e7300 commit badb237

33 files changed

Lines changed: 1548 additions & 0 deletions
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# dependencies (bun install)
2+
node_modules
3+
4+
# output
5+
out
6+
dist
7+
*.tgz
8+
9+
# code coverage
10+
coverage
11+
*.lcov
12+
13+
# logs
14+
logs
15+
_.log
16+
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17+
18+
# dotenv environment variable files
19+
.env
20+
.env.development.local
21+
.env.test.local
22+
.env.production.local
23+
.env.local
24+
25+
# caches
26+
.eslintcache
27+
.cache
28+
*.tsbuildinfo
29+
30+
# IntelliJ based IDEs
31+
.idea
32+
33+
# Finder (MacOS) folder config
34+
.DS_Store
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
---
2+
description: Use Bun instead of Node.js, npm, pnpm, or vite.
3+
globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json"
4+
alwaysApply: false
5+
---
6+
7+
Default to using Bun instead of Node.js.
8+
9+
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
10+
- Use `bun test` instead of `jest` or `vitest`
11+
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
12+
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
13+
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
14+
- Use `bunx <package> <command>` instead of `npx <package> <command>`
15+
- Bun automatically loads .env, so don't use dotenv.
16+
17+
## APIs
18+
19+
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
20+
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
21+
- `Bun.redis` for Redis. Don't use `ioredis`.
22+
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
23+
- `WebSocket` is built-in. Don't use `ws`.
24+
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
25+
- Bun.$`ls` instead of execa.
26+
27+
## Testing
28+
29+
Use `bun test` to run tests.
30+
31+
```ts#index.test.ts
32+
import { test, expect } from "bun:test";
33+
34+
test("hello world", () => {
35+
expect(1).toBe(1);
36+
});
37+
```
38+
39+
## Frontend
40+
41+
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
42+
43+
Server:
44+
45+
```ts#index.ts
46+
import index from "./index.html"
47+
48+
Bun.serve({
49+
routes: {
50+
"/": index,
51+
"/api/users/:id": {
52+
GET: (req) => {
53+
return new Response(JSON.stringify({ id: req.params.id }));
54+
},
55+
},
56+
},
57+
// optional websocket support
58+
websocket: {
59+
open: (ws) => {
60+
ws.send("Hello, world!");
61+
},
62+
message: (ws, message) => {
63+
ws.send(message);
64+
},
65+
close: (ws) => {
66+
// handle close
67+
}
68+
},
69+
development: {
70+
hmr: true,
71+
console: true,
72+
}
73+
})
74+
```
75+
76+
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
77+
78+
```html#index.html
79+
<html>
80+
<body>
81+
<h1>Hello, world!</h1>
82+
<script type="module" src="./frontend.tsx"></script>
83+
</body>
84+
</html>
85+
```
86+
87+
With the following `frontend.tsx`:
88+
89+
```tsx#frontend.tsx
90+
import React from "react";
91+
import { createRoot } from "react-dom/client";
92+
93+
// import .css files directly and it works
94+
import './index.css';
95+
96+
const root = createRoot(document.body);
97+
98+
export default function Frontend() {
99+
return <h1>Hello, world!</h1>;
100+
}
101+
102+
root.render(<Frontend />);
103+
```
104+
105+
Then, run index.ts
106+
107+
```sh
108+
bun --hot ./index.ts
109+
```
110+
111+
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# bun-react-tailwind-shadcn-template
2+
3+
To install dependencies:
4+
5+
```bash
6+
bun install
7+
```
8+
9+
To start a development server:
10+
11+
```bash
12+
bun dev
13+
```
14+
15+
To run for production:
16+
17+
```bash
18+
bun start
19+
```
20+
21+
This project was created using `bun init` in bun v1.3.4. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#!/usr/bin/env bun
2+
import plugin from "bun-plugin-tailwind";
3+
import { existsSync } from "fs";
4+
import { rm } from "fs/promises";
5+
import path from "path";
6+
7+
if (process.argv.includes("--help") || process.argv.includes("-h")) {
8+
console.log(`
9+
🏗️ Bun Build Script
10+
11+
Usage: bun run build.ts [options]
12+
13+
Common Options:
14+
--outdir <path> Output directory (default: "dist")
15+
--minify Enable minification (or --minify.whitespace, --minify.syntax, etc)
16+
--sourcemap <type> Sourcemap type: none|linked|inline|external
17+
--target <target> Build target: browser|bun|node
18+
--format <format> Output format: esm|cjs|iife
19+
--splitting Enable code splitting
20+
--packages <type> Package handling: bundle|external
21+
--public-path <path> Public path for assets
22+
--env <mode> Environment handling: inline|disable|prefix*
23+
--conditions <list> Package.json export conditions (comma separated)
24+
--external <list> External packages (comma separated)
25+
--banner <text> Add banner text to output
26+
--footer <text> Add footer text to output
27+
--define <obj> Define global constants (e.g. --define.VERSION=1.0.0)
28+
--help, -h Show this help message
29+
30+
Example:
31+
bun run build.ts --outdir=dist --minify --sourcemap=linked --external=react,react-dom
32+
`);
33+
process.exit(0);
34+
}
35+
36+
const toCamelCase = (str: string): string => str.replace(/-([a-z])/g, g => g[1].toUpperCase());
37+
38+
const parseValue = (value: string): any => {
39+
if (value === "true") return true;
40+
if (value === "false") return false;
41+
42+
if (/^\d+$/.test(value)) return parseInt(value, 10);
43+
if (/^\d*\.\d+$/.test(value)) return parseFloat(value);
44+
45+
if (value.includes(",")) return value.split(",").map(v => v.trim());
46+
47+
return value;
48+
};
49+
50+
function parseArgs(): Partial<Bun.BuildConfig> {
51+
const config: Partial<Bun.BuildConfig> = {};
52+
const args = process.argv.slice(2);
53+
54+
for (let i = 0; i < args.length; i++) {
55+
const arg = args[i];
56+
if (arg === undefined) continue;
57+
if (!arg.startsWith("--")) continue;
58+
59+
if (arg.startsWith("--no-")) {
60+
const key = toCamelCase(arg.slice(5));
61+
config[key] = false;
62+
continue;
63+
}
64+
65+
if (!arg.includes("=") && (i === args.length - 1 || args[i + 1]?.startsWith("--"))) {
66+
const key = toCamelCase(arg.slice(2));
67+
config[key] = true;
68+
continue;
69+
}
70+
71+
let key: string;
72+
let value: string;
73+
74+
if (arg.includes("=")) {
75+
[key, value] = arg.slice(2).split("=", 2) as [string, string];
76+
} else {
77+
key = arg.slice(2);
78+
value = args[++i] ?? "";
79+
}
80+
81+
key = toCamelCase(key);
82+
83+
if (key.includes(".")) {
84+
const [parentKey, childKey] = key.split(".");
85+
config[parentKey] = config[parentKey] || {};
86+
config[parentKey][childKey] = parseValue(value);
87+
} else {
88+
config[key] = parseValue(value);
89+
}
90+
}
91+
92+
return config;
93+
}
94+
95+
const formatFileSize = (bytes: number): string => {
96+
const units = ["B", "KB", "MB", "GB"];
97+
let size = bytes;
98+
let unitIndex = 0;
99+
100+
while (size >= 1024 && unitIndex < units.length - 1) {
101+
size /= 1024;
102+
unitIndex++;
103+
}
104+
105+
return `${size.toFixed(2)} ${units[unitIndex]}`;
106+
};
107+
108+
console.log("\n🚀 Starting build process...\n");
109+
110+
const cliConfig = parseArgs();
111+
const outdir = cliConfig.outdir || path.join(process.cwd(), "dist");
112+
113+
if (existsSync(outdir)) {
114+
console.log(`🗑️ Cleaning previous build at ${outdir}`);
115+
await rm(outdir, { recursive: true, force: true });
116+
}
117+
118+
const start = performance.now();
119+
120+
const entrypoints = [...new Bun.Glob("**.html").scanSync("src")]
121+
.map(a => path.resolve("src", a))
122+
.filter(dir => !dir.includes("node_modules"));
123+
console.log(`📄 Found ${entrypoints.length} HTML ${entrypoints.length === 1 ? "file" : "files"} to process\n`);
124+
125+
const result = await Bun.build({
126+
entrypoints,
127+
outdir,
128+
plugins: [plugin],
129+
minify: true,
130+
target: "browser",
131+
sourcemap: "linked",
132+
define: {
133+
"process.env.NODE_ENV": JSON.stringify("production"),
134+
},
135+
...cliConfig,
136+
});
137+
138+
const end = performance.now();
139+
140+
const outputTable = result.outputs.map(output => ({
141+
File: path.relative(process.cwd(), output.path),
142+
Type: output.kind,
143+
Size: formatFileSize(output.size),
144+
}));
145+
146+
console.table(outputTable);
147+
const buildTime = (end - start).toFixed(2);
148+
149+
console.log(`\n✅ Build completed in ${buildTime}ms\n`);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Generated by `bun init`
2+
3+
declare module "*.svg" {
4+
/**
5+
* A path to the SVG file
6+
*/
7+
const path: `${string}.svg`;
8+
export = path;
9+
}
10+
11+
declare module "*.module.css" {
12+
/**
13+
* A record of class names to their corresponding CSS module classes
14+
*/
15+
const classes: { readonly [key: string]: string };
16+
export = classes;
17+
}

0 commit comments

Comments
 (0)