@webjourney/vite-plugins 1.0.1 → 1.1.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.
- package/dist/build.d.ts +7 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +126 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/package.json +10 -2
- package/README.md +0 -66
package/dist/build.d.ts
ADDED
|
@@ -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
|
+
}
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;;;
|
|
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
|
|
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
|
-
|
|
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
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Vite plugins for Webjourney WYSIWYG editing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,10 @@
|
|
|
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"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
@@ -23,12 +27,16 @@
|
|
|
23
27
|
"@babel/generator": "^7.26.5",
|
|
24
28
|
"@babel/parser": "^7.26.5",
|
|
25
29
|
"@babel/traverse": "^7.26.5",
|
|
26
|
-
"@babel/types": "^7.26.5"
|
|
30
|
+
"@babel/types": "^7.26.5",
|
|
31
|
+
"jsdom": "^26.1.0"
|
|
27
32
|
},
|
|
28
33
|
"devDependencies": {
|
|
29
34
|
"@types/babel__generator": "^7.6.8",
|
|
30
35
|
"@types/babel__traverse": "^7.20.6",
|
|
36
|
+
"@types/jsdom": "^21.1.7",
|
|
31
37
|
"@types/node": "^20.0.0",
|
|
38
|
+
"@types/react": "^18.0.0",
|
|
39
|
+
"@types/react-dom": "^18.0.0",
|
|
32
40
|
"typescript": "^5.8.3",
|
|
33
41
|
"vite": "^5.0.0"
|
|
34
42
|
},
|
package/README.md
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# @webjourney/vite-plugins
|
|
2
|
-
|
|
3
|
-
Vite plugins for Webjourney WYSIWYG editing functionality.
|
|
4
|
-
|
|
5
|
-
## Requirements
|
|
6
|
-
|
|
7
|
-
- Vite 5.x, 6.x, or 7.x
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
yarn add @webjourney/vite-plugins
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Or with npm:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npm install @webjourney/vite-plugins
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Usage
|
|
22
|
-
|
|
23
|
-
In your `vite.config.ts`:
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
import { defineConfig } from 'vite';
|
|
27
|
-
import { webjourneyPlugins } from '@webjourney/vite-plugins';
|
|
28
|
-
|
|
29
|
-
export default defineConfig({
|
|
30
|
-
plugins: [
|
|
31
|
-
...webjourneyPlugins(), // Must run BEFORE react() to see original JSX
|
|
32
|
-
// ... other plugins
|
|
33
|
-
],
|
|
34
|
-
});
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## What it does
|
|
38
|
-
|
|
39
|
-
This package provides Vite plugins that enable WYSIWYG editing in Webjourney:
|
|
40
|
-
|
|
41
|
-
1. **`webjourneyElementTagger()`** - Injects source mapping attributes (`data-wj-*`) into JSX elements for tracking
|
|
42
|
-
2. **`webjourneyPluginScript()`** - Injects the Webjourney plugin script into the HTML head
|
|
43
|
-
3. **`webjourneyPlugins()`** - Convenience function that returns an array of the above plugins
|
|
44
|
-
|
|
45
|
-
## Features
|
|
46
|
-
|
|
47
|
-
- Automatically adds `data-wj-file`, `data-wj-line`, `data-wj-type`, and `data-wj-id` attributes to text and image elements
|
|
48
|
-
- Only runs in development mode for performance
|
|
49
|
-
- Zero runtime overhead in production builds
|
|
50
|
-
|
|
51
|
-
## Development
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
# Build the package
|
|
55
|
-
yarn build
|
|
56
|
-
|
|
57
|
-
# Watch mode
|
|
58
|
-
yarn dev
|
|
59
|
-
|
|
60
|
-
# Type check
|
|
61
|
-
yarn typecheck
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## License
|
|
65
|
-
|
|
66
|
-
Private - Webjourney internal use only
|