@sprlab/wccompiler 0.12.0 → 0.12.1
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/README.md +46 -7
- package/bin/wcc.js +53 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -458,12 +458,13 @@ Consumer (receives data via template props):
|
|
|
458
458
|
|
|
459
459
|
## Nested Components
|
|
460
460
|
|
|
461
|
-
Components can use other components in their templates
|
|
461
|
+
Components can import and use other components in their templates using PascalCase tags:
|
|
462
462
|
|
|
463
463
|
```html
|
|
464
|
+
<!-- src/nested/wcc-profile.wcc -->
|
|
464
465
|
<script>
|
|
465
466
|
import { defineComponent, signal } from 'wcc'
|
|
466
|
-
import './wcc-badge.wcc'
|
|
467
|
+
import WccBadge from './wcc-badge.wcc'
|
|
467
468
|
|
|
468
469
|
export default defineComponent({ tag: 'wcc-profile' })
|
|
469
470
|
|
|
@@ -476,15 +477,17 @@ function increment() {
|
|
|
476
477
|
|
|
477
478
|
<template>
|
|
478
479
|
<div class="profile">
|
|
479
|
-
<
|
|
480
|
+
<WccBadge :count="count()" @click="increment"></WccBadge>
|
|
480
481
|
</div>
|
|
481
482
|
</template>
|
|
482
483
|
```
|
|
483
484
|
|
|
484
|
-
- **
|
|
485
|
-
- **
|
|
485
|
+
- **Named import**: `import WccBadge from './wcc-badge.wcc'` — the PascalCase identifier becomes the tag alias in the template
|
|
486
|
+
- **Side-effect import**: `import './wcc-child.wcc'` — registers the child without using it in the template (for programmatic creation)
|
|
486
487
|
- **Reactive props**: Use `:prop="expr"` to pass reactive data down — updates automatically when the expression changes
|
|
487
488
|
- **Event listening**: Use `@event="handler"` to listen to custom events emitted by the child
|
|
489
|
+
- **Compile-time validation**: Using a PascalCase tag without a matching import throws an error at build time
|
|
490
|
+
- **Hyphenated tags**: Tags like `<my-element>` without a corresponding import are treated as plain custom elements (no import generated)
|
|
488
491
|
|
|
489
492
|
## Lifecycle Hooks
|
|
490
493
|
|
|
@@ -613,12 +616,48 @@ timer.value!.start() // ✅ typed
|
|
|
613
616
|
## CLI
|
|
614
617
|
|
|
615
618
|
```bash
|
|
616
|
-
wcc build
|
|
617
|
-
wcc
|
|
619
|
+
wcc build # Compile all .wcc files from input/ to output/
|
|
620
|
+
wcc build --bundle # Compile + produce a single bundle.js (works from file://)
|
|
621
|
+
wcc build --minify # Compile with minification
|
|
622
|
+
wcc build --bundle --minify # Production bundle (smallest output)
|
|
623
|
+
wcc dev # Build + watch + live-reload dev server
|
|
618
624
|
```
|
|
619
625
|
|
|
620
626
|
The CLI discovers all `.wcc` files in your source directory and compiles each into a standalone `.js` file.
|
|
621
627
|
|
|
628
|
+
### Bundle Mode
|
|
629
|
+
|
|
630
|
+
The `--bundle` flag produces a single `bundle.js` file that includes all components and their dependencies in one IIFE (Immediately Invoked Function Expression). This file:
|
|
631
|
+
|
|
632
|
+
- Works with `<script src="bundle.js">` (no `type="module"` needed)
|
|
633
|
+
- Works from `file://` protocol (no server required)
|
|
634
|
+
- Includes all child component imports resolved and inlined
|
|
635
|
+
- Includes the reactive runtime
|
|
636
|
+
- Supports `--minify` for production
|
|
637
|
+
|
|
638
|
+
```html
|
|
639
|
+
<!-- Works by double-clicking the HTML file — no server needed -->
|
|
640
|
+
<!DOCTYPE html>
|
|
641
|
+
<html>
|
|
642
|
+
<body>
|
|
643
|
+
<wcc-my-app></wcc-my-app>
|
|
644
|
+
<script src="dist/bundle.js"></script>
|
|
645
|
+
</body>
|
|
646
|
+
</html>
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
**When to use `--bundle`:**
|
|
650
|
+
- Static HTML files opened from disk
|
|
651
|
+
- Electron apps loading local files
|
|
652
|
+
- Offline-first applications
|
|
653
|
+
- Quick prototyping without a dev server
|
|
654
|
+
- Distributing a complete app as HTML + JS
|
|
655
|
+
|
|
656
|
+
**When NOT to use `--bundle`:**
|
|
657
|
+
- Apps served via HTTP (use ES modules for better caching)
|
|
658
|
+
- When you need per-component lazy loading
|
|
659
|
+
- When using a bundler like Vite/Webpack (they handle bundling themselves)
|
|
660
|
+
|
|
622
661
|
### Configuration
|
|
623
662
|
|
|
624
663
|
Create `wcc.config.js` in your project root:
|
package/bin/wcc.js
CHANGED
|
@@ -291,6 +291,26 @@ function discoverFiles(dir) {
|
|
|
291
291
|
return results;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
+
/**
|
|
295
|
+
* Discovers compiled .js entry points in the output directory.
|
|
296
|
+
* Excludes runtime files, stubs, and metadata.
|
|
297
|
+
*/
|
|
298
|
+
function discoverCompiledEntries(outputDir) {
|
|
299
|
+
const skip = new Set(['__wcc-signals.js', 'wcc-runtime.js', 'wcc-react.js', 'wcc-vue.js', 'bundle.js']);
|
|
300
|
+
const results = [];
|
|
301
|
+
function walk(dir) {
|
|
302
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
303
|
+
if (entry.isDirectory()) {
|
|
304
|
+
walk(join(dir, entry.name));
|
|
305
|
+
} else if (entry.isFile() && entry.name.endsWith('.js') && !skip.has(entry.name) && !entry.name.endsWith('.d.ts')) {
|
|
306
|
+
results.push(join(dir, entry.name));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
walk(outputDir);
|
|
311
|
+
return results;
|
|
312
|
+
}
|
|
313
|
+
|
|
294
314
|
async function main() {
|
|
295
315
|
const cwd = process.cwd();
|
|
296
316
|
const config = await loadConfig(cwd);
|
|
@@ -298,10 +318,43 @@ async function main() {
|
|
|
298
318
|
// CLI flags override config
|
|
299
319
|
if (process.argv.includes('--minify')) config.minify = true;
|
|
300
320
|
if (process.argv.includes('--comments')) config.comments = true;
|
|
321
|
+
const shouldBundle = process.argv.includes('--bundle');
|
|
301
322
|
|
|
302
323
|
if (command === 'build') {
|
|
303
324
|
const errors = await build(config, cwd);
|
|
304
325
|
if (errors > 0) process.exit(1);
|
|
326
|
+
|
|
327
|
+
// Bundle step: produce a single IIFE file from all compiled entry points
|
|
328
|
+
if (shouldBundle) {
|
|
329
|
+
const { build: esbuild } = await import('esbuild');
|
|
330
|
+
const outputDir = resolve(cwd, config.output);
|
|
331
|
+
const entryPoints = discoverCompiledEntries(outputDir);
|
|
332
|
+
|
|
333
|
+
if (entryPoints.length > 0) {
|
|
334
|
+
// Generate a virtual entry that imports all components
|
|
335
|
+
const bundleEntry = join(outputDir, '__bundle-entry.js');
|
|
336
|
+
const imports = entryPoints.map(f => {
|
|
337
|
+
let rel = relative(outputDir, f).replace(/\\/g, '/');
|
|
338
|
+
if (!rel.startsWith('.')) rel = './' + rel;
|
|
339
|
+
return `import '${rel}';`;
|
|
340
|
+
}).join('\n');
|
|
341
|
+
writeFileSync(bundleEntry, imports);
|
|
342
|
+
|
|
343
|
+
await esbuild({
|
|
344
|
+
entryPoints: [bundleEntry],
|
|
345
|
+
bundle: true,
|
|
346
|
+
format: 'iife',
|
|
347
|
+
outfile: join(outputDir, 'bundle.js'),
|
|
348
|
+
minify: !!config.minify,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Clean up temp entry
|
|
352
|
+
const { unlinkSync } = await import('node:fs');
|
|
353
|
+
unlinkSync(bundleEntry);
|
|
354
|
+
|
|
355
|
+
console.log(`Bundled ${entryPoints.length} components → ${config.output}/bundle.js`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
305
358
|
} else if (command === 'dev') {
|
|
306
359
|
await build(config, cwd);
|
|
307
360
|
const outputDir = resolve(cwd, config.output);
|
package/package.json
CHANGED