Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"start": "bun run dev",
"dev": "winterspec dev -p 3062",
"build": "bun run build:bundle && bun run build:cli",
"build:bundle": "winterspec bundle -o dist/bundle.js",
"build:bundle": "bun scripts/build-bundle.ts",
"build:cli": "tsup cli.ts --format esm --dts",
"next:dev": "next dev",
"format": "biome format --write .",
Expand Down
101 changes: 101 additions & 0 deletions scripts/build-bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import esbuild from "esbuild"
import { mkdir, readdir, writeFile } from "node:fs/promises"
import path from "node:path"

type RouteFile = {
absolutePath: string
relativePath: string
route: string
}

const projectRoot = path.resolve(import.meta.dir, "..")
const routesDir = path.join(projectRoot, "routes")
const outputPath = path.join(projectRoot, "dist", "bundle.js")

const collectRouteFiles = async (
dir: string,
baseDir = dir,
): Promise<Array<RouteFile>> => {
const entries = await readdir(dir, { withFileTypes: true })
const files: Array<RouteFile> = []

for (const entry of entries) {
const absolutePath = path.join(dir, entry.name)

if (entry.isDirectory()) {
files.push(...(await collectRouteFiles(absolutePath, baseDir)))
continue
}

if (!/\.(ts|tsx)$/.test(entry.name)) {
continue
}

const relativePath = path.relative(baseDir, absolutePath)
const posixRelativePath = relativePath.split(path.sep).join("/")
const routePath = `/${posixRelativePath}`
const route =
routePath.endsWith("/index.ts") || routePath.endsWith("/index.tsx")
? routePath.replace(/\/index\.tsx*$/g, "")
: routePath.replace(/\.tsx*$/g, "")

files.push({
absolutePath,
relativePath: posixRelativePath,
route: route === "" ? "/" : route,
})
}

return files
}

const routes = (await collectRouteFiles(routesDir)).sort((a, b) =>
a.route.localeCompare(b.route),
)

const manifest = `
import { getRouteMatcher } from "next-route-matcher"
import { makeRequestAgainstWinterSpec } from "winterspec"

${routes
.map(
({ absolutePath }, index) =>
`import * as route_${index} from ${JSON.stringify(
absolutePath.replace(/\\/g, "/"),
)}`,
)
.join("\n")}

const routeMapWithHandlers = {
${routes
.map(({ route }, index) => `"${route}": route_${index}.default`)
.join(",\n ")}
}

const winterSpec = {
routeMatcher: getRouteMatcher(Object.keys(routeMapWithHandlers)),
routeMapWithHandlers,
makeRequest: async (req, options) => makeRequestAgainstWinterSpec(winterSpec, options)(req),
}

export default winterSpec
`

const result = await esbuild.build({
stdin: {
contents: manifest,
resolveDir: routesDir,
loader: "ts",
},
bundle: true,
format: "esm",
write: false,
sourcemap: "inline",
platform: "node",
packages: "external",
})

await mkdir(path.dirname(outputPath), { recursive: true })
await writeFile(outputPath, result.outputFiles[0].text)

console.log(`Built bundle to ${path.relative(projectRoot, outputPath)}`)
Loading