Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
panthyy committed May 6, 2023
1 parent 4ef5720 commit 7bf70a0
Show file tree
Hide file tree
Showing 12 changed files with 389 additions and 14 deletions.
17 changes: 14 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
{
"name": "cli",
"name": "cinnabun-cli",
"version": "1.0.0",
"description": "",
"main": "src/main",
"type": "commonjs",
"bin": {
"cinnabun": "dist/index.js"
},
"scripts": {
"build": "tsc",
"build:watch": "tsc -w",
"start": "pnpm build && node dist/index.js",
"test": "vitest"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@chialab/esbuild-plugin-virtual": "^0.17.1",
"@fastify/compress": "^6.2.1",
"@fastify/static": "^6.10.1",
"@fastify/websocket": "^8.0.0",
"chalk": "4.1.2",
"cinnabun": "workspace:^",
"commander": "^7.2.0",
"glob": "^10.2.2",
"esbuild": "^0.17.18",
"fast-glob": "^3.2.12",
"fastify": "^4.17.0",
"inquirer": "^9.2.0",
"vitest": "^0.31.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"type-fest": "^3.10.0"
"type-fest": "^3.10.0",
"typescript": "^5.0.4"
}
}
10 changes: 10 additions & 0 deletions packages/cli/src/build/_tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"jsx": "transform",
"jsxFactory": "Cinnabun.h",
"jsxFragment": "Cinnabun.fragment",
"module": "CommonJS",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"esModuleInterop": true,
"isolatedModules": true
}
46 changes: 46 additions & 0 deletions packages/cli/src/build/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const esbuild = require("esbuild")

const {
regexPatterns,
replaceServerFunctions,
generateFileRouter,
} = require("./transform.plugin")

/**
* @type {esbuild.BuildOptions}
*/
export const sharedSettings = {
bundle: true,
//minify: true,
format: "cjs",
target: "esnext",
tsconfig: "_tsconfig.json",
jsx: "transform",
jsxFactory: "Cinnabun.h",
jsxFragment: "Cinnabun.fragment",
jsxImportSource: "Cinnabun",
}

export const buildServer = async () =>
esbuild.build({
sourcemap: "linked",
entryPoints: ["./src/App.tsx"],
write: false,
platform: "node",
...sharedSettings,
plugins: [generateFileRouter()],
})

export const buildClient = async () =>
esbuild.build({
entryPoints: ["./src/index.ts"],
outdir: "dist/static",
splitting: true,
...sharedSettings,
format: "esm",
plugins: [
generateFileRouter(),
replaceServerFunctions(regexPatterns.ServerPromise),
replaceServerFunctions(regexPatterns.$fn),
],
})
3 changes: 3 additions & 0 deletions packages/cli/src/build/cinnabun-shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { Cinnabun } = require("cinnabun")

export default Cinnabun
76 changes: 76 additions & 0 deletions packages/cli/src/build/prebuild.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
var fs = require("fs")
var path = require("path")

function getFiles(source, outputRoutes = []) {
if (fs.lstatSync(source).isDirectory()) {
let files = fs.readdirSync(source)
files.forEach(function (file) {
let curSource = path.join(source, file)
if (fs.lstatSync(curSource).isDirectory()) {
getFiles(curSource, outputRoutes)
} else {
outputRoutes.push(curSource)
}
})
}
return outputRoutes
}

const scanDir = () => {
return getFiles("app")
}

const transformRoutePath = (routePath, isComponentRoute) => {
let res = routePath
.replaceAll(path.sep, "/")
.replace(".tsx", "")
.replace(".ts", "")

if (isComponentRoute) {
if (res.startsWith("app/")) res = `./${res.substring(4)}`
res = res.replace("/Page", "").replaceAll("[", ":").replaceAll("]", "")
if (res[0] === ".") res = res.substring(1)
if (res === "") res = "/"
}
return res
}

const createFileRouter = (routes) => {
const cwd = process.cwd().replaceAll(path.sep, "/")

const pageRoutes = routes.filter((r) =>
["Page.tsx", "Page.jsx"].some((name) => r.includes(name))
)
const routeImports = pageRoutes.map(
(r) => `import("${cwd}/${transformRoutePath(r)}")`
)
const content = `import * as Cinnabun from "../../"
import { Cinnabun as cb, createSignal } from "../../../"
import { Route, Router } from "../"
const pathStore = createSignal(cb.isClient ? window.location.pathname : "/")
var FileRoutes = () => {
return (
<Router store={pathStore}>
${routeImports
.map(
(r, i) =>
`<Route path="${transformRoutePath(
pageRoutes[i],
true
)}" component={(props) => Cinnabun.lazy(${r}, props)} />\n `
)
.join("")}
</Router>
)
}`
return content
}
const prebuild = () => {
const routes = scanDir()
return createFileRouter(routes)
}

module.exports = {
prebuild,
}
59 changes: 59 additions & 0 deletions packages/cli/src/build/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fastify from "fastify"
import compress from "@fastify/compress"
import fStatic from "@fastify/static"
import path from "path"
import { Cinnabun } from "cinnabun"
import { SSR, SSRConfig } from "cinnabun/ssr"
import { ComponentFunc } from "cinnabun/src/types"

export function createServer(App: ComponentFunc) {
//const { App } = await import(path.resolve(process.cwd(), "src", "App"))

//console.log("Creating server - App: ", App)

const app = fastify()

app.register(compress, { global: false })
app.register(fStatic, {
prefix: "/static/",
root: path.join(__dirname, "../../dist/static"),
})
app.get("/favicon.ico", (_, res) => {
res.status(404).send()
})

app.get("/*", async (req, res) => {
console.log("req.url: ", req.url)
const cinnabunInstance = new Cinnabun()

cinnabunInstance.setServerRequestData({
path: req.url,
data: {},
})

const config: SSRConfig = {
cinnabunInstance,
stream: res.raw,
}

res.header("Content-Type", "text/html").status(200)
res.header("Transfer-Encoding", "chunked")
res.raw.write("<!DOCTYPE html><html>")

const { componentTree } = await SSR.serverBake(App(), config)

res.raw.write(`
<script id="server-props">
window.__cbData = {
root: document.documentElement,
component: ${JSON.stringify(componentTree)}
}
</script>
<script type="module" src="/static/index.js"></script>
</html>
`)
res.raw.end()
})

return app
}
123 changes: 123 additions & 0 deletions packages/cli/src/build/transform-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"use strict"
const fs = require("fs")
const { prebuild } = require("./prebuild")

const regexPatterns = {
ServerPromise:
/async function\s+(\w+)\s*\([^)]*\)\s*:\s*ServerPromise\s*<[^>]*>\s*{(?:[^{}]*|{(?:[^{}]*|{(?:[^{}]*|{[^{}]*})*})*})*}/gm,
$fn: /async function\s+(\$[\w\d]+)\(\): Promise<[\w\d]+>\s*{(?:[^{}]*|{(?:[^{}]*|{(?:[^{}]*|{[^{}]*})*})*})*}/gm,
}

const replaceServerFunctions = (rgxPattern) => ({
name: "function-replacer-plugin",
setup(build) {
build.onLoad({ filter: /\.tsx?$/ }, async (args) => {
const contents = await fs.promises.readFile(args.path, "utf8")

const transformedContents = contents.replace(
rgxPattern,
(match, p1) => `async function ${p1}() {}`
)
return { contents: transformedContents, loader: "tsx" }
})
},
})

const generateServer = () => ({
name: "generate-server-plugin",
setup(build) {
build.onLoad({ filter: /App\.tsx?$/ }, async (args) => {
console.log("GENERATE_SERVER")
const contents = await fs.promises.readFile(args.path, "utf8")
const server = `
export default function createServer() {
const app = fastify()
app.register(compress, { global: false })
app.register(fStatic, {
prefix: "/static/",
root: path.join(__dirname, "../../dist/static"),
})
app.get("/favicon.ico", (_, res) => {
res.status(404).send()
})
app.get("/*", async (req, res) => {
const cinnabunInstance = new Cinnabun.Cinnabun()
console.log("cinnabunInstance", cinnabunInstance)
console.log("req.url", req.url)
cinnabunInstance.setServerRequestData({
path: req.url,
data: {},
})
const config: SSRConfig = {
cinnabunInstance,
stream: res.raw,
}
res.header("Content-Type", "text/html").status(200)
res.header("Transfer-Encoding", "chunked")
res.raw.write("<!DOCTYPE html><html>")
const { componentTree } = await SSR.serverBake(App(), config)
console.log("SUPERFISH")
res.raw.write("<script id='server-props'>window.__cbData = {root: document.documentElement,component: " + JSON.stringify(componentTree) + "}</script><script type='module' src='static/index.js'></script></html>")
res.raw.end()
})
return app
}
globalThis.createServer = createServer;
`

return {
contents: `
import fastify from "fastify"
import compress from "@fastify/compress"
import fStatic from "@fastify/static"
import path from "path"
import { SSR, SSRConfig } from "cinnabun/ssr"
import { ComponentFunc } from "cinnabun/src/types"
${contents}
//~~~~~~~~
${server}
`,
loader: "tsx",
}
})
},
})

const generateFileRouter = () => ({
name: "fileRoute-generator-plugin",
setup(build) {
build.onLoad({ filter: /fileRouter\.js?$/ }, async (args) => {
const contents = await fs.promises.readFile(args.path, "utf8")

const replaced = contents
.replace("//@ts-expect-error TS2552", "")
.replace("var FileRoutes = $FILE_ROUTES", prebuild())

return {
contents: replaced,
loader: "jsx",
}
})
},
})

module.exports = {
replaceServerFunctions,
regexPatterns,
generateFileRouter,
generateServer,
}
4 changes: 3 additions & 1 deletion packages/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// TypeScript (.ts)
import commander, { Command } from "commander"
import chalk from "chalk"
import { build, start, dev } from "./routes"
import start from "./routes/start.js"
import dev from "./routes/dev.js"
import build from "./routes/build.js"

const program = new Command()

Expand Down
3 changes: 0 additions & 3 deletions packages/cli/src/routes/index.ts

This file was deleted.

Loading

0 comments on commit 7bf70a0

Please sign in to comment.