@fluffjs/cli 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BabelHelpers.js +8 -5
- package/Cli.d.ts +9 -5
- package/Cli.js +218 -155
- package/CodeGenerator.d.ts +19 -10
- package/CodeGenerator.js +146 -106
- package/ComponentCompiler.d.ts +19 -3
- package/ComponentCompiler.js +175 -47
- package/DevServer.d.ts +6 -4
- package/DevServer.js +102 -23
- package/DomPreProcessor.js +22 -40
- package/IndexHtmlTransformer.js +20 -28
- package/PluginLoader.d.ts +22 -0
- package/PluginLoader.js +286 -0
- package/PluginManager.d.ts +39 -0
- package/PluginManager.js +209 -0
- package/TemplateParser.d.ts +5 -0
- package/TemplateParser.js +55 -0
- package/babel-plugin-directive.d.ts +12 -0
- package/babel-plugin-directive.js +78 -0
- package/babel-plugin-reactive.js +19 -14
- package/fluff-esbuild-plugin.js +66 -22
- package/interfaces/ClassTransformContext.d.ts +8 -0
- package/interfaces/ClassTransformContext.js +1 -0
- package/interfaces/CodeGenContext.d.ts +9 -0
- package/interfaces/CodeGenContext.js +1 -0
- package/interfaces/DiscoveryInfo.d.ts +15 -0
- package/interfaces/DiscoveryInfo.js +1 -0
- package/interfaces/EntryPointContext.d.ts +6 -0
- package/interfaces/EntryPointContext.js +1 -0
- package/interfaces/FluffConfigInterface.d.ts +2 -0
- package/interfaces/FluffPlugin.d.ts +26 -0
- package/interfaces/FluffPlugin.js +1 -0
- package/interfaces/FluffPluginOptions.d.ts +3 -0
- package/interfaces/FluffTarget.d.ts +1 -0
- package/interfaces/HtmlTransformOptions.d.ts +2 -0
- package/interfaces/PluginCustomTable.d.ts +6 -0
- package/interfaces/PluginCustomTable.js +1 -0
- package/interfaces/PluginHookDependency.d.ts +5 -0
- package/interfaces/PluginHookDependency.js +1 -0
- package/interfaces/PluginHookName.d.ts +2 -0
- package/interfaces/PluginHookName.js +1 -0
- package/interfaces/ScopeElementConfig.d.ts +5 -0
- package/interfaces/ScopeElementConfig.js +1 -0
- package/interfaces/index.d.ts +8 -0
- package/package.json +5 -3
- package/PeerDependencies.d.ts +0 -6
- package/PeerDependencies.js +0 -7
package/BabelHelpers.js
CHANGED
|
@@ -43,23 +43,26 @@ export function parseMethodBody(body) {
|
|
|
43
43
|
}
|
|
44
44
|
return [];
|
|
45
45
|
}
|
|
46
|
+
function buildHostElementCall() {
|
|
47
|
+
return t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('__getHostElement')), []);
|
|
48
|
+
}
|
|
46
49
|
export function buildHostBindingUpdateStatement(hostProperty) {
|
|
47
50
|
if (hostProperty.startsWith('class.')) {
|
|
48
51
|
const className = hostProperty.slice(6);
|
|
49
|
-
return t.ifStatement(t.identifier('__v'), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(
|
|
52
|
+
return t.ifStatement(t.identifier('__v'), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(buildHostElementCall(), t.identifier('classList')), t.identifier('add')), [t.stringLiteral(className)])), t.expressionStatement(t.callExpression(t.memberExpression(t.memberExpression(buildHostElementCall(), t.identifier('classList')), t.identifier('remove')), [t.stringLiteral(className)])));
|
|
50
53
|
}
|
|
51
54
|
else if (hostProperty.startsWith('attr.')) {
|
|
52
55
|
const attrName = hostProperty.slice(5);
|
|
53
|
-
return t.ifStatement(t.binaryExpression('!=', t.identifier('__v'), t.nullLiteral()), t.expressionStatement(t.callExpression(t.memberExpression(
|
|
56
|
+
return t.ifStatement(t.binaryExpression('!=', t.identifier('__v'), t.nullLiteral()), t.expressionStatement(t.callExpression(t.memberExpression(buildHostElementCall(), t.identifier('setAttribute')), [
|
|
54
57
|
t.stringLiteral(attrName),
|
|
55
58
|
t.callExpression(t.identifier('String'), [t.identifier('__v')])
|
|
56
|
-
])), t.expressionStatement(t.callExpression(t.memberExpression(
|
|
59
|
+
])), t.expressionStatement(t.callExpression(t.memberExpression(buildHostElementCall(), t.identifier('removeAttribute')), [t.stringLiteral(attrName)])));
|
|
57
60
|
}
|
|
58
61
|
else if (hostProperty.startsWith('style.')) {
|
|
59
62
|
const styleProp = hostProperty.slice(6);
|
|
60
|
-
return t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.memberExpression(
|
|
63
|
+
return t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.memberExpression(buildHostElementCall(), t.identifier('style')), t.identifier(styleProp)), t.logicalExpression('||', t.identifier('__v'), t.stringLiteral(''))));
|
|
61
64
|
}
|
|
62
65
|
else {
|
|
63
|
-
return t.expressionStatement(t.assignmentExpression('=', t.memberExpression(
|
|
66
|
+
return t.expressionStatement(t.assignmentExpression('=', t.memberExpression(buildHostElementCall(), t.identifier(hostProperty)), t.identifier('__v')));
|
|
64
67
|
}
|
|
65
68
|
}
|
package/Cli.d.ts
CHANGED
|
@@ -6,8 +6,12 @@ export declare class Cli {
|
|
|
6
6
|
private readonly noMinify;
|
|
7
7
|
private readonly gzScriptTag;
|
|
8
8
|
constructor(options?: CliOptions);
|
|
9
|
-
|
|
9
|
+
static parseArgs(argv: string[]): {
|
|
10
|
+
options: CliOptions;
|
|
11
|
+
args: string[];
|
|
12
|
+
};
|
|
10
13
|
run(args: string[]): Promise<void>;
|
|
14
|
+
private resolveCwd;
|
|
11
15
|
private showHelp;
|
|
12
16
|
private getProjectRoot;
|
|
13
17
|
private findNxPackageRoot;
|
|
@@ -25,9 +29,13 @@ export declare class Cli {
|
|
|
25
29
|
private serve;
|
|
26
30
|
private serveTarget;
|
|
27
31
|
private resolveEntryPoint;
|
|
32
|
+
private loadPlugins;
|
|
33
|
+
private cleanupTempEntry;
|
|
34
|
+
private buildBaseEsbuildConfig;
|
|
28
35
|
private getEsbuildEntryConfig;
|
|
29
36
|
private getJsBundleName;
|
|
30
37
|
private collectStyles;
|
|
38
|
+
private collectGlobalStyles;
|
|
31
39
|
private loadTsConfig;
|
|
32
40
|
private runTypeCheck;
|
|
33
41
|
private generateEntryContent;
|
|
@@ -39,9 +47,5 @@ export declare class Cli {
|
|
|
39
47
|
private copyAssetsForServe;
|
|
40
48
|
private copyDirectoryRecursive;
|
|
41
49
|
private copyDirectoryRecursiveSync;
|
|
42
|
-
static parseArgs(argv: string[]): {
|
|
43
|
-
options: CliOptions;
|
|
44
|
-
args: string[];
|
|
45
|
-
};
|
|
46
50
|
}
|
|
47
51
|
//# sourceMappingURL=Cli.d.ts.map
|
package/Cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as t from '@babel/types';
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
|
-
import { randomUUID } from 'crypto';
|
|
3
|
+
import { randomBytes, randomUUID } from 'crypto';
|
|
4
4
|
import * as esbuild from 'esbuild';
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
@@ -12,6 +12,7 @@ import { DevServer } from './DevServer.js';
|
|
|
12
12
|
import { fluffPlugin } from './fluff-esbuild-plugin.js';
|
|
13
13
|
import { Generator } from './Generator.js';
|
|
14
14
|
import { IndexHtmlTransformer } from './IndexHtmlTransformer.js';
|
|
15
|
+
import { PluginLoader } from './PluginLoader.js';
|
|
15
16
|
import { DEFAULT_CONFIG } from './types/FluffConfig.js';
|
|
16
17
|
export class Cli {
|
|
17
18
|
cwd;
|
|
@@ -26,12 +27,45 @@ export class Cli {
|
|
|
26
27
|
this.noMinify = options.noMinify ?? false;
|
|
27
28
|
this.gzScriptTag = options.gzScriptTag ?? false;
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
static parseArgs(argv) {
|
|
31
|
+
const options = {};
|
|
32
|
+
const args = [];
|
|
33
|
+
let i = 0;
|
|
34
|
+
while (i < argv.length) {
|
|
35
|
+
const arg = argv[i];
|
|
36
|
+
if (arg === '--nx' && argv[i + 1]) {
|
|
37
|
+
options.nxPackage = argv[i + 1];
|
|
38
|
+
i += 2;
|
|
39
|
+
}
|
|
40
|
+
else if (arg === '--cwd' && argv[i + 1]) {
|
|
41
|
+
options.cwd = argv[i + 1];
|
|
42
|
+
i += 2;
|
|
43
|
+
}
|
|
44
|
+
else if (arg === '--no-gzip') {
|
|
45
|
+
options.noGzip = true;
|
|
46
|
+
i++;
|
|
47
|
+
}
|
|
48
|
+
else if (arg === '--no-minify') {
|
|
49
|
+
options.noMinify = true;
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
else if (arg === '--gz-script-tag') {
|
|
53
|
+
options.gzScriptTag = true;
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
else if (arg?.startsWith('--')) {
|
|
57
|
+
console.error(`Unknown option: ${arg}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
else if (arg) {
|
|
61
|
+
args.push(arg);
|
|
62
|
+
i++;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
33
67
|
}
|
|
34
|
-
return
|
|
68
|
+
return { options, args };
|
|
35
69
|
}
|
|
36
70
|
async run(args) {
|
|
37
71
|
const [command, ...commandArgs] = args;
|
|
@@ -61,6 +95,13 @@ export class Cli {
|
|
|
61
95
|
process.exit(1);
|
|
62
96
|
}
|
|
63
97
|
}
|
|
98
|
+
resolveCwd() {
|
|
99
|
+
const processCwd = process.cwd();
|
|
100
|
+
if (fs.existsSync(path.join(processCwd, 'fluff.json'))) {
|
|
101
|
+
return processCwd;
|
|
102
|
+
}
|
|
103
|
+
return process.env.INIT_CWD ?? processCwd;
|
|
104
|
+
}
|
|
64
105
|
showHelp() {
|
|
65
106
|
console.log(`
|
|
66
107
|
Fluff CLI - Build tool for Fluff components
|
|
@@ -253,10 +294,7 @@ Examples:
|
|
|
253
294
|
if (targetName) {
|
|
254
295
|
config.targets = {
|
|
255
296
|
[targetName]: {
|
|
256
|
-
name: targetName,
|
|
257
|
-
srcDir: 'src',
|
|
258
|
-
outDir: 'dist',
|
|
259
|
-
assets: ['**/*.html', '**/*.css']
|
|
297
|
+
name: targetName, srcDir: 'src', outDir: 'dist', assets: ['**/*.html', '**/*.css']
|
|
260
298
|
}
|
|
261
299
|
};
|
|
262
300
|
config.defaultTarget = targetName;
|
|
@@ -289,9 +327,7 @@ Examples:
|
|
|
289
327
|
}
|
|
290
328
|
const generator = new Generator();
|
|
291
329
|
generator.generate({
|
|
292
|
-
appName,
|
|
293
|
-
outputDir: this.cwd,
|
|
294
|
-
packageManager
|
|
330
|
+
appName, outputDir: this.cwd, packageManager
|
|
295
331
|
});
|
|
296
332
|
}
|
|
297
333
|
async build(args) {
|
|
@@ -314,6 +350,7 @@ Examples:
|
|
|
314
350
|
throw new Error(`fluff.json not found at ${configPath}. Run 'fluff init' first.`);
|
|
315
351
|
}
|
|
316
352
|
const config = this.loadConfigFrom(configPath);
|
|
353
|
+
const pluginManager = await this.loadPlugins(config, projectRoot);
|
|
317
354
|
let targets = [];
|
|
318
355
|
if (targetOrProject) {
|
|
319
356
|
const target = config.targets[targetOrProject];
|
|
@@ -337,16 +374,14 @@ Examples:
|
|
|
337
374
|
targets = Object.values(config.targets);
|
|
338
375
|
}
|
|
339
376
|
for (const target of targets) {
|
|
340
|
-
await this.buildTarget(target, projectRoot, workspaceRoot, projectRelativePath);
|
|
377
|
+
await this.buildTarget(target, projectRoot, workspaceRoot, projectRelativePath, pluginManager);
|
|
341
378
|
}
|
|
342
379
|
}
|
|
343
|
-
async buildTarget(target, projectRoot, workspaceRoot, projectRelativePath) {
|
|
380
|
+
async buildTarget(target, projectRoot, workspaceRoot, projectRelativePath, pluginManager) {
|
|
344
381
|
console.log(`🔨 Building target '${target.name}'...`);
|
|
345
382
|
const srcDir = path.resolve(projectRoot, target.srcDir);
|
|
346
383
|
const appDir = path.join(srcDir, target.componentsDir ?? 'app');
|
|
347
|
-
const outDir = (workspaceRoot && projectRelativePath)
|
|
348
|
-
? path.join(workspaceRoot, 'dist', projectRelativePath)
|
|
349
|
-
: path.resolve(projectRoot, target.outDir);
|
|
384
|
+
const outDir = (workspaceRoot && projectRelativePath) ? path.join(workspaceRoot, 'dist', projectRelativePath) : path.resolve(projectRoot, target.outDir);
|
|
350
385
|
if (!fs.existsSync(srcDir)) {
|
|
351
386
|
throw new Error(`Source directory not found: ${srcDir}`);
|
|
352
387
|
}
|
|
@@ -360,42 +395,31 @@ Examples:
|
|
|
360
395
|
if (this.noMinify) {
|
|
361
396
|
bundleOptions.minify = false;
|
|
362
397
|
}
|
|
363
|
-
const
|
|
398
|
+
const splitting = bundleOptions.splitting ?? false;
|
|
399
|
+
const entry = this.resolveEntryPoint(target, srcDir, splitting);
|
|
364
400
|
const inlineStyles = await this.collectStyles(target, srcDir, bundleOptions.minify ?? true);
|
|
401
|
+
const globalStylesCss = await this.collectGlobalStyles(target, srcDir, bundleOptions.minify ?? true);
|
|
365
402
|
this.runTypeCheck(target, projectRoot);
|
|
366
403
|
console.log(' Building with esbuild...');
|
|
367
404
|
const tsconfigRaw = this.loadTsConfig(target, projectRoot);
|
|
368
|
-
const result = await esbuild.build({
|
|
369
|
-
|
|
370
|
-
bundle: true,
|
|
371
|
-
...(entry.useStdin
|
|
372
|
-
? { outfile: path.join(outDir, 'fluff-app.js') }
|
|
373
|
-
: { outdir: outDir, entryNames: '[name]' }),
|
|
374
|
-
format: 'esm',
|
|
375
|
-
platform: 'browser',
|
|
376
|
-
target: bundleOptions.target ?? 'es2022',
|
|
405
|
+
const result = await esbuild.build(this.buildBaseEsbuildConfig({
|
|
406
|
+
entry, appDir, outDir, splitting,
|
|
377
407
|
minify: bundleOptions.minify ?? true,
|
|
378
|
-
|
|
379
|
-
|
|
408
|
+
tsconfigRaw, pluginManager,
|
|
409
|
+
production: true,
|
|
410
|
+
target: bundleOptions.target ?? 'es2022',
|
|
380
411
|
metafile: true,
|
|
381
|
-
plugins: [
|
|
382
|
-
fluffPlugin({
|
|
383
|
-
srcDir: appDir,
|
|
384
|
-
outDir,
|
|
385
|
-
minify: bundleOptions.minify ?? true,
|
|
386
|
-
skipDefine: false,
|
|
387
|
-
production: true
|
|
388
|
-
})
|
|
389
|
-
],
|
|
390
412
|
external: bundleOptions.external ?? [],
|
|
391
|
-
|
|
392
|
-
|
|
413
|
+
globalStylesCss
|
|
414
|
+
}))
|
|
415
|
+
.finally(() => {
|
|
416
|
+
this.cleanupTempEntry(entry);
|
|
393
417
|
});
|
|
394
|
-
const
|
|
395
|
-
const
|
|
396
|
-
const
|
|
418
|
+
const outputKeys = Object.keys(result.metafile?.outputs ?? {});
|
|
419
|
+
const jsBundleName = this.getJsBundleName(entry);
|
|
420
|
+
const jsBundle = outputKeys.find(f => path.basename(f) === jsBundleName);
|
|
421
|
+
const cssBundle = outputKeys.find(f => f.endsWith('.css'));
|
|
397
422
|
if (jsBundle) {
|
|
398
|
-
const jsBundleName = path.basename(jsBundle);
|
|
399
423
|
const jsPath = path.join(outDir, jsBundleName);
|
|
400
424
|
if (bundleOptions.gzip) {
|
|
401
425
|
const gzipContent = fs.readFileSync(jsPath);
|
|
@@ -432,7 +456,8 @@ Examples:
|
|
|
432
456
|
inlineStyles: inlineStyles || undefined,
|
|
433
457
|
gzip: bundleOptions.gzip,
|
|
434
458
|
gzScriptTag: bundleOptions.gzScriptTag ?? this.gzScriptTag,
|
|
435
|
-
minify: bundleOptions.minify
|
|
459
|
+
minify: bundleOptions.minify,
|
|
460
|
+
pluginManager
|
|
436
461
|
});
|
|
437
462
|
fs.writeFileSync(path.join(outDir, 'index.html'), transformed);
|
|
438
463
|
console.log(' ✓ Transformed index.html');
|
|
@@ -463,6 +488,7 @@ Examples:
|
|
|
463
488
|
throw new Error(`fluff.json not found at ${configPath}. Run 'fluff init' first.`);
|
|
464
489
|
}
|
|
465
490
|
const config = this.loadConfigFrom(configPath);
|
|
491
|
+
const pluginManager = await this.loadPlugins(config, projectRoot);
|
|
466
492
|
let target = undefined;
|
|
467
493
|
if (targetOrProject) {
|
|
468
494
|
target = config.targets[targetOrProject];
|
|
@@ -485,9 +511,9 @@ Examples:
|
|
|
485
511
|
process.exit(1);
|
|
486
512
|
}
|
|
487
513
|
}
|
|
488
|
-
await this.serveTarget(target, projectRoot, workspaceRoot, projectRelativePath);
|
|
514
|
+
await this.serveTarget(target, projectRoot, workspaceRoot, projectRelativePath, pluginManager);
|
|
489
515
|
}
|
|
490
|
-
async serveTarget(target, projectRoot, workspaceRoot, projectRelativePath) {
|
|
516
|
+
async serveTarget(target, projectRoot, workspaceRoot, projectRelativePath, pluginManager) {
|
|
491
517
|
const srcDir = path.resolve(projectRoot, target.srcDir);
|
|
492
518
|
const appDir = path.join(srcDir, target.componentsDir ?? 'app');
|
|
493
519
|
const fluffDir = path.join(this.cwd, '.fluff');
|
|
@@ -496,8 +522,17 @@ Examples:
|
|
|
496
522
|
if (!fs.existsSync(outDir)) {
|
|
497
523
|
fs.mkdirSync(outDir, { recursive: true });
|
|
498
524
|
}
|
|
525
|
+
let entry = null;
|
|
526
|
+
let ctx = null;
|
|
499
527
|
const cleanup = () => {
|
|
500
528
|
try {
|
|
529
|
+
if (ctx) {
|
|
530
|
+
ctx.dispose().catch((e) => {
|
|
531
|
+
console.error('Failed to dispose esbuild context:', e);
|
|
532
|
+
});
|
|
533
|
+
ctx = null;
|
|
534
|
+
}
|
|
535
|
+
this.cleanupTempEntry(entry);
|
|
501
536
|
if (fs.existsSync(outDir)) {
|
|
502
537
|
fs.rmSync(outDir, { recursive: true, force: true });
|
|
503
538
|
}
|
|
@@ -517,7 +552,6 @@ Examples:
|
|
|
517
552
|
const serveOptions = target.serve ?? {};
|
|
518
553
|
const port = serveOptions.port ?? 3000;
|
|
519
554
|
const host = serveOptions.host ?? 'localhost';
|
|
520
|
-
const esbuildPort = port + 1;
|
|
521
555
|
let proxyConfig = undefined;
|
|
522
556
|
if (serveOptions.proxyConfig) {
|
|
523
557
|
const proxyConfigPath = path.resolve(projectRoot, serveOptions.proxyConfig);
|
|
@@ -529,8 +563,11 @@ Examples:
|
|
|
529
563
|
}
|
|
530
564
|
}
|
|
531
565
|
}
|
|
532
|
-
const
|
|
566
|
+
const bundleOptions = { ...target.bundle };
|
|
567
|
+
const splitting = bundleOptions.splitting ?? false;
|
|
568
|
+
entry = this.resolveEntryPoint(target, srcDir, splitting);
|
|
533
569
|
const inlineStyles = await this.collectStyles(target, srcDir, false);
|
|
570
|
+
const globalStylesCss = await this.collectGlobalStyles(target, srcDir, false);
|
|
534
571
|
if (target.indexHtml) {
|
|
535
572
|
const indexHtmlPath = path.join(srcDir, target.indexHtml);
|
|
536
573
|
if (fs.existsSync(indexHtmlPath)) {
|
|
@@ -541,7 +578,8 @@ Examples:
|
|
|
541
578
|
inlineStyles: inlineStyles || undefined,
|
|
542
579
|
gzip: false,
|
|
543
580
|
minify: false,
|
|
544
|
-
liveReload: true
|
|
581
|
+
liveReload: true,
|
|
582
|
+
pluginManager
|
|
545
583
|
});
|
|
546
584
|
fs.writeFileSync(path.join(outDir, 'index.html'), transformed);
|
|
547
585
|
}
|
|
@@ -551,73 +589,104 @@ Examples:
|
|
|
551
589
|
}
|
|
552
590
|
console.log(`🚀 Starting dev server for '${target.name}'...`);
|
|
553
591
|
const tsconfigRaw = this.loadTsConfig(target, projectRoot);
|
|
554
|
-
const
|
|
555
|
-
|
|
592
|
+
const devServer = new DevServer({
|
|
593
|
+
port, host, outDir, proxyConfig
|
|
594
|
+
});
|
|
595
|
+
ctx = await esbuild.context(this.buildBaseEsbuildConfig({
|
|
596
|
+
entry, appDir, outDir, splitting,
|
|
597
|
+
minify: false,
|
|
598
|
+
tsconfigRaw, pluginManager,
|
|
599
|
+
production: false,
|
|
600
|
+
sourcemap: true,
|
|
601
|
+
globalStylesCss,
|
|
602
|
+
extraPlugins: [{
|
|
603
|
+
name: 'fluff-live-reload', setup(build) {
|
|
604
|
+
build.onEnd((result) => {
|
|
605
|
+
if (result.errors.length === 0) {
|
|
606
|
+
console.log('[watch] build finished, watching for changes...');
|
|
607
|
+
devServer.notifyReload();
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
}]
|
|
612
|
+
}));
|
|
613
|
+
await ctx.watch();
|
|
614
|
+
console.log(' Watching for changes...');
|
|
615
|
+
await devServer.start();
|
|
616
|
+
console.log(` Server running at http://${host}:${port}`);
|
|
617
|
+
console.log(' Press Ctrl+C to stop\n');
|
|
618
|
+
}
|
|
619
|
+
resolveEntryPoint(target, srcDir, splitting) {
|
|
620
|
+
if (!target.entryPoint) {
|
|
621
|
+
const generated = this.generateEntryContent(srcDir, target.exclude);
|
|
622
|
+
if (splitting) {
|
|
623
|
+
let tempPath = path.join(srcDir, 'fluff-app.ts');
|
|
624
|
+
if (fs.existsSync(tempPath)) {
|
|
625
|
+
const hex = randomBytes(4).toString('hex');
|
|
626
|
+
tempPath = path.join(srcDir, `fluff-app-${hex}.ts`);
|
|
627
|
+
}
|
|
628
|
+
fs.writeFileSync(tempPath, generated.contents);
|
|
629
|
+
return { useStdin: false, entryPointFile: tempPath, generatedEntry: null, tempEntryFile: tempPath };
|
|
630
|
+
}
|
|
631
|
+
return { useStdin: true, entryPointFile: null, generatedEntry: generated, tempEntryFile: null };
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
useStdin: false,
|
|
635
|
+
entryPointFile: path.join(srcDir, target.entryPoint),
|
|
636
|
+
generatedEntry: null,
|
|
637
|
+
tempEntryFile: null
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
async loadPlugins(config, projectRoot) {
|
|
641
|
+
const pluginManager = await PluginLoader.load(config, projectRoot);
|
|
642
|
+
if (pluginManager.hasPlugins) {
|
|
643
|
+
await pluginManager.runAfterConfig(config, config.pluginConfig ?? {});
|
|
644
|
+
}
|
|
645
|
+
return pluginManager;
|
|
646
|
+
}
|
|
647
|
+
cleanupTempEntry(entry) {
|
|
648
|
+
if (entry?.tempEntryFile && fs.existsSync(entry.tempEntryFile)) {
|
|
649
|
+
fs.unlinkSync(entry.tempEntryFile);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
buildBaseEsbuildConfig(params) {
|
|
653
|
+
return {
|
|
654
|
+
...this.getEsbuildEntryConfig(params.entry),
|
|
556
655
|
bundle: true,
|
|
557
|
-
...(entry.useStdin
|
|
558
|
-
? { outfile: path.join(outDir, 'fluff-app.js') }
|
|
559
|
-
: { outdir: outDir, entryNames: '[name]' }),
|
|
656
|
+
...(params.entry.useStdin
|
|
657
|
+
? { outfile: path.join(params.outDir, 'fluff-app.js') }
|
|
658
|
+
: { outdir: params.outDir, entryNames: '[name]' }),
|
|
560
659
|
format: 'esm',
|
|
561
660
|
platform: 'browser',
|
|
562
|
-
target: 'es2022',
|
|
563
|
-
minify:
|
|
661
|
+
target: params.target ?? 'es2022',
|
|
662
|
+
minify: params.minify,
|
|
663
|
+
splitting: params.splitting,
|
|
564
664
|
treeShaking: true,
|
|
565
|
-
|
|
665
|
+
metafile: params.metafile ?? false,
|
|
666
|
+
sourcemap: params.sourcemap ?? false,
|
|
566
667
|
plugins: [
|
|
567
668
|
fluffPlugin({
|
|
568
|
-
srcDir: appDir,
|
|
569
|
-
outDir,
|
|
570
|
-
minify:
|
|
571
|
-
sourcemap:
|
|
669
|
+
srcDir: params.appDir,
|
|
670
|
+
outDir: params.outDir,
|
|
671
|
+
minify: params.minify,
|
|
672
|
+
sourcemap: params.sourcemap,
|
|
572
673
|
skipDefine: false,
|
|
573
|
-
production:
|
|
574
|
-
|
|
674
|
+
production: params.production,
|
|
675
|
+
pluginManager: params.pluginManager,
|
|
676
|
+
globalStylesCss: params.globalStylesCss
|
|
677
|
+
}),
|
|
678
|
+
...(params.extraPlugins ?? [])
|
|
575
679
|
],
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
console.log(' Watching for changes...');
|
|
581
|
-
if (proxyConfig) {
|
|
582
|
-
await ctx.serve({
|
|
583
|
-
servedir: outDir,
|
|
584
|
-
port: esbuildPort,
|
|
585
|
-
host: '127.0.0.1'
|
|
586
|
-
});
|
|
587
|
-
const devServer = new DevServer({
|
|
588
|
-
port,
|
|
589
|
-
host,
|
|
590
|
-
esbuildPort,
|
|
591
|
-
esbuildHost: '127.0.0.1',
|
|
592
|
-
proxyConfig
|
|
593
|
-
});
|
|
594
|
-
await devServer.start();
|
|
595
|
-
console.log(` Server running at http://${host}:${port}`);
|
|
596
|
-
console.log(' Press Ctrl+C to stop\n');
|
|
597
|
-
}
|
|
598
|
-
else {
|
|
599
|
-
const { hosts, port: actualPort } = await ctx.serve({
|
|
600
|
-
servedir: outDir,
|
|
601
|
-
port,
|
|
602
|
-
host
|
|
603
|
-
});
|
|
604
|
-
console.log(` Server running at http://${hosts[0]}:${actualPort}`);
|
|
605
|
-
console.log(' Press Ctrl+C to stop\n');
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
resolveEntryPoint(target, srcDir) {
|
|
609
|
-
const useStdin = !target.entryPoint;
|
|
610
|
-
const entryPointFile = target.entryPoint ? path.join(srcDir, target.entryPoint) : null;
|
|
611
|
-
const generatedEntry = useStdin ? this.generateEntryContent(srcDir, target.exclude) : null;
|
|
612
|
-
return { useStdin, entryPointFile, generatedEntry };
|
|
680
|
+
external: params.external ?? [],
|
|
681
|
+
logLevel: 'warning',
|
|
682
|
+
tsconfigRaw: params.tsconfigRaw
|
|
683
|
+
};
|
|
613
684
|
}
|
|
614
685
|
getEsbuildEntryConfig(entry) {
|
|
615
686
|
if (entry.useStdin && entry.generatedEntry) {
|
|
616
687
|
return {
|
|
617
688
|
stdin: {
|
|
618
|
-
contents: entry.generatedEntry.contents,
|
|
619
|
-
resolveDir: entry.generatedEntry.resolveDir,
|
|
620
|
-
loader: 'ts'
|
|
689
|
+
contents: entry.generatedEntry.contents, resolveDir: entry.generatedEntry.resolveDir, loader: 'ts'
|
|
621
690
|
}
|
|
622
691
|
};
|
|
623
692
|
}
|
|
@@ -627,7 +696,8 @@ Examples:
|
|
|
627
696
|
if (entry.useStdin) {
|
|
628
697
|
return 'fluff-app.js';
|
|
629
698
|
}
|
|
630
|
-
return path.basename(entry.entryPointFile ?? '')
|
|
699
|
+
return path.basename(entry.entryPointFile ?? '')
|
|
700
|
+
.replace(/\.ts$/, '.js');
|
|
631
701
|
}
|
|
632
702
|
async collectStyles(target, srcDir, minify) {
|
|
633
703
|
if (!target.styles || target.styles.length === 0) {
|
|
@@ -636,7 +706,8 @@ Examples:
|
|
|
636
706
|
const styleContents = [];
|
|
637
707
|
for (const stylePath of target.styles) {
|
|
638
708
|
const fullPath = path.resolve(srcDir, stylePath);
|
|
639
|
-
if (fs.existsSync(fullPath) && fs.statSync(fullPath)
|
|
709
|
+
if (fs.existsSync(fullPath) && fs.statSync(fullPath)
|
|
710
|
+
.isFile()) {
|
|
640
711
|
console.log(` ✓ Style: ${stylePath}`);
|
|
641
712
|
styleContents.push(fs.readFileSync(fullPath, 'utf-8'));
|
|
642
713
|
}
|
|
@@ -657,18 +728,51 @@ Examples:
|
|
|
657
728
|
let inlineStyles = styleContents.join('\n');
|
|
658
729
|
if (minify) {
|
|
659
730
|
const cssResult = await esbuild.transform(inlineStyles, {
|
|
660
|
-
loader: 'css',
|
|
661
|
-
minify: true
|
|
731
|
+
loader: 'css', minify: true
|
|
662
732
|
});
|
|
663
733
|
inlineStyles = cssResult.code;
|
|
664
734
|
}
|
|
665
735
|
console.log(' ✓ Bundled global styles');
|
|
666
736
|
return inlineStyles;
|
|
667
737
|
}
|
|
738
|
+
async collectGlobalStyles(target, srcDir, minify) {
|
|
739
|
+
if (!target.globalStyles || target.globalStyles.length === 0) {
|
|
740
|
+
return '';
|
|
741
|
+
}
|
|
742
|
+
const styleContents = [];
|
|
743
|
+
for (const stylePath of target.globalStyles) {
|
|
744
|
+
const fullPath = path.resolve(srcDir, stylePath);
|
|
745
|
+
if (fs.existsSync(fullPath) && fs.statSync(fullPath)
|
|
746
|
+
.isFile()) {
|
|
747
|
+
console.log(` ✓ Global style: ${stylePath}`);
|
|
748
|
+
styleContents.push(fs.readFileSync(fullPath, 'utf-8'));
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
const styleFiles = this.findFiles(srcDir, [stylePath]);
|
|
752
|
+
if (styleFiles.length === 0) {
|
|
753
|
+
console.warn(` ⚠ Global style not found: ${fullPath}`);
|
|
754
|
+
}
|
|
755
|
+
for (const styleFile of styleFiles) {
|
|
756
|
+
console.log(` ✓ Global style: ${path.relative(srcDir, styleFile)}`);
|
|
757
|
+
styleContents.push(fs.readFileSync(styleFile, 'utf-8'));
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (styleContents.length === 0) {
|
|
762
|
+
return '';
|
|
763
|
+
}
|
|
764
|
+
let css = styleContents.join('\n');
|
|
765
|
+
if (minify) {
|
|
766
|
+
const cssResult = await esbuild.transform(css, {
|
|
767
|
+
loader: 'css', minify: true
|
|
768
|
+
});
|
|
769
|
+
css = cssResult.code;
|
|
770
|
+
}
|
|
771
|
+
console.log(' ✓ Bundled global component styles');
|
|
772
|
+
return css;
|
|
773
|
+
}
|
|
668
774
|
loadTsConfig(target, projectRoot) {
|
|
669
|
-
return target.tsConfigPath
|
|
670
|
-
? fs.readFileSync(path.resolve(projectRoot, target.tsConfigPath), 'utf-8')
|
|
671
|
-
: '{}';
|
|
775
|
+
return target.tsConfigPath ? fs.readFileSync(path.resolve(projectRoot, target.tsConfigPath), 'utf-8') : '{}';
|
|
672
776
|
}
|
|
673
777
|
runTypeCheck(target, projectRoot) {
|
|
674
778
|
if (!target.tsConfigPath) {
|
|
@@ -682,8 +786,7 @@ Examples:
|
|
|
682
786
|
console.log(' Checking types...');
|
|
683
787
|
try {
|
|
684
788
|
execSync(`npx -p typescript tsc --noEmit -p ${target.tsConfigPath}`, {
|
|
685
|
-
cwd: projectRoot,
|
|
686
|
-
stdio: 'inherit'
|
|
789
|
+
cwd: projectRoot, stdio: 'inherit'
|
|
687
790
|
});
|
|
688
791
|
console.log(' ✓ Type check passed');
|
|
689
792
|
}
|
|
@@ -709,7 +812,7 @@ Examples:
|
|
|
709
812
|
}
|
|
710
813
|
findAllTsFiles(dir, userExclude = []) {
|
|
711
814
|
const files = [];
|
|
712
|
-
const excludePatterns = ['*.spec.ts', '*.test.ts', '
|
|
815
|
+
const excludePatterns = ['*.spec.ts', '*.test.ts', 'fluff-app*.ts', ...userExclude];
|
|
713
816
|
const walk = (currentDir) => {
|
|
714
817
|
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
715
818
|
for (const entry of entries) {
|
|
@@ -888,44 +991,4 @@ Examples:
|
|
|
888
991
|
}
|
|
889
992
|
}
|
|
890
993
|
}
|
|
891
|
-
static parseArgs(argv) {
|
|
892
|
-
const options = {};
|
|
893
|
-
const args = [];
|
|
894
|
-
let i = 0;
|
|
895
|
-
while (i < argv.length) {
|
|
896
|
-
const arg = argv[i];
|
|
897
|
-
if (arg === '--nx' && argv[i + 1]) {
|
|
898
|
-
options.nxPackage = argv[i + 1];
|
|
899
|
-
i += 2;
|
|
900
|
-
}
|
|
901
|
-
else if (arg === '--cwd' && argv[i + 1]) {
|
|
902
|
-
options.cwd = argv[i + 1];
|
|
903
|
-
i += 2;
|
|
904
|
-
}
|
|
905
|
-
else if (arg === '--no-gzip') {
|
|
906
|
-
options.noGzip = true;
|
|
907
|
-
i++;
|
|
908
|
-
}
|
|
909
|
-
else if (arg === '--no-minify') {
|
|
910
|
-
options.noMinify = true;
|
|
911
|
-
i++;
|
|
912
|
-
}
|
|
913
|
-
else if (arg === '--gz-script-tag') {
|
|
914
|
-
options.gzScriptTag = true;
|
|
915
|
-
i++;
|
|
916
|
-
}
|
|
917
|
-
else if (arg?.startsWith('--')) {
|
|
918
|
-
console.error(`Unknown option: ${arg}`);
|
|
919
|
-
process.exit(1);
|
|
920
|
-
}
|
|
921
|
-
else if (arg) {
|
|
922
|
-
args.push(arg);
|
|
923
|
-
i++;
|
|
924
|
-
}
|
|
925
|
-
else {
|
|
926
|
-
i++;
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
return { options, args };
|
|
930
|
-
}
|
|
931
994
|
}
|