Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create SSR production server #178

Merged
merged 8 commits into from
Feb 22, 2024
Merged
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 README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<h1 align="center" style="text-align:center">🪜 chersite</h1>

<p align="center">
chersite is multi apps structure witch include front static-site generator for cher-ami projects
chersite is multi apps structure witch include a SSG/SSR front framework for cher-ami projects

<br/>
<br/>
Expand Down
29 changes: 23 additions & 6 deletions apps/front/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

## About

This front app is a React static-site generator build in order to obtain a static server rendering for best performance. It run with [vite](https://vitejs.dev/), [react](https://reactjs.org/),[typescript](https://www.typescriptlang.org/), and [scss](https://sass-lang.com/). The build step prepare a server script, a prerender script and a SPA version to leave choice of use. This one embeds [@cher-ami/router](https://github.com/cher-ami/router) to manage server static props, routes transitions and languages.
This front app is a React SSG/SSR framework. It run with [vite](https://vitejs.dev/), [react](https://reactjs.org/),[typescript](https://www.typescriptlang.org/), and [scss](https://sass-lang.com/). The build step prepare a server script, a prerender script and a SPA version to leave choice of use. This one embeds [@cher-ami/router](https://github.com/cher-ami/router) to manage server static props, routes transitions and languages.

## Entry points

Two entry points are set:

- server side [src/server/index-server.tsx](src/server/index-server.tsx)
- client side [src/index.tsx](src/index.tsx)
- server side [src/index-server.tsx](src/index-server.tsx)
- client side [src/index-client.tsx](src/index-client.tsx)

## Configuration Files

Expand All @@ -28,10 +28,19 @@ Vite's configuration is managed by two main files:
- [vite.scripts.config.ts](vite.scripts.config.ts): contains the whole vite scripts config. It built scripts files relative to the SSR and SSG part.
- [config/config.js](config/config.js): is the internal paths and tasks config file.

## Prerender
## SSR

The main goal of this app is to generate a static site. The prerender script is used to generate static html files from the server side.
The app is SSR ready:

```shell
npm run build && npm run start
```

## SSG

chersite front allows to generate a static site. The prerender script is used to generate static html files from the server side.

The "prerender" fonction need to know the list of routes to generate as static html files.
You have to list manually all routes you want to prerender in [prerender/urls.ts](prerender/urls.ts):

```ts
Expand All @@ -50,7 +59,7 @@ return new Promise((resolve) => {
})
```

⚠️ **The front application routing is not dependent to the generated html files, so you can add any route you want in
⚠️ **The front application routing is not linked to the generated html files, so you can add any route you want in
this list**. In case you use a backend, you will have to get all routes from a backend API call and add them in this list.

By default, the generate command is executed on build step, but you can run it manually:
Expand Down Expand Up @@ -92,6 +101,14 @@ Generate static html files from the server side.
npm run generate
```

### start

Start the production server for SSR

```shell
npm run start
```

## Vite plugins

By default, chersite implement:
Expand Down
2 changes: 1 addition & 1 deletion apps/front/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
// Set the relative paths, don't resolve them.
// This config is used only if the index is not generated by vite
input: [
// "src/index.tsx",
// "src/index-client.tsx",
],

// Build dotenv outDir array
Expand Down
2 changes: 1 addition & 1 deletion apps/front/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<script type="module" src="/src/index-client.tsx"></script>
</body>
</html>
58 changes: 58 additions & 0 deletions apps/front/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 11 additions & 8 deletions apps/front/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"name": "chersite-front",
"version": "0.1.0",
"main": "src/index.tsx",
"main": "src/index-client.tsx",
"type": "module",
"scripts": {
"dev": "node server.js",
"build:client": "vite build --outDir dist/client",
"build:server": "vite build --ssr src/server/index-server.tsx --outDir dist/server",
"dev": "node server.dev.js",
"build:client": "vite build --ssrManifest --outDir dist/client",
"build:server": "vite build --ssr src/index-server.tsx --outDir dist/server",
"build:scripts": "vite build -c vite.scripts.config.ts",
"build:static": "vite build --outDir dist/static",
"build": "npm run build:server && npm run build:scripts && npm run build:static && npm run generate",
"build:static": "vite build --outDir dist/static --ssrManifest",
"build": "npm run build:server && npm run build:client && npm run build:scripts && npm run build:static",
"generate": "node dist/_scripts/exe-prerender.js",
"preview": "serve dist/static",
"start": "cross-env NODE_ENV=production node server.prod",
"test:watch": "vitest",
"test": "vitest run"
},
Expand All @@ -36,17 +37,19 @@
"autoprefixer": "^10.4.17",
"chalk": "^5.3.0",
"compression": "^1.7.4",
"cross-env": "^7.0.3",
"express": "^4.18.2",
"husky": "^9.0.10",
"ip": "^1.1.8",
"portfinder-sync": "^0.0.2",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.70.0",
"sirv": "^2.0.4",
"terser": "^5.27.0",
"typescript": "^5.3.3",
"vite": "^5.0.12",
"vite-plugin-checker": "^0.6.4",
"vitest": "^1.2.2",
"sass": "^1.70.0"
"vitest": "^1.2.2"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.6.1",
Expand Down
16 changes: 12 additions & 4 deletions apps/front/prerender/prerender.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-ignore
import { render } from "~/server/index-server"
import { render } from "~/index-server"
import * as mfs from "@cher-ami/mfs"
import path from "path"
import chalk from "chalk"
Expand All @@ -9,7 +9,6 @@ import { isRouteIndex } from "./helpers/isRouteIndex"
import { ManifestParser } from "./helpers/ManifestParser"
import { renderToPipeableStream, renderToString } from "react-dom/server"
import { JSXElementConstructor, ReactElement } from "react"
import { htmlReplacement } from "~/server/helpers/htmlReplacement"

/**
* Prerender
Expand All @@ -26,7 +25,7 @@ export const prerender = async (urls: string[], outDirStatic = config.outDirStat
}

// get script tags to inject in render
const base = process.env.VITE_APP_BASE || loadEnv("", process.cwd(), "").VITE_APP_BASE
const base = loadEnv("", process.cwd(), "").VITE_APP_BASE || process.env.VITE_APP_BASE
const manifest = (await mfs.readFile(`${outDirStatic}/.vite/manifest.json`)) as string
const scriptTags = ManifestParser.getScriptTagFromManifest(manifest, base)

Expand All @@ -36,7 +35,7 @@ export const prerender = async (urls: string[], outDirStatic = config.outDirStat

try {
// Request DOM
const dom = await render(url, scriptTags, true)
const dom = await render(url, scriptTags, true, base)
// create stream and generate current file when all DOM is ready
renderToPipeableStream(dom, {
onAllReady() {
Expand Down Expand Up @@ -73,3 +72,12 @@ const createHtmlFile = async (
await mfs.createFile(htmlFilePath, htmlReplacement(renderToString(dom)))
console.log(chalk.green(` → ${htmlFilePath.split("static")[1]}`))
}

/**
* Render string patch middleware
*/
const htmlReplacement = (render: string): string =>
render
.replace("<html", `<!DOCTYPE html><html`)
.replaceAll('<script nomodule=""', "<script nomodule")
.replaceAll('crossorigin="anonymous"', "crossorigin")
Loading
Loading