@easy-editor/easypack 0.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,1078 @@
1
+ import mri from 'mri';
2
+ import pc from 'picocolors';
3
+ import { spawn } from 'node:child_process';
4
+ import { rollup } from 'rollup';
5
+ import { build } from 'esbuild';
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { pathToFileURL } from 'node:url';
9
+ import babel from '@rollup/plugin-babel';
10
+ import commonjs from '@rollup/plugin-commonjs';
11
+ import nodeResolve from '@rollup/plugin-node-resolve';
12
+ import json from '@rollup/plugin-json';
13
+ import alias from '@rollup/plugin-alias';
14
+ import cleanup from 'rollup-plugin-cleanup';
15
+ import postcss from 'rollup-plugin-postcss';
16
+ import terser from '@rollup/plugin-terser';
17
+ import { createServer } from 'vite';
18
+ import react from '@vitejs/plugin-react';
19
+ import { WebSocketServer, WebSocket } from 'ws';
20
+ import * as prompts from '@clack/prompts';
21
+
22
+ const materialPreset = {
23
+ entry: {
24
+ main: 'src/index.tsx',
25
+ meta: 'src/meta.ts',
26
+ component: 'src/component.tsx'
27
+ },
28
+ output: {
29
+ dir: 'dist',
30
+ umd: true,
31
+ minify: true
32
+ },
33
+ css: {
34
+ scopedName: '[name]__[local]___[hash:base64:5]',
35
+ mode: 'inject'
36
+ },
37
+ jsxRuntime: 'automatic',
38
+ dev: {
39
+ port: 5001,
40
+ materialApi: true
41
+ }
42
+ };
43
+
44
+ const setterPreset = {
45
+ entry: {
46
+ main: 'src/index.ts'
47
+ },
48
+ output: {
49
+ dir: 'dist',
50
+ umd: true,
51
+ minify: true
52
+ },
53
+ css: {
54
+ scopedName: '[name]-[local]-[hash:base64:5]',
55
+ mode: 'extract',
56
+ extractFilename: 'index.css'
57
+ },
58
+ jsxRuntime: 'classic',
59
+ alias: {
60
+ '@': './src'
61
+ },
62
+ dev: {
63
+ port: 5002,
64
+ materialApi: false
65
+ }
66
+ };
67
+
68
+ const libraryPreset = {
69
+ entry: {
70
+ main: 'src/index.ts'
71
+ },
72
+ output: {
73
+ dir: 'dist',
74
+ umd: true,
75
+ minify: true
76
+ },
77
+ css: {
78
+ scopedName: '[name]__[local]___[hash:base64:5]',
79
+ mode: 'inject'
80
+ },
81
+ jsxRuntime: 'automatic',
82
+ dev: {
83
+ port: 5000,
84
+ materialApi: false
85
+ }
86
+ };
87
+
88
+ function getPreset(preset) {
89
+ switch (preset) {
90
+ case 'material':
91
+ return materialPreset;
92
+ case 'setter':
93
+ return setterPreset;
94
+ case 'library':
95
+ return libraryPreset;
96
+ default:
97
+ throw new Error(`Unknown preset: ${preset}`);
98
+ }
99
+ }
100
+
101
+ const DEFAULT_EXTERNALS$1 = ['react', 'react-dom', 'react/jsx-runtime'];
102
+ const DEFAULT_GLOBALS$1 = {
103
+ react: 'React',
104
+ 'react-dom': 'ReactDOM',
105
+ 'react/jsx-runtime': 'jsxRuntime'
106
+ };
107
+ const DEFAULT_ENTRY = {
108
+ main: 'src/index.ts',
109
+ meta: 'src/meta.ts',
110
+ component: 'src/component.tsx'
111
+ };
112
+ const DEFAULT_OUTPUT = {
113
+ dir: 'dist',
114
+ esm: false,
115
+ cjs: false,
116
+ umd: true,
117
+ minify: true,
118
+ sourcemap: false,
119
+ types: false
120
+ };
121
+ const DEFAULT_CSS = {
122
+ scopedName: '[name]__[local]___[hash:base64:5]',
123
+ mode: 'inject',
124
+ extractFilename: 'index.css'
125
+ };
126
+ const DEFAULT_DEV = {
127
+ port: 5001,
128
+ materialApi: true
129
+ };
130
+ function deriveGlobalName(pkgName) {
131
+ const withoutScope = pkgName.replace(/^@[^/]+\//, '');
132
+ if (withoutScope.startsWith('materials-dashboard-')) {
133
+ const componentName = withoutScope.replace('materials-dashboard-', '');
134
+ return `EasyEditorMaterials${toPascalCase(componentName)}`;
135
+ }
136
+ return `EasyEditor${toPascalCase(withoutScope)}`;
137
+ }
138
+ function toPascalCase(str) {
139
+ return str.split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join('');
140
+ }
141
+ function deepMerge(target, source) {
142
+ const result = {
143
+ ...target
144
+ };
145
+ for (const key of Object.keys(source)) {
146
+ const sourceValue = source[key];
147
+ const targetValue = target[key];
148
+ if (sourceValue !== undefined && typeof sourceValue === 'object' && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === 'object' && targetValue !== null && !Array.isArray(targetValue)) {
149
+ result[key] = deepMerge(targetValue, sourceValue);
150
+ } else if (sourceValue !== undefined) {
151
+ result[key] = sourceValue;
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ function resolveConfig(userConfig, pkg) {
157
+ const presetConfig = getPreset(userConfig.preset);
158
+ const merged = deepMerge(presetConfig, userConfig);
159
+ const resolved = {
160
+ preset: userConfig.preset,
161
+ globalName: merged.globalName || deriveGlobalName(pkg.name),
162
+ entry: {
163
+ main: merged.entry?.main || DEFAULT_ENTRY.main,
164
+ meta: merged.entry?.meta || DEFAULT_ENTRY.meta,
165
+ component: merged.entry?.component || DEFAULT_ENTRY.component
166
+ },
167
+ output: {
168
+ dir: merged.output?.dir || DEFAULT_OUTPUT.dir,
169
+ esm: merged.output?.esm ?? DEFAULT_OUTPUT.esm,
170
+ cjs: merged.output?.cjs ?? DEFAULT_OUTPUT.cjs,
171
+ umd: merged.output?.umd ?? DEFAULT_OUTPUT.umd,
172
+ minify: merged.output?.minify ?? DEFAULT_OUTPUT.minify,
173
+ sourcemap: merged.output?.sourcemap ?? DEFAULT_OUTPUT.sourcemap,
174
+ types: merged.output?.types ?? DEFAULT_OUTPUT.types
175
+ },
176
+ external: {
177
+ externals: merged.external?.externals || DEFAULT_EXTERNALS$1,
178
+ globals: {
179
+ ...DEFAULT_GLOBALS$1,
180
+ ...merged.external?.globals
181
+ }
182
+ },
183
+ css: {
184
+ scopedName: merged.css?.scopedName || DEFAULT_CSS.scopedName,
185
+ mode: merged.css?.mode || DEFAULT_CSS.mode,
186
+ extractFilename: merged.css?.extractFilename || DEFAULT_CSS.extractFilename
187
+ },
188
+ jsxRuntime: merged.jsxRuntime || 'automatic',
189
+ alias: merged.alias || {},
190
+ dev: {
191
+ port: merged.dev?.port || DEFAULT_DEV.port,
192
+ materialApi: merged.dev?.materialApi ?? DEFAULT_DEV.materialApi
193
+ },
194
+ vitePlugins: merged.vitePlugins || [],
195
+ pkg
196
+ };
197
+ return resolved;
198
+ }
199
+
200
+ const CONFIG_FILES = ['easypack.config.ts', 'easypack.config.js', 'easypack.config.mjs'];
201
+ function readPackageJson(cwd) {
202
+ const pkgPath = path.join(cwd, 'package.json');
203
+ if (!fs.existsSync(pkgPath)) {
204
+ throw new Error(`package.json not found in ${cwd}`);
205
+ }
206
+ const content = fs.readFileSync(pkgPath, 'utf-8');
207
+ const pkg = JSON.parse(content);
208
+ return {
209
+ name: pkg.name || 'unknown',
210
+ version: pkg.version || '0.0.0'
211
+ };
212
+ }
213
+ async function loadConfigFile(configPath) {
214
+ const ext = path.extname(configPath);
215
+ if (ext === '.js' || ext === '.mjs') {
216
+ const module = await import(pathToFileURL(configPath).href);
217
+ return module.default;
218
+ }
219
+ const result = await build({
220
+ entryPoints: [configPath],
221
+ bundle: true,
222
+ format: 'esm',
223
+ platform: 'node',
224
+ write: false,
225
+ external: ['@easy-editor/easypack']
226
+ });
227
+ const code = result.outputFiles[0].text;
228
+ const tempFile = path.join(path.dirname(configPath), '.easypack.config.tmp.mjs');
229
+ fs.writeFileSync(tempFile, code);
230
+ try {
231
+ const module = await import(pathToFileURL(tempFile).href);
232
+ return module.default;
233
+ } finally {
234
+ try {
235
+ fs.unlinkSync(tempFile);
236
+ } catch {
237
+ }
238
+ }
239
+ }
240
+ function findConfigFile(cwd, customPath) {
241
+ if (customPath) {
242
+ const fullPath = path.isAbsolute(customPath) ? customPath : path.join(cwd, customPath);
243
+ if (fs.existsSync(fullPath)) {
244
+ return fullPath;
245
+ }
246
+ throw new Error(`Config file not found: ${customPath}`);
247
+ }
248
+ for (const file of CONFIG_FILES) {
249
+ const fullPath = path.join(cwd, file);
250
+ if (fs.existsSync(fullPath)) {
251
+ return fullPath;
252
+ }
253
+ }
254
+ return null;
255
+ }
256
+ async function loadConfig(customConfigPath, cwd = process.cwd()) {
257
+ const configPath = findConfigFile(cwd, customConfigPath);
258
+ if (!configPath) {
259
+ throw new Error(`No config file found. Run \`easypack init\` to create one.\nSupported config files: ${CONFIG_FILES.join(', ')}`);
260
+ }
261
+ const pkg = readPackageJson(cwd);
262
+ const userConfig = await loadConfigFile(configPath);
263
+ return resolveConfig(userConfig, pkg);
264
+ }
265
+ function defineConfig(config) {
266
+ return config;
267
+ }
268
+
269
+ const DEFAULT_EXTENSIONS = ['.js', '.ts', '.jsx', '.tsx'];
270
+
271
+ function createPlugins(options) {
272
+ const {
273
+ config,
274
+ minify = false,
275
+ cwd = process.cwd()
276
+ } = options;
277
+ const plugins = [];
278
+ if (Object.keys(config.alias).length > 0) {
279
+ const entries = Object.entries(config.alias).map(([find, replacement]) => ({
280
+ find,
281
+ replacement: path.resolve(cwd, replacement)
282
+ }));
283
+ plugins.push(alias({
284
+ entries
285
+ }));
286
+ }
287
+ plugins.push(nodeResolve({
288
+ extensions: DEFAULT_EXTENSIONS
289
+ }));
290
+ plugins.push(commonjs());
291
+ plugins.push(json());
292
+ plugins.push(postcss({
293
+ modules: {
294
+ generateScopedName: config.css.scopedName
295
+ },
296
+ autoModules: true,
297
+ minimize: true,
298
+ inject: config.css.mode === 'inject',
299
+ extract: config.css.mode === 'extract' ? config.css.extractFilename : false
300
+ }));
301
+ plugins.push(babel({
302
+ extensions: DEFAULT_EXTENSIONS,
303
+ exclude: 'node_modules/**',
304
+ babelrc: false,
305
+ babelHelpers: 'bundled',
306
+ presets: [['@babel/preset-react', {
307
+ runtime: config.jsxRuntime
308
+ }], ['@babel/preset-typescript', {
309
+ allowDeclareFields: true
310
+ }]]
311
+ }));
312
+ plugins.push(cleanup({
313
+ comments: ['some', /PURE/],
314
+ extensions: ['.js', '.ts']
315
+ }));
316
+ if (minify) {
317
+ plugins.push(terser());
318
+ }
319
+ return plugins;
320
+ }
321
+
322
+ function createBanner(pkgName, version, suffix) {
323
+ const suffixPart = suffix ? ` (${suffix})` : '';
324
+ return `/* ${pkgName} v${version}${suffixPart} */`;
325
+ }
326
+ function getExternals(config) {
327
+ return config.external.externals;
328
+ }
329
+ function getGlobals(config) {
330
+ return config.external.globals;
331
+ }
332
+ function getUmdName(globalName, type) {
333
+ switch (type) {
334
+ case 'meta':
335
+ return `${globalName}Meta`;
336
+ case 'component':
337
+ return `${globalName}Component`;
338
+ default:
339
+ return globalName;
340
+ }
341
+ }
342
+ function getFilePrefix(type) {
343
+ switch (type) {
344
+ case 'meta':
345
+ return 'meta';
346
+ case 'component':
347
+ return 'component';
348
+ default:
349
+ return 'index';
350
+ }
351
+ }
352
+ function createOutputConfigs(options) {
353
+ const {
354
+ config,
355
+ input,
356
+ type,
357
+ cwd = process.cwd()
358
+ } = options;
359
+ const configs = [];
360
+ const external = getExternals(config);
361
+ const globals = getGlobals(config);
362
+ const umdName = getUmdName(config.globalName, type);
363
+ const filePrefix = getFilePrefix(type);
364
+ const {
365
+ pkg,
366
+ output: outputConfig
367
+ } = config;
368
+ const {
369
+ minify
370
+ } = outputConfig;
371
+ const plugins = createPlugins({
372
+ config,
373
+ minify,
374
+ cwd
375
+ });
376
+ if (outputConfig.esm) {
377
+ const filename = minify ? `${filePrefix}.min.esm.js` : `${filePrefix}.esm.js`;
378
+ configs.push({
379
+ input,
380
+ output: {
381
+ file: `${outputConfig.dir}/${filename}`,
382
+ format: 'esm',
383
+ sourcemap: outputConfig.sourcemap,
384
+ banner: createBanner(pkg.name, pkg.version, minify ? 'minified' : undefined),
385
+ exports: 'named'
386
+ },
387
+ plugins,
388
+ external
389
+ });
390
+ }
391
+ if (outputConfig.umd) {
392
+ const filename = minify ? `${filePrefix}.min.js` : `${filePrefix}.js`;
393
+ configs.push({
394
+ input,
395
+ output: {
396
+ file: `${outputConfig.dir}/${filename}`,
397
+ format: 'umd',
398
+ name: umdName,
399
+ globals,
400
+ sourcemap: outputConfig.sourcemap,
401
+ banner: createBanner(pkg.name, pkg.version, minify ? 'minified' : undefined),
402
+ exports: 'named'
403
+ },
404
+ plugins,
405
+ external
406
+ });
407
+ }
408
+ if (type === 'full' && outputConfig.cjs) {
409
+ const filename = minify ? `${filePrefix}.min.cjs` : `${filePrefix}.cjs`;
410
+ configs.push({
411
+ input,
412
+ output: {
413
+ file: `${outputConfig.dir}/${filename}`,
414
+ format: 'cjs',
415
+ sourcemap: outputConfig.sourcemap,
416
+ exports: 'named'
417
+ },
418
+ plugins,
419
+ external
420
+ });
421
+ }
422
+ return configs;
423
+ }
424
+
425
+ function entryExists(entry, cwd) {
426
+ const fullPath = path.join(cwd, entry);
427
+ return fs.existsSync(fullPath);
428
+ }
429
+ function createRollupConfig(options) {
430
+ const {
431
+ config,
432
+ cwd = process.cwd()
433
+ } = options;
434
+ const configs = [];
435
+ if (config.preset === 'material') {
436
+ if (config.entry.meta && entryExists(config.entry.meta, cwd)) {
437
+ configs.push(...createOutputConfigs({
438
+ config,
439
+ input: config.entry.meta,
440
+ type: 'meta',
441
+ cwd
442
+ }));
443
+ }
444
+ if (config.entry.component && entryExists(config.entry.component, cwd)) {
445
+ configs.push(...createOutputConfigs({
446
+ config,
447
+ input: config.entry.component,
448
+ type: 'component',
449
+ cwd
450
+ }));
451
+ }
452
+ }
453
+ if (config.entry.main && entryExists(config.entry.main, cwd)) {
454
+ configs.push(...createOutputConfigs({
455
+ config,
456
+ input: config.entry.main,
457
+ type: 'full',
458
+ cwd
459
+ }));
460
+ } else {
461
+ throw new Error(`Main entry file not found: ${config.entry.main}`);
462
+ }
463
+ return configs;
464
+ }
465
+
466
+ async function generateTypes(config) {
467
+ return new Promise((resolve, reject) => {
468
+ const args = ['tsc', '--declaration', '--emitDeclarationOnly', '--outDir', config.output.dir];
469
+ const tsc = spawn('npx', args, {
470
+ stdio: 'pipe'
471
+ });
472
+ let stderr = '';
473
+ tsc.stderr?.on('data', data => {
474
+ stderr += data.toString();
475
+ });
476
+ tsc.on('close', code => {
477
+ if (code === 0) {
478
+ resolve([`${config.output.dir}/index.d.ts`]);
479
+ } else {
480
+ reject(new Error(`TypeScript compilation failed:\n${stderr}`));
481
+ }
482
+ });
483
+ tsc.on('error', reject);
484
+ });
485
+ }
486
+ async function buildCommand(argv) {
487
+ const startTime = Date.now();
488
+ console.log(pc.cyan('Building for production...\n'));
489
+ const config = await loadConfig(argv.config);
490
+ console.log(pc.gray(` Package: ${config.pkg.name}@${config.pkg.version}`));
491
+ console.log(pc.gray(` Preset: ${config.preset}`));
492
+ console.log(pc.gray(` Output: ${config.output.dir}/\n`));
493
+ const rollupConfigs = createRollupConfig({
494
+ config
495
+ });
496
+ let fileCount = 0;
497
+ for (const rollupConfig of rollupConfigs) {
498
+ const bundle = await rollup(rollupConfig);
499
+ const outputs = Array.isArray(rollupConfig.output) ? rollupConfig.output : [rollupConfig.output];
500
+ for (const output of outputs) {
501
+ if (output && output.file) {
502
+ await bundle.write(output);
503
+ console.log(pc.green(` ✓ ${output.file}`));
504
+ fileCount++;
505
+ }
506
+ }
507
+ await bundle.close();
508
+ }
509
+ if (config.output.types) {
510
+ try {
511
+ const typeFiles = await generateTypes(config);
512
+ for (const file of typeFiles) {
513
+ console.log(pc.green(` ✓ ${file}`));
514
+ fileCount++;
515
+ }
516
+ } catch (error) {
517
+ console.log(pc.yellow(` ⚠ Types generation skipped (no tsconfig.json or tsc error)`));
518
+ }
519
+ }
520
+ const duration = Date.now() - startTime;
521
+ console.log('');
522
+ console.log(pc.green(`Build completed! `) + pc.gray(`(${fileCount} files in ${duration}ms)`));
523
+ }
524
+
525
+ const DEFAULT_EXTERNALS = ['react', 'react-dom', 'react/jsx-runtime'];
526
+ const DEFAULT_GLOBALS = {
527
+ react: 'React',
528
+ 'react-dom': 'ReactDOM',
529
+ 'react/jsx-runtime': 'jsxRuntime'
530
+ };
531
+ const VIRTUAL_PREFIX = '\0virtual:external:';
532
+ function generateReactCode(globalName) {
533
+ return `
534
+ // External module: react -> window.${globalName}
535
+ const React = window.${globalName};
536
+ if (!React) {
537
+ throw new Error(
538
+ 'External dependency "react" (window.${globalName}) is not available. ' +
539
+ 'Make sure the parent application has loaded it globally.'
540
+ );
541
+ }
542
+
543
+ export default React;
544
+
545
+ export const {
546
+ useState, useEffect, useContext, useReducer, useCallback, useMemo,
547
+ useRef, useImperativeHandle, useLayoutEffect, useDebugValue,
548
+ useDeferredValue, useTransition, useId, useSyncExternalStore,
549
+ Fragment, StrictMode, Suspense, createElement, createContext,
550
+ forwardRef, lazy, memo, startTransition, Component, PureComponent,
551
+ Children, cloneElement, isValidElement,
552
+ } = React;
553
+ `;
554
+ }
555
+ function generateReactDomCode(globalName) {
556
+ return `
557
+ // External module: react-dom -> window.${globalName}
558
+ const ReactDOM = window.${globalName};
559
+ if (!ReactDOM) {
560
+ throw new Error(
561
+ 'External dependency "react-dom" (window.${globalName}) is not available. ' +
562
+ 'Make sure the parent application has loaded it globally.'
563
+ );
564
+ }
565
+
566
+ export default ReactDOM;
567
+
568
+ export const {
569
+ createRoot, hydrateRoot, render, hydrate,
570
+ unmountComponentAtNode, findDOMNode, flushSync,
571
+ } = ReactDOM;
572
+ `;
573
+ }
574
+ function generateJsxRuntimeCode(globalName) {
575
+ return `
576
+ // External module: react/jsx-runtime -> window.${globalName}
577
+ const jsxRuntime = window.${globalName};
578
+ if (!jsxRuntime) {
579
+ throw new Error(
580
+ 'External dependency "react/jsx-runtime" (window.${globalName}) is not available. ' +
581
+ 'Make sure the parent application has loaded it globally.'
582
+ );
583
+ }
584
+
585
+ export const { jsx, jsxs, Fragment } = jsxRuntime;
586
+ export default jsxRuntime;
587
+ `;
588
+ }
589
+ function generateEasyEditorCoreCode(globalName) {
590
+ return `
591
+ // External module: @easy-editor/core -> window.${globalName}
592
+ const EasyEditorCore = window.${globalName};
593
+ if (!EasyEditorCore) {
594
+ throw new Error(
595
+ 'External dependency "@easy-editor/core" (window.${globalName}) is not available. ' +
596
+ 'Make sure the parent application has loaded it globally.'
597
+ );
598
+ }
599
+
600
+ export default EasyEditorCore;
601
+
602
+ // 动态导出所有属性
603
+ const keys = Object.keys(EasyEditorCore || {});
604
+ keys.forEach(key => {
605
+ Object.defineProperty(module.exports, key, {
606
+ get: () => EasyEditorCore[key],
607
+ enumerable: true,
608
+ });
609
+ });
610
+ `;
611
+ }
612
+ function generateGenericCode(moduleName, globalName) {
613
+ return `
614
+ // External module: ${moduleName} -> window.${globalName}
615
+ const mod = window.${globalName};
616
+ if (!mod) {
617
+ throw new Error(
618
+ 'External dependency "${moduleName}" (window.${globalName}) is not available. ' +
619
+ 'Make sure the parent application has loaded it globally.'
620
+ );
621
+ }
622
+ export default mod;
623
+ `;
624
+ }
625
+ function externalDepsPlugin(options = {}) {
626
+ const externals = options.externals || DEFAULT_EXTERNALS;
627
+ const globals = {
628
+ ...DEFAULT_GLOBALS,
629
+ ...options.globals
630
+ };
631
+ return {
632
+ name: 'vite-plugin-external-deps',
633
+ enforce: 'pre',
634
+ resolveId(id) {
635
+ if (externals.includes(id)) {
636
+ return VIRTUAL_PREFIX + id;
637
+ }
638
+ return null;
639
+ },
640
+ load(id) {
641
+ if (!id.startsWith(VIRTUAL_PREFIX)) {
642
+ return null;
643
+ }
644
+ const moduleName = id.slice(VIRTUAL_PREFIX.length);
645
+ const globalName = globals[moduleName];
646
+ if (!globalName) {
647
+ throw new Error(`[vite-plugin-external-deps] No global mapping found for "${moduleName}". ` + 'Please add it to the globals option.');
648
+ }
649
+ switch (moduleName) {
650
+ case 'react':
651
+ return generateReactCode(globalName);
652
+ case 'react-dom':
653
+ return generateReactDomCode(globalName);
654
+ case 'react/jsx-runtime':
655
+ return generateJsxRuntimeCode(globalName);
656
+ case '@easy-editor/core':
657
+ return generateEasyEditorCoreCode(globalName);
658
+ default:
659
+ return generateGenericCode(moduleName, globalName);
660
+ }
661
+ },
662
+ config() {
663
+ return {
664
+ build: {
665
+ rollupOptions: {
666
+ external: externals,
667
+ output: {
668
+ globals
669
+ }
670
+ }
671
+ }
672
+ };
673
+ }
674
+ };
675
+ }
676
+
677
+ function materialDevPlugin(options = {}) {
678
+ const {
679
+ entry = '/src/index.tsx'
680
+ } = options;
681
+ let server;
682
+ let wss = null;
683
+ const clients = new Set();
684
+ function broadcast(message) {
685
+ const data = JSON.stringify(message);
686
+ for (const client of clients) {
687
+ if (client.readyState === WebSocket.OPEN) {
688
+ client.send(data);
689
+ }
690
+ }
691
+ }
692
+ return {
693
+ name: 'vite-plugin-material-dev',
694
+ configureServer(_server) {
695
+ server = _server;
696
+ wss = new WebSocketServer({
697
+ noServer: true
698
+ });
699
+ server.httpServer?.on('upgrade', (request, socket, head) => {
700
+ if (request.url === '/ws' || request.url === '/__material_ws__') {
701
+ wss?.handleUpgrade(request, socket, head, ws => {
702
+ wss?.emit('connection', ws, request);
703
+ });
704
+ }
705
+ });
706
+ wss.on('connection', ws => {
707
+ clients.add(ws);
708
+ ws.send(JSON.stringify({
709
+ type: 'connected',
710
+ message: 'Material dev server connected',
711
+ timestamp: Date.now()
712
+ }));
713
+ ws.on('close', () => {
714
+ clients.delete(ws);
715
+ });
716
+ ws.on('error', () => {
717
+ clients.delete(ws);
718
+ });
719
+ });
720
+ server.middlewares.use((req, res, next) => {
721
+ if (req.method === 'OPTIONS') {
722
+ res.setHeader('Access-Control-Allow-Origin', '*');
723
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
724
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
725
+ res.statusCode = 204;
726
+ res.end();
727
+ return;
728
+ }
729
+ next();
730
+ });
731
+ server.middlewares.use('/api/health', (_req, res) => {
732
+ res.setHeader('Content-Type', 'application/json');
733
+ res.setHeader('Access-Control-Allow-Origin', '*');
734
+ res.end(JSON.stringify({
735
+ status: 'ok',
736
+ timestamp: Date.now(),
737
+ server: 'vite',
738
+ wsPath: '/ws'
739
+ }));
740
+ });
741
+ server.middlewares.use('/api/material', async (_req, res) => {
742
+ res.setHeader('Content-Type', 'application/json');
743
+ res.setHeader('Access-Control-Allow-Origin', '*');
744
+ try {
745
+ const module = await server.ssrLoadModule(entry);
746
+ const meta = module.meta || module.default?.meta;
747
+ const component = module.component || module.default;
748
+ if (!meta) {
749
+ res.statusCode = 400;
750
+ res.end(JSON.stringify({
751
+ error: 'Material meta not found. Make sure to export "meta" from the entry file.'
752
+ }));
753
+ return;
754
+ }
755
+ const materialInfo = {
756
+ name: meta.componentName,
757
+ title: meta.title,
758
+ version: meta.npm?.version || '0.0.0-dev',
759
+ group: meta.group,
760
+ category: meta.category,
761
+ entry,
762
+ hasComponent: !!component,
763
+ hasMeta: !!meta,
764
+ hasConfigure: !!meta.configure,
765
+ hasSnippets: Array.isArray(meta.snippets) && meta.snippets.length > 0,
766
+ wsPath: '/ws'
767
+ };
768
+ res.end(JSON.stringify(materialInfo));
769
+ } catch (error) {
770
+ res.statusCode = 500;
771
+ res.end(JSON.stringify({
772
+ error: error instanceof Error ? error.message : String(error)
773
+ }));
774
+ }
775
+ });
776
+ server.httpServer?.once('listening', () => {
777
+ const address = server.httpServer?.address();
778
+ const port = typeof address === 'object' && address ? address.port : 5001;
779
+ const host = server.config.server.host || 'localhost';
780
+ setTimeout(() => {
781
+ console.log('');
782
+ console.log('\x1b[36m%s\x1b[0m', ' Material Dev Server Ready');
783
+ console.log('');
784
+ console.log(` Health Check: http://${host}:${port}/api/health`);
785
+ console.log(` Material Info: http://${host}:${port}/api/material`);
786
+ console.log(` Module Entry: http://${host}:${port}${entry}`);
787
+ console.log(` WebSocket: ws://${host}:${port}/ws`);
788
+ console.log('');
789
+ console.log('\x1b[33m%s\x1b[0m', ' Connect this URL in EasyEditor to start debugging');
790
+ console.log('');
791
+ }, 100);
792
+ });
793
+ },
794
+ handleHotUpdate({
795
+ file,
796
+ modules
797
+ }) {
798
+ broadcast({
799
+ type: 'update',
800
+ file,
801
+ timestamp: Date.now(),
802
+ modules: modules.map(m => m.id)
803
+ });
804
+ return;
805
+ },
806
+ closeBundle() {
807
+ if (wss) {
808
+ for (const client of clients) {
809
+ client.close();
810
+ }
811
+ clients.clear();
812
+ wss.close();
813
+ wss = null;
814
+ }
815
+ }
816
+ };
817
+ }
818
+
819
+ function createViteConfig(options) {
820
+ const {
821
+ config,
822
+ cwd = process.cwd()
823
+ } = options;
824
+ const {
825
+ externals,
826
+ globals
827
+ } = config.external;
828
+ const plugins = [react()];
829
+ plugins.push(externalDepsPlugin({
830
+ externals,
831
+ globals
832
+ }));
833
+ if (config.dev.materialApi) {
834
+ plugins.push(materialDevPlugin({
835
+ entry: `/${config.entry.main}`
836
+ }));
837
+ }
838
+ if (config.vitePlugins.length > 0) {
839
+ plugins.push(...config.vitePlugins);
840
+ }
841
+ const aliasConfig = {};
842
+ for (const [key, value] of Object.entries(config.alias)) {
843
+ aliasConfig[key] = path.resolve(cwd, value);
844
+ }
845
+ return {
846
+ plugins,
847
+ server: {
848
+ port: config.dev.port,
849
+ host: 'localhost',
850
+ cors: true,
851
+ hmr: {
852
+ port: config.dev.port
853
+ }
854
+ },
855
+ build: {
856
+ target: 'esnext',
857
+ rollupOptions: {
858
+ external: externals,
859
+ output: {
860
+ globals
861
+ }
862
+ }
863
+ },
864
+ resolve: {
865
+ alias: aliasConfig,
866
+ dedupe: ['react', 'react-dom']
867
+ },
868
+ css: {
869
+ modules: {
870
+ generateScopedName: config.css.scopedName
871
+ }
872
+ }
873
+ };
874
+ }
875
+
876
+ async function devCommand(argv) {
877
+ console.log(pc.cyan('Starting development server...\n'));
878
+ const config = await loadConfig(argv.config);
879
+ console.log(pc.gray(` Package: ${config.pkg.name}@${config.pkg.version}`));
880
+ console.log(pc.gray(` Preset: ${config.preset}`));
881
+ console.log(pc.gray(` Port: ${config.dev.port}\n`));
882
+ const viteConfig = createViteConfig({
883
+ config
884
+ });
885
+ const server = await createServer(viteConfig);
886
+ await server.listen();
887
+ server.printUrls();
888
+ const shutdown = async () => {
889
+ console.log(pc.yellow('\nShutting down...'));
890
+ await server.close();
891
+ process.exit(0);
892
+ };
893
+ process.on('SIGINT', shutdown);
894
+ process.on('SIGTERM', shutdown);
895
+ }
896
+
897
+ const MATERIAL_TEMPLATE = `/**
898
+ * @easy-editor/easypack configuration
899
+ * @type {import('@easy-editor/easypack').EasypackConfig}
900
+ */
901
+ export default {
902
+ preset: 'material',
903
+ // globalName 自动从 package.json 推导
904
+ dev: {
905
+ port: 5001,
906
+ },
907
+ // output: {
908
+ // umd: true, // UMD 格式(默认开启)
909
+ // esm: false, // ESM 格式
910
+ // cjs: false, // CJS 格式
911
+ // minify: true, // 压缩输出(默认开启)
912
+ // types: false, // TypeScript 类型声明
913
+ // },
914
+ }
915
+ `;
916
+ const SETTER_TEMPLATE = `/**
917
+ * @easy-editor/easypack configuration
918
+ * @type {import('@easy-editor/easypack').EasypackConfig}
919
+ */
920
+ export default {
921
+ preset: 'setter',
922
+ globalName: 'EasyEditorSetters',
923
+ // output: {
924
+ // umd: true, // UMD 格式(默认开启)
925
+ // esm: false, // ESM 格式
926
+ // cjs: false, // CJS 格式
927
+ // minify: true, // 压缩输出(默认开启)
928
+ // types: false, // TypeScript 类型声明
929
+ // },
930
+ }
931
+ `;
932
+ const LIBRARY_TEMPLATE = `/**
933
+ * @easy-editor/easypack configuration
934
+ * @type {import('@easy-editor/easypack').EasypackConfig}
935
+ */
936
+ export default {
937
+ preset: 'library',
938
+ // globalName: 'MyLibrary',
939
+ // output: {
940
+ // umd: true, // UMD 格式(默认开启)
941
+ // esm: false, // ESM 格式
942
+ // cjs: false, // CJS 格式
943
+ // minify: true, // 压缩输出(默认开启)
944
+ // types: false, // TypeScript 类型声明
945
+ // },
946
+ }
947
+ `;
948
+ async function initCommand(argv) {
949
+ const cwd = process.cwd();
950
+ const configPath = path.join(cwd, 'easypack.config.ts');
951
+ if (fs.existsSync(configPath)) {
952
+ const overwrite = await prompts.confirm({
953
+ message: 'easypack.config.ts already exists. Overwrite?'
954
+ });
955
+ if (prompts.isCancel(overwrite) || !overwrite) {
956
+ prompts.cancel('Operation cancelled');
957
+ return;
958
+ }
959
+ }
960
+ let preset = argv.preset;
961
+ if (!preset) {
962
+ const selected = await prompts.select({
963
+ message: 'Select a preset:',
964
+ options: [{
965
+ label: 'material',
966
+ value: 'material',
967
+ hint: 'For EasyMaterials components'
968
+ }, {
969
+ label: 'setter',
970
+ value: 'setter',
971
+ hint: 'For EasySetters package'
972
+ }, {
973
+ label: 'library',
974
+ value: 'library',
975
+ hint: 'For general React libraries'
976
+ }]
977
+ });
978
+ if (prompts.isCancel(selected)) {
979
+ prompts.cancel('Operation cancelled');
980
+ return;
981
+ }
982
+ preset = selected;
983
+ }
984
+ let template;
985
+ switch (preset) {
986
+ case 'material':
987
+ template = MATERIAL_TEMPLATE;
988
+ break;
989
+ case 'setter':
990
+ template = SETTER_TEMPLATE;
991
+ break;
992
+ case 'library':
993
+ default:
994
+ template = LIBRARY_TEMPLATE;
995
+ break;
996
+ }
997
+ fs.writeFileSync(configPath, template);
998
+ console.log('');
999
+ console.log(pc.green('✓ Created easypack.config.ts'));
1000
+ console.log('');
1001
+ console.log(pc.gray('Next steps:'));
1002
+ console.log(pc.gray(' 1. Review and customize the config file'));
1003
+ console.log(pc.gray(' 2. Run `easypack build` to build for production'));
1004
+ console.log(pc.gray(' 3. Run `easypack dev` to start dev server'));
1005
+ console.log('');
1006
+ }
1007
+
1008
+ const VERSION = '0.0.1';
1009
+ const helpMessage = `
1010
+ ${pc.bold(pc.cyan('@easy-editor/easypack'))} - Build and dev tools for EasyEditor ecosystem
1011
+
1012
+ ${pc.bold('Usage:')}
1013
+ easypack <command> [options]
1014
+
1015
+ ${pc.bold('Commands:')}
1016
+ build Build for production
1017
+ dev Start development server
1018
+ init Generate config file template
1019
+
1020
+ ${pc.bold('Options:')}
1021
+ -c, --config <file> Config file path
1022
+ -h, --help Show help
1023
+ -v, --version Show version
1024
+
1025
+ ${pc.bold('Examples:')}
1026
+ ${pc.gray('# Build for production')}
1027
+ easypack build
1028
+
1029
+ ${pc.gray('# Start dev server')}
1030
+ easypack dev
1031
+
1032
+ ${pc.gray('# Generate config template')}
1033
+ easypack init
1034
+ `;
1035
+ async function cli() {
1036
+ const argv = mri(process.argv.slice(2), {
1037
+ alias: {
1038
+ h: 'help',
1039
+ v: 'version',
1040
+ c: 'config',
1041
+ p: 'preset'
1042
+ },
1043
+ boolean: ['help', 'version'],
1044
+ string: ['config', 'preset']
1045
+ });
1046
+ if (argv.version) {
1047
+ console.log(VERSION);
1048
+ return;
1049
+ }
1050
+ if (argv.help || argv._.length === 0) {
1051
+ console.log(helpMessage);
1052
+ return;
1053
+ }
1054
+ const command = argv._[0];
1055
+ try {
1056
+ switch (command) {
1057
+ case 'build':
1058
+ await buildCommand(argv);
1059
+ break;
1060
+ case 'dev':
1061
+ await devCommand(argv);
1062
+ break;
1063
+ case 'init':
1064
+ await initCommand(argv);
1065
+ break;
1066
+ default:
1067
+ console.log(pc.red(`Unknown command: ${command}`));
1068
+ console.log(helpMessage);
1069
+ process.exit(1);
1070
+ }
1071
+ } catch (error) {
1072
+ console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
1073
+ process.exit(1);
1074
+ }
1075
+ }
1076
+
1077
+ export { DEFAULT_CSS, DEFAULT_DEV, DEFAULT_ENTRY, DEFAULT_EXTENSIONS, DEFAULT_EXTERNALS$1 as DEFAULT_EXTERNALS, DEFAULT_GLOBALS$1 as DEFAULT_GLOBALS, DEFAULT_OUTPUT, cli, createOutputConfigs, createPlugins, createRollupConfig, createViteConfig, defineConfig, externalDepsPlugin, getPreset, libraryPreset, loadConfig, materialDevPlugin, materialPreset, setterPreset };
1078
+ //# sourceMappingURL=index.js.map