@fluffjs/cli 0.1.8 → 0.1.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/Cli.js CHANGED
@@ -7,6 +7,7 @@ import picomatch from 'picomatch';
7
7
  import { gzipSync } from 'zlib';
8
8
  import { generate } from './BabelHelpers.js';
9
9
  import { ComponentCompiler } from './ComponentCompiler.js';
10
+ import { DevServer } from './DevServer.js';
10
11
  import { fluffPlugin } from './fluff-esbuild-plugin.js';
11
12
  import { Generator } from './Generator.js';
12
13
  import { IndexHtmlTransformer } from './IndexHtmlTransformer.js';
@@ -492,6 +493,18 @@ Examples:
492
493
  const serveOptions = target.serve ?? {};
493
494
  const port = serveOptions.port ?? 3000;
494
495
  const host = serveOptions.host ?? 'localhost';
496
+ const esbuildPort = port + 1;
497
+ let proxyConfig = undefined;
498
+ if (serveOptions.proxyConfig) {
499
+ const proxyConfigPath = path.resolve(projectRoot, serveOptions.proxyConfig);
500
+ proxyConfig = DevServer.loadProxyConfig(proxyConfigPath);
501
+ if (proxyConfig) {
502
+ console.log(` ✓ Proxy config: ${serveOptions.proxyConfig}`);
503
+ for (const route of Object.keys(proxyConfig)) {
504
+ console.log(` ${route} -> ${proxyConfig[route].target}`);
505
+ }
506
+ }
507
+ }
495
508
  const entryPoint = target.entryPoint
496
509
  ? path.join(srcDir, target.entryPoint)
497
510
  : this.generateEntryPoint(srcDir, target.components);
@@ -567,13 +580,32 @@ Examples:
567
580
  });
568
581
  await ctx.watch();
569
582
  console.log(' Watching for changes...');
570
- const { hosts, port: actualPort } = await ctx.serve({
571
- servedir: outDir,
572
- port,
573
- host
574
- });
575
- console.log(` Server running at http://${hosts[0]}:${actualPort}`);
576
- console.log(' Press Ctrl+C to stop\n');
583
+ if (proxyConfig) {
584
+ await ctx.serve({
585
+ servedir: outDir,
586
+ port: esbuildPort,
587
+ host: '127.0.0.1'
588
+ });
589
+ const devServer = new DevServer({
590
+ port,
591
+ host,
592
+ esbuildPort,
593
+ esbuildHost: '127.0.0.1',
594
+ proxyConfig
595
+ });
596
+ await devServer.start();
597
+ console.log(` Server running at http://${host}:${port}`);
598
+ console.log(' Press Ctrl+C to stop\n');
599
+ }
600
+ else {
601
+ const { hosts, port: actualPort } = await ctx.serve({
602
+ servedir: outDir,
603
+ port,
604
+ host
605
+ });
606
+ console.log(` Server running at http://${hosts[0]}:${actualPort}`);
607
+ console.log(' Press Ctrl+C to stop\n');
608
+ }
577
609
  }
578
610
  generateEntryPoint(srcDir, componentPatterns) {
579
611
  const componentFiles = this.findFiles(srcDir, componentPatterns);
package/CodeGenerator.js CHANGED
@@ -52,7 +52,7 @@ export class CodeGenerator {
52
52
  const fragment = parse5.parseFragment(html);
53
53
  const styleElement = Parse5Helpers.createElement('style', []);
54
54
  Parse5Helpers.appendText(styleElement, styles);
55
- fragment.childNodes.unshift(styleElement);
55
+ fragment.childNodes.push(styleElement);
56
56
  styleElement.parentNode = fragment;
57
57
  content = parse5.serialize(fragment);
58
58
  }
@@ -51,7 +51,8 @@ export class ComponentCompiler {
51
51
  filename: filePath,
52
52
  presets,
53
53
  plugins,
54
- parserOpts
54
+ parserOpts,
55
+ cwd: path.dirname(new URL(import.meta.url).pathname)
55
56
  });
56
57
  return result?.code ?? code;
57
58
  }
package/DevServer.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export interface ProxyConfigEntry {
2
+ target: string;
3
+ changeOrigin?: boolean;
4
+ }
5
+ export type ProxyConfig = Record<string, ProxyConfigEntry>;
6
+ export interface DevServerOptions {
7
+ port: number;
8
+ host: string;
9
+ esbuildPort: number;
10
+ esbuildHost: string;
11
+ proxyConfig?: ProxyConfig;
12
+ }
13
+ export declare class DevServer {
14
+ private readonly options;
15
+ private readonly proxy;
16
+ private server;
17
+ constructor(options: DevServerOptions);
18
+ static loadProxyConfig(configPath: string): ProxyConfig | undefined;
19
+ private static isProxyEntry;
20
+ start(): Promise<number>;
21
+ stop(): void;
22
+ private handleRequest;
23
+ private findProxyEntry;
24
+ private proxyRequest;
25
+ private forwardToEsbuild;
26
+ }
27
+ //# sourceMappingURL=DevServer.d.ts.map
package/DevServer.js ADDED
@@ -0,0 +1,109 @@
1
+ import * as http from 'node:http';
2
+ import * as fs from 'node:fs';
3
+ import httpProxy from 'http-proxy';
4
+ export class DevServer {
5
+ options;
6
+ proxy;
7
+ server = null;
8
+ constructor(options) {
9
+ this.options = options;
10
+ this.proxy = httpProxy.createProxyServer({});
11
+ this.proxy.on('error', (err, req, res) => {
12
+ console.error('Proxy error:', err.message);
13
+ if (res instanceof http.ServerResponse && !res.headersSent) {
14
+ res.writeHead(502, { 'Content-Type': 'text/plain' });
15
+ res.end('Proxy error: ' + err.message);
16
+ }
17
+ });
18
+ }
19
+ static loadProxyConfig(configPath) {
20
+ if (!fs.existsSync(configPath)) {
21
+ console.warn(`Proxy config not found: ${configPath}`);
22
+ return undefined;
23
+ }
24
+ try {
25
+ const content = fs.readFileSync(configPath, 'utf-8');
26
+ const config = JSON.parse(content);
27
+ if (typeof config === 'object' && config !== null && !Array.isArray(config)) {
28
+ const result = {};
29
+ for (const [key, value] of Object.entries(config)) {
30
+ if (DevServer.isProxyEntry(value)) {
31
+ result[key] = {
32
+ target: value.target,
33
+ changeOrigin: typeof value.changeOrigin === 'boolean' ? value.changeOrigin : undefined
34
+ };
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+ return undefined;
40
+ }
41
+ catch (err) {
42
+ console.error('Failed to parse proxy config:', err);
43
+ return undefined;
44
+ }
45
+ }
46
+ static isProxyEntry(value) {
47
+ return typeof value === 'object' &&
48
+ value !== null &&
49
+ 'target' in value &&
50
+ typeof value.target === 'string';
51
+ }
52
+ async start() {
53
+ return new Promise((resolve, reject) => {
54
+ this.server = http.createServer((req, res) => {
55
+ this.handleRequest(req, res);
56
+ });
57
+ this.server.on('error', (err) => {
58
+ reject(err);
59
+ });
60
+ this.server.listen(this.options.port, () => {
61
+ const address = this.server?.address();
62
+ const port = typeof address === 'object' && address ? address.port : this.options.port;
63
+ resolve(port);
64
+ });
65
+ });
66
+ }
67
+ stop() {
68
+ if (this.server) {
69
+ this.server.close();
70
+ this.server = null;
71
+ }
72
+ this.proxy.close();
73
+ }
74
+ handleRequest(req, res) {
75
+ const url = req.url ?? '/';
76
+ const [pathname] = url.split('?');
77
+ const proxyEntry = this.findProxyEntry(pathname);
78
+ if (proxyEntry) {
79
+ this.proxyRequest(req, res, proxyEntry);
80
+ }
81
+ else {
82
+ this.forwardToEsbuild(req, res);
83
+ }
84
+ }
85
+ findProxyEntry(pathname) {
86
+ if (!this.options.proxyConfig) {
87
+ return undefined;
88
+ }
89
+ for (const [pattern, entry] of Object.entries(this.options.proxyConfig)) {
90
+ if (pathname === pattern || pathname.startsWith(pattern + '/') || pathname.startsWith(pattern + '?')) {
91
+ return entry;
92
+ }
93
+ }
94
+ return undefined;
95
+ }
96
+ proxyRequest(req, res, entry) {
97
+ const options = {
98
+ target: entry.target,
99
+ changeOrigin: entry.changeOrigin ?? false
100
+ };
101
+ this.proxy.web(req, res, options);
102
+ }
103
+ forwardToEsbuild(req, res) {
104
+ const options = {
105
+ target: `http://${this.options.esbuildHost}:${this.options.esbuildPort}`
106
+ };
107
+ this.proxy.web(req, res, options);
108
+ }
109
+ }
@@ -1,5 +1,6 @@
1
1
  export interface ServeOptions {
2
2
  port?: number;
3
3
  host?: string;
4
+ proxyConfig?: string;
4
5
  }
5
6
  //# sourceMappingURL=ServeOptions.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluffjs/cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",
@@ -32,6 +32,7 @@
32
32
  "esbuild": "^0.27.2",
33
33
  "he": "^1.2.0",
34
34
  "html-minifier-terser": "^7.2.0",
35
+ "http-proxy": "^1.18.1",
35
36
  "picomatch": "^4.0.2",
36
37
  "parse5": "^8.0.0",
37
38
  "parse5-sax-parser": "^8.0.0",
@@ -40,6 +41,7 @@
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/he": "^1.2.3",
44
+ "@types/http-proxy": "^1.17.16",
43
45
  "@types/jsesc": "^3.0.3",
44
46
  "jsesc": "^3.1.0"
45
47
  },