@webjourney/vite-plugins 1.0.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/README.md +56 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @webjourney/vite-plugins
|
|
2
|
+
|
|
3
|
+
Vite plugins for Webjourney WYSIWYG editing functionality.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
yarn add @webjourney/vite-plugins
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
In your `vite.config.ts`:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { defineConfig } from 'vite';
|
|
17
|
+
import { webjourneyPlugins } from '@webjourney/vite-plugins';
|
|
18
|
+
|
|
19
|
+
export default defineConfig({
|
|
20
|
+
plugins: [
|
|
21
|
+
...webjourneyPlugins(), // Must run BEFORE react() to see original JSX
|
|
22
|
+
// ... other plugins
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## What it does
|
|
28
|
+
|
|
29
|
+
This package provides Vite plugins that enable WYSIWYG editing in Webjourney:
|
|
30
|
+
|
|
31
|
+
1. **`webjourneyElementTagger()`** - Injects source mapping attributes (`data-wj-*`) into JSX elements for tracking
|
|
32
|
+
2. **`webjourneyPluginScript()`** - Injects the Webjourney plugin script into the HTML head
|
|
33
|
+
3. **`webjourneyPlugins()`** - Convenience function that returns an array of the above plugins
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Automatically adds `data-wj-file`, `data-wj-line`, `data-wj-type`, and `data-wj-id` attributes to text and image elements
|
|
38
|
+
- Only runs in development mode for performance
|
|
39
|
+
- Zero runtime overhead in production builds
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Build the package
|
|
45
|
+
yarn build
|
|
46
|
+
|
|
47
|
+
# Watch mode
|
|
48
|
+
yarn dev
|
|
49
|
+
|
|
50
|
+
# Type check
|
|
51
|
+
yarn typecheck
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## License
|
|
55
|
+
|
|
56
|
+
Private - Webjourney internal use only
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare function webjourneyElementTagger(): {
|
|
2
|
+
name: string;
|
|
3
|
+
enforce: "pre";
|
|
4
|
+
transform(code: string, id: string): {
|
|
5
|
+
code: any;
|
|
6
|
+
map: null;
|
|
7
|
+
} | null;
|
|
8
|
+
};
|
|
9
|
+
export declare function webjourneyPluginScript(): {
|
|
10
|
+
name: string;
|
|
11
|
+
enforce: "pre";
|
|
12
|
+
transformIndexHtml(html: string): string;
|
|
13
|
+
};
|
|
14
|
+
export declare function webjourneyPlugins(): {
|
|
15
|
+
name: string;
|
|
16
|
+
enforce: "pre";
|
|
17
|
+
transformIndexHtml(html: string): string;
|
|
18
|
+
}[];
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { parse } from '@babel/parser';
|
|
3
|
+
import _traverse from '@babel/traverse';
|
|
4
|
+
import _generate from '@babel/generator';
|
|
5
|
+
import * as t from '@babel/types';
|
|
6
|
+
// Handle CommonJS default exports
|
|
7
|
+
const traverse = _traverse.default || _traverse;
|
|
8
|
+
const generate = _generate.default || _generate;
|
|
9
|
+
// Use local plugin for development, production URL for deployed sites
|
|
10
|
+
const webjourneyPluginScriptHost = process.env.NODE_ENV === 'production'
|
|
11
|
+
? 'https://app.webjourney.pro'
|
|
12
|
+
: 'http://127.0.0.1:3000';
|
|
13
|
+
// Plugin to inject source mapping attributes for WYSIWYG editing
|
|
14
|
+
export function webjourneyElementTagger() {
|
|
15
|
+
return {
|
|
16
|
+
name: 'webjourney-source-mapping',
|
|
17
|
+
enforce: 'pre',
|
|
18
|
+
transform(code, id) {
|
|
19
|
+
// Only process React components in development
|
|
20
|
+
if (process.env.NODE_ENV === 'production')
|
|
21
|
+
return null;
|
|
22
|
+
if (!id.match(/\.(tsx|jsx)$/))
|
|
23
|
+
return null;
|
|
24
|
+
if (id.includes('node_modules'))
|
|
25
|
+
return null;
|
|
26
|
+
// Get relative path from project root
|
|
27
|
+
const relativePath = path.relative(process.cwd(), id);
|
|
28
|
+
try {
|
|
29
|
+
// Parse the code into an AST
|
|
30
|
+
const ast = parse(code, {
|
|
31
|
+
sourceType: 'module',
|
|
32
|
+
plugins: ['typescript', 'jsx'],
|
|
33
|
+
});
|
|
34
|
+
let modified = false;
|
|
35
|
+
// Traverse the AST
|
|
36
|
+
traverse(ast, {
|
|
37
|
+
JSXElement(path) {
|
|
38
|
+
const openingElement = path.node.openingElement;
|
|
39
|
+
const elementName = openingElement.name;
|
|
40
|
+
// Only process specific element types
|
|
41
|
+
if (!t.isJSXIdentifier(elementName))
|
|
42
|
+
return;
|
|
43
|
+
const tagName = elementName.name;
|
|
44
|
+
// Check if already has data-wj-file attribute
|
|
45
|
+
const hasDataWj = openingElement.attributes.some((attr) => t.isJSXAttribute(attr) &&
|
|
46
|
+
t.isJSXIdentifier(attr.name) &&
|
|
47
|
+
attr.name.name === 'data-wj-file');
|
|
48
|
+
if (hasDataWj)
|
|
49
|
+
return;
|
|
50
|
+
const lineNumber = openingElement.loc?.start.line ?? 0;
|
|
51
|
+
// Handle text elements
|
|
52
|
+
if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span', 'div', 'button', 'a', 'label', 'li'].includes(tagName)) {
|
|
53
|
+
// Check if element has text content
|
|
54
|
+
const hasTextContent = path.node.children.some((child) => t.isJSXText(child) && child.value.trim() !== '');
|
|
55
|
+
if (hasTextContent) {
|
|
56
|
+
// Generate unique ID: filename:line
|
|
57
|
+
const elementId = `${relativePath}:${lineNumber}`;
|
|
58
|
+
openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier('data-wj-file'), t.stringLiteral(relativePath)), t.jsxAttribute(t.jsxIdentifier('data-wj-line'), t.stringLiteral(String(lineNumber))), t.jsxAttribute(t.jsxIdentifier('data-wj-type'), t.stringLiteral('text')), t.jsxAttribute(t.jsxIdentifier('data-wj-id'), t.stringLiteral(elementId)));
|
|
59
|
+
modified = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Handle img elements
|
|
63
|
+
if (tagName === 'img') {
|
|
64
|
+
// Check if img has src attribute
|
|
65
|
+
const hasSrc = openingElement.attributes.some((attr) => t.isJSXAttribute(attr) &&
|
|
66
|
+
t.isJSXIdentifier(attr.name) &&
|
|
67
|
+
attr.name.name === 'src');
|
|
68
|
+
if (hasSrc) {
|
|
69
|
+
// Generate unique ID: filename:line
|
|
70
|
+
const elementId = `${relativePath}:${lineNumber}`;
|
|
71
|
+
openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier('data-wj-file'), t.stringLiteral(relativePath)), t.jsxAttribute(t.jsxIdentifier('data-wj-line'), t.stringLiteral(String(lineNumber))), t.jsxAttribute(t.jsxIdentifier('data-wj-type'), t.stringLiteral('image')), t.jsxAttribute(t.jsxIdentifier('data-wj-id'), t.stringLiteral(elementId)));
|
|
72
|
+
modified = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
if (modified) {
|
|
78
|
+
// Generate code from the modified AST
|
|
79
|
+
const output = generate(ast, {
|
|
80
|
+
retainLines: true,
|
|
81
|
+
compact: false,
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
code: output.code,
|
|
85
|
+
map: null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error(`Error transforming ${id}:`, error);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function webjourneyPluginScript() {
|
|
98
|
+
return {
|
|
99
|
+
name: 'webjourney-plugin-script',
|
|
100
|
+
enforce: 'pre',
|
|
101
|
+
transformIndexHtml(html) {
|
|
102
|
+
return html.replace('</head>', `<script src="${webjourneyPluginScriptHost}/plugins/plugin.iife.js"></script></head>`);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function webjourneyPlugins() {
|
|
107
|
+
return [
|
|
108
|
+
// webjourneyElementTagger(),
|
|
109
|
+
webjourneyPluginScript()
|
|
110
|
+
];
|
|
111
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@webjourney/vite-plugins",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Vite plugins for Webjourney WYSIWYG editing",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@babel/generator": "^7.26.5",
|
|
24
|
+
"@babel/parser": "^7.26.5",
|
|
25
|
+
"@babel/traverse": "^7.26.5",
|
|
26
|
+
"@babel/types": "^7.26.5"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/babel__generator": "^7.6.8",
|
|
30
|
+
"@types/babel__traverse": "^7.20.6",
|
|
31
|
+
"@types/node": "^20.0.0",
|
|
32
|
+
"typescript": "^5.8.3",
|
|
33
|
+
"vite": "^5.0.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"vite": "^5.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|