@webjourney/vite-plugins 1.0.2 → 1.2.0

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.
@@ -0,0 +1,7 @@
1
+ export interface BuildOptions {
2
+ projectRoot: string;
3
+ ssrEntry?: string;
4
+ clientBuildOptions?: string;
5
+ }
6
+ export declare function buildWithSSR(options: BuildOptions): Promise<void>;
7
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,iBA4BvD"}
package/dist/build.js ADDED
@@ -0,0 +1,126 @@
1
+ import { execSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { JSDOM } from 'jsdom';
5
+ export async function buildWithSSR(options) {
6
+ const { projectRoot, ssrEntry = 'src/entry-server.tsx', clientBuildOptions = '--base=\'./\'' } = options;
7
+ const toAbsolute = (p) => path.resolve(projectRoot, p);
8
+ console.log('Building for production with SSR...\n');
9
+ // Step 1: Type check
10
+ console.log('1. Type checking...');
11
+ execSync('tsc -b', { stdio: 'inherit', cwd: projectRoot });
12
+ // Step 2: Build SSR bundle
13
+ console.log('\n2. Building SSR bundle...');
14
+ execSync(`vite build --ssr ${ssrEntry} --outDir dist-ssr`, { stdio: 'inherit', cwd: projectRoot });
15
+ // Step 3: Build client bundle
16
+ console.log('\n3. Building client bundle...');
17
+ execSync(`vite build ${clientBuildOptions}`, { stdio: 'inherit', cwd: projectRoot });
18
+ // Step 4: Pre-render HTML
19
+ console.log('\n4. Pre-rendering HTML...');
20
+ await prerender(projectRoot);
21
+ console.log('\n✓ Build complete!');
22
+ }
23
+ async function extractRoutes(projectRoot) {
24
+ const toAbsolute = (p) => path.resolve(projectRoot, p);
25
+ // Import App component from the built SSR bundle
26
+ const entryServerPath = toAbsolute('dist-ssr/entry-server.js');
27
+ const { App } = await import(entryServerPath);
28
+ // Create a temporary React element to traverse
29
+ const appElement = App();
30
+ // Extract routes by traversing the React element tree
31
+ const routes = [];
32
+ function traverseElement(element) {
33
+ if (!element)
34
+ return;
35
+ // Check if this is a Route component with a path prop
36
+ if (element.type?.name === 'Route' || element.type?.displayName === 'Route') {
37
+ const path = element.props?.path;
38
+ if (path && typeof path === 'string') {
39
+ routes.push(path);
40
+ }
41
+ }
42
+ // Traverse children
43
+ if (element.props?.children) {
44
+ const children = Array.isArray(element.props.children)
45
+ ? element.props.children
46
+ : [element.props.children];
47
+ children.forEach((child) => {
48
+ if (child && typeof child === 'object') {
49
+ traverseElement(child);
50
+ }
51
+ });
52
+ }
53
+ }
54
+ traverseElement(appElement);
55
+ // If no routes found, default to root
56
+ return routes.length > 0 ? routes : ['/'];
57
+ }
58
+ async function prerender(projectRoot) {
59
+ const toAbsolute = (p) => path.resolve(projectRoot, p);
60
+ // Read the built index.html
61
+ const templatePath = toAbsolute('dist/index.html');
62
+ const template = fs.readFileSync(templatePath, 'utf-8');
63
+ // Setup JSDOM for React rendering
64
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
65
+ url: 'http://localhost',
66
+ });
67
+ // Setup globals for React SSR
68
+ const originalWindow = global.window;
69
+ const originalDocument = global.document;
70
+ Object.defineProperty(global, 'window', {
71
+ writable: true,
72
+ configurable: true,
73
+ value: dom.window,
74
+ });
75
+ Object.defineProperty(global, 'document', {
76
+ writable: true,
77
+ configurable: true,
78
+ value: dom.window.document,
79
+ });
80
+ // Import the server entry after setting up globals
81
+ const entryServerPath = toAbsolute('dist-ssr/entry-server.js');
82
+ const { render } = await import(entryServerPath);
83
+ // Dynamically import renderToString from the project's react-dom
84
+ const reactDomServerPath = path.resolve(projectRoot, 'node_modules/react-dom/server');
85
+ const { renderToString } = await import(reactDomServerPath);
86
+ // Extract routes from App.tsx
87
+ const routes = await extractRoutes(projectRoot);
88
+ console.log(` Found ${routes.length} route(s): ${routes.join(', ')}`);
89
+ for (const route of routes) {
90
+ // Render the app HTML
91
+ const appHtml = renderToString(render(route));
92
+ // Replace the empty root div with the rendered content
93
+ let html = template.replace('<div id="root"></div>', `<div id="root">${appHtml}</div>`);
94
+ // Adjust asset paths based on route depth
95
+ if (route !== '/') {
96
+ const depth = route.split('/').filter(Boolean).length;
97
+ const prefix = '../'.repeat(depth);
98
+ // Replace asset references: ./assets/ -> ../assets/ or ../../assets/ etc
99
+ html = html.replace(/\.\/assets\//g, `${prefix}assets/`);
100
+ }
101
+ // Write the pre-rendered HTML
102
+ const filePath = route === '/'
103
+ ? toAbsolute('dist/index.html')
104
+ : toAbsolute(`dist${route}/index.html`);
105
+ // Ensure directory exists
106
+ const dir = path.dirname(filePath);
107
+ if (!fs.existsSync(dir)) {
108
+ fs.mkdirSync(dir, { recursive: true });
109
+ }
110
+ fs.writeFileSync(filePath, html);
111
+ console.log(` Pre-rendered: ${route}`);
112
+ }
113
+ // Clean up
114
+ if (originalWindow !== undefined) {
115
+ global.window = originalWindow;
116
+ }
117
+ else {
118
+ delete global.window;
119
+ }
120
+ if (originalDocument !== undefined) {
121
+ global.document = originalDocument;
122
+ }
123
+ else {
124
+ delete global.document;
125
+ }
126
+ }
@@ -0,0 +1,8 @@
1
+ import { ComponentType } from 'react';
2
+ /**
3
+ * Creates a render function for server-side rendering
4
+ * @param App - The root App component to render
5
+ * @returns A render function that wraps the App in StrictMode and StaticRouter
6
+ */
7
+ export declare function createServerRenderer(App: ComponentType): (url: string) => import("react/jsx-runtime").JSX.Element;
8
+ //# sourceMappingURL=entry-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-server.d.ts","sourceRoot":"","sources":["../src/entry-server.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,aAAa,EAAE,MAAM,OAAO,CAAC;AAGlD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,IAC9B,KAAK,MAAM,6CASnC"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { StrictMode } from 'react';
3
+ import { StaticRouter } from 'react-router';
4
+ /**
5
+ * Creates a render function for server-side rendering
6
+ * @param App - The root App component to render
7
+ * @returns A render function that wraps the App in StrictMode and StaticRouter
8
+ */
9
+ export function createServerRenderer(App) {
10
+ return function render(url) {
11
+ return (_jsx(StrictMode, { children: _jsx(StaticRouter, { location: url, children: _jsx(App, {}) }) }));
12
+ };
13
+ }
package/dist/index.d.ts CHANGED
@@ -11,9 +11,16 @@ export declare function webjourneyPluginScript(): {
11
11
  enforce: "pre";
12
12
  transformIndexHtml(html: string): string;
13
13
  };
14
- export declare function webjourneyPlugins(): {
14
+ export declare function webjourneyPlugins(): ({
15
+ name: string;
16
+ enforce: "pre";
17
+ transform(code: string, id: string): {
18
+ code: any;
19
+ map: null;
20
+ } | null;
21
+ } | {
15
22
  name: string;
16
23
  enforce: "pre";
17
24
  transformIndexHtml(html: string): string;
18
- }[];
25
+ })[];
19
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,wBAAgB,uBAAuB;;;oBAKnB,MAAM,MAAM,MAAM;;;;EAkIrC;AAED,wBAAgB,sBAAsB;;;6BAKT,MAAM;EAIlC;AAED,wBAAgB,iBAAiB;;;6BANJ,MAAM;IAUlC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiBA,wBAAgB,uBAAuB;;;oBAKnB,MAAM,MAAM,MAAM;;;;EAkIrC;AAED,wBAAgB,sBAAsB;;;6BAKT,MAAM;EAIlC;AAED,wBAAgB,iBAAiB;;;oBA/Ib,MAAM,MAAM,MAAM;;;;;;;6BAyIT,MAAM;KAUlC"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import path from 'path';
1
+ import _generate from '@babel/generator';
2
2
  import { parse } from '@babel/parser';
3
3
  import _traverse from '@babel/traverse';
4
- import _generate from '@babel/generator';
5
4
  import * as t from '@babel/types';
5
+ import path from 'path';
6
6
  // Handle CommonJS default exports
7
7
  const traverse = _traverse.default || _traverse;
8
8
  const generate = _generate.default || _generate;
@@ -105,7 +105,7 @@ export function webjourneyPluginScript() {
105
105
  }
106
106
  export function webjourneyPlugins() {
107
107
  return [
108
- // webjourneyElementTagger(),
108
+ webjourneyElementTagger(),
109
109
  webjourneyPluginScript()
110
110
  ];
111
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjourney/vite-plugins",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "Vite plugins for Webjourney WYSIWYG editing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,6 +9,14 @@
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts"
12
+ },
13
+ "./build": {
14
+ "import": "./dist/build.js",
15
+ "types": "./dist/build.d.ts"
16
+ },
17
+ "./entry-server": {
18
+ "import": "./dist/entry-server.js",
19
+ "types": "./dist/entry-server.d.ts"
12
20
  }
13
21
  },
14
22
  "files": [
@@ -23,16 +31,24 @@
23
31
  "@babel/generator": "^7.26.5",
24
32
  "@babel/parser": "^7.26.5",
25
33
  "@babel/traverse": "^7.26.5",
26
- "@babel/types": "^7.26.5"
34
+ "@babel/types": "^7.26.5",
35
+ "jsdom": "^26.1.0"
27
36
  },
28
37
  "devDependencies": {
29
38
  "@types/babel__generator": "^7.6.8",
30
39
  "@types/babel__traverse": "^7.20.6",
40
+ "@types/jsdom": "^21.1.7",
31
41
  "@types/node": "^20.0.0",
42
+ "@types/react": "^18.0.0",
43
+ "@types/react-dom": "^18.0.0",
44
+ "react": "^18.0.0",
45
+ "react-router": "^7.0.0",
32
46
  "typescript": "^5.8.3",
33
47
  "vite": "^5.0.0"
34
48
  },
35
49
  "peerDependencies": {
50
+ "react": "^18.0.0 || ^19.0.0",
51
+ "react-router": "^6.0.0 || ^7.0.0",
36
52
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
37
53
  }
38
54
  }