@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 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
@@ -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
+ }