Skip to content

Commit 52a416a

Browse files
authored
Feature: update to work for react 19 (#110)
1 parent 99d1f22 commit 52a416a

File tree

16 files changed

+3071
-1790
lines changed

16 files changed

+3071
-1790
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1313
- [MAJOR] Converted package into an es-module
1414
- [MINOR] Added react-app-ssr-vite to build SSR apps with vite
1515
- [MINOR] Added react-app-static-vite to build SSR apps with vite
16+
- [MAJOR] Update ssr and static rendering to work with react 19 (requires setting NODE_ENV externally)
1617

1718
### Changed
1819

makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
install:
2-
@ npm ci
2+
@ npm ci --legacy-peer-deps
33

44
install-updates:
5-
@ npm install
5+
@ npm install --legacy-peer-deps
66

77
list-outdated: install
8-
@ npm outdated
8+
@ npm outdated --legacy-peer-deps
99

1010
lint-check:
1111
@ node scripts/linting/run.js --config-modifier ./config.build.js

package-lock.json

+2,933-1,689
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/linting/lint.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import chalk from 'chalk';
55
import { ESLint } from 'eslint';
66

77
import { buildEslintConfig } from './eslint.config.js';
8-
import { removeUndefinedProperties, runParamsConfigModifier } from '../util.js';
8+
import { buildParams } from '../util.js';
99

1010

1111
export const runLinting = async (inputParams = {}) => {
@@ -17,10 +17,7 @@ export const runLinting = async (inputParams = {}) => {
1717
outputFileFormat: undefined,
1818
fix: false,
1919
};
20-
let params = { ...defaultParams, ...removeUndefinedProperties(inputParams) };
21-
params = await runParamsConfigModifier(params);
22-
process.env.NODE_ENV = params.dev ? 'development' : 'production';
23-
20+
const params = await buildParams(defaultParams, inputParams);
2421
const config = buildEslintConfig(params);
2522
const eslint = new ESLint({
2623
baseConfig: config,

scripts/module-rolldown/build.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ import path from 'node:path';
33
import { rolldown } from 'rolldown';
44

55
import { buildModuleRolldownConfig } from './module.config.js';
6-
import { removeUndefinedProperties, runParamsConfigModifier } from '../util.js';
6+
import { buildParams } from '../util.js';
77

88

99
export const buildModuleRolldown = async (inputParams = {}) => {
1010
const defaultParams = {
1111
configModifier: undefined,
12-
dev: false,
1312
start: false,
1413
rolldownConfigModifier: undefined,
1514
name: undefined,
@@ -19,12 +18,7 @@ export const buildModuleRolldown = async (inputParams = {}) => {
1918
entryFilePath: path.join(process.cwd(), './src/index.ts'),
2019
outputDirectory: path.join(process.cwd(), './dist'),
2120
};
22-
let params = { ...defaultParams, ...removeUndefinedProperties(inputParams) };
23-
params = await runParamsConfigModifier(params);
24-
// NOTE(krishan711): starting modules in dev mode doesn't work yet. Test in everyview console before re-enabling
25-
params.dev = false;
26-
process.env.NODE_ENV = params.dev ? 'development' : 'production';
27-
21+
const params = await buildParams(defaultParams, inputParams, false);
2822
let rolldownConfig = buildModuleRolldownConfig(params);
2923
if (params.rolldownConfigModifier) {
3024
rolldownConfig = params.rolldownConfigModifier(rolldownConfig);

scripts/module-rolldown/run.js

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { buildModuleRolldown } from './build.js';
55

66
const params = program
77
.option('-c, --config-modifier <path>')
8-
.option('-d, --dev')
98
.option('-s, --start')
109
.parse(process.argv)
1110
.opts();

scripts/react-app-ssr-vite/build.js

+8-9
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import { fileURLToPath } from 'node:url';
55
import { build, mergeConfig } from 'vite';
66

77
import { buildReactAppViteConfig } from '../react-app-vite/app.config.js';
8-
import { removeUndefinedProperties, runParamsConfigModifier } from '../util.js';
8+
import { buildParams } from '../util.js';
99

1010
// NOTE(krishan711): most ideas from https://thenewstack.io/how-to-build-a-server-side-react-app-using-vite-and-express/
1111
export const buildSsrReactApp = async (inputParams = {}) => {
1212
const defaultParams = {
13-
dev: false,
1413
start: false,
1514
port: 3000,
1615
configModifier: undefined,
@@ -28,8 +27,7 @@ export const buildSsrReactApp = async (inputParams = {}) => {
2827
publicDirectory: path.join(process.cwd(), './public'),
2928
appEntryFilePath: path.join(process.cwd(), './src/App.tsx'),
3029
};
31-
let params = { ...defaultParams, ...removeUndefinedProperties(inputParams) };
32-
params = await runParamsConfigModifier(params);
30+
const params = await buildParams(defaultParams, inputParams, false);
3331
let viteConfig = buildReactAppViteConfig(params);
3432
if (params.viteConfigModifier) {
3533
viteConfig = params.viteConfigModifier(viteConfig);
@@ -39,19 +37,19 @@ export const buildSsrReactApp = async (inputParams = {}) => {
3937

4038
const outputDirectoryPath = path.resolve(params.outputDirectory);
4139
const appEntryFilePath = path.resolve(params.appEntryFilePath);
42-
const clientOutputDirectoryPath = path.join(outputDirectoryPath, '_client');
43-
const ssrOutputDirectoryPath = path.join(outputDirectoryPath, '_ssr');
40+
const clientDirectory = path.join(outputDirectoryPath, '_client');
41+
const ssrDirectory = path.join(outputDirectoryPath, '_ssr');
4442
console.log('building app...');
4543
await build(mergeConfig(viteConfig, {
4644
build: {
47-
outDir: clientOutputDirectoryPath,
45+
outDir: clientDirectory,
4846
},
4947
}));
5048
console.log('building server app...');
5149
await build(mergeConfig(viteConfig, {
5250
build: {
5351
ssr: true,
54-
outDir: ssrOutputDirectoryPath,
52+
outDir: ssrDirectory,
5553
rollupOptions: {
5654
input: appEntryFilePath,
5755
// NOTE(krishan711): prevent the hashes in the names
@@ -63,8 +61,9 @@ export const buildSsrReactApp = async (inputParams = {}) => {
6361
},
6462
},
6563
}));
64+
const appData = { name, port: params.port, defaultSeoTags: params.seoTags };
6665
const __dirname = path.dirname(fileURLToPath(import.meta.url));
6766
fs.copyFileSync(path.join(__dirname, './server.js'), path.join(outputDirectoryPath, 'index.js'));
68-
fs.writeFileSync(path.join(outputDirectoryPath, 'data.json'), JSON.stringify({ name, port: params.port, defaultSeoTags: params.seoTags }));
67+
fs.writeFileSync(path.join(ssrDirectory, 'appData.json'), JSON.stringify(appData));
6968
console.log('Run `node dist/index.js` to start the server');
7069
};

scripts/react-app-ssr-vite/server.js

+14-9
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ import { getPageData, renderViteHtml } from '@kibalabs/build/scripts/react-app-s
77
import compression from 'compression';
88
import express from 'express';
99

10-
import * as app from './_ssr/assets/App.js';
11-
import data from './data.json' with { type: 'json' };
12-
1310
const shouldCompress = (req, res) => {
1411
if (req.headers['x-no-compression']) {
1512
return false;
@@ -18,17 +15,25 @@ const shouldCompress = (req, res) => {
1815
};
1916

2017
const __dirname = path.dirname(fileURLToPath(import.meta.url));
21-
const htmlTemplate = await fs.readFileSync(path.join(__dirname, '_client/index.html'), 'utf-8');
18+
const clientDirectory = path.join(__dirname, '_client');
19+
const ssrDirectory = path.join(__dirname, '_ssr');
20+
const app = (await import(path.join(ssrDirectory, 'assets/app.js')));
21+
const appData = (await import(path.join(ssrDirectory, 'appData.json'), { with: { type: 'json' } })).default;
22+
const htmlTemplate = await fs.readFileSync(path.join(clientDirectory, 'index.html'), 'utf-8');
2223
export const createAppServer = () => {
2324
const server = express();
2425
server.disable('x-powered-by');
25-
server.use(express.static(path.join(__dirname, '_client'), { immutable: true, maxAge: '1y', index: false }));
26+
server.use(express.static(clientDirectory, { immutable: true, maxAge: '1y', index: false }));
2627
server.use(compression({ filter: shouldCompress }));
2728
server.get('*', async (req, res) => {
29+
const queryString = Object.entries(req.query)
30+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
31+
.join('&');
32+
console.log(`${req.method}:${req.path}:${queryString}`);
2833
const startTime = new Date();
2934
const page = { path: req.path };
30-
const pageData = await getPageData(req.path, app.routes, app.globals);
31-
const html = renderViteHtml(app.App, page, data.defaultSeoTags, data.name, pageData, htmlTemplate);
35+
const pageData = (app.routes && app.globals) ? await getPageData(page.path, app.routes, app.globals) : null;
36+
const html = await renderViteHtml(app.App, page, appData.defaultSeoTags, appData.name, pageData, htmlTemplate);
3237
// TODO(krishan711): move this stuff to a middleware
3338
if (process.env.NAME) {
3439
res.header('X-Server-Name', process.env.NAME);
@@ -41,14 +46,14 @@ export const createAppServer = () => {
4146
}
4247
const duration = (new Date() - startTime) / 1000.0;
4348
res.header('X-Response-Time', String(duration));
44-
console.log(req.method, req.path, req.query, res.statusCode, duration);
49+
console.log(`${req.method}:${req.path}:${queryString}:${res.statusCode}:${duration}`);
4550
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
4651
});
4752
return server;
4853
};
4954

5055
const host = '0.0.0.0';
51-
const port = data.port || 3000;
56+
const port = appData.port || 3000;
5257
const server = createAppServer();
5358
server.listen(port, host, () => {
5459
console.log(`Started server at http://${host}:${port}`);

scripts/react-app-static-vite/build.js

+12-14
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@ import { build, mergeConfig } from 'vite';
66

77
import { getPageData, renderViteHtml } from '../react-app-static/static.js';
88
import { buildReactAppViteConfig } from '../react-app-vite/app.config.js';
9-
import { removeUndefinedProperties, runParamsConfigModifier } from '../util.js';
9+
import { buildParams } from '../util.js';
1010

1111

1212
export const buildStaticReactApp = async (inputParams = {}) => {
1313
const defaultParams = {
14-
dev: false,
1514
configModifier: undefined,
1615
polyfill: true,
1716
polyfillTargets: undefined,
1817
webpackConfigModifier: undefined,
1918
analyzeBundle: false,
2019
shouldAliasModules: true,
21-
addHtmlOutput: false,
20+
addHtmlOutput: true,
2221
addRuntimeConfig: true,
2322
runtimeConfigVars: {},
2423
seoTags: [],
@@ -28,8 +27,7 @@ export const buildStaticReactApp = async (inputParams = {}) => {
2827
publicDirectory: path.join(process.cwd(), './public'),
2928
appEntryFilePath: path.join(process.cwd(), './src/App.tsx'),
3029
};
31-
let params = { ...defaultParams, ...removeUndefinedProperties(inputParams) };
32-
params = await runParamsConfigModifier(params);
30+
const params = await buildParams(defaultParams, inputParams, false);
3331
let viteConfig = buildReactAppViteConfig(params);
3432
if (params.viteConfigModifier) {
3533
viteConfig = params.viteConfigModifier(viteConfig);
@@ -39,19 +37,19 @@ export const buildStaticReactApp = async (inputParams = {}) => {
3937

4038
const outputDirectoryPath = path.resolve(params.outputDirectory);
4139
const appEntryFilePath = path.resolve(params.appEntryFilePath);
42-
const clientOutputDirectoryPath = path.join(outputDirectoryPath, '_client');
43-
const ssrOutputDirectoryPath = path.join(outputDirectoryPath, '_ssr');
40+
const clientDirectory = path.join(outputDirectoryPath, '_client');
41+
const ssrDirectory = path.join(outputDirectoryPath, '_ssr');
4442
console.log('building app...');
4543
await build(mergeConfig(viteConfig, {
4644
build: {
47-
outDir: clientOutputDirectoryPath,
45+
outDir: clientDirectory,
4846
},
4947
}));
5048
console.log('building server app...');
5149
await build(mergeConfig(viteConfig, {
5250
build: {
5351
ssr: true,
54-
outDir: ssrOutputDirectoryPath,
52+
outDir: ssrDirectory,
5553
rollupOptions: {
5654
input: appEntryFilePath,
5755
// NOTE(krishan711): prevent the hashes in the names
@@ -63,17 +61,17 @@ export const buildStaticReactApp = async (inputParams = {}) => {
6361
},
6462
},
6563
}));
66-
67-
const app = (await import(path.join(ssrOutputDirectoryPath, 'assets/App.js')));
68-
const htmlTemplate = await fs.readFileSync(path.join(clientOutputDirectoryPath, 'index.html'), 'utf-8');
64+
const app = (await import(path.join(ssrDirectory, 'assets/app.js')));
65+
const appData = { name, port: params.port, defaultSeoTags: params.seoTags };
66+
const htmlTemplate = await fs.readFileSync(path.join(clientDirectory, 'index.html'), 'utf-8');
6967
// NOTE(krishan711): if this could be done in an parallel way it would be faster!
7068
params.pages.forEach(async (page) => {
7169
console.log(`Rendering page ${page.path} to ${page.filename}`);
7270
const pageData = (app.routes && app.globals) ? await getPageData(page.path, app.routes, app.globals) : null;
73-
const output = renderViteHtml(app.App, page, params.seoTags, name, pageData, htmlTemplate);
71+
const html = await renderViteHtml(app.App, page, appData.defaultSeoTags, appData.name, pageData, htmlTemplate);
7472
const outputPath = path.join(outputDirectoryPath, page.filename);
7573
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
76-
fs.writeFileSync(outputPath, output);
74+
fs.writeFileSync(outputPath, html);
7775
console.log(`Done rendering page ${page.path}`);
7876
});
7977
};

0 commit comments

Comments
 (0)