@blocklet/pages-kit-block-studio 0.6.0 โ†’ 0.6.2

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.
@@ -1,194 +1,274 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.vitePluginCodeSplitter = vitePluginCodeSplitter;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
40
+ /**
41
+ * Vite Plugin: Component Code Splitter
42
+ *
43
+ * ๐Ÿš€ WORKFLOW OVERVIEW:
44
+ *
45
+ * โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
46
+ * โ”‚ PLUGIN 1: CODE SPLITTER โ”‚
47
+ * โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
48
+ *
49
+ * ๐Ÿ“‹ Phase 1: Config Stage
50
+ * โ”œโ”€โ”€ Analyze entry files to find all exports
51
+ * โ”œโ”€โ”€ Detect: default, EditComponent, PropertiesSchema, GetServerSideProps
52
+ * โ””โ”€โ”€ Create separate entry points for each export:
53
+ * โ€ข Component โ†’ Component?exportName=default&target=browser
54
+ * โ€ข EditComponent โ†’ Component_EditComponent?exportName=EditComponent&target=browser
55
+ * โ€ข GetServerSideProps โ†’ Component_GetServerSideProps?exportName=GetServerSideProps&target=node
56
+ *
57
+ * ๐Ÿ”„ Phase 2: Resolve & Load Stage
58
+ * โ”œโ”€โ”€ resolveId: Identify virtual modules with ?exportName= params
59
+ * โ””โ”€โ”€ load: Transform code and split exports
60
+ * โ”œโ”€โ”€ Use esbuild for fast transformation
61
+ * โ”œโ”€โ”€ Apply tree-shaking to remove unused code
62
+ * โ””โ”€โ”€ Filter to keep only specified exports
63
+ *
64
+ * โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
65
+ * โ”‚ PLUGIN 2: POST-BUILD PROCESSING โ”‚
66
+ * โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
67
+ *
68
+ * ๐Ÿ”ง Phase 3: Post-Build Optimization
69
+ * โ”œโ”€โ”€ Scan generated files and classify by target:
70
+ * โ”‚ โ”œโ”€โ”€ Node.js Target: GetServerSideProps functions
71
+ * โ”‚ โ””โ”€โ”€ Browser Target: Components, EditComponents, Schemas
72
+ * โ”œโ”€โ”€ Node.js files: Re-bundle with esbuild (platform: node, format: cjs)
73
+ * โ”œโ”€โ”€ Browser files: Transpile with TypeScript + builtin module transformer
74
+ * โ””โ”€โ”€ Generate dependency mapping (chunks-map.json)
75
+ *
76
+ * ๐Ÿ’ก WHY THIS DESIGN:
77
+ * โ€ข Reduces bundle size by splitting unused exports
78
+ * โ€ข Optimizes for different runtime environments (browser vs node)
79
+ * โ€ข Enables selective loading in Component Studio
80
+ * โ€ข Maintains clean separation between edit-time and runtime code
81
+ */
82
+ const builtin_1 = require("@blocklet/pages-kit/utils/builtin");
83
+ const builtin_module_transformer_1 = require("@blocklet/pages-kit/utils/typescript/builtin-module-transformer");
84
+ // @ts-ignore
85
+ const chunks_analyzer_transformer_1 = require("@blocklet/pages-kit/utils/typescript/chunks-analyzer-transformer");
86
+ const esbuild = __importStar(require("esbuild"));
87
+ const fs_1 = __importStar(require("fs"));
88
+ const p_limit_1 = __importDefault(require("p-limit"));
89
+ const path_1 = __importStar(require("path"));
9
90
  const typescript_1 = __importDefault(require("typescript"));
10
91
  const constants_1 = require("../constants");
11
92
  const helper_1 = require("../utils/helper");
93
+ const minify = true;
12
94
  /**
13
- * ๅˆ†ๆž็ป„ไปถๆ–‡ไปถ็ป“ๆž„
14
- * @param sourceFile TypeScriptๆบๆ–‡ไปถ
95
+ * ๅฏผๅ‡บ้…็ฝฎ
15
96
  */
16
- function analyzeComponent(sourceFile) {
17
- const result = {};
18
- // ่ฎฟ้—ฎAST่Š‚็‚น
97
+ const EXPORT_CONFIGS = [
98
+ {
99
+ exportName: 'default',
100
+ getBlockName: (key) => `${key}`,
101
+ description: 'Default',
102
+ supportSeparateFile: false,
103
+ target: 'browser',
104
+ external: [],
105
+ },
106
+ // {
107
+ // exportName: 'default',
108
+ // getBlockName: (key) => `${key}(default)`,
109
+ // description: 'Default CJS',
110
+ // supportSeparateFile: false,
111
+ // target: 'node',
112
+ // external: [],
113
+ // },
114
+ {
115
+ exportName: helper_1.EDIT_COMPONENT_NAME,
116
+ getBlockName: helper_1.getEditComponentBlockName,
117
+ description: 'EditComponent',
118
+ supportSeparateFile: true, // ๆ”ฏๆŒ็‹ฌ็ซ‹็š„ @edit-component ๆ–‡ไปถ
119
+ target: 'browser', // ๅ‰็ซฏ็ป„ไปถ
120
+ external: [],
121
+ },
122
+ {
123
+ exportName: helper_1.PROPERTIES_SCHEMA_NAME,
124
+ getBlockName: helper_1.getPropertiesSchemaBlockName,
125
+ description: 'PropertiesSchema',
126
+ supportSeparateFile: false,
127
+ target: 'browser', // ๅ‰็ซฏ schema
128
+ external: [],
129
+ },
130
+ {
131
+ exportName: helper_1.AIGNE_OUTPUT_VALUE_SCHEMA_NAME,
132
+ getBlockName: helper_1.getAigneOutputValueSchemaBlockName,
133
+ description: 'AigneOutputValueSchema',
134
+ supportSeparateFile: false,
135
+ target: 'browser', // ๅ‰็ซฏ schema
136
+ external: [],
137
+ },
138
+ {
139
+ exportName: helper_1.GET_SERVER_SIDE_PROPS_NAME,
140
+ getBlockName: helper_1.getGetServerSidePropsBlockName,
141
+ description: 'GetServerSideProps',
142
+ supportSeparateFile: false,
143
+ target: 'node', // ๆœๅŠก็ซฏๅ‡ฝๆ•ฐ
144
+ format: 'esm', // esm ๆ ผๅผ
145
+ // ๆŽ’้™ค็š„ไพ่ต–, ้œ€่ฆ่ทŸๅŽ็ซฏไฟๆŒไธ€่‡ด
146
+ external: [...Object.keys(builtin_1.BuiltinModules)],
147
+ },
148
+ ];
149
+ /**
150
+ * ๅˆ†ๆž็ป„ไปถๆ–‡ไปถไธญ็š„ๆ‰€ๆœ‰ๅฏผๅ‡บ
151
+ */
152
+ function analyzeAllExports(sourceFile) {
153
+ const result = {
154
+ namedExports: new Map(),
155
+ exportDeclarations: [],
156
+ };
19
157
  function visit(node) {
20
- // ๆ‰พๅˆฐ้ป˜่ฎคๅฏผๅ‡บ
21
- if (typescript_1.default.isExportAssignment(node)) {
22
- result.defaultExport = {
23
- pos: node.pos,
24
- end: node.end,
25
- };
158
+ // ้ป˜่ฎคๅฏผๅ‡บ - export default xxx
159
+ if (typescript_1.default.isExportAssignment(node) && !node.isExportEquals) {
160
+ result.defaultExport = { pos: node.pos, end: node.end };
26
161
  }
27
- // ๆฃ€ๆŸฅๅ‡ฝๆ•ฐๅฃฐๆ˜Ž็š„้ป˜่ฎคๅฏผๅ‡บ
162
+ // ๅ‡ฝๆ•ฐๅฃฐๆ˜Ž็š„้ป˜่ฎคๅฏผๅ‡บ - export default function
28
163
  if (typescript_1.default.isFunctionDeclaration(node) && node.modifiers) {
29
164
  const isExport = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword);
30
165
  const isDefault = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.DefaultKeyword);
31
166
  if (isExport && isDefault) {
32
- result.defaultExport = {
33
- pos: node.pos,
34
- end: node.end,
35
- };
167
+ result.defaultExport = { pos: node.pos, end: node.end };
36
168
  }
37
- // ๆฃ€ๆŸฅๅฏผๅ‡บ็š„ EditComponent ๅ‡ฝๆ•ฐๅฃฐๆ˜Ž
38
- if (isExport && !isDefault && node.name && node.name.text === helper_1.EDIT_COMPONENT_NAME) {
39
- result.editComponent = {
40
- pos: node.pos,
41
- end: node.end,
42
- };
169
+ else if (isExport && !isDefault && node.name) {
170
+ // ๅ‘ฝๅๅฏผๅ‡บ็š„ๅ‡ฝๆ•ฐ - export function xxx
171
+ result.namedExports.set(node.name.text, { pos: node.pos, end: node.end });
43
172
  }
44
173
  }
45
- // ๆฃ€ๆŸฅ็ฑปๅฃฐๆ˜Ž็š„ๅฏผๅ‡บ
174
+ // ็ฑปๅฃฐๆ˜Ž็š„ๅฏผๅ‡บ
46
175
  if (typescript_1.default.isClassDeclaration(node) && node.modifiers) {
47
176
  const isExport = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword);
48
- // ๆฃ€ๆŸฅๅฏผๅ‡บ็š„ EditComponent ็ฑปๅฃฐๆ˜Ž
49
- if (isExport && node.name && node.name.text === helper_1.EDIT_COMPONENT_NAME) {
50
- result.editComponent = {
51
- pos: node.pos,
52
- end: node.end,
53
- };
177
+ if (isExport && node.name) {
178
+ result.namedExports.set(node.name.text, { pos: node.pos, end: node.end });
54
179
  }
55
180
  }
56
- // ๆ‰พๅˆฐๅ‘ฝๅๅฏผๅ‡บ - EditComponent
181
+ // ๅ˜้‡ๅฃฐๆ˜Ž็š„ๅฏผๅ‡บ - export const xxx
57
182
  if (typescript_1.default.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword)) {
58
183
  const { declarations } = node.declarationList;
59
184
  for (const decl of declarations) {
60
- if (typescript_1.default.isIdentifier(decl.name) && decl.name.text === helper_1.EDIT_COMPONENT_NAME) {
61
- result.editComponent = {
62
- pos: node.pos,
63
- end: node.end,
64
- };
65
- break;
185
+ if (typescript_1.default.isIdentifier(decl.name)) {
186
+ result.namedExports.set(decl.name.text, { pos: node.pos, end: node.end });
66
187
  }
67
188
  }
68
189
  }
69
- // ๆฃ€ๆŸฅๅฏผๅ‡บๅฃฐๆ˜Ž
70
- if (typescript_1.default.isExportDeclaration(node) && node.exportClause) {
71
- if (typescript_1.default.isNamedExports(node.exportClause)) {
72
- // ๆฃ€ๆŸฅๆ™ฎ้€šๅฏผๅ‡บ export { EditComponent }
73
- const hasEditComponent = node.exportClause.elements.some((element) => typescript_1.default.isExportSpecifier(element) && element.name.text === helper_1.EDIT_COMPONENT_NAME);
74
- // ๆฃ€ๆŸฅ้‡ๅ‘ฝๅๅฏผๅ‡บ export { SomeComponent as EditComponent }
75
- const hasRenamedEditComponent = node.exportClause.elements.some((element) => typescript_1.default.isExportSpecifier(element) && element.propertyName && element.name.text === helper_1.EDIT_COMPONENT_NAME);
76
- if (hasEditComponent || hasRenamedEditComponent) {
77
- result.editComponent = {
78
- pos: node.pos,
79
- end: node.end,
80
- };
81
- }
82
- }
83
- }
84
- // ๅค„็†ๅฏผๅ‡บ็š„็ฎญๅคดๅ‡ฝๆ•ฐ/ๅ‡ฝๆ•ฐ่กจ่พพๅผ
85
- if (typescript_1.default.isVariableStatement(node)) {
86
- const { declarations } = node.declarationList;
87
- for (const decl of declarations) {
88
- if (typescript_1.default.isIdentifier(decl.name) && decl.name.text === helper_1.EDIT_COMPONENT_NAME) {
89
- if (node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword)) {
90
- result.editComponent = {
91
- pos: node.pos,
92
- end: node.end,
93
- };
94
- break;
190
+ // ๅฏผๅ‡บๅฃฐๆ˜Ž - export { xxx, yyy }
191
+ if (typescript_1.default.isExportDeclaration(node)) {
192
+ result.exportDeclarations.push({ pos: node.pos, end: node.end });
193
+ if (node.exportClause && typescript_1.default.isNamedExports(node.exportClause)) {
194
+ // ่ฎฐๅฝ•่ฟ™ไธชๅฏผๅ‡บๅฃฐๆ˜ŽๅŒ…ๅซ็š„ๆ‰€ๆœ‰ๅฏผๅ‡บๅ
195
+ node.exportClause.elements.forEach((element) => {
196
+ if (typescript_1.default.isExportSpecifier(element)) {
197
+ const exportName = element.propertyName ? element.name.text : element.name.text;
198
+ result.namedExports.set(exportName, { pos: node.pos, end: node.end });
95
199
  }
96
- }
200
+ });
97
201
  }
98
202
  }
99
- // ้€’ๅฝ’ๅค„็†ๆ‰€ๆœ‰ๅญ่Š‚็‚น
100
203
  typescript_1.default.forEachChild(node, visit);
101
204
  }
102
- // ๅผ€ๅง‹้ๅކ
103
205
  visit(sourceFile);
104
206
  return result;
105
207
  }
106
208
  /**
107
- * ่ฝฌๆขไปฃ็ ๏ผŒไฝฟ็”จTypeScript็ผ–่ฏ‘ๅ™จAPI
209
+ * ่งฃๆž exportName ๅ‚ๆ•ฐ
108
210
  */
109
- function transformCode(code, renderType) {
110
- // ๅˆ›ๅปบๆบๆ–‡ไปถ
111
- const sourceFile = typescript_1.default.createSourceFile('temp.tsx', code, typescript_1.default.ScriptTarget.Latest, true);
112
- // ๅˆ†ๆžๆบไปฃ็ ็ป“ๆž„
113
- const analysis = analyzeComponent(sourceFile);
114
- if (renderType === 'view') {
115
- // ็งป้™ค EditComponent
116
- if (analysis.editComponent) {
117
- // ๆ นๆฎไฝ็ฝฎๆ›ฟๆขไธบ็ฉบๅ†…ๅฎน
118
- const beforeEdit = code.substring(0, analysis.editComponent.pos);
119
- const afterEdit = code.substring(analysis.editComponent.end);
120
- return beforeEdit + afterEdit;
121
- }
122
- }
123
- else if (renderType === 'setting') {
124
- // ็งป้™คๆˆ–ๆ›ฟๆข้ป˜่ฎคๅฏผๅ‡บ๏ผŒ็›ดๆŽฅๅฏผๅ‡บEditComponent
125
- if (analysis.defaultExport && analysis.editComponent) {
126
- // ็ผ–่พ‘ๆจกๅผ๏ผŒไฟๆŒๅ‘ฝๅๅฏผๅ‡บ๏ผŒไฝ†่ฎฉEditComponentๅŒๆ—ถไนŸไฝœไธบ้ป˜่ฎคๅฏผๅ‡บ
127
- const defaultExport = `
128
- // Export EditComponent as both named export and default
129
- export { ${helper_1.EDIT_COMPONENT_NAME} as default };
130
- `;
131
- const beforeDefault = code.substring(0, analysis.defaultExport.pos);
132
- const afterDefault = code.substring(analysis.defaultExport.end);
133
- // ๆ›ฟๆข้ป˜่ฎคๅฏผๅ‡บไธบEditComponent
134
- return beforeDefault + defaultExport + afterDefault;
135
- }
136
- }
137
- // ๅฆ‚ๆžœๆฒกๆœ‰่ฟ›่กŒไฟฎๆ”น๏ผŒ่ฟ”ๅ›žๅŽŸๅง‹ไปฃ็ 
138
- return code;
211
+ function parseExportNames(exportNameParam) {
212
+ return exportNameParam
213
+ .split(',')
214
+ .map((name) => name.trim())
215
+ .filter(Boolean);
139
216
  }
140
217
  /**
141
- * ่ฟ›ไธ€ๆญฅๅขžๅผบ็‰ˆๆœฌ๏ผš้€š่ฟ‡ๅฎŒๆ•ด็š„AST่ฝฌๆข
218
+ * ่ฝฌๆขไปฃ็ ๏ผŒๅชไฟ็•™ๆŒ‡ๅฎš็š„ๅฏผๅ‡บ
142
219
  */
143
- function transformCodeWithPrinter(code, renderType) {
220
+ function transformCodeWithExports(code, exportNames) {
144
221
  try {
145
- // ๅˆ›ๅปบๆบๆ–‡ไปถ
146
222
  const sourceFile = typescript_1.default.createSourceFile('temp.tsx', code, typescript_1.default.ScriptTarget.Latest, true);
147
- // ๅˆ›ๅปบ่ฝฌๆขๅ™จไธŠไธ‹ๆ–‡
223
+ // ๆ ‡ๅ‡†ๅŒ–ๅฏผๅ‡บๅ็งฐ๏ผˆdefault ๅค„็†๏ผ‰
224
+ const normalizedExportNames = new Set(exportNames.map((name) => (name === 'default' ? 'default' : name)));
148
225
  const transformerFactory = (context) => {
149
226
  return (sourceFile) => {
150
- // ่ฎฟ้—ฎๅนถ่ฝฌๆข่Š‚็‚น
151
227
  const visitor = (node) => {
152
- // viewๆจกๅผ๏ผš็งป้™คEditComponent็›ธๅ…ณไปฃ็ 
153
- if (renderType === 'view') {
154
- // ็งป้™ค export const EditComponent ๅฃฐๆ˜Ž
155
- if (typescript_1.default.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword)) {
156
- const { declarations } = node.declarationList;
157
- if (declarations.some((d) => typescript_1.default.isIdentifier(d.name) && d.name.text === helper_1.EDIT_COMPONENT_NAME)) {
158
- return typescript_1.default.factory.createEmptyStatement();
159
- }
228
+ // ๅค„็†้ป˜่ฎคๅฏผๅ‡บ
229
+ if (typescript_1.default.isExportAssignment(node) && !node.isExportEquals) {
230
+ return normalizedExportNames.has('default') ? node : typescript_1.default.factory.createEmptyStatement();
231
+ }
232
+ // ๅค„็†ๅ‡ฝๆ•ฐ/็ฑป็š„้ป˜่ฎคๅฏผๅ‡บ
233
+ if (typescript_1.default.isFunctionDeclaration(node) && node.modifiers) {
234
+ const isExport = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword);
235
+ const isDefault = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.DefaultKeyword);
236
+ if (isExport && isDefault) {
237
+ return normalizedExportNames.has('default') ? node : typescript_1.default.factory.createEmptyStatement();
160
238
  }
161
- // ็งป้™ค export { EditComponent } ๅฝขๅผ็š„ๅฏผๅ‡บ
162
- if (typescript_1.default.isExportDeclaration(node) && node.exportClause && typescript_1.default.isNamedExports(node.exportClause)) {
163
- const { elements } = node.exportClause;
164
- if (elements.some((e) => typescript_1.default.isExportSpecifier(e) && e.name.text === helper_1.EDIT_COMPONENT_NAME)) {
165
- // ๅฆ‚ๆžœๅชๆœ‰EditComponentไธ€ไธชๅฏผๅ‡บ๏ผŒๅฐฑๅฎŒๅ…จ็งป้™ค
166
- if (elements.length === 1) {
167
- return typescript_1.default.factory.createEmptyStatement();
168
- }
169
- // ๅฆๅˆ™ๅˆ›ๅปบๆ–ฐ็š„ๅฏผๅ‡บๅฃฐๆ˜Ž๏ผŒไฝ†ไธๅŒ…ๅซEditComponent
170
- const newElements = elements.filter((e) => !(typescript_1.default.isExportSpecifier(e) && e.name.text === helper_1.EDIT_COMPONENT_NAME));
171
- return typescript_1.default.factory.createExportDeclaration(node.modifiers, node.isTypeOnly, typescript_1.default.factory.createNamedExports(newElements), node.moduleSpecifier);
172
- }
239
+ if (isExport && !isDefault && node.name) {
240
+ return normalizedExportNames.has(node.name.text) ? node : typescript_1.default.factory.createEmptyStatement();
173
241
  }
174
242
  }
175
- // settingๆจกๅผ๏ผš็›ดๆŽฅๅฏผๅ‡บEditComponent
176
- if (renderType === 'setting') {
177
- // ๆ‰พๅˆฐ้ป˜่ฎคๅฏผๅ‡บ่Š‚็‚น่ฟ›่กŒๆ›ฟๆข
178
- if (typescript_1.default.isExportAssignment(node) && node.isExportEquals === false) {
179
- // ๆ›ฟๆข export default xxx ๅฝขๅผไธบ export { EditComponent as default }
180
- return typescript_1.default.factory.createExportDeclaration(undefined, false, typescript_1.default.factory.createNamedExports([
181
- typescript_1.default.factory.createExportSpecifier(false, typescript_1.default.factory.createIdentifier(helper_1.EDIT_COMPONENT_NAME), typescript_1.default.factory.createIdentifier('default')),
182
- ]));
243
+ // ๅค„็†็ฑปๅฃฐๆ˜Ž็š„ๅฏผๅ‡บ
244
+ if (typescript_1.default.isClassDeclaration(node) && node.modifiers) {
245
+ const isExport = node.modifiers.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword);
246
+ if (isExport && node.name) {
247
+ return normalizedExportNames.has(node.name.text) ? node : typescript_1.default.factory.createEmptyStatement();
248
+ }
249
+ }
250
+ // ๅค„็†ๅ˜้‡ๅฃฐๆ˜Ž็š„ๅฏผๅ‡บ
251
+ if (typescript_1.default.isVariableStatement(node) && node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword)) {
252
+ const { declarations } = node.declarationList;
253
+ const shouldKeep = declarations.some((decl) => typescript_1.default.isIdentifier(decl.name) && normalizedExportNames.has(decl.name.text));
254
+ return shouldKeep ? node : typescript_1.default.factory.createEmptyStatement();
255
+ }
256
+ // ๅค„็†ๅฏผๅ‡บๅฃฐๆ˜Ž - export { xxx, yyy }
257
+ if (typescript_1.default.isExportDeclaration(node) && node.exportClause && typescript_1.default.isNamedExports(node.exportClause)) {
258
+ const { elements } = node.exportClause;
259
+ const keptElements = elements.filter((element) => {
260
+ if (typescript_1.default.isExportSpecifier(element)) {
261
+ const exportName = element.propertyName ? element.name.text : element.name.text;
262
+ return normalizedExportNames.has(exportName);
263
+ }
264
+ return false;
265
+ });
266
+ if (keptElements.length === 0) {
267
+ return typescript_1.default.factory.createEmptyStatement();
183
268
  }
184
- // ๅค„็† export default function Xxx() {} ๅฝขๅผ
185
- if (typescript_1.default.isFunctionDeclaration(node) &&
186
- node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword) &&
187
- node.modifiers?.some((m) => m.kind === typescript_1.default.SyntaxKind.DefaultKeyword)) {
188
- // ๅˆ›ๅปบๆ–ฐ็š„้ป˜่ฎคๅฏผๅ‡บ๏ผŒๅฏผๅ‡บEditComponentไฝœไธบdefault
189
- return typescript_1.default.factory.createExportDeclaration(undefined, false, typescript_1.default.factory.createNamedExports([
190
- typescript_1.default.factory.createExportSpecifier(false, typescript_1.default.factory.createIdentifier(helper_1.EDIT_COMPONENT_NAME), typescript_1.default.factory.createIdentifier('default')),
191
- ]));
269
+ if (keptElements.length < elements.length) {
270
+ // ๅˆ›ๅปบๆ–ฐ็š„ๅฏผๅ‡บๅฃฐๆ˜Ž๏ผŒๅชๅŒ…ๅซ้œ€่ฆไฟ็•™็š„ๅฏผๅ‡บ
271
+ return typescript_1.default.factory.createExportDeclaration(node.modifiers, node.isTypeOnly, typescript_1.default.factory.createNamedExports(keptElements), node.moduleSpecifier);
192
272
  }
193
273
  }
194
274
  return typescript_1.default.visitEachChild(node, visitor, context);
@@ -201,10 +281,9 @@ function transformCodeWithPrinter(code, renderType) {
201
281
  const printer = typescript_1.default.createPrinter({ newLine: typescript_1.default.NewLineKind.LineFeed });
202
282
  if (result.transformed.length > 0) {
203
283
  const transformedSourceFile = result.transformed[0];
204
- // TypeScript ็ฑปๅž‹ไฟ่ฏ
205
284
  if (transformedSourceFile) {
206
285
  const transformedCode = printer.printFile(transformedSourceFile);
207
- result.dispose(); // ๆธ…็†่ต„ๆบ
286
+ result.dispose();
208
287
  return transformedCode;
209
288
  }
210
289
  }
@@ -212,40 +291,68 @@ function transformCodeWithPrinter(code, renderType) {
212
291
  return code;
213
292
  }
214
293
  catch (error) {
215
- helper_1.logger.error('Error transforming with printer:', error);
216
- // ๅฆ‚ๆžœ้ซ˜็บง่ฝฌๆขๅคฑ่ดฅ๏ผŒๅ›ž้€€ๅˆฐ็ฎ€ๅ•่ฝฌๆข
217
- return transformCode(code, renderType);
294
+ helper_1.logger.error('Error transforming with exports:', error);
295
+ return code;
296
+ }
297
+ }
298
+ /**
299
+ * ็ฎ€ๅ•็š„ไปฃ็ ่ฝฌๆข๏ผŒ้€š่ฟ‡ๅญ—็ฌฆไธฒๆ›ฟๆข๏ผˆfallback๏ผ‰
300
+ */
301
+ function transformCodeSimple(code, exportNames) {
302
+ const sourceFile = typescript_1.default.createSourceFile('temp.tsx', code, typescript_1.default.ScriptTarget.Latest, true);
303
+ const analysis = analyzeAllExports(sourceFile);
304
+ const normalizedExportNames = new Set(exportNames.map((name) => (name === 'default' ? 'default' : name)));
305
+ let result = code;
306
+ const toRemove = [];
307
+ // ๆ”ถ้›†้œ€่ฆ็งป้™ค็š„่Š‚็‚น
308
+ if (analysis.defaultExport && !normalizedExportNames.has('default')) {
309
+ toRemove.push(analysis.defaultExport);
310
+ }
311
+ analysis.namedExports.forEach((range, name) => {
312
+ if (!normalizedExportNames.has(name)) {
313
+ toRemove.push(range);
314
+ }
315
+ });
316
+ // ๆŒ‰ไฝ็ฝฎๅ€’ๅบๆŽ’ๅˆ—๏ผŒ้ฟๅ…ไฝ็ฝฎๅ็งป
317
+ toRemove.sort((a, b) => b.pos - a.pos);
318
+ // ็งป้™คไธ้œ€่ฆ็š„ๅฏผๅ‡บ
319
+ for (const range of toRemove) {
320
+ const before = result.substring(0, range.pos);
321
+ const after = result.substring(range.end);
322
+ result = before + after;
218
323
  }
324
+ return result;
219
325
  }
220
326
  /**
221
- * ๆฃ€ๆŸฅๆ–‡ไปถๆ˜ฏๅฆๅŒ…ๅซEditComponentๅฏผๅ‡บ
327
+ * ่Žทๅ–ๆ–‡ไปถไธญ็š„ๆ‰€ๆœ‰ๅฏผๅ‡บๅ็งฐ
222
328
  */
223
- function hasEditComponentExportInEntryFile(filePath) {
329
+ function getFileExports(filePath) {
224
330
  try {
225
331
  if (!fs_1.default.existsSync(filePath)) {
226
- return false;
332
+ return [];
227
333
  }
228
- // ่ฏปๅ–ๆ–‡ไปถๅ†…ๅฎน
229
334
  const content = fs_1.default.readFileSync(filePath, 'utf-8');
230
- // ๅˆ›ๅปบๆบๆ–‡ไปถ
231
335
  const sourceFile = typescript_1.default.createSourceFile(filePath, content, typescript_1.default.ScriptTarget.Latest, true);
232
- // ไฝฟ็”จๅทฒๆœ‰็š„analyzeComponentๅ‡ฝๆ•ฐๅˆ†ๆž
233
- const analysis = analyzeComponent(sourceFile);
234
- // ๅฆ‚ๆžœๅญ˜ๅœจEditComponentๅฏผๅ‡บ๏ผŒๅˆ™่ฟ”ๅ›žtrue
235
- return !!analysis.editComponent;
336
+ const analysis = analyzeAllExports(sourceFile);
337
+ const exports = [];
338
+ if (analysis.defaultExport) {
339
+ exports.push('default');
340
+ }
341
+ exports.push(...Array.from(analysis.namedExports.keys()));
342
+ return exports;
236
343
  }
237
344
  catch (error) {
238
- helper_1.logger.warn(`Error checking EditComponent in ${filePath}:`, error);
239
- return false;
345
+ helper_1.logger.warn(`Error analyzing exports in ${filePath}:`, error);
346
+ return [];
240
347
  }
241
348
  }
242
- // ๆฃ€ๆŸฅ็›ฎๅฝ•ไธญๆ˜ฏๅฆๅญ˜ๅœจ@edit-componentๆ–‡ไปถ
349
+ /**
350
+ * ๆฃ€ๆŸฅ็›ฎๅฝ•ไธญๆ˜ฏๅฆๅญ˜ๅœจ@edit-componentๆ–‡ไปถ
351
+ */
243
352
  function findEditComponentFileInDir(filePath) {
244
353
  const dirPath = path_1.default.dirname(filePath);
245
- // ่Žทๅ–็›ฎๅฝ•ไธญ็š„ๆ‰€ๆœ‰ๆ–‡ไปถ
246
354
  try {
247
355
  const files = fs_1.default.readdirSync(dirPath);
248
- // ๆฃ€ๆŸฅๆ˜ฏๅฆๆœ‰ๅŒน้…็š„ๆ–‡ไปถ
249
356
  const file = files.find((file) => constants_1.EDIT_COMPONENT_FILE_NAME_REGEX.test(file));
250
357
  if (file) {
251
358
  return path_1.default.join(dirPath, file);
@@ -258,105 +365,346 @@ function findEditComponentFileInDir(filePath) {
258
365
  }
259
366
  }
260
367
  /**
261
- * Vite ๆ’ไปถ๏ผš็ป„ไปถไปฃ็ ๆ‹†ๅˆ†ๅ™จ
262
- * ็”จไบŽ่‡ชๅŠจๅฐ†็ป„ไปถๆ–‡ไปถๆ‹†ๅˆ†ไธบ่ง†ๅ›พ็ป„ไปถๅ’Œ็ผ–่พ‘็ป„ไปถ
368
+ * ๐ŸŽฏ MAIN EXPORT: Vite Plugin Factory
369
+ * Creates two plugins that work together to split and optimize component code
263
370
  */
264
- function vitePluginCodeSplitter() {
265
- return {
266
- name: 'vite-plugin-code-splitter',
267
- config(config) {
268
- // ๅชๆœ‰ๅœจๆž„ๅปบๆจกๅผไธ”lib้…็ฝฎๅญ˜ๅœจๆ—ถๅค„็†
269
- if (config.build && config.build.lib && typeof config.build.lib === 'object') {
270
- const libConfig = config.build.lib;
271
- if (libConfig.entry && typeof libConfig.entry === 'object' && !Array.isArray(libConfig.entry)) {
272
- // ๅˆ›ๅปบๆ–ฐ็š„ๅ…ฅๅฃๅˆ—่กจ
273
- const newEntry = {};
274
- Object.entries(libConfig.entry).forEach(([key, filePath]) => {
275
- // ๅฏนไบŽๆ™ฎ้€šๆจกๅ—่ทฏๅพ„๏ผŒๆทปๅŠ URLๅ‚ๆ•ฐ
276
- if (typeof filePath === 'string') {
277
- let editComponentFilePath = null;
278
- // ๆฃ€ๆต‹ๆ–‡ไปถๆ˜ฏๅฆๅŒ…ๅซEditComponent
279
- let hasEditComponent = false;
280
- try {
281
- // ไฝฟ็”จTypeScriptๅˆ†ๆžๆ–‡ไปถ
282
- hasEditComponent = hasEditComponentExportInEntryFile(filePath);
283
- // ่ฎฐๅฝ•ๆฃ€ๆต‹ๅˆฐ็š„ๆ–‡ไปถ
284
- const fileName = path_1.default.basename(filePath);
285
- if (hasEditComponent) {
286
- helper_1.logger.info(`Found EditComponent in ${fileName}`);
287
- editComponentFilePath = filePath;
371
+ function vitePluginCodeSplitter(options) {
372
+ const formats = options?.formats || ['es', 'cjs'];
373
+ const transpileBuiltinModule = options?.transpileBuiltinModule ?? true;
374
+ const skipBundleNodeTarget = options?.skipBundleNodeTarget ?? false;
375
+ return [
376
+ // ๐Ÿ”ง PLUGIN 1: CODE SPLITTER & TRANSFORMER
377
+ {
378
+ name: 'vite-plugin-code-splitter',
379
+ /**
380
+ * ๐Ÿ“‹ PHASE 1: CONFIG STAGE
381
+ * Analyzes entry files and creates separate entry points for each export type
382
+ */
383
+ config(config) {
384
+ if (config.build && config.build.lib && typeof config.build.lib === 'object') {
385
+ const libConfig = config.build.lib;
386
+ if (libConfig.entry && typeof libConfig.entry === 'object' && !Array.isArray(libConfig.entry)) {
387
+ const newEntry = {};
388
+ Object.entries(libConfig.entry).forEach(([key, filePath]) => {
389
+ if (typeof filePath === 'string') {
390
+ try {
391
+ // ๅˆ†ๆžๆ–‡ไปถไธญ็š„ๆ‰€ๆœ‰ๅฏผๅ‡บ
392
+ const exports = getFileExports(filePath);
393
+ const fileName = path_1.default.basename(filePath);
394
+ helper_1.logger.info(`Found exports in ${fileName}: ${exports.join(', ')}`);
395
+ // ๅค„็†ๆ‰€ๆœ‰้…็ฝฎ็š„ๅฏผๅ‡บ็ฑปๅž‹
396
+ EXPORT_CONFIGS.forEach(({ exportName, getBlockName, description, supportSeparateFile, target }) => {
397
+ if (exports.includes(exportName)) {
398
+ newEntry[getBlockName(key)] = `${filePath}?exportName=${exportName}&target=${target}`;
399
+ helper_1.logger.debug(`Added ${description} entry for ${fileName} (target: ${target})`);
400
+ }
401
+ else if (supportSeparateFile && exportName === helper_1.EDIT_COMPONENT_NAME) {
402
+ // ๆฃ€ๆŸฅๆ˜ฏๅฆๆœ‰็‹ฌ็ซ‹็š„ @edit-component ๆ–‡ไปถ
403
+ const editComponentFile = findEditComponentFileInDir(filePath);
404
+ if (editComponentFile) {
405
+ const editExports = getFileExports(editComponentFile);
406
+ if (editExports.includes(helper_1.EDIT_COMPONENT_NAME)) {
407
+ newEntry[(0, helper_1.getEditComponentBlockName)(key)] =
408
+ `${editComponentFile}?exportName=${helper_1.EDIT_COMPONENT_NAME}&target=${target}`;
409
+ helper_1.logger.info(`Found separate @edit-component file for ${path_1.default.basename(editComponentFile)} (target: ${target})`);
410
+ }
411
+ }
412
+ }
413
+ });
288
414
  }
289
- else {
290
- helper_1.logger.debug(`No EditComponent found in ${fileName}`);
291
- editComponentFilePath = findEditComponentFileInDir(filePath);
292
- // ๆฃ€ๆŸฅๆ˜ฏๅฆๅญ˜ๅœจ็‹ฌ็ซ‹็š„@edit-componentๆ–‡ไปถ
293
- if (editComponentFilePath) {
294
- hasEditComponent = true;
295
- helper_1.logger.info(`Found separate @edit-component file for ${editComponentFilePath}`);
296
- }
415
+ catch (err) {
416
+ helper_1.logger.warn(`Failed to analyze exports in ${filePath}: ${err}`);
417
+ // fallback ๅˆฐๅŽŸๅง‹ๆ–‡ไปถ
418
+ newEntry[key] = filePath;
297
419
  }
298
420
  }
299
- catch (err) {
300
- helper_1.logger.warn(`Failed to check EditComponent in ${filePath}: ${err}`);
301
- }
302
- // ่ง†ๅ›พ็ป„ไปถๆ€ปๆ˜ฏไฟ็•™
303
- newEntry[key] = `${filePath}?renderType=view`;
304
- // ๅชไธบๅŒ…ๅซEditComponent็š„ๆ–‡ไปถๅˆ›ๅปบ็ผ–่พ‘ๅ…ฅๅฃ
305
- if (hasEditComponent) {
306
- newEntry[(0, helper_1.getEditComponentBlockName)(key)] = `${editComponentFilePath}?renderType=setting`;
307
- }
308
- }
309
- });
310
- // ๆ›ดๆ–ฐ้…็ฝฎ
311
- libConfig.entry = newEntry;
312
- helper_1.logger.info('Auto-split components enabled, entries updated');
421
+ });
422
+ libConfig.entry = newEntry;
423
+ helper_1.logger.info('Auto-split components enabled with export-based splitting');
424
+ }
313
425
  }
314
- }
315
- return config;
316
- },
317
- resolveId(id) {
318
- // ๅค„็†ๅธฆๆœ‰ renderType ๅ‚ๆ•ฐ็š„ๆจกๅ— ID
319
- if (id.includes('?renderType=')) {
320
- return id; // ๆ ‡่ฎฐไธบ้œ€่ฆๅค„็†็š„่™šๆ‹Ÿๆจกๅ—
321
- }
322
- return null;
323
- },
324
- load(id) {
325
- if (!id.includes('?renderType=')) {
326
- return null;
327
- }
328
- try {
329
- // ่งฃๆž id๏ผŒๆๅ–ๆ–‡ไปถ่ทฏๅพ„ๅ’ŒๆŸฅ่ฏขๅ‚ๆ•ฐ
330
- const [filePath, query] = id.split('?');
331
- const params = new URLSearchParams(query);
332
- const renderType = params.get('renderType');
333
- if (!filePath || !renderType || (renderType !== 'view' && renderType !== 'setting')) {
334
- return null;
426
+ return config;
427
+ },
428
+ /**
429
+ * ๐Ÿ” PHASE 2A: RESOLVE STAGE
430
+ * Identifies virtual modules with exportName parameters
431
+ */
432
+ resolveId(id) {
433
+ if (id.includes('?exportName=')) {
434
+ return id; // Mark as resolved to trigger load() for this virtual module
335
435
  }
336
- // ็กฎไฟๆ–‡ไปถๅญ˜ๅœจ
337
- if (!fs_1.default.existsSync(filePath)) {
338
- helper_1.logger.error(`File not found: ${filePath}`);
436
+ return null;
437
+ },
438
+ /**
439
+ * ๐Ÿ”„ PHASE 2B: LOAD & TRANSFORM STAGE
440
+ * Loads and transforms code, keeping only specified exports
441
+ */
442
+ async load(id) {
443
+ if (!id.includes('?exportName=')) {
339
444
  return null;
340
445
  }
341
- // ่ฏปๅ–ๆ–‡ไปถๅ†…ๅฎน
342
- const code = fs_1.default.readFileSync(filePath, 'utf-8');
343
- // ๆ นๆฎๆธฒๆŸ“็ฑปๅž‹่ฟ›่กŒไปฃ็ ่ฝฌๆข
344
- // logger.info(`Splitting code for ${renderType}: ${filePath}`);
345
446
  try {
346
- // ้ฆ–ๅ…ˆๅฐ่ฏ•ไฝฟ็”จ้ซ˜็บง่ฝฌๆข
347
- return transformCodeWithPrinter(code, renderType);
447
+ const [filePath, query] = id.split('?');
448
+ const params = new URLSearchParams(query);
449
+ const exportNameParam = params.get('exportName');
450
+ const target = params.get('target') || 'browser';
451
+ if (!filePath || !exportNameParam) {
452
+ return null;
453
+ }
454
+ if (!fs_1.default.existsSync(filePath)) {
455
+ helper_1.logger.error(`File not found: ${filePath}`);
456
+ return null;
457
+ }
458
+ const exportNames = parseExportNames(exportNameParam);
459
+ helper_1.logger.debug(`Processing exports [${exportNames.join(', ')}] with esbuild for: ${path_1.default.basename(filePath)} (target: ${target})`);
460
+ try {
461
+ // Use esbuild for transform + tree-shaking in one step
462
+ const result = await esbuild.transform(transformCodeWithExports(fs_1.default.readFileSync(filePath, 'utf-8'), exportNames), {
463
+ loader: path_1.default.extname(filePath).slice(1), // .tsx -> tsx
464
+ target: target === 'node' ? 'node18' : 'es2020',
465
+ platform: target === 'node' ? 'node' : 'browser',
466
+ format: 'esm',
467
+ jsx: 'automatic',
468
+ treeShaking: true,
469
+ minify,
470
+ sourcemap: false,
471
+ });
472
+ const transformedCode = result.code;
473
+ return transformedCode;
474
+ }
475
+ catch (esbuildError) {
476
+ helper_1.logger.warn(`esbuild transform failed, falling back to TypeScript transform: ${esbuildError}`);
477
+ // Fallback to original method
478
+ const code = fs_1.default.readFileSync(filePath, 'utf-8');
479
+ try {
480
+ return transformCodeWithExports(code, exportNames);
481
+ }
482
+ catch (transformError) {
483
+ helper_1.logger.warn(`TypeScript transform also failed, using simple transform: ${transformError}`);
484
+ return transformCodeSimple(code, exportNames);
485
+ }
486
+ }
348
487
  }
349
- catch (transformError) {
350
- helper_1.logger.warn(`Advanced transform failed, falling back to basic transform: ${transformError}`);
351
- // ๅฆ‚ๆžœๅคฑ่ดฅ๏ผŒๅ›ž้€€ๅˆฐๅŸบๆœฌ่ฝฌๆข
352
- return transformCode(code, renderType);
488
+ catch (error) {
489
+ helper_1.logger.error(`Error processing module ${id}:`, error);
353
490
  }
354
- }
355
- catch (error) {
356
- helper_1.logger.error(`Error processing module ${id}:`, error);
357
- }
358
- return null;
491
+ return null;
492
+ },
359
493
  },
360
- };
494
+ // ๐Ÿ› ๏ธ PLUGIN 2: POST-BUILD PROCESSOR
495
+ {
496
+ name: 'vite-plugin-code-splitter-post-build',
497
+ apply: 'build',
498
+ enforce: 'post',
499
+ /**
500
+ * ๐Ÿ”ง PHASE 3: POST-BUILD OPTIMIZATION
501
+ * Processes generated files based on their target environment
502
+ */
503
+ async writeBundle(options) {
504
+ if (!transpileBuiltinModule) {
505
+ helper_1.logger.info('Transpile builtin module is disabled, skipping post-build processing');
506
+ return;
507
+ }
508
+ // ็”จไบŽๅญ˜ๅ‚จๆฏไธชๆ ผๅผ็š„ chunks ๆ˜ ๅฐ„
509
+ const allChunksMap = {};
510
+ const getExportConfig = (fileName) => {
511
+ // Extract export type from filename pattern: Component(ExportType).js
512
+ const match = fileName.match(/\(([^)]+)\)\.js$/);
513
+ if (!match || !match[1]) {
514
+ return null; // Regular component file, defaults to browser
515
+ }
516
+ const exportName = match[1];
517
+ return EXPORT_CONFIGS.find((config) => config.exportName === exportName || config.exportName.toLowerCase().includes(exportName.toLowerCase()));
518
+ };
519
+ /**
520
+ * ๐ŸŽฏ FILE TYPE CLASSIFIER
521
+ * Determines if a generated file should be treated as Node.js target
522
+ * Examples: Timeline(getServerSideProps).js โ†’ Node.js target
523
+ * Timeline.js โ†’ Browser target
524
+ */
525
+ const isNodeTargetFile = (fileName) => {
526
+ // Look up target environment in EXPORT_CONFIGS
527
+ const config = getExportConfig(fileName);
528
+ return config?.target === 'node';
529
+ };
530
+ // ๆ”ถ้›†ๆ‰€ๆœ‰ Node.js ็›ฎๆ ‡ๆ–‡ไปถ๏ผŒๅ‡†ๅค‡้‡ๆ–ฐๆž„ๅปบ
531
+ const nodeTargetFiles = [];
532
+ // ๆ‰ซๆๆž„ๅปบ่พ“ๅ‡บ๏ผŒๆ‰พๅˆฐ Node.js ็›ฎๆ ‡ๆ–‡ไปถ
533
+ const scanForNodeFiles = (dir) => {
534
+ const files = (0, fs_1.readdirSync)(dir);
535
+ files.forEach((file) => {
536
+ const filePath = path_1.default.join(dir, file);
537
+ const stats = (0, fs_1.statSync)(filePath);
538
+ if (stats.isDirectory()) {
539
+ scanForNodeFiles(filePath); // ้€’ๅฝ’ๅค„็†ๅญ็›ฎๅฝ•
540
+ }
541
+ else if (file.endsWith('.js') && isNodeTargetFile(file)) {
542
+ helper_1.logger.debug(`Found Node.js target file: ${file}, external: ${getExportConfig(file)?.external?.length ?? 0}`);
543
+ nodeTargetFiles.push({
544
+ filePath,
545
+ external: getExportConfig(file)?.external || [],
546
+ format: getExportConfig(file)?.format,
547
+ });
548
+ }
549
+ });
550
+ };
551
+ formats.forEach((format) => {
552
+ const formatDir = path_1.default.resolve(options.dir || 'dist', `${format}`);
553
+ if ((0, fs_1.existsSync)(formatDir)) {
554
+ scanForNodeFiles(formatDir);
555
+ }
556
+ });
557
+ // ๅฆ‚ๆžœๆœ‰ Node.js ็›ฎๆ ‡ๆ–‡ไปถ๏ผŒไธบๅฎƒไปฌ้ขๅค–่งฆๅ‘ Vite build
558
+ if (nodeTargetFiles.length > 0) {
559
+ helper_1.logger.info(`Found ${nodeTargetFiles.length} Node.js target files, triggering clean Vite build...`);
560
+ await Promise.all(nodeTargetFiles.map(async ({ filePath, external, format }) => {
561
+ try {
562
+ const fileName = path_1.default.basename(filePath, '.js');
563
+ helper_1.logger.debug(`Rebuilding Node.js target file: ${fileName}`);
564
+ // ไฝฟ็”จ esbuild ่ฟ›่กŒๅ•ๆ–‡ไปถๆ‰“ๅŒ…
565
+ const result = await esbuild.build({
566
+ entryPoints: [filePath],
567
+ bundle: !skipBundleNodeTarget, // ๆ˜ฏๅฆๆ‰“ๅŒ…ๆ‰€ๆœ‰ไพ่ต–
568
+ platform: 'node', // Node.js ๅนณๅฐ
569
+ format: format ?? 'cjs', // CommonJS ๆ ผๅผ
570
+ target: 'node18', // Node.js ็›ฎๆ ‡็‰ˆๆœฌ
571
+ outfile: filePath, // ็›ดๆŽฅ่ฆ†็›–ๅŽŸๆ–‡ไปถ
572
+ allowOverwrite: true, // ๅ…่ฎธ่ฆ†็›–่พ“ๅ…ฅๆ–‡ไปถ
573
+ external: external ?? [], // ๆŽ’้™ค็š„ไพ่ต–
574
+ minify, // ๅฏๅ‡ๅฐ‘ 50-70% ๅคงๅฐ
575
+ treeShaking: true, // ๅŽป้™คๆœชไฝฟ็”จไปฃ็ 
576
+ sourcemap: false, // ไธ็”Ÿๆˆ sourcemap
577
+ write: true, // ็›ดๆŽฅๅ†™ๅ…ฅๆ–‡ไปถ
578
+ logLevel: 'error', // ๅชๆ˜พ็คบ้”™่ฏฏ
579
+ // ่งฃๆž JSX ๅ’Œ TypeScript
580
+ loader: {
581
+ '.tsx': 'tsx',
582
+ '.ts': 'ts',
583
+ '.jsx': 'jsx',
584
+ '.js': 'js',
585
+ },
586
+ });
587
+ if (result.errors.length === 0) {
588
+ helper_1.logger.info(`Successfully rebuilt ${fileName} as single CJS file using esbuild`);
589
+ }
590
+ else {
591
+ helper_1.logger.error(`esbuild errors for ${fileName}:`, result.errors);
592
+ }
593
+ }
594
+ catch (error) {
595
+ helper_1.logger.error(`Failed to rebuild Node.js target file ${filePath}:`, error);
596
+ }
597
+ }));
598
+ }
599
+ // ๅฏน็”Ÿๆˆ็š„ JavaScript ๆ–‡ไปถ่ฟ›่กŒ transpileModule ๅค„็†
600
+ const transpileBuiltinModuleFn = (dir, format) => {
601
+ const files = (0, fs_1.readdirSync)(dir);
602
+ files.forEach((file) => {
603
+ const filePath = path_1.default.join(dir, file);
604
+ const stats = (0, fs_1.statSync)(filePath);
605
+ if (stats.isDirectory()) {
606
+ transpileBuiltinModuleFn(filePath, format); // ้€’ๅฝ’ๅค„็†ๅญ็›ฎๅฝ•
607
+ }
608
+ else if (file.endsWith('.js')) {
609
+ try {
610
+ // ่ทณ่ฟ‡ node target ๆ–‡ไปถ็š„ transpile
611
+ if (isNodeTargetFile(file)) {
612
+ helper_1.logger.info(`Skipping transpile for Node.js target file: ${file}`);
613
+ return;
614
+ }
615
+ const script = (0, fs_1.readFileSync)(filePath, 'utf8');
616
+ // @ts-ignore
617
+ const chunks = (0, chunks_analyzer_transformer_1.analyzeFileChunks)(typescript_1.default, script);
618
+ // ensure chunksMap is with all chunks
619
+ allChunksMap[(0, path_1.basename)(filePath)] = new Set(chunks);
620
+ const moduleMap = {
621
+ es: typescript_1.default.ModuleKind.ESNext,
622
+ cjs: typescript_1.default.ModuleKind.CommonJS,
623
+ umd: typescript_1.default.ModuleKind.ESNext,
624
+ };
625
+ const code = typescript_1.default.transpileModule(script, {
626
+ compilerOptions: {
627
+ jsx: typescript_1.default.JsxEmit.React,
628
+ target: typescript_1.default.ScriptTarget.ES2016,
629
+ module: moduleMap[format],
630
+ },
631
+ transformers: {
632
+ // @ts-ignore
633
+ before: [(0, builtin_module_transformer_1.createBuiltinModuleTransformer)(typescript_1.default)],
634
+ },
635
+ }).outputText;
636
+ (0, fs_1.writeFileSync)(filePath, code);
637
+ helper_1.logger.info(`Transpiled browser target file: ${filePath}`);
638
+ }
639
+ catch (error) {
640
+ helper_1.logger.error(`Failed to transpile ${filePath}:`, error);
641
+ }
642
+ }
643
+ });
644
+ // ่ฟ”ๅ›žไธ€ไธช Promise ไปฅไพฟ await
645
+ return new Promise((resolve, reject) => {
646
+ try {
647
+ resolve();
648
+ }
649
+ catch (error) {
650
+ reject(error);
651
+ }
652
+ });
653
+ };
654
+ // ่Žทๅ–่พ“ๅ‡บ็›ฎๅฝ•
655
+ const outDir = options.dir || 'dist';
656
+ const limit = (0, p_limit_1.default)(20);
657
+ // ไฝฟ็”จ Promise.all ็ญ‰ๅพ…ๆ‰€ๆœ‰ๆ ผๅผๅค„็†ๅฎŒๆˆ
658
+ await Promise.all(formats.map(async (format) => {
659
+ const formatDir = path_1.default.resolve(outDir, `${format}`);
660
+ const chunkDir = path_1.default.resolve(formatDir, 'chunks');
661
+ // if not exists, create it
662
+ if (!(0, fs_1.existsSync)(chunkDir)) {
663
+ (0, fs_1.mkdirSync)(chunkDir, { recursive: true });
664
+ }
665
+ await limit(() => transpileBuiltinModuleFn(formatDir, format));
666
+ }));
667
+ // ็Žฐๅœจๅฏไปฅๅค„็†ๅฎŒๆ•ดไพ่ต–้“พ
668
+ helper_1.logger.info('All transpile tasks done, start to handle dependency chain...');
669
+ // ๅœจ่ฟ™้‡Œๅค„็† allChunksMap ็š„ๅฎŒๆ•ดไพ่ต–้“พ
670
+ Object.entries(allChunksMap).forEach(([entryFile, directDeps]) => {
671
+ // ๆ”ถ้›†ๆ‰€ๆœ‰้—ดๆŽฅไพ่ต–
672
+ const allDeps = [...directDeps];
673
+ // ้€’ๅฝ’ๅฏปๆ‰พ้—ดๆŽฅไพ่ต–
674
+ function findTransitiveDeps(chunks) {
675
+ chunks.forEach((chunk) => {
676
+ // ๅฆ‚ๆžœ่ฏฅchunkๆœฌ่บซไนŸๆ˜ฏไธชๅ…ฅๅฃ(ๆœ‰ไพ่ต–ๅˆ—่กจ)
677
+ if (chunk in allChunksMap) {
678
+ const subDeps = allChunksMap[chunk];
679
+ // ๆทปๅŠ ๆœชๅŒ…ๅซ็š„ไพ่ต–
680
+ if (subDeps) {
681
+ subDeps.forEach((dep) => {
682
+ if (!allDeps.includes(dep)) {
683
+ allDeps.push(dep);
684
+ // ้€’ๅฝ’ๅฏปๆ‰พ่ฟ™ไธชไพ่ต–็š„ไพ่ต–
685
+ findTransitiveDeps([dep]);
686
+ }
687
+ });
688
+ }
689
+ }
690
+ });
691
+ }
692
+ // ๅผ€ๅง‹้€’ๅฝ’ๆŸฅๆ‰พ
693
+ findTransitiveDeps([...directDeps]);
694
+ // ๆ›ดๆ–ฐไธบๅฎŒๆ•ดไพ่ต–ๅˆ—่กจ
695
+ allChunksMap[entryFile] = new Set(allDeps);
696
+ });
697
+ // ่ฝฌๆข Set ไธบๆ•ฐ็ป„ไปฅไพฟๆญฃ็กฎๅบๅˆ—ๅŒ–
698
+ const serializedMap = Object.entries(allChunksMap).reduce((result, [key, deps]) => {
699
+ result[key] = Array.from(deps);
700
+ return result;
701
+ }, {});
702
+ formats.forEach((format) => {
703
+ // ๅญ˜ไธ‹ๆฅ
704
+ (0, fs_1.writeFileSync)(path_1.default.join(outDir, `${format}/chunks-map.json`), JSON.stringify(serializedMap, null, 2));
705
+ });
706
+ },
707
+ },
708
+ ];
361
709
  }
362
710
  exports.default = vitePluginCodeSplitter;