vite-plugin-ssr-config 1.0.3

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/dist/index.js ADDED
@@ -0,0 +1,452 @@
1
+ // src/index.ts
2
+ import path5 from "path";
3
+
4
+ // src/model.ts
5
+ var assertSSRConfig = (ssrOpts = {}) => {
6
+ let {
7
+ root = process.cwd(),
8
+ disableBuild = false,
9
+ //Main Entry
10
+ entryClient = ".ssr/entryClient.jsx",
11
+ entryRender = ".ssr/entryRender.jsx",
12
+ rootDocument = ".ssr/root.jsx",
13
+ //Server
14
+ server = ".ssr/server.js",
15
+ handler = ".ssr/handler.js",
16
+ //SSR
17
+ pageServer = ".ssr/pageServer.jsx",
18
+ pageBrowser = ".ssr/pageBrowser.jsx",
19
+ rootRoutes = ".ssr/rootRoutes.jsx",
20
+ errorBoundary = ".ssr/errorBoundary.jsx",
21
+ //Scripts
22
+ liveReload = ".ssr/liveReload.jsx",
23
+ viteScripts = ".ssr/viteScripts.jsx",
24
+ //Out directories
25
+ serverOutDir = "dist/",
26
+ serverMinify = false,
27
+ serverBuild = (config) => config,
28
+ clientOutDir = "dist/client",
29
+ clientMinify = true,
30
+ clientBuild = (config) => config
31
+ } = ssrOpts;
32
+ return {
33
+ root,
34
+ disableBuild,
35
+ entryClient,
36
+ entryRender,
37
+ rootDocument,
38
+ server,
39
+ handler,
40
+ pageServer,
41
+ pageBrowser,
42
+ rootRoutes,
43
+ errorBoundary,
44
+ liveReload,
45
+ viteScripts,
46
+ serverOutDir,
47
+ serverMinify,
48
+ serverBuild,
49
+ clientOutDir,
50
+ clientMinify,
51
+ clientBuild
52
+ };
53
+ };
54
+
55
+ // src/utils.ts
56
+ import fs from "fs-extra";
57
+ import path from "path";
58
+ import { fileURLToPath } from "url";
59
+ var finalUrl = (base, name) => {
60
+ return path.join(base, name).replaceAll("\\", "/");
61
+ };
62
+ var getPluginDirectory = () => {
63
+ if (typeof __dirname === "undefined") {
64
+ const filename = fileURLToPath(import.meta.url);
65
+ return path.dirname(filename);
66
+ } else {
67
+ return __dirname;
68
+ }
69
+ };
70
+ var findDirPlugin = (dirname, max = 5) => {
71
+ const basedir = getPluginDirectory();
72
+ let relative = "/";
73
+ let dirPath = "";
74
+ for (var i = 0; i < max; i++) {
75
+ dirPath = path.join(basedir, relative, dirname);
76
+ if (fs.existsSync(dirPath)) {
77
+ return dirPath;
78
+ }
79
+ relative += "../";
80
+ }
81
+ throw Error(`Not found: ${dirPath}`);
82
+ };
83
+ var cleanDirectory = (target) => {
84
+ if (fs.existsSync(target)) {
85
+ fs.rmSync(target, { recursive: true, force: true });
86
+ }
87
+ fs.mkdirSync(target, { recursive: true });
88
+ };
89
+ var copyFilesDirectory = (origin, target, {
90
+ files = [],
91
+ oldId = "",
92
+ newId = ""
93
+ }) => {
94
+ files.forEach((file) => {
95
+ const sourceFilePath = path.join(origin, file);
96
+ const targetFilePath = path.join(target, file);
97
+ if (oldId !== newId) {
98
+ let fileContent = fs.readFileSync(sourceFilePath, "utf-8");
99
+ fileContent = fileContent.replace(new RegExp(oldId, "g"), newId);
100
+ fs.writeFileSync(targetFilePath, fileContent, "utf-8");
101
+ } else {
102
+ fs.copySync(sourceFilePath, targetFilePath, { overwrite: true });
103
+ }
104
+ });
105
+ };
106
+
107
+ // src/plugin-build/build.ts
108
+ import fs2 from "fs-extra";
109
+ import path2 from "path";
110
+ import { build, mergeConfig } from "vite";
111
+ var doBuildServer = async (ssrConfig2, viteConfig) => {
112
+ const {
113
+ root,
114
+ serverMinify,
115
+ serverOutDir,
116
+ entryClient,
117
+ clientOutDir,
118
+ server,
119
+ handler,
120
+ serverBuild,
121
+ rootDocument,
122
+ entryRender,
123
+ pageServer,
124
+ pageBrowser,
125
+ rootRoutes,
126
+ errorBoundary,
127
+ liveReload,
128
+ viteScripts
129
+ } = ssrConfig2;
130
+ const { base = "/" } = viteConfig;
131
+ const ssrServerFile = path2.resolve(root, server);
132
+ const ssrPublicDir = path2.relative(serverOutDir, clientOutDir);
133
+ const manifestFile = path2.resolve(`${clientOutDir}/manifest.json`);
134
+ const manifestContent = fs2.readFileSync(manifestFile, "utf-8");
135
+ const manifest = JSON.parse(manifestContent);
136
+ const manifestOut = manifest[entryClient].file;
137
+ const ssrEntryClientURL = finalUrl(base, manifestOut);
138
+ const ssrFiles = [
139
+ handler,
140
+ rootDocument,
141
+ entryClient,
142
+ entryRender,
143
+ pageServer,
144
+ pageBrowser,
145
+ rootRoutes,
146
+ errorBoundary,
147
+ liveReload,
148
+ viteScripts
149
+ ];
150
+ const baseConfig = {
151
+ appType: "custom",
152
+ base,
153
+ root,
154
+ publicDir: "private",
155
+ define: {
156
+ "process.env.SSR_BASENAME": JSON.stringify(base),
157
+ "process.env.SSR_PUBLIC_DIR": JSON.stringify(ssrPublicDir),
158
+ "process.env.SSR_ENTRY_CLIENT": JSON.stringify(ssrEntryClientURL),
159
+ "process.env.SSR": JSON.stringify(true)
160
+ },
161
+ ssr: {
162
+ noExternal: []
163
+ },
164
+ build: {
165
+ outDir: serverOutDir,
166
+ ssr: ssrServerFile,
167
+ write: true,
168
+ minify: serverMinify,
169
+ target: "esnext",
170
+ emptyOutDir: false,
171
+ rollupOptions: {
172
+ external: viteConfig.build?.rollupOptions?.external,
173
+ output: {
174
+ format: "es",
175
+ entryFileNames: "app.js",
176
+ chunkFileNames: "bin/[name]-[hash].js",
177
+ assetFileNames: "assets/[name]-[hash].[ext]",
178
+ manualChunks: (id) => {
179
+ const isSsr = ssrFiles.find(
180
+ (it) => id.startsWith(it) || id.endsWith(it)
181
+ );
182
+ if (isSsr) {
183
+ return "ssr";
184
+ }
185
+ if (id.startsWith("virtual")) {
186
+ return "virtual";
187
+ }
188
+ }
189
+ },
190
+ onwarn: (warning, handler2) => {
191
+ if (warning.code === "UNUSED_EXTERNAL_IMPORT" && warning.ids.some((id) => id.includes("node_modules"))) {
192
+ return;
193
+ }
194
+ handler2(warning);
195
+ }
196
+ }
197
+ }
198
+ };
199
+ const customConfig = await serverBuild(baseConfig);
200
+ const finalConfig = mergeConfig(baseConfig, customConfig);
201
+ await build(finalConfig);
202
+ };
203
+ var doBuildClient = async (ssrConfig2, viteConfig) => {
204
+ const { base = "/" } = viteConfig;
205
+ const { root, clientMinify, clientOutDir, entryClient, clientBuild } = ssrConfig2;
206
+ const preloadFiles = [
207
+ "modulepreload",
208
+ "commonjsHelpers",
209
+ "vite/",
210
+ "installHook"
211
+ ];
212
+ const baseConfig = {
213
+ root,
214
+ appType: "custom",
215
+ base,
216
+ define: {
217
+ "process.env.SSR_BASENAME": JSON.stringify(base),
218
+ "process.env.SSR": JSON.stringify(false)
219
+ },
220
+ build: {
221
+ write: true,
222
+ manifest: true,
223
+ minify: clientMinify,
224
+ target: "modules",
225
+ emptyOutDir: false,
226
+ outDir: clientOutDir,
227
+ rollupOptions: {
228
+ external: viteConfig.build?.rollupOptions?.external,
229
+ input: {
230
+ main: path2.resolve(root, entryClient)
231
+ },
232
+ output: {
233
+ format: "es",
234
+ entryFileNames: `assets/[name]-[hash].js`,
235
+ chunkFileNames: `chunks/[name]-[hash].js`,
236
+ assetFileNames: `assets/[name]-[hash].[ext]`,
237
+ manualChunks: (id) => {
238
+ const isInternal = preloadFiles.find((it) => id.includes(it));
239
+ if (isInternal) {
240
+ return "preload";
241
+ }
242
+ if (id.includes("node_modules")) {
243
+ return "vendor";
244
+ }
245
+ }
246
+ }
247
+ }
248
+ }
249
+ };
250
+ const customConfig = await clientBuild(baseConfig);
251
+ const finalConfig = mergeConfig(baseConfig, customConfig);
252
+ await build(finalConfig);
253
+ };
254
+
255
+ // src/plugin-build/index.ts
256
+ var pluginBuildSkip = () => {
257
+ const ENTRY_NONE = "____.html";
258
+ return {
259
+ name: "vite-plugin-ssr-config:skip",
260
+ enforce: "pre",
261
+ apply: "build",
262
+ config: () => {
263
+ if (process.env.IS_SSR_KIT_BUILD) return {};
264
+ return {
265
+ build: {
266
+ emptyOutDir: true,
267
+ copyPublicDir: false,
268
+ write: false,
269
+ rollupOptions: {
270
+ input: {
271
+ main: ENTRY_NONE
272
+ }
273
+ }
274
+ }
275
+ };
276
+ },
277
+ resolveId: (id) => {
278
+ if (id === ENTRY_NONE) {
279
+ return id;
280
+ }
281
+ return null;
282
+ },
283
+ load: (id) => {
284
+ if (id === ENTRY_NONE) {
285
+ return "";
286
+ }
287
+ return null;
288
+ }
289
+ };
290
+ };
291
+ var pluginBuildSSR = (ssrConfig2) => {
292
+ let viteConfig = {};
293
+ return {
294
+ name: "vite-plugin-ssr-config:build",
295
+ enforce: "pre",
296
+ apply: "build",
297
+ configResolved: (config) => {
298
+ viteConfig = config;
299
+ },
300
+ buildStart: async () => {
301
+ if (process.env.IS_SSR_KIT_BUILD) return;
302
+ process.env.IS_SSR_KIT_BUILD = "true";
303
+ cleanDirectory(ssrConfig2.clientOutDir);
304
+ cleanDirectory(ssrConfig2.serverOutDir);
305
+ viteConfig.logger.info("");
306
+ viteConfig.logger.info("\x1B[1m\x1B[31mCLIENT BUILD\x1B[0m");
307
+ await doBuildClient(ssrConfig2, viteConfig);
308
+ viteConfig.logger.info("");
309
+ viteConfig.logger.info("\x1B[1m\x1B[31mSERVER BUILD\x1B[0m");
310
+ await doBuildServer(ssrConfig2, viteConfig);
311
+ viteConfig.logger.info("");
312
+ }
313
+ };
314
+ };
315
+ var pluginBuild = (ssrConfig2) => {
316
+ if (ssrConfig2.disableBuild) {
317
+ return null;
318
+ }
319
+ return [pluginBuildSkip(), pluginBuildSSR(ssrConfig2)];
320
+ };
321
+
322
+ // src/plugin-resolve/index.ts
323
+ import path3 from "path";
324
+ var pluginResolve = (ssrConfig2) => {
325
+ let {
326
+ root,
327
+ server,
328
+ handler,
329
+ rootDocument,
330
+ entryClient,
331
+ entryRender,
332
+ pageServer,
333
+ pageBrowser,
334
+ rootRoutes,
335
+ errorBoundary,
336
+ liveReload,
337
+ viteScripts
338
+ } = ssrConfig2;
339
+ const absoluteFile = (name) => {
340
+ return path3.join(root, name);
341
+ };
342
+ return {
343
+ name: "vite-plugin-ssr-config:resolve",
344
+ enforce: "pre",
345
+ config: () => {
346
+ return {
347
+ resolve: {
348
+ alias: {
349
+ "@ssr/server.js": absoluteFile(server),
350
+ "@ssr/handler.js": absoluteFile(handler),
351
+ "@ssr/root.jsx": absoluteFile(rootDocument),
352
+ "@ssr/entryClient.jsx": absoluteFile(entryClient),
353
+ "@ssr/entryRender.jsx": absoluteFile(entryRender),
354
+ "@ssr/pageServer.jsx": absoluteFile(pageServer),
355
+ "@ssr/pageBrowser.jsx": absoluteFile(pageBrowser),
356
+ "@ssr/rootRoutes.jsx": absoluteFile(rootRoutes),
357
+ "@ssr/errorBoundary.jsx": absoluteFile(errorBoundary),
358
+ "@ssr/liveReload.jsx": absoluteFile(liveReload),
359
+ "@ssr/viteScripts.jsx": absoluteFile(viteScripts)
360
+ }
361
+ }
362
+ };
363
+ }
364
+ };
365
+ };
366
+
367
+ // src/plugin-serve/index.ts
368
+ import fs3 from "fs-extra";
369
+ import path4 from "path";
370
+ var pluginServe = (ssrConfig2) => {
371
+ const { entryClient, root } = ssrConfig2;
372
+ return {
373
+ name: "vite-plugin-ssr-config:serve",
374
+ enforce: "post",
375
+ apply: "serve",
376
+ config: ({ base = "/" }) => {
377
+ const ssrClientEntry = finalUrl(base, entryClient);
378
+ return {
379
+ appType: "custom",
380
+ define: {
381
+ "process.env.SSR_BASENAME": JSON.stringify(base),
382
+ "process.env.SSR_ENTRY_CLIENT": JSON.stringify(ssrClientEntry)
383
+ }
384
+ };
385
+ },
386
+ configureServer: async (devServer) => {
387
+ return async () => {
388
+ devServer.middlewares.use(async (req, res, next) => {
389
+ const indexHtmlPath = path4.join(root, req.url, "index.html");
390
+ if (fs3.existsSync(indexHtmlPath)) {
391
+ return devServer.transformIndexHtml(
392
+ req.url,
393
+ fs3.readFileSync(indexHtmlPath, "utf-8")
394
+ ).then((html) => {
395
+ res.setHeader("Content-Type", "text/html");
396
+ res.setHeader("Pragma", "no-cache");
397
+ res.setHeader("Expires", "0");
398
+ res.end(html);
399
+ });
400
+ }
401
+ next();
402
+ });
403
+ devServer.middlewares.use(async (req, res, next) => {
404
+ try {
405
+ process.env.SSR = true;
406
+ const mod = await devServer.ssrLoadModule("@ssr/handler.js", {
407
+ fixStacktrace: true
408
+ });
409
+ await mod.handler(req, res, next);
410
+ } catch (error) {
411
+ next(error);
412
+ }
413
+ });
414
+ };
415
+ }
416
+ };
417
+ };
418
+
419
+ // src/index.ts
420
+ var ssrConfig = (opts = {}) => {
421
+ const ssrConfig2 = assertSSRConfig(opts);
422
+ const cacheOrigin = findDirPlugin("ssr");
423
+ const cacheTarget = path5.join(ssrConfig2.root, ".ssr");
424
+ cleanDirectory(cacheTarget);
425
+ copyFilesDirectory(cacheOrigin, cacheTarget, {
426
+ files: [
427
+ "entryClient.jsx",
428
+ "entryRender.jsx",
429
+ "errorBoundary.jsx",
430
+ "handler.js",
431
+ "liveReload.jsx",
432
+ "pageBrowser.jsx",
433
+ "pageServer.jsx",
434
+ "root.jsx",
435
+ "rootRoutes.jsx",
436
+ "server.js",
437
+ "viteScripts.jsx"
438
+ ]
439
+ });
440
+ return [
441
+ pluginResolve(ssrConfig2),
442
+ pluginServe(ssrConfig2),
443
+ pluginBuild(ssrConfig2)
444
+ ];
445
+ };
446
+ var ssr = ssrConfig;
447
+ var index_default = ssrConfig;
448
+ export {
449
+ index_default as default,
450
+ ssr,
451
+ ssrConfig
452
+ };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "vite-plugin-ssr-config",
3
+ "version": "1.0.3",
4
+ "license": "MIT",
5
+ "description": "A powerful Vite plugin designed to enable Server-Side Rendering (SSR) for React applications. It provides a comprehensive solution for bundling both SSR and CSR, with built-in support for React Router and React Query for efficient API handling and page rendering.",
6
+ "keywords": [
7
+ "vite",
8
+ "vite plugin",
9
+ "ssr",
10
+ "react",
11
+ "react-router",
12
+ "react-query",
13
+ "server",
14
+ "express"
15
+ ],
16
+ "author": "Willyams Yujra",
17
+ "type": "module",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist/",
27
+ "ssr/",
28
+ "README.md"
29
+ ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/yracnet/vite-plugin-ssr-config.git"
33
+ },
34
+ "homepage": "https://github.com/yracnet/vite-plugin-ssr-config",
35
+ "bugs": "https://github.com/yracnet/vite-plugin-ssr-config/issues",
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "prepublish": "yarn build",
39
+ "prepack": "yarn build"
40
+ },
41
+ "dependencies": {
42
+ "dotenv-local": "^1.0.2",
43
+ "fs-extra": "^11.2.0"
44
+ },
45
+ "peerDependencies": {
46
+ "vite": "^2 || ^3 || ^4 || ^5 || ^6"
47
+ },
48
+ "devDependencies": {
49
+ "@types/express": "^5.0.0",
50
+ "@types/fs-extra": "^11.0.4",
51
+ "@types/node": "^22.10.2",
52
+ "express": "^4.21.2",
53
+ "tsup": "^8.3.5",
54
+ "typescript": "^5.7.2",
55
+ "vite": "^4.0.0"
56
+ }
57
+ }
@@ -0,0 +1,25 @@
1
+ import { PageBrowser } from "@ssr/pageBrowser.jsx";
2
+ import { startTransition, StrictMode } from "react";
3
+ import { hydrateRoot } from "react-dom/client";
4
+
5
+ startTransition(() => {
6
+ const hydratedState = JSON.parse(atob(window.__HYDRATED_STATE__));
7
+ const setHydratedState = () => {
8
+ throw Error("Changes Not Allowed");
9
+ };
10
+ hydrateRoot(
11
+ document,
12
+ <StrictMode>
13
+ <PageBrowser
14
+ hydratedState={hydratedState}
15
+ setHydratedState={setHydratedState}
16
+ />
17
+ </StrictMode>,
18
+ {
19
+ onRecoverableError: (error, { componentStack }) => {
20
+ const logs = componentStack?.split("\n");
21
+ console.log("Error:", error, logs);
22
+ },
23
+ }
24
+ );
25
+ });
@@ -0,0 +1,44 @@
1
+ import { PageServer } from "@ssr/pageServer.jsx";
2
+ import { StrictMode } from "react";
3
+ import { renderToPipeableStream } from "react-dom/server";
4
+
5
+ const renderDefault = async (request, response, next) => {
6
+ let hydratedState = {};
7
+ const setHydratedState = (state) => {
8
+ hydratedState = state;
9
+ };
10
+ const { pipe } = renderToPipeableStream(
11
+ <StrictMode>
12
+ <PageServer
13
+ path={request.originalUrl}
14
+ hydratedState={""} // Access is Not Allowed
15
+ setHydratedState={setHydratedState}
16
+ />
17
+ </StrictMode>,
18
+ {
19
+ bootstrapScripts: [],
20
+ onShellReady: () => {
21
+ // console.log(request.originalUrl, "onShellReady");
22
+ },
23
+ onAllReady: () => {
24
+ // console.log(request.originalUrl, "onAllReady");
25
+ response.setHeader("content-type", "text/html");
26
+ pipe(response);
27
+ response.write(
28
+ `<script>window.__HYDRATED_STATE__ = "${btoa(
29
+ JSON.stringify(hydratedState)
30
+ )}";</script>`
31
+ );
32
+ },
33
+ onShellError: (error) => {
34
+ // console.log(request.originalUrl, "onShellError", error);
35
+ },
36
+ onError: (error, errorInfo) => {
37
+ // console.log(request.originalUrl, "onError", error, errorInfo);
38
+ next(error);
39
+ },
40
+ }
41
+ );
42
+ };
43
+
44
+ export const render = renderDefault;