@wsxjs/wsx-vite-plugin 0.0.7 → 0.0.9
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.d.mts +6 -26
- package/dist/index.d.ts +6 -26
- package/dist/index.js +585 -46
- package/dist/index.mjs +575 -46
- package/package.json +14 -6
- package/src/babel-plugin-wsx-focus.ts +219 -0
- package/src/babel-plugin-wsx-state.ts +394 -0
- package/src/babel-plugin-wsx-style.ts +149 -0
- package/src/index.ts +2 -1
- package/src/vite-plugin-wsx-babel.ts +182 -0
- package/src/vite-plugin-wsx.ts +0 -166
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Babel plugin to automatically inject CSS styles for WSX components
|
|
3
|
+
*
|
|
4
|
+
* Transforms:
|
|
5
|
+
* // Button.wsx (if Button.css exists)
|
|
6
|
+
* export default class Button extends WebComponent { ... }
|
|
7
|
+
*
|
|
8
|
+
* To:
|
|
9
|
+
* import styles from "./Button.css?inline";
|
|
10
|
+
* export default class Button extends WebComponent {
|
|
11
|
+
* private _autoStyles = styles;
|
|
12
|
+
* ...
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { PluginObj, PluginPass } from "@babel/core";
|
|
17
|
+
import type * as t from "@babel/types";
|
|
18
|
+
import * as tModule from "@babel/types";
|
|
19
|
+
|
|
20
|
+
interface WSXStylePluginPass extends PluginPass {
|
|
21
|
+
cssFileExists: boolean;
|
|
22
|
+
cssFilePath: string;
|
|
23
|
+
componentName: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if styles are already imported in the file
|
|
28
|
+
*/
|
|
29
|
+
function hasStylesImport(program: t.Program): boolean {
|
|
30
|
+
for (const node of program.body) {
|
|
31
|
+
if (node.type === "ImportDeclaration") {
|
|
32
|
+
const source = node.source.value;
|
|
33
|
+
// Check if it's a CSS import with ?inline
|
|
34
|
+
if (
|
|
35
|
+
typeof source === "string" &&
|
|
36
|
+
(source.endsWith(".css?inline") || source.endsWith(".css"))
|
|
37
|
+
) {
|
|
38
|
+
// Check if it's imported as "styles"
|
|
39
|
+
const defaultSpecifier = node.specifiers.find(
|
|
40
|
+
(spec) => spec.type === "ImportDefaultSpecifier"
|
|
41
|
+
);
|
|
42
|
+
if (defaultSpecifier) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if _autoStyles property already exists in the class
|
|
53
|
+
*/
|
|
54
|
+
function hasAutoStylesProperty(classBody: t.ClassBody): boolean {
|
|
55
|
+
for (const member of classBody.body) {
|
|
56
|
+
if (
|
|
57
|
+
(member.type === "ClassProperty" || member.type === "ClassPrivateProperty") &&
|
|
58
|
+
member.key.type === "Identifier" &&
|
|
59
|
+
member.key.name === "_autoStyles"
|
|
60
|
+
) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default function babelPluginWSXStyle(): PluginObj<WSXStylePluginPass> {
|
|
68
|
+
const t = tModule;
|
|
69
|
+
return {
|
|
70
|
+
name: "babel-plugin-wsx-style",
|
|
71
|
+
visitor: {
|
|
72
|
+
Program(path, state) {
|
|
73
|
+
const { cssFileExists, cssFilePath, componentName } =
|
|
74
|
+
state.opts as WSXStylePluginPass;
|
|
75
|
+
|
|
76
|
+
// Skip if CSS file doesn't exist
|
|
77
|
+
if (!cssFileExists) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if styles are already manually imported
|
|
82
|
+
if (hasStylesImport(path.node)) {
|
|
83
|
+
console.info(
|
|
84
|
+
`[Babel Plugin WSX Style] Skipping ${componentName}: styles already manually imported`
|
|
85
|
+
);
|
|
86
|
+
return; // Skip auto-injection if manual import exists
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.info(
|
|
90
|
+
`[Babel Plugin WSX Style] Injecting CSS import for ${componentName}: ${cssFilePath}`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// Add CSS import at the top of the file
|
|
94
|
+
const importStatement = t.importDeclaration(
|
|
95
|
+
[t.importDefaultSpecifier(t.identifier("styles"))],
|
|
96
|
+
t.stringLiteral(cssFilePath)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// Insert after existing imports (if any)
|
|
100
|
+
let insertIndex = 0;
|
|
101
|
+
for (let i = 0; i < path.node.body.length; i++) {
|
|
102
|
+
const node = path.node.body[i];
|
|
103
|
+
if (node.type === "ImportDeclaration") {
|
|
104
|
+
insertIndex = i + 1;
|
|
105
|
+
} else {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
path.node.body.splice(insertIndex, 0, importStatement);
|
|
111
|
+
},
|
|
112
|
+
ClassDeclaration(path, state) {
|
|
113
|
+
const { cssFileExists } = state.opts as WSXStylePluginPass;
|
|
114
|
+
|
|
115
|
+
// Skip if CSS file doesn't exist
|
|
116
|
+
if (!cssFileExists) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const classBody = path.node.body;
|
|
121
|
+
|
|
122
|
+
// Check if _autoStyles property already exists
|
|
123
|
+
if (hasAutoStylesProperty(classBody)) {
|
|
124
|
+
return; // Skip if already exists
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Note: We don't check for manual imports here because:
|
|
128
|
+
// 1. Program visitor already handled that and skipped if manual import exists
|
|
129
|
+
// 2. If we reach here, it means Program visitor added the import (or it was already there)
|
|
130
|
+
// 3. We should add the class property regardless
|
|
131
|
+
|
|
132
|
+
// Add class property: private _autoStyles = styles;
|
|
133
|
+
// Use classProperty (not classPrivateProperty) to create TypeScript private property
|
|
134
|
+
// TypeScript private is compile-time only and becomes a regular property at runtime
|
|
135
|
+
const autoStylesProperty = t.classProperty(
|
|
136
|
+
t.identifier("_autoStyles"),
|
|
137
|
+
t.identifier("styles"),
|
|
138
|
+
null, // typeAnnotation
|
|
139
|
+
[], // decorators
|
|
140
|
+
false, // computed
|
|
141
|
+
false // static
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Insert at the beginning of class body (before methods and other properties)
|
|
145
|
+
classBody.body.unshift(autoStylesProperty);
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
// Export the Babel-based plugin (with compile-time decorator support)
|
|
2
|
+
export { vitePluginWSXWithBabel as wsx } from "./vite-plugin-wsx-babel";
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite Plugin for WSX with Babel decorator support
|
|
3
|
+
*
|
|
4
|
+
* Uses Babel to preprocess decorators before esbuild transformation
|
|
5
|
+
* This ensures decorators work correctly even with esbuild's limitations
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Plugin } from "vite";
|
|
9
|
+
import { transform } from "esbuild";
|
|
10
|
+
import { transformSync } from "@babel/core";
|
|
11
|
+
import { existsSync } from "fs";
|
|
12
|
+
import { dirname, join, basename } from "path";
|
|
13
|
+
import babelPluginWSXState from "./babel-plugin-wsx-state";
|
|
14
|
+
import babelPluginWSXStyle from "./babel-plugin-wsx-style";
|
|
15
|
+
import babelPluginWSXFocus from "./babel-plugin-wsx-focus";
|
|
16
|
+
|
|
17
|
+
export interface WSXPluginOptions {
|
|
18
|
+
jsxFactory?: string;
|
|
19
|
+
jsxFragment?: string;
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
extensions?: string[];
|
|
22
|
+
autoStyleInjection?: boolean; // Default: true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getJSXFactoryImportPath(_options: WSXPluginOptions): string {
|
|
26
|
+
return "@wsxjs/wsx-core";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function vitePluginWSXWithBabel(options: WSXPluginOptions = {}): Plugin {
|
|
30
|
+
const {
|
|
31
|
+
jsxFactory = "h",
|
|
32
|
+
jsxFragment = "Fragment",
|
|
33
|
+
extensions = [".wsx"],
|
|
34
|
+
autoStyleInjection = true,
|
|
35
|
+
} = options;
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
name: "vite-plugin-wsx-babel",
|
|
39
|
+
enforce: "pre",
|
|
40
|
+
|
|
41
|
+
async transform(code: string, id: string) {
|
|
42
|
+
const isWSXFile = extensions.some((ext) => id.endsWith(ext));
|
|
43
|
+
|
|
44
|
+
if (!isWSXFile) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if corresponding CSS file exists (for auto style injection)
|
|
49
|
+
let cssFileExists = false;
|
|
50
|
+
let cssFilePath = "";
|
|
51
|
+
let componentName = "";
|
|
52
|
+
|
|
53
|
+
if (autoStyleInjection) {
|
|
54
|
+
const fileDir = dirname(id);
|
|
55
|
+
const fileName = basename(id, extensions.find((ext) => id.endsWith(ext)) || "");
|
|
56
|
+
const cssFilePathWithoutQuery = join(fileDir, `${fileName}.css`);
|
|
57
|
+
cssFileExists = existsSync(cssFilePathWithoutQuery);
|
|
58
|
+
componentName = fileName;
|
|
59
|
+
|
|
60
|
+
// Generate relative path for import (e.g., "./Button.css?inline")
|
|
61
|
+
// Use relative path from the file's directory
|
|
62
|
+
if (cssFileExists) {
|
|
63
|
+
// For import statement, use relative path with ?inline query
|
|
64
|
+
cssFilePath = `./${fileName}.css?inline`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let transformedCode = code;
|
|
69
|
+
|
|
70
|
+
// 1. Add JSX imports if needed
|
|
71
|
+
// Check for actual import statement
|
|
72
|
+
const hasWSXCoreImport = code.includes('from "@wsxjs/wsx-core"');
|
|
73
|
+
// Check if JSX factory functions are already imported
|
|
74
|
+
const hasJSXInImport =
|
|
75
|
+
hasWSXCoreImport &&
|
|
76
|
+
(new RegExp(`[{,]\\s*${jsxFactory}\\s*[},]`).test(code) ||
|
|
77
|
+
new RegExp(`[{,]\\s*${jsxFragment}\\s*[},]`).test(code));
|
|
78
|
+
|
|
79
|
+
// If file has JSX syntax but no import, add it
|
|
80
|
+
// Note: @jsxImportSource pragma is just a hint, we need actual import for esbuild
|
|
81
|
+
if ((code.includes("<") || code.includes("Fragment")) && !hasJSXInImport) {
|
|
82
|
+
const importPath = getJSXFactoryImportPath(options);
|
|
83
|
+
const importStatement = `import { ${jsxFactory}, ${jsxFragment} } from "${importPath}";\n`;
|
|
84
|
+
transformedCode = importStatement + transformedCode;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 2. Use Babel to preprocess decorators
|
|
88
|
+
try {
|
|
89
|
+
const babelResult = transformSync(transformedCode, {
|
|
90
|
+
filename: id, // Pass the actual filename so Babel knows it's .wsx
|
|
91
|
+
presets: [
|
|
92
|
+
[
|
|
93
|
+
"@babel/preset-typescript",
|
|
94
|
+
{
|
|
95
|
+
isTSX: true, // Enable JSX syntax
|
|
96
|
+
allExtensions: true, // Process all extensions, including .wsx
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
],
|
|
100
|
+
plugins: [
|
|
101
|
+
// CRITICAL: Style injection plugin must run FIRST
|
|
102
|
+
// This ensures _autoStyles property exists before state transformations
|
|
103
|
+
...(autoStyleInjection && cssFileExists
|
|
104
|
+
? [
|
|
105
|
+
[
|
|
106
|
+
babelPluginWSXStyle,
|
|
107
|
+
{
|
|
108
|
+
cssFileExists,
|
|
109
|
+
cssFilePath,
|
|
110
|
+
componentName,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
]
|
|
114
|
+
: []),
|
|
115
|
+
// Focus key generation plugin runs early to add data-wsx-key attributes
|
|
116
|
+
// This must run before JSX is transformed to h() calls
|
|
117
|
+
babelPluginWSXFocus,
|
|
118
|
+
// State decorator transformation runs after style injection
|
|
119
|
+
babelPluginWSXState,
|
|
120
|
+
[
|
|
121
|
+
"@babel/plugin-proposal-decorators",
|
|
122
|
+
{
|
|
123
|
+
version: "2023-05",
|
|
124
|
+
decoratorsBeforeExport: true,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
[
|
|
128
|
+
"@babel/plugin-proposal-class-properties",
|
|
129
|
+
{
|
|
130
|
+
loose: false,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
"@babel/plugin-transform-class-static-block", // Support static class blocks
|
|
134
|
+
],
|
|
135
|
+
// parserOpts not needed - @babel/preset-typescript and plugins handle it
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (babelResult && babelResult.code) {
|
|
139
|
+
transformedCode = babelResult.code;
|
|
140
|
+
}
|
|
141
|
+
} catch {
|
|
142
|
+
// Babel transform failed, fallback to esbuild only
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 2.5. Ensure JSX imports still exist after Babel transformation
|
|
146
|
+
// Babel might have removed or modified imports, so we check again
|
|
147
|
+
const hasJSXAfterBabel =
|
|
148
|
+
transformedCode.includes('from "@wsxjs/wsx-core"') &&
|
|
149
|
+
(new RegExp(`[{,]\\s*${jsxFactory}\\s*[},]`).test(transformedCode) ||
|
|
150
|
+
new RegExp(`[{,]\\s*${jsxFragment}\\s*[},]`).test(transformedCode));
|
|
151
|
+
|
|
152
|
+
if (
|
|
153
|
+
(transformedCode.includes("<") || transformedCode.includes("Fragment")) &&
|
|
154
|
+
!hasJSXAfterBabel
|
|
155
|
+
) {
|
|
156
|
+
const importPath = getJSXFactoryImportPath(options);
|
|
157
|
+
const importStatement = `import { ${jsxFactory}, ${jsxFragment} } from "${importPath}";\n`;
|
|
158
|
+
transformedCode = importStatement + transformedCode;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 3. Use esbuild for JSX transformation
|
|
162
|
+
try {
|
|
163
|
+
const result = await transform(transformedCode, {
|
|
164
|
+
loader: "jsx", // Already TypeScript-transformed by Babel
|
|
165
|
+
jsx: "transform",
|
|
166
|
+
jsxFactory: jsxFactory,
|
|
167
|
+
jsxFragment: jsxFragment,
|
|
168
|
+
target: "es2020",
|
|
169
|
+
format: "esm",
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
code: result.code,
|
|
174
|
+
map: null,
|
|
175
|
+
};
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error(`[WSX Plugin Babel] Transform error for ${id}:`, error);
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
package/src/vite-plugin-wsx.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
/**
|
|
3
|
-
* Vite Plugin for WSX (Web Component JSX)
|
|
4
|
-
*
|
|
5
|
-
* 专门处理.wsx文件:
|
|
6
|
-
* - 自动添加JSX pragma
|
|
7
|
-
* - 支持TypeScript编译
|
|
8
|
-
* - 完全隔离,不影响主项目React配置
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type { Plugin } from "vite";
|
|
12
|
-
import { transform } from "esbuild";
|
|
13
|
-
|
|
14
|
-
export interface WSXPluginOptions {
|
|
15
|
-
/**
|
|
16
|
-
* JSX工厂函数名
|
|
17
|
-
* @default 'h'
|
|
18
|
-
*/
|
|
19
|
-
jsxFactory?: string;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* JSX Fragment函数名
|
|
23
|
-
* @default 'Fragment'
|
|
24
|
-
*/
|
|
25
|
-
jsxFragment?: string;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* 是否启用调试日志
|
|
29
|
-
* @default false
|
|
30
|
-
*/
|
|
31
|
-
debug?: boolean;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 文件扩展名
|
|
35
|
-
* @default ['.wsx']
|
|
36
|
-
*/
|
|
37
|
-
extensions?: string[];
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 获取 JSX 工厂函数的导入路径
|
|
42
|
-
*/
|
|
43
|
-
function getJSXFactoryImportPath(_options: WSXPluginOptions): string {
|
|
44
|
-
// 使用 @wsxjs/wsx-core 包中的 JSX 工厂
|
|
45
|
-
return "@wsxjs/wsx-core";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* WSX Vite插件
|
|
50
|
-
*/
|
|
51
|
-
export function vitePluginWSX(options: WSXPluginOptions = {}): Plugin {
|
|
52
|
-
const {
|
|
53
|
-
jsxFactory = "h",
|
|
54
|
-
jsxFragment = "Fragment",
|
|
55
|
-
debug = false,
|
|
56
|
-
extensions = [".wsx"],
|
|
57
|
-
} = options;
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
name: "vite-plugin-wsx",
|
|
61
|
-
enforce: "pre", // 确保在 React 插件之前执行
|
|
62
|
-
|
|
63
|
-
// 处理 .wsx 文件加载
|
|
64
|
-
load(id: string) {
|
|
65
|
-
const isWSXFile = extensions.some((ext) => id.endsWith(ext));
|
|
66
|
-
|
|
67
|
-
if (!isWSXFile) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (debug) {
|
|
72
|
-
console.log(`[WSX Plugin] Loading: ${id}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 返回 null 让 Vite 继续处理文件
|
|
76
|
-
return null;
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
// 在transform阶段处理文件
|
|
80
|
-
async transform(code: string, id: string) {
|
|
81
|
-
// 检查是否是WSX文件
|
|
82
|
-
const isWSXFile = extensions.some((ext) => id.endsWith(ext));
|
|
83
|
-
|
|
84
|
-
if (!isWSXFile) {
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (debug) {
|
|
89
|
-
console.log(`[WSX Plugin] Processing: ${id}`);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let transformedCode = code;
|
|
93
|
-
|
|
94
|
-
// 1. 检查是否已经有JSX工厂导入
|
|
95
|
-
const hasWSXCoreImport = code.includes('from "@wsxjs/wsx-core"');
|
|
96
|
-
// 更精确的检测:使用正则表达式检查 JSX 工厂函数是否在导入中
|
|
97
|
-
const hasJSXInImport =
|
|
98
|
-
hasWSXCoreImport &&
|
|
99
|
-
(new RegExp(`[{,]\\s*${jsxFactory}\\s*[},]`).test(code) ||
|
|
100
|
-
new RegExp(`[{,]\\s*${jsxFragment}\\s*[},]`).test(code));
|
|
101
|
-
|
|
102
|
-
// 调试信息
|
|
103
|
-
if (debug) {
|
|
104
|
-
console.log(`[WSX Plugin] Checking JSX imports for: ${id}`);
|
|
105
|
-
console.log(` - hasWSXCoreImport: ${hasWSXCoreImport}`);
|
|
106
|
-
console.log(` - hasJSXInImport: ${hasJSXInImport}`);
|
|
107
|
-
console.log(` - has < character: ${code.includes("<")}`);
|
|
108
|
-
console.log(` - has Fragment: ${code.includes("Fragment")}`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 如果有JSX语法但没有JSX工厂导入,则需要注入
|
|
112
|
-
if ((code.includes("<") || code.includes("Fragment")) && !hasJSXInImport) {
|
|
113
|
-
// 使用标准的包导入
|
|
114
|
-
const importPath = getJSXFactoryImportPath(options);
|
|
115
|
-
const importStatement = `import { ${jsxFactory}, ${jsxFragment} } from "${importPath}";\n`;
|
|
116
|
-
transformedCode = importStatement + transformedCode;
|
|
117
|
-
|
|
118
|
-
if (debug) {
|
|
119
|
-
console.log(`[WSX Plugin] Added JSX factory import to: ${id}`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// 2. 添加JSX pragma - 不添加,让esbuild使用jsxFactory config
|
|
124
|
-
// JSX transformation will be handled by esbuild with our custom config
|
|
125
|
-
|
|
126
|
-
// 3. 使用 esbuild 进行 JSX 转换
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
const result = await transform(transformedCode, {
|
|
130
|
-
loader: "tsx",
|
|
131
|
-
jsx: "transform",
|
|
132
|
-
jsxFactory: jsxFactory,
|
|
133
|
-
jsxFragment: jsxFragment,
|
|
134
|
-
target: "es2020",
|
|
135
|
-
format: "esm",
|
|
136
|
-
// Esbuild supports decorators natively with tsx loader
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
if (debug) {
|
|
140
|
-
console.log(`[WSX Plugin] JSX transformed: ${id}`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
code: result.code,
|
|
145
|
-
map: null,
|
|
146
|
-
};
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error(`[WSX Plugin] Transform error for ${id}:`, error);
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
// We handle JSX transformation directly in the transform hook
|
|
154
|
-
// No need to modify global esbuild config
|
|
155
|
-
|
|
156
|
-
// 构建开始时的日志
|
|
157
|
-
buildStart() {
|
|
158
|
-
if (debug) {
|
|
159
|
-
console.log(`[WSX Plugin] Build started with extensions: ${extensions.join(", ")}`);
|
|
160
|
-
console.log(`[WSX Plugin] JSX Factory: ${jsxFactory}, Fragment: ${jsxFragment}`);
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export default vitePluginWSX;
|