Skip to content

Commit

Permalink
feat: add support for prerendering
Browse files Browse the repository at this point in the history
  • Loading branch information
svedova committed Jan 13, 2023
1 parent 556c4b8 commit b5d4021
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 2 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"type": "module",
"scripts": {
"dev": "nodemon --watch './**/*.ts' --exec 'node --loader ts-node/esm' src/vite-server.ts",
"build": "tsc && vite build",
"build": "npm run build:spa && npm run build:ssg",
"build:spa": "tsc && vite build",
"build:ssg": "tsc && SSG=true node --loader ts-node/esm ./src/vite-server.ts",
"preview": "vite preview"
},
"dependencies": {
Expand Down
7 changes: 7 additions & 0 deletions src/prerender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This file contains the routes to be prerendered.
// The exported array is a static one, but could be easily
// transformed into a dynamic list.
// Check import.meta.glob provided by Vite to scan folders dynamically
// and build the routes to be prerendered.

export default ["/", "/my-page", "/my-other-page"];
64 changes: 63 additions & 1 deletion src/vite-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,66 @@ async function createServer() {
});
}

createServer();
async function generateStaticPages() {
// Create Vite server to load the routes files
const vite = await createViteServer({
server: { middlewareMode: true },
appType: "custom",
});

const { default: routesToPrerender } = (await vite.ssrLoadModule(
"./src/prerender"
)) as { default: string[] };

const { render } = await vite.ssrLoadModule("./src/entry-server");

const dist = path.join(path.dirname(__dirname), ".stormkit/public");

if (!fs.existsSync(dist)) {
throw new Error(
".stormkit/public is not available. Did you run `npm run build:spa`?"
);
}

const template = fs.readFileSync(path.join(dist, "index.html"), "utf-8");
const manifest = JSON.parse(
fs.readFileSync(path.join(dist, "manifest.json"), "utf-8")
);

// Push `/` to the end if any.
routesToPrerender.sort((a: string, b: string) => {
return a === "/" || b === "/" ? -1 : 0;
});

for (const r of routesToPrerender) {
const data = await render(r);
const fileName = r.endsWith("/") ? `${r}index.html` : `${r}.html`;
const absPath = path.join(dist, fileName);
let content = injectContent(data.head, data.content, template);

// Fix the path to the static assets.
Object.keys(manifest).forEach((fileName) => {
if (fileName.startsWith("src/assets")) {
content = content.replace(fileName, manifest[fileName].fileName);
}
});

fs.mkdirSync(path.dirname(absPath), { recursive: true });
fs.writeFileSync(absPath, content, "utf-8");

console.log(`Prerendered: ${fileName}`);
}

fs.unlinkSync(path.join(dist, "manifest.json"));

await vite.close();
}

(async () => {
if (process.env.SSG === "true") {
console.info("Detected SSG=true - generating static routes...");
await generateStaticPages();
} else {
createServer();
}
})();
7 changes: 7 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,12 @@ export default defineConfig({
],
extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json"],
},
build: {
manifest: true,
rollupOptions: {
input: "index.html",
},
outDir: ".stormkit/public",
},
plugins: [react()],
});

0 comments on commit b5d4021

Please sign in to comment.