hadars 0.1.36 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli-lib.ts +18 -10
- package/dist/{chunk-OID7K4D3.js → chunk-F7IIMM3J.js} +7 -7
- package/dist/{chunk-OZUZS2PD.js → chunk-OS3V4CPN.js} +4 -4
- package/dist/cli.js +40 -13
- package/dist/{hadars-ScRgKezP.d.cts → hadars-B3b_6sj2.d.cts} +12 -0
- package/dist/{hadars-ScRgKezP.d.ts → hadars-B3b_6sj2.d.ts} +12 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/lambda.cjs +28 -28
- package/dist/lambda.d.cts +1 -1
- package/dist/lambda.d.ts +1 -1
- package/dist/lambda.js +24 -24
- package/dist/slim-react/index.cjs +10 -10
- package/dist/slim-react/index.js +2 -2
- package/dist/slim-react/jsx-runtime.cjs +4 -2
- package/dist/slim-react/jsx-runtime.js +1 -1
- package/dist/ssr-watch.js +21 -1
- package/package.json +2 -2
- package/src/build.ts +3 -0
- package/src/lambda.ts +24 -5
- package/src/types/hadars.ts +10 -0
- package/src/utils/rspack.ts +27 -0
- package/src/utils/ssrHandler.ts +21 -0
package/cli-lib.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { mkdir, writeFile, unlink } from 'node:fs/promises'
|
|
3
3
|
import { resolve, join, dirname } from 'node:path'
|
|
4
|
-
import {
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import * as Hadars from './src/build'
|
|
6
6
|
import type { HadarsOptions } from './src/types/hadars'
|
|
7
7
|
|
|
@@ -70,11 +70,16 @@ async function bundleLambda(
|
|
|
70
70
|
|
|
71
71
|
// 3. Write a temporary entry shim that statically imports the SSR module
|
|
72
72
|
// and the HTML template so esbuild can inline both.
|
|
73
|
-
|
|
73
|
+
// Write the shim inside cwd so esbuild's module resolution finds local
|
|
74
|
+
// node_modules when walking up from the shim's directory.
|
|
75
|
+
// Use the absolute path to lambda.js (sibling of the CLI in dist/) so the
|
|
76
|
+
// shim doesn't depend on package name resolution at all.
|
|
77
|
+
const lambdaModule = resolve(dirname(fileURLToPath(import.meta.url)), 'lambda.js')
|
|
78
|
+
const shimPath = join(cwd, `.hadars-lambda-shim-${Date.now()}.ts`)
|
|
74
79
|
const shim = [
|
|
75
80
|
`import * as ssrModule from ${JSON.stringify(ssrBundle)};`,
|
|
76
81
|
`import outHtml from ${JSON.stringify(outHtml)};`,
|
|
77
|
-
`import { createLambdaHandler } from
|
|
82
|
+
`import { createLambdaHandler } from ${JSON.stringify(lambdaModule)};`,
|
|
78
83
|
`import config from ${JSON.stringify(configPath)};`,
|
|
79
84
|
`export const handler = createLambdaHandler(config as any, { ssrModule: ssrModule as any, outHtml });`,
|
|
80
85
|
].join('\n') + '\n'
|
|
@@ -93,16 +98,19 @@ async function bundleLambda(
|
|
|
93
98
|
outfile: outputFile,
|
|
94
99
|
sourcemap: false,
|
|
95
100
|
loader: { '.html': 'text', '.tsx': 'tsx', '.ts': 'ts' },
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
101
|
+
// @rspack/* contains native binaries and is build-time only —
|
|
102
|
+
// it is never imported at Lambda runtime, so mark it external.
|
|
103
|
+
// Everything else (React, hadars runtime, etc.) is bundled in to
|
|
104
|
+
// produce a truly self-contained single-file deployment.
|
|
105
|
+
external: ['@rspack/*'],
|
|
100
106
|
})
|
|
101
107
|
console.log(`Lambda bundle written to ${outputFile}`)
|
|
102
108
|
console.log(`\nDeploy instructions:`)
|
|
103
|
-
console.log(` 1.
|
|
104
|
-
console.log(`
|
|
105
|
-
console.log(`
|
|
109
|
+
console.log(` 1. Create a staging directory with just this file:`)
|
|
110
|
+
console.log(` mkdir -p lambda-deploy && cp ${outputFile} lambda-deploy/lambda.mjs`)
|
|
111
|
+
console.log(` 2. Upload lambda-deploy/ as your Lambda function code`)
|
|
112
|
+
console.log(` 3. Set handler to: lambda.handler (runtime: Node.js 20.x)`)
|
|
113
|
+
console.log(` 4. Upload .hadars/static/ assets to S3 and serve via CloudFront`)
|
|
106
114
|
console.log(` (the Lambda handler does not serve static JS/CSS — route those to S3)`)
|
|
107
115
|
} finally {
|
|
108
116
|
await unlink(shimPath).catch(() => {})
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
SLIM_ELEMENT,
|
|
6
6
|
SUSPENSE_TYPE,
|
|
7
7
|
createElement
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OS3V4CPN.js";
|
|
9
9
|
|
|
10
10
|
// src/slim-react/renderContext.ts
|
|
11
11
|
var MAP_KEY = "__slimReactContextMap";
|
|
@@ -577,12 +577,12 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
577
577
|
}
|
|
578
578
|
writer.write(`</${tag}>`);
|
|
579
579
|
}
|
|
580
|
-
var REACT_MEMO =
|
|
581
|
-
var REACT_FORWARD_REF =
|
|
582
|
-
var REACT_PROVIDER =
|
|
583
|
-
var REACT_CONTEXT =
|
|
584
|
-
var REACT_CONSUMER =
|
|
585
|
-
var REACT_LAZY =
|
|
580
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
581
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
582
|
+
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
583
|
+
var REACT_CONTEXT = Symbol.for("react.context");
|
|
584
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
585
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
586
586
|
function renderComponent(type, props, writer, isSvg) {
|
|
587
587
|
const typeOf = type?.$$typeof;
|
|
588
588
|
if (typeOf === REACT_MEMO) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/slim-react/types.ts
|
|
2
|
-
var SLIM_ELEMENT =
|
|
3
|
-
var REACT19_ELEMENT =
|
|
4
|
-
var FRAGMENT_TYPE =
|
|
5
|
-
var SUSPENSE_TYPE =
|
|
2
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
3
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
4
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
5
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
6
6
|
|
|
7
7
|
// src/slim-react/jsx.ts
|
|
8
8
|
var Fragment = FRAGMENT_TYPE;
|
package/dist/cli.js
CHANGED
|
@@ -6,8 +6,8 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
6
6
|
// cli-lib.ts
|
|
7
7
|
import { existsSync as existsSync3 } from "node:fs";
|
|
8
8
|
import { mkdir, writeFile, unlink } from "node:fs/promises";
|
|
9
|
-
import { resolve, join } from "node:path";
|
|
10
|
-
import {
|
|
9
|
+
import { resolve, join, dirname } from "node:path";
|
|
10
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
11
11
|
|
|
12
12
|
// src/utils/proxyHandler.tsx
|
|
13
13
|
var cloneHeaders = (headers) => {
|
|
@@ -1307,6 +1307,25 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1307
1307
|
}
|
|
1308
1308
|
}
|
|
1309
1309
|
const extraPlugins = [];
|
|
1310
|
+
if (!isServerBuild) {
|
|
1311
|
+
extraPlugins.push({
|
|
1312
|
+
apply(compiler) {
|
|
1313
|
+
compiler.hooks.compilation.tap("HadarsWorkerChunkLoading", (compilation) => {
|
|
1314
|
+
compilation.hooks.childCompiler.tap(
|
|
1315
|
+
"HadarsWorkerChunkLoading",
|
|
1316
|
+
(childCompiler) => {
|
|
1317
|
+
if (childCompiler.options?.output) {
|
|
1318
|
+
childCompiler.options.output.chunkLoading = "import-scripts";
|
|
1319
|
+
}
|
|
1320
|
+
if (childCompiler.options?.experiments) {
|
|
1321
|
+
childCompiler.options.experiments.outputModule = false;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
);
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
}
|
|
1310
1329
|
const defineValues = { ...opts.define ?? {} };
|
|
1311
1330
|
if (!isServerBuild && opts.reactMode !== void 0) {
|
|
1312
1331
|
defineValues["process.env.NODE_ENV"] = JSON.stringify(opts.reactMode);
|
|
@@ -1383,7 +1402,8 @@ var buildCompilerConfig = (entry, opts, includeHotPlugin) => {
|
|
|
1383
1402
|
},
|
|
1384
1403
|
isDev && !isServerBuild && new ReactRefreshPlugin(),
|
|
1385
1404
|
includeHotPlugin && isDev && !isServerBuild && new rspack.HotModuleReplacementPlugin(),
|
|
1386
|
-
...extraPlugins
|
|
1405
|
+
...extraPlugins,
|
|
1406
|
+
...opts.plugins ?? []
|
|
1387
1407
|
],
|
|
1388
1408
|
...localConfig,
|
|
1389
1409
|
// Merge base resolve (modules, tsConfig, extensions) with per-build resolve
|
|
@@ -1983,6 +2003,7 @@ var dev = async (options) => {
|
|
|
1983
2003
|
swcPlugins: options.swcPlugins,
|
|
1984
2004
|
define: options.define,
|
|
1985
2005
|
moduleRules: options.moduleRules,
|
|
2006
|
+
plugins: options.plugins,
|
|
1986
2007
|
reactMode: options.reactMode,
|
|
1987
2008
|
htmlTemplate: resolvedHtmlTemplate
|
|
1988
2009
|
});
|
|
@@ -2201,6 +2222,7 @@ var build = async (options) => {
|
|
|
2201
2222
|
swcPlugins: options.swcPlugins,
|
|
2202
2223
|
define: options.define,
|
|
2203
2224
|
moduleRules: options.moduleRules,
|
|
2225
|
+
plugins: options.plugins,
|
|
2204
2226
|
optimization: options.optimization,
|
|
2205
2227
|
reactMode: options.reactMode,
|
|
2206
2228
|
htmlTemplate: resolvedHtmlTemplate
|
|
@@ -2218,7 +2240,8 @@ var build = async (options) => {
|
|
|
2218
2240
|
mode: "production",
|
|
2219
2241
|
swcPlugins: options.swcPlugins,
|
|
2220
2242
|
define: options.define,
|
|
2221
|
-
moduleRules: options.moduleRules
|
|
2243
|
+
moduleRules: options.moduleRules,
|
|
2244
|
+
plugins: options.plugins
|
|
2222
2245
|
})
|
|
2223
2246
|
]);
|
|
2224
2247
|
await fs.rm(tmpFilePath);
|
|
@@ -2374,11 +2397,12 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
2374
2397
|
console.error(`HTML template not found: ${outHtml}`);
|
|
2375
2398
|
process.exit(1);
|
|
2376
2399
|
}
|
|
2377
|
-
const
|
|
2400
|
+
const lambdaModule = resolve(dirname(fileURLToPath3(import.meta.url)), "lambda.js");
|
|
2401
|
+
const shimPath = join(cwd, `.hadars-lambda-shim-${Date.now()}.ts`);
|
|
2378
2402
|
const shim = [
|
|
2379
2403
|
`import * as ssrModule from ${JSON.stringify(ssrBundle)};`,
|
|
2380
2404
|
`import outHtml from ${JSON.stringify(outHtml)};`,
|
|
2381
|
-
`import { createLambdaHandler } from
|
|
2405
|
+
`import { createLambdaHandler } from ${JSON.stringify(lambdaModule)};`,
|
|
2382
2406
|
`import config from ${JSON.stringify(configPath)};`,
|
|
2383
2407
|
`export const handler = createLambdaHandler(config as any, { ssrModule: ssrModule as any, outHtml });`
|
|
2384
2408
|
].join("\n") + "\n";
|
|
@@ -2395,17 +2419,20 @@ async function bundleLambda(config, configPath, outputFile, cwd) {
|
|
|
2395
2419
|
outfile: outputFile,
|
|
2396
2420
|
sourcemap: false,
|
|
2397
2421
|
loader: { ".html": "text", ".tsx": "tsx", ".ts": "ts" },
|
|
2398
|
-
//
|
|
2399
|
-
|
|
2400
|
-
//
|
|
2401
|
-
|
|
2422
|
+
// @rspack/* contains native binaries and is build-time only —
|
|
2423
|
+
// it is never imported at Lambda runtime, so mark it external.
|
|
2424
|
+
// Everything else (React, hadars runtime, etc.) is bundled in to
|
|
2425
|
+
// produce a truly self-contained single-file deployment.
|
|
2426
|
+
external: ["@rspack/*"]
|
|
2402
2427
|
});
|
|
2403
2428
|
console.log(`Lambda bundle written to ${outputFile}`);
|
|
2404
2429
|
console.log(`
|
|
2405
2430
|
Deploy instructions:`);
|
|
2406
|
-
console.log(` 1.
|
|
2407
|
-
console.log(`
|
|
2408
|
-
console.log(`
|
|
2431
|
+
console.log(` 1. Create a staging directory with just this file:`);
|
|
2432
|
+
console.log(` mkdir -p lambda-deploy && cp ${outputFile} lambda-deploy/lambda.mjs`);
|
|
2433
|
+
console.log(` 2. Upload lambda-deploy/ as your Lambda function code`);
|
|
2434
|
+
console.log(` 3. Set handler to: lambda.handler (runtime: Node.js 20.x)`);
|
|
2435
|
+
console.log(` 4. Upload .hadars/static/ assets to S3 and serve via CloudFront`);
|
|
2409
2436
|
console.log(` (the Lambda handler does not serve static JS/CSS \u2014 route those to S3)`);
|
|
2410
2437
|
} finally {
|
|
2411
2438
|
await unlink(shimPath).catch(() => {
|
|
@@ -137,6 +137,18 @@ interface HadarsOptions {
|
|
|
137
137
|
* ]
|
|
138
138
|
*/
|
|
139
139
|
moduleRules?: Record<string, any>[];
|
|
140
|
+
/**
|
|
141
|
+
* Additional rspack/webpack-compatible plugins applied to both the client
|
|
142
|
+
* and SSR bundles. Any object that implements the `apply(compiler)` method
|
|
143
|
+
* (the standard webpack/rspack plugin interface) is accepted.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
|
|
147
|
+
* plugins: [new SubresourceIntegrityPlugin()]
|
|
148
|
+
*/
|
|
149
|
+
plugins?: Array<{
|
|
150
|
+
apply(compiler: any): void;
|
|
151
|
+
}>;
|
|
140
152
|
/**
|
|
141
153
|
* SSR response cache for `run()` mode. Has no effect in `dev()` mode.
|
|
142
154
|
*
|
|
@@ -137,6 +137,18 @@ interface HadarsOptions {
|
|
|
137
137
|
* ]
|
|
138
138
|
*/
|
|
139
139
|
moduleRules?: Record<string, any>[];
|
|
140
|
+
/**
|
|
141
|
+
* Additional rspack/webpack-compatible plugins applied to both the client
|
|
142
|
+
* and SSR bundles. Any object that implements the `apply(compiler)` method
|
|
143
|
+
* (the standard webpack/rspack plugin interface) is accepted.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
|
|
147
|
+
* plugins: [new SubresourceIntegrityPlugin()]
|
|
148
|
+
*/
|
|
149
|
+
plugins?: Array<{
|
|
150
|
+
apply(compiler: any): void;
|
|
151
|
+
}>;
|
|
140
152
|
/**
|
|
141
153
|
* SSR response cache for `run()` mode. Has no effect in `dev()` mode.
|
|
142
154
|
*
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default from 'react';
|
|
3
|
-
import { A as AppContext } from './hadars-
|
|
4
|
-
export { b as HadarsApp, H as HadarsEntryModule, c as HadarsGetAfterRenderProps, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest } from './hadars-
|
|
3
|
+
import { A as AppContext } from './hadars-B3b_6sj2.cjs';
|
|
4
|
+
export { b as HadarsApp, H as HadarsEntryModule, c as HadarsGetAfterRenderProps, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest } from './hadars-B3b_6sj2.cjs';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
/** Call this before hydrating to seed the client cache from the server's data.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React$1 from 'react';
|
|
2
2
|
import React__default from 'react';
|
|
3
|
-
import { A as AppContext } from './hadars-
|
|
4
|
-
export { b as HadarsApp, H as HadarsEntryModule, c as HadarsGetAfterRenderProps, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest } from './hadars-
|
|
3
|
+
import { A as AppContext } from './hadars-B3b_6sj2.js';
|
|
4
|
+
export { b as HadarsApp, H as HadarsEntryModule, c as HadarsGetAfterRenderProps, d as HadarsGetClientProps, e as HadarsGetFinalProps, f as HadarsGetInitialProps, a as HadarsOptions, g as HadarsProps, h as HadarsRequest } from './hadars-B3b_6sj2.js';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
/** Call this before hydrating to seed the client cache from the server's data.
|
package/dist/lambda.cjs
CHANGED
|
@@ -193,10 +193,10 @@ async function tryServeFile(filePath) {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// src/slim-react/types.ts
|
|
196
|
-
var SLIM_ELEMENT =
|
|
197
|
-
var REACT19_ELEMENT =
|
|
198
|
-
var FRAGMENT_TYPE =
|
|
199
|
-
var SUSPENSE_TYPE =
|
|
196
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
197
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
198
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
199
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
200
200
|
|
|
201
201
|
// src/slim-react/jsx.ts
|
|
202
202
|
function createElement(type, props, ...children) {
|
|
@@ -754,12 +754,12 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
754
754
|
}
|
|
755
755
|
writer.write(`</${tag}>`);
|
|
756
756
|
}
|
|
757
|
-
var REACT_MEMO =
|
|
758
|
-
var REACT_FORWARD_REF =
|
|
759
|
-
var REACT_PROVIDER =
|
|
760
|
-
var REACT_CONTEXT =
|
|
761
|
-
var REACT_CONSUMER =
|
|
762
|
-
var REACT_LAZY =
|
|
757
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
758
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
759
|
+
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
760
|
+
var REACT_CONTEXT = Symbol.for("react.context");
|
|
761
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
762
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
763
763
|
function renderComponent(type, props, writer, isSvg) {
|
|
764
764
|
const typeOf = type?.$$typeof;
|
|
765
765
|
if (typeOf === REACT_MEMO) {
|
|
@@ -1161,22 +1161,10 @@ var getReactResponse = async (req, opts) => {
|
|
|
1161
1161
|
var HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
1162
1162
|
var BODY_MARKER = '<meta name="HADARS_BODY">';
|
|
1163
1163
|
var encoder = new TextEncoder();
|
|
1164
|
-
async function
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
controller.enqueue(encoder.encode(precontentHtml));
|
|
1169
|
-
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
1170
|
-
controller.enqueue(encoder.encode(
|
|
1171
|
-
`<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` + postContent
|
|
1172
|
-
));
|
|
1173
|
-
controller.close();
|
|
1174
|
-
}
|
|
1175
|
-
});
|
|
1176
|
-
return new Response(responseStream, {
|
|
1177
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
1178
|
-
status
|
|
1179
|
-
});
|
|
1164
|
+
async function buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml) {
|
|
1165
|
+
const [precontentHtml, postContent] = await getPrecontentHtml(headHtml);
|
|
1166
|
+
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
1167
|
+
return precontentHtml + `<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` + postContent;
|
|
1180
1168
|
}
|
|
1181
1169
|
var makePrecontentHtmlGetter = (htmlFilePromise) => {
|
|
1182
1170
|
let preHead = null;
|
|
@@ -1340,6 +1328,14 @@ function createLambdaHandler(options, bundled) {
|
|
|
1340
1328
|
const fetchHandler = options.fetch;
|
|
1341
1329
|
const handleProxy = createProxyHandler(options);
|
|
1342
1330
|
const getPrecontentHtml = bundled ? makePrecontentHtmlGetter(Promise.resolve(bundled.outHtml)) : makePrecontentHtmlGetter(import_promises2.default.readFile(import_node_path.default.join(cwd, StaticPath, "out.html"), "utf-8"));
|
|
1331
|
+
let ssrModulePromise = null;
|
|
1332
|
+
const getSsrModule = () => {
|
|
1333
|
+
if (bundled) return Promise.resolve(bundled.ssrModule);
|
|
1334
|
+
if (!ssrModulePromise) {
|
|
1335
|
+
ssrModulePromise = import((0, import_node_url.pathToFileURL)(import_node_path.default.resolve(cwd, HadarsFolder, SSR_FILENAME)).href);
|
|
1336
|
+
}
|
|
1337
|
+
return ssrModulePromise;
|
|
1338
|
+
};
|
|
1343
1339
|
const runHandler = async (req) => {
|
|
1344
1340
|
const request = parseRequest(req);
|
|
1345
1341
|
if (fetchHandler) {
|
|
@@ -1369,7 +1365,7 @@ function createLambdaHandler(options, bundled) {
|
|
|
1369
1365
|
getInitProps,
|
|
1370
1366
|
getAfterRenderProps,
|
|
1371
1367
|
getFinalProps
|
|
1372
|
-
} =
|
|
1368
|
+
} = await getSsrModule();
|
|
1373
1369
|
const { bodyHtml, clientProps, status, headHtml } = await getReactResponse(request, {
|
|
1374
1370
|
document: {
|
|
1375
1371
|
body: Component,
|
|
@@ -1386,7 +1382,11 @@ function createLambdaHandler(options, bundled) {
|
|
|
1386
1382
|
headers: { "Content-Type": "application/json; charset=utf-8" }
|
|
1387
1383
|
});
|
|
1388
1384
|
}
|
|
1389
|
-
|
|
1385
|
+
const html = await buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml);
|
|
1386
|
+
return new Response(html, {
|
|
1387
|
+
status,
|
|
1388
|
+
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
1389
|
+
});
|
|
1390
1390
|
} catch (err) {
|
|
1391
1391
|
console.error("[hadars] SSR render error:", err);
|
|
1392
1392
|
return new Response("Internal Server Error", { status: 500 });
|
package/dist/lambda.d.cts
CHANGED
package/dist/lambda.d.ts
CHANGED
package/dist/lambda.js
CHANGED
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
} from "./chunk-UNQSQIOO.js";
|
|
4
4
|
import {
|
|
5
5
|
renderToString
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-F7IIMM3J.js";
|
|
7
7
|
import {
|
|
8
8
|
createElement
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OS3V4CPN.js";
|
|
10
10
|
|
|
11
11
|
// src/lambda.ts
|
|
12
12
|
import "react";
|
|
13
|
-
import pathMod from "path";
|
|
14
|
-
import { pathToFileURL } from "url";
|
|
15
|
-
import fs from "fs/promises";
|
|
13
|
+
import pathMod from "node:path";
|
|
14
|
+
import { pathToFileURL } from "node:url";
|
|
15
|
+
import fs from "node:fs/promises";
|
|
16
16
|
|
|
17
17
|
// src/utils/proxyHandler.tsx
|
|
18
18
|
var cloneHeaders = (headers) => {
|
|
@@ -127,7 +127,7 @@ var parseRequest = (request) => {
|
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
// src/utils/staticFile.ts
|
|
130
|
-
import { readFile, stat } from "fs/promises";
|
|
130
|
+
import { readFile, stat } from "node:fs/promises";
|
|
131
131
|
var MIME = {
|
|
132
132
|
html: "text/html; charset=utf-8",
|
|
133
133
|
htm: "text/html; charset=utf-8",
|
|
@@ -256,22 +256,10 @@ var getReactResponse = async (req, opts) => {
|
|
|
256
256
|
var HEAD_MARKER = '<meta name="HADARS_HEAD">';
|
|
257
257
|
var BODY_MARKER = '<meta name="HADARS_BODY">';
|
|
258
258
|
var encoder = new TextEncoder();
|
|
259
|
-
async function
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
controller.enqueue(encoder.encode(precontentHtml));
|
|
264
|
-
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
265
|
-
controller.enqueue(encoder.encode(
|
|
266
|
-
`<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` + postContent
|
|
267
|
-
));
|
|
268
|
-
controller.close();
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
return new Response(responseStream, {
|
|
272
|
-
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
273
|
-
status
|
|
274
|
-
});
|
|
259
|
+
async function buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml) {
|
|
260
|
+
const [precontentHtml, postContent] = await getPrecontentHtml(headHtml);
|
|
261
|
+
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, "\\u003c");
|
|
262
|
+
return precontentHtml + `<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` + postContent;
|
|
275
263
|
}
|
|
276
264
|
var makePrecontentHtmlGetter = (htmlFilePromise) => {
|
|
277
265
|
let preHead = null;
|
|
@@ -435,6 +423,14 @@ function createLambdaHandler(options, bundled) {
|
|
|
435
423
|
const fetchHandler = options.fetch;
|
|
436
424
|
const handleProxy = createProxyHandler(options);
|
|
437
425
|
const getPrecontentHtml = bundled ? makePrecontentHtmlGetter(Promise.resolve(bundled.outHtml)) : makePrecontentHtmlGetter(fs.readFile(pathMod.join(cwd, StaticPath, "out.html"), "utf-8"));
|
|
426
|
+
let ssrModulePromise = null;
|
|
427
|
+
const getSsrModule = () => {
|
|
428
|
+
if (bundled) return Promise.resolve(bundled.ssrModule);
|
|
429
|
+
if (!ssrModulePromise) {
|
|
430
|
+
ssrModulePromise = import(pathToFileURL(pathMod.resolve(cwd, HadarsFolder, SSR_FILENAME)).href);
|
|
431
|
+
}
|
|
432
|
+
return ssrModulePromise;
|
|
433
|
+
};
|
|
438
434
|
const runHandler = async (req) => {
|
|
439
435
|
const request = parseRequest(req);
|
|
440
436
|
if (fetchHandler) {
|
|
@@ -464,7 +460,7 @@ function createLambdaHandler(options, bundled) {
|
|
|
464
460
|
getInitProps,
|
|
465
461
|
getAfterRenderProps,
|
|
466
462
|
getFinalProps
|
|
467
|
-
} =
|
|
463
|
+
} = await getSsrModule();
|
|
468
464
|
const { bodyHtml, clientProps, status, headHtml } = await getReactResponse(request, {
|
|
469
465
|
document: {
|
|
470
466
|
body: Component,
|
|
@@ -481,7 +477,11 @@ function createLambdaHandler(options, bundled) {
|
|
|
481
477
|
headers: { "Content-Type": "application/json; charset=utf-8" }
|
|
482
478
|
});
|
|
483
479
|
}
|
|
484
|
-
|
|
480
|
+
const html = await buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml);
|
|
481
|
+
return new Response(html, {
|
|
482
|
+
status,
|
|
483
|
+
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
484
|
+
});
|
|
485
485
|
} catch (err) {
|
|
486
486
|
console.error("[hadars] SSR render error:", err);
|
|
487
487
|
return new Response("Internal Server Error", { status: 500 });
|
|
@@ -77,10 +77,10 @@ __export(slim_react_exports, {
|
|
|
77
77
|
module.exports = __toCommonJS(slim_react_exports);
|
|
78
78
|
|
|
79
79
|
// src/slim-react/types.ts
|
|
80
|
-
var SLIM_ELEMENT =
|
|
81
|
-
var REACT19_ELEMENT =
|
|
82
|
-
var FRAGMENT_TYPE =
|
|
83
|
-
var SUSPENSE_TYPE =
|
|
80
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
81
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
82
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
83
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
84
84
|
|
|
85
85
|
// src/slim-react/jsx.ts
|
|
86
86
|
var Fragment = FRAGMENT_TYPE;
|
|
@@ -679,12 +679,12 @@ function renderHostElement(tag, props, writer, isSvg) {
|
|
|
679
679
|
}
|
|
680
680
|
writer.write(`</${tag}>`);
|
|
681
681
|
}
|
|
682
|
-
var REACT_MEMO =
|
|
683
|
-
var REACT_FORWARD_REF =
|
|
684
|
-
var REACT_PROVIDER =
|
|
685
|
-
var REACT_CONTEXT =
|
|
686
|
-
var REACT_CONSUMER =
|
|
687
|
-
var REACT_LAZY =
|
|
682
|
+
var REACT_MEMO = Symbol.for("react.memo");
|
|
683
|
+
var REACT_FORWARD_REF = Symbol.for("react.forward_ref");
|
|
684
|
+
var REACT_PROVIDER = Symbol.for("react.provider");
|
|
685
|
+
var REACT_CONTEXT = Symbol.for("react.context");
|
|
686
|
+
var REACT_CONSUMER = Symbol.for("react.consumer");
|
|
687
|
+
var REACT_LAZY = Symbol.for("react.lazy");
|
|
688
688
|
function renderComponent(type, props, writer, isSvg) {
|
|
689
689
|
const typeOf = type?.$$typeof;
|
|
690
690
|
if (typeOf === REACT_MEMO) {
|
package/dist/slim-react/index.js
CHANGED
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
useSyncExternalStore,
|
|
34
34
|
useTransition,
|
|
35
35
|
version
|
|
36
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-F7IIMM3J.js";
|
|
37
37
|
import {
|
|
38
38
|
FRAGMENT_TYPE,
|
|
39
39
|
Fragment,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
SUSPENSE_TYPE,
|
|
42
42
|
createElement,
|
|
43
43
|
jsx
|
|
44
|
-
} from "../chunk-
|
|
44
|
+
} from "../chunk-OS3V4CPN.js";
|
|
45
45
|
export {
|
|
46
46
|
Children,
|
|
47
47
|
Component,
|
|
@@ -28,8 +28,10 @@ __export(jsx_runtime_exports, {
|
|
|
28
28
|
module.exports = __toCommonJS(jsx_runtime_exports);
|
|
29
29
|
|
|
30
30
|
// src/slim-react/types.ts
|
|
31
|
-
var SLIM_ELEMENT =
|
|
32
|
-
var
|
|
31
|
+
var SLIM_ELEMENT = Symbol.for("react.element");
|
|
32
|
+
var REACT19_ELEMENT = Symbol.for("react.transitional.element");
|
|
33
|
+
var FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
34
|
+
var SUSPENSE_TYPE = Symbol.for("react.suspense");
|
|
33
35
|
|
|
34
36
|
// src/slim-react/jsx.ts
|
|
35
37
|
var Fragment = FRAGMENT_TYPE;
|
package/dist/ssr-watch.js
CHANGED
|
@@ -208,6 +208,25 @@ var buildCompilerConfig = (entry2, opts, includeHotPlugin) => {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
const extraPlugins = [];
|
|
211
|
+
if (!isServerBuild) {
|
|
212
|
+
extraPlugins.push({
|
|
213
|
+
apply(compiler) {
|
|
214
|
+
compiler.hooks.compilation.tap("HadarsWorkerChunkLoading", (compilation) => {
|
|
215
|
+
compilation.hooks.childCompiler.tap(
|
|
216
|
+
"HadarsWorkerChunkLoading",
|
|
217
|
+
(childCompiler) => {
|
|
218
|
+
if (childCompiler.options?.output) {
|
|
219
|
+
childCompiler.options.output.chunkLoading = "import-scripts";
|
|
220
|
+
}
|
|
221
|
+
if (childCompiler.options?.experiments) {
|
|
222
|
+
childCompiler.options.experiments.outputModule = false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
211
230
|
const defineValues = { ...opts.define ?? {} };
|
|
212
231
|
if (!isServerBuild && opts.reactMode !== void 0) {
|
|
213
232
|
defineValues["process.env.NODE_ENV"] = JSON.stringify(opts.reactMode);
|
|
@@ -284,7 +303,8 @@ var buildCompilerConfig = (entry2, opts, includeHotPlugin) => {
|
|
|
284
303
|
},
|
|
285
304
|
isDev && !isServerBuild && new ReactRefreshPlugin(),
|
|
286
305
|
includeHotPlugin && isDev && !isServerBuild && new rspack.HotModuleReplacementPlugin(),
|
|
287
|
-
...extraPlugins
|
|
306
|
+
...extraPlugins,
|
|
307
|
+
...opts.plugins ?? []
|
|
288
308
|
],
|
|
289
309
|
...localConfig,
|
|
290
310
|
// Merge base resolve (modules, tsConfig, extensions) with per-build resolve
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hadars",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.37",
|
|
4
4
|
"description": "Minimal SSR framework for React — rspack, HMR, TypeScript, Bun/Node/Deno",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"@types/react-dom": "^19.2.3",
|
|
80
80
|
"react": "^19.2.4",
|
|
81
81
|
"react-dom": "^19.2.4",
|
|
82
|
-
"tsup": "^8.5
|
|
82
|
+
"tsup": "^8.3.5",
|
|
83
83
|
"typescript": "^5.9.3"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
package/src/build.ts
CHANGED
|
@@ -341,6 +341,7 @@ export const dev = async (options: HadarsRuntimeOptions) => {
|
|
|
341
341
|
swcPlugins: options.swcPlugins,
|
|
342
342
|
define: options.define,
|
|
343
343
|
moduleRules: options.moduleRules,
|
|
344
|
+
plugins: options.plugins,
|
|
344
345
|
reactMode: options.reactMode,
|
|
345
346
|
htmlTemplate: resolvedHtmlTemplate,
|
|
346
347
|
});
|
|
@@ -596,6 +597,7 @@ export const build = async (options: HadarsRuntimeOptions) => {
|
|
|
596
597
|
swcPlugins: options.swcPlugins,
|
|
597
598
|
define: options.define,
|
|
598
599
|
moduleRules: options.moduleRules,
|
|
600
|
+
plugins: options.plugins,
|
|
599
601
|
optimization: options.optimization,
|
|
600
602
|
reactMode: options.reactMode,
|
|
601
603
|
htmlTemplate: resolvedHtmlTemplate,
|
|
@@ -614,6 +616,7 @@ export const build = async (options: HadarsRuntimeOptions) => {
|
|
|
614
616
|
swcPlugins: options.swcPlugins,
|
|
615
617
|
define: options.define,
|
|
616
618
|
moduleRules: options.moduleRules,
|
|
619
|
+
plugins: options.plugins,
|
|
617
620
|
}),
|
|
618
621
|
]);
|
|
619
622
|
await fs.rm(tmpFilePath);
|
package/src/lambda.ts
CHANGED
|
@@ -24,7 +24,7 @@ import { createProxyHandler } from './utils/proxyHandler';
|
|
|
24
24
|
import { parseRequest } from './utils/request';
|
|
25
25
|
import { tryServeFile } from './utils/staticFile';
|
|
26
26
|
import { getReactResponse } from './utils/response';
|
|
27
|
-
import { buildSsrResponse, makePrecontentHtmlGetter, createRenderCache } from './utils/ssrHandler';
|
|
27
|
+
import { buildSsrResponse, buildSsrHtml, makePrecontentHtmlGetter, createRenderCache } from './utils/ssrHandler';
|
|
28
28
|
import type { HadarsOptions, HadarsEntryModule, HadarsProps } from './types/hadars';
|
|
29
29
|
|
|
30
30
|
// ── Lambda event / response types ────────────────────────────────────────────
|
|
@@ -189,6 +189,21 @@ export function createLambdaHandler(options: HadarsOptions, bundled?: LambdaBund
|
|
|
189
189
|
? makePrecontentHtmlGetter(Promise.resolve(bundled.outHtml))
|
|
190
190
|
: makePrecontentHtmlGetter(fs.readFile(pathMod.join(cwd, StaticPath, 'out.html'), 'utf-8'));
|
|
191
191
|
|
|
192
|
+
// Hoist the SSR module reference so it is resolved once, not on every
|
|
193
|
+
// request. In bundled mode the module is already in-memory; in file-based
|
|
194
|
+
// mode we lazily import it and cache the promise so Node's module cache is
|
|
195
|
+
// only consulted once.
|
|
196
|
+
let ssrModulePromise: Promise<HadarsEntryModule<any>> | null = null;
|
|
197
|
+
const getSsrModule = (): Promise<HadarsEntryModule<any>> => {
|
|
198
|
+
if (bundled) return Promise.resolve(bundled.ssrModule);
|
|
199
|
+
if (!ssrModulePromise) {
|
|
200
|
+
ssrModulePromise = import(
|
|
201
|
+
pathToFileURL(pathMod.resolve(cwd, HadarsFolder, SSR_FILENAME)).href
|
|
202
|
+
) as Promise<HadarsEntryModule<any>>;
|
|
203
|
+
}
|
|
204
|
+
return ssrModulePromise;
|
|
205
|
+
};
|
|
206
|
+
|
|
192
207
|
const runHandler = async (req: Request): Promise<Response> => {
|
|
193
208
|
const request = parseRequest(req);
|
|
194
209
|
|
|
@@ -227,9 +242,7 @@ export function createLambdaHandler(options: HadarsOptions, bundled?: LambdaBund
|
|
|
227
242
|
getInitProps,
|
|
228
243
|
getAfterRenderProps,
|
|
229
244
|
getFinalProps,
|
|
230
|
-
} =
|
|
231
|
-
? bundled.ssrModule
|
|
232
|
-
: (await import(pathToFileURL(pathMod.resolve(cwd, HadarsFolder, SSR_FILENAME)).href)) as HadarsEntryModule<any>;
|
|
245
|
+
} = await getSsrModule();
|
|
233
246
|
|
|
234
247
|
const { bodyHtml, clientProps, status, headHtml } = await getReactResponse(request, {
|
|
235
248
|
document: {
|
|
@@ -249,7 +262,13 @@ export function createLambdaHandler(options: HadarsOptions, bundled?: LambdaBund
|
|
|
249
262
|
});
|
|
250
263
|
}
|
|
251
264
|
|
|
252
|
-
|
|
265
|
+
// Build the HTML string directly — avoids creating a ReadableStream
|
|
266
|
+
// that would immediately be drained by the Lambda response serialiser.
|
|
267
|
+
const html = await buildSsrHtml(bodyHtml, clientProps, headHtml, getPrecontentHtml);
|
|
268
|
+
return new Response(html, {
|
|
269
|
+
status,
|
|
270
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
271
|
+
});
|
|
253
272
|
} catch (err: any) {
|
|
254
273
|
console.error('[hadars] SSR render error:', err);
|
|
255
274
|
return new Response('Internal Server Error', { status: 500 });
|
package/src/types/hadars.ts
CHANGED
|
@@ -142,6 +142,16 @@ export interface HadarsOptions {
|
|
|
142
142
|
* ]
|
|
143
143
|
*/
|
|
144
144
|
moduleRules?: Record<string, any>[];
|
|
145
|
+
/**
|
|
146
|
+
* Additional rspack/webpack-compatible plugins applied to both the client
|
|
147
|
+
* and SSR bundles. Any object that implements the `apply(compiler)` method
|
|
148
|
+
* (the standard webpack/rspack plugin interface) is accepted.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* import { SubresourceIntegrityPlugin } from 'webpack-subresource-integrity';
|
|
152
|
+
* plugins: [new SubresourceIntegrityPlugin()]
|
|
153
|
+
*/
|
|
154
|
+
plugins?: Array<{ apply(compiler: any): void }>;
|
|
145
155
|
/**
|
|
146
156
|
* SSR response cache for `run()` mode. Has no effect in `dev()` mode.
|
|
147
157
|
*
|
package/src/utils/rspack.ts
CHANGED
|
@@ -136,6 +136,8 @@ interface EntryOptions {
|
|
|
136
136
|
optimization?: Record<string, unknown>;
|
|
137
137
|
// additional module rules appended after the built-in rules
|
|
138
138
|
moduleRules?: Record<string, any>[];
|
|
139
|
+
// additional rspack/webpack-compatible plugins (applied after built-in plugins)
|
|
140
|
+
plugins?: Array<{ apply(compiler: any): void }>;
|
|
139
141
|
// force React runtime mode independently of build mode (client only)
|
|
140
142
|
reactMode?: 'development' | 'production';
|
|
141
143
|
}
|
|
@@ -264,6 +266,30 @@ const buildCompilerConfig = (
|
|
|
264
266
|
}
|
|
265
267
|
|
|
266
268
|
const extraPlugins: any[] = [];
|
|
269
|
+
|
|
270
|
+
// Built-in plugin: force classic chunk loading for web worker sub-compilations.
|
|
271
|
+
// Without this, worker child compilers inherit the parent's outputModule:true context
|
|
272
|
+
// and may emit ES module chunks that cannot be loaded inside classic workers
|
|
273
|
+
// via importScripts. Applied to client builds only — SSR doesn't spawn workers.
|
|
274
|
+
if (!isServerBuild) {
|
|
275
|
+
extraPlugins.push({
|
|
276
|
+
apply(compiler: any) {
|
|
277
|
+
compiler.hooks.compilation.tap('HadarsWorkerChunkLoading', (compilation: any) => {
|
|
278
|
+
compilation.hooks.childCompiler.tap(
|
|
279
|
+
'HadarsWorkerChunkLoading',
|
|
280
|
+
(childCompiler: any) => {
|
|
281
|
+
if (childCompiler.options?.output) {
|
|
282
|
+
childCompiler.options.output.chunkLoading = 'import-scripts';
|
|
283
|
+
}
|
|
284
|
+
if (childCompiler.options?.experiments) {
|
|
285
|
+
childCompiler.options.experiments.outputModule = false;
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
}
|
|
267
293
|
const defineValues: Record<string, string> = { ...(opts.define ?? {}) };
|
|
268
294
|
// When reactMode overrides the React runtime we must also set process.env.NODE_ENV
|
|
269
295
|
// so React picks its dev/prod bundle, independently of the rspack build mode.
|
|
@@ -352,6 +378,7 @@ const buildCompilerConfig = (
|
|
|
352
378
|
isDev && !isServerBuild && new ReactRefreshPlugin(),
|
|
353
379
|
includeHotPlugin && isDev && !isServerBuild && new rspack.HotModuleReplacementPlugin(),
|
|
354
380
|
...extraPlugins,
|
|
381
|
+
...(opts.plugins ?? []),
|
|
355
382
|
],
|
|
356
383
|
...localConfig,
|
|
357
384
|
// Merge base resolve (modules, tsConfig, extensions) with per-build resolve
|
package/src/utils/ssrHandler.ts
CHANGED
|
@@ -36,6 +36,27 @@ export async function buildSsrResponse(
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Like {@link buildSsrResponse} but returns the complete HTML string directly
|
|
41
|
+
* instead of wrapping it in a streaming Response. Use this in environments
|
|
42
|
+
* where streaming is not beneficial (e.g. AWS Lambda) to avoid the
|
|
43
|
+
* ReadableStream allocation and the subsequent `.text()` drain overhead.
|
|
44
|
+
*/
|
|
45
|
+
export async function buildSsrHtml(
|
|
46
|
+
bodyHtml: string,
|
|
47
|
+
clientProps: Record<string, unknown>,
|
|
48
|
+
headHtml: string,
|
|
49
|
+
getPrecontentHtml: (headHtml: string) => Promise<[string, string]>,
|
|
50
|
+
): Promise<string> {
|
|
51
|
+
const [precontentHtml, postContent] = await getPrecontentHtml(headHtml);
|
|
52
|
+
const scriptContent = JSON.stringify({ hadars: { props: clientProps } }).replace(/</g, '\\u003c');
|
|
53
|
+
return (
|
|
54
|
+
precontentHtml +
|
|
55
|
+
`<div id="app">${bodyHtml}</div><script id="hadars" type="application/json">${scriptContent}</script>` +
|
|
56
|
+
postContent
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
/**
|
|
40
61
|
* Returns a function that parses `out.html` into pre-head, post-head, and
|
|
41
62
|
* post-content segments and caches the result. Call the returned function with
|