zero-query 0.2.5 → 0.2.7
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 +272 -1401
- package/cli.js +237 -31
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +2 -2
- package/dist/zquery.min.js +2 -2
- package/package.json +2 -3
package/cli.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* zQuery CLI
|
|
5
5
|
*
|
|
6
|
-
* Zero-dependency command-line tool for building the zQuery library
|
|
7
|
-
*
|
|
6
|
+
* Zero-dependency command-line tool for building the zQuery library,
|
|
7
|
+
* bundling zQuery-based applications, and running a dev server with
|
|
8
|
+
* live-reload.
|
|
8
9
|
*
|
|
9
10
|
* Usage:
|
|
10
11
|
* zquery build Build the zQuery library (dist/)
|
|
@@ -13,7 +14,9 @@
|
|
|
13
14
|
* zquery bundle scripts/app.js Specify entry explicitly
|
|
14
15
|
* zquery bundle -o build/ Custom output directory
|
|
15
16
|
* zquery bundle --html other.html Use a specific HTML file instead of auto-detected
|
|
16
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* zquery dev [root] Start dev server with live-reload
|
|
19
|
+
* zquery dev --port 8080 Custom port (default: 3100)
|
|
17
20
|
*
|
|
18
21
|
* Smart defaults (no flags needed for typical projects):
|
|
19
22
|
* - Entry is auto-detected from index.html's <script type="module" src="...">
|
|
@@ -24,6 +27,7 @@
|
|
|
24
27
|
* Examples:
|
|
25
28
|
* cd my-app && npx zero-query bundle # just works!
|
|
26
29
|
* npx zero-query bundle path/to/scripts/app.js # works from anywhere
|
|
30
|
+
* cd my-app && npx zquery dev # dev server with live-reload
|
|
27
31
|
*/
|
|
28
32
|
|
|
29
33
|
const fs = require('fs');
|
|
@@ -412,7 +416,6 @@ function bundleApp() {
|
|
|
412
416
|
}
|
|
413
417
|
|
|
414
418
|
const outPath = option('out', 'o', null);
|
|
415
|
-
const watchMode = flag('watch', 'w');
|
|
416
419
|
|
|
417
420
|
// Auto-detect index.html by walking up from the entry file, then check cwd
|
|
418
421
|
let htmlFile = option('html', null, null);
|
|
@@ -595,26 +598,6 @@ function bundleApp() {
|
|
|
595
598
|
}
|
|
596
599
|
|
|
597
600
|
doBuild();
|
|
598
|
-
|
|
599
|
-
// Watch mode
|
|
600
|
-
if (watchMode) {
|
|
601
|
-
const watchDirs = new Set();
|
|
602
|
-
const files = walkImportGraph(entry);
|
|
603
|
-
files.forEach(f => watchDirs.add(path.dirname(f)));
|
|
604
|
-
|
|
605
|
-
console.log(' Watching for changes...\n');
|
|
606
|
-
let debounceTimer;
|
|
607
|
-
for (const dir of watchDirs) {
|
|
608
|
-
fs.watch(dir, { recursive: true }, (_, filename) => {
|
|
609
|
-
if (!filename || !filename.endsWith('.js')) return;
|
|
610
|
-
clearTimeout(debounceTimer);
|
|
611
|
-
debounceTimer = setTimeout(() => {
|
|
612
|
-
console.log(` Changed: ${filename} — rebuilding...`);
|
|
613
|
-
try { doBuild(); } catch (e) { console.error(` ✗ ${e.message}`); }
|
|
614
|
-
}, 200);
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
601
|
}
|
|
619
602
|
|
|
620
603
|
/**
|
|
@@ -745,13 +728,232 @@ function rewriteHtml(projectRoot, htmlRelPath, bundleFile, includeLib, bundledFi
|
|
|
745
728
|
}
|
|
746
729
|
|
|
747
730
|
|
|
731
|
+
// ---------------------------------------------------------------------------
|
|
732
|
+
// "dev" command — development server with live-reload
|
|
733
|
+
// ---------------------------------------------------------------------------
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* SSE live-reload client script injected into served HTML.
|
|
737
|
+
* Connects to /__zq_reload, reloads on 'reload' events,
|
|
738
|
+
* and hot-swaps CSS on 'css' events without a full reload.
|
|
739
|
+
*/
|
|
740
|
+
const LIVE_RELOAD_SNIPPET = `<script>
|
|
741
|
+
(function(){
|
|
742
|
+
var es, timer;
|
|
743
|
+
function connect(){
|
|
744
|
+
es = new EventSource('/__zq_reload');
|
|
745
|
+
es.addEventListener('reload', function(){ location.reload(); });
|
|
746
|
+
es.addEventListener('css', function(e){
|
|
747
|
+
var sheets = document.querySelectorAll('link[rel="stylesheet"]');
|
|
748
|
+
sheets.forEach(function(l){
|
|
749
|
+
var href = l.getAttribute('href');
|
|
750
|
+
if(!href) return;
|
|
751
|
+
var sep = href.indexOf('?') >= 0 ? '&' : '?';
|
|
752
|
+
l.setAttribute('href', href.replace(/[?&]_zqr=\\d+/, '') + sep + '_zqr=' + Date.now());
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
es.onerror = function(){
|
|
756
|
+
es.close();
|
|
757
|
+
clearTimeout(timer);
|
|
758
|
+
timer = setTimeout(connect, 2000);
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
connect();
|
|
762
|
+
})();
|
|
763
|
+
</script>`;
|
|
764
|
+
|
|
765
|
+
function devServer() {
|
|
766
|
+
let zeroHttp;
|
|
767
|
+
try {
|
|
768
|
+
zeroHttp = require('zero-http');
|
|
769
|
+
} catch (_) {
|
|
770
|
+
console.error(`\n ✗ zero-http is required for the dev server.`);
|
|
771
|
+
console.error(` Install it: npm install zero-http --save-dev\n`);
|
|
772
|
+
process.exit(1);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
const { createApp, static: serveStatic } = zeroHttp;
|
|
776
|
+
|
|
777
|
+
// Determine the project root to serve
|
|
778
|
+
let root = null;
|
|
779
|
+
for (let i = 1; i < args.length; i++) {
|
|
780
|
+
if (!args[i].startsWith('-') && args[i - 1] !== '-p' && args[i - 1] !== '--port') {
|
|
781
|
+
root = path.resolve(process.cwd(), args[i]);
|
|
782
|
+
break;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
if (!root) {
|
|
786
|
+
// Auto-detect: look for index.html in cwd or common sub-dirs
|
|
787
|
+
const candidates = [
|
|
788
|
+
process.cwd(),
|
|
789
|
+
path.join(process.cwd(), 'public'),
|
|
790
|
+
path.join(process.cwd(), 'src'),
|
|
791
|
+
];
|
|
792
|
+
for (const c of candidates) {
|
|
793
|
+
if (fs.existsSync(path.join(c, 'index.html'))) { root = c; break; }
|
|
794
|
+
}
|
|
795
|
+
if (!root) root = process.cwd();
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const PORT = parseInt(option('port', 'p', '3100'));
|
|
799
|
+
|
|
800
|
+
// SSE clients for live-reload
|
|
801
|
+
const sseClients = new Set();
|
|
802
|
+
|
|
803
|
+
const app = createApp();
|
|
804
|
+
|
|
805
|
+
// SSE endpoint — clients connect here for reload notifications
|
|
806
|
+
app.get('/__zq_reload', (req, res) => {
|
|
807
|
+
const sse = res.sse({ keepAlive: 30000, keepAliveComment: 'ping' });
|
|
808
|
+
sseClients.add(sse);
|
|
809
|
+
sse.on('close', () => sseClients.delete(sse));
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
// Auto-resolve zquery.min.js — serve the freshest version regardless of
|
|
813
|
+
// what's on disk in the project. Priority:
|
|
814
|
+
// 1. Package dist/ (when running from the repo after `npm run build`)
|
|
815
|
+
// 2. node_modules/zero-query/dist/ (when installed as a dependency)
|
|
816
|
+
// 3. Fall through to static serving (vendor copy on disk)
|
|
817
|
+
// Registered as middleware so it runs BEFORE serveStatic.
|
|
818
|
+
app.use((req, res, next) => {
|
|
819
|
+
const basename = path.basename(req.url.split('?')[0]).toLowerCase();
|
|
820
|
+
if (basename !== 'zquery.min.js') return next();
|
|
821
|
+
|
|
822
|
+
const candidates = [
|
|
823
|
+
path.join(__dirname, 'dist', 'zquery.min.js'), // package repo
|
|
824
|
+
path.join(root, 'node_modules', 'zero-query', 'dist', 'zquery.min.js'), // npm dep
|
|
825
|
+
];
|
|
826
|
+
for (const p of candidates) {
|
|
827
|
+
if (fs.existsSync(p)) {
|
|
828
|
+
res.set('Content-Type', 'application/javascript; charset=utf-8');
|
|
829
|
+
res.set('Cache-Control', 'no-cache');
|
|
830
|
+
res.send(fs.readFileSync(p, 'utf-8'));
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
next(); // fall through to static / 404
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// Static file serving
|
|
838
|
+
app.use(serveStatic(root, { index: false, dotfiles: 'ignore' }));
|
|
839
|
+
|
|
840
|
+
// SPA fallback — inject live-reload snippet into HTML
|
|
841
|
+
app.get('*', (req, res) => {
|
|
842
|
+
if (path.extname(req.url) && path.extname(req.url) !== '.html') {
|
|
843
|
+
res.status(404).send('Not Found');
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const indexPath = path.join(root, 'index.html');
|
|
847
|
+
if (!fs.existsSync(indexPath)) {
|
|
848
|
+
res.status(404).send('index.html not found');
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
let html = fs.readFileSync(indexPath, 'utf-8');
|
|
852
|
+
// Inject live-reload snippet before </body> or at end
|
|
853
|
+
if (html.includes('</body>')) {
|
|
854
|
+
html = html.replace('</body>', LIVE_RELOAD_SNIPPET + '\n</body>');
|
|
855
|
+
} else {
|
|
856
|
+
html += LIVE_RELOAD_SNIPPET;
|
|
857
|
+
}
|
|
858
|
+
res.html(html);
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// Broadcast a reload event to all connected SSE clients
|
|
862
|
+
function broadcast(eventType, data) {
|
|
863
|
+
for (const sse of sseClients) {
|
|
864
|
+
try { sse.event(eventType, data || ''); } catch (_) { sseClients.delete(sse); }
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// File watcher — watch the project root for changes
|
|
869
|
+
const WATCH_EXTS = new Set(['.js', '.css', '.html', '.htm', '.json', '.svg']);
|
|
870
|
+
const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', '.cache']);
|
|
871
|
+
let debounceTimer;
|
|
872
|
+
|
|
873
|
+
function shouldWatch(filename) {
|
|
874
|
+
if (!filename) return false;
|
|
875
|
+
const ext = path.extname(filename).toLowerCase();
|
|
876
|
+
return WATCH_EXTS.has(ext);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
function isIgnored(filepath) {
|
|
880
|
+
const parts = filepath.split(path.sep);
|
|
881
|
+
return parts.some(p => IGNORE_DIRS.has(p));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Collect directories to watch (walk root, skip ignored)
|
|
885
|
+
function collectWatchDirs(dir) {
|
|
886
|
+
const dirs = [dir];
|
|
887
|
+
try {
|
|
888
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
889
|
+
for (const entry of entries) {
|
|
890
|
+
if (!entry.isDirectory()) continue;
|
|
891
|
+
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
892
|
+
const sub = path.join(dir, entry.name);
|
|
893
|
+
dirs.push(...collectWatchDirs(sub));
|
|
894
|
+
}
|
|
895
|
+
} catch (_) {}
|
|
896
|
+
return dirs;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
const watchDirs = collectWatchDirs(root);
|
|
900
|
+
const watchers = [];
|
|
901
|
+
|
|
902
|
+
for (const dir of watchDirs) {
|
|
903
|
+
try {
|
|
904
|
+
const watcher = fs.watch(dir, (eventType, filename) => {
|
|
905
|
+
if (!shouldWatch(filename)) return;
|
|
906
|
+
const fullPath = path.join(dir, filename || '');
|
|
907
|
+
if (isIgnored(fullPath)) return;
|
|
908
|
+
|
|
909
|
+
clearTimeout(debounceTimer);
|
|
910
|
+
debounceTimer = setTimeout(() => {
|
|
911
|
+
const rel = path.relative(root, fullPath).replace(/\\/g, '/');
|
|
912
|
+
const ext = path.extname(filename).toLowerCase();
|
|
913
|
+
const now = new Date().toLocaleTimeString();
|
|
914
|
+
|
|
915
|
+
if (ext === '.css') {
|
|
916
|
+
console.log(` ${now} \x1b[35m css \x1b[0m ${rel}`);
|
|
917
|
+
broadcast('css', rel);
|
|
918
|
+
} else {
|
|
919
|
+
console.log(` ${now} \x1b[36m reload \x1b[0m ${rel}`);
|
|
920
|
+
broadcast('reload', rel);
|
|
921
|
+
}
|
|
922
|
+
}, 100);
|
|
923
|
+
});
|
|
924
|
+
watchers.push(watcher);
|
|
925
|
+
} catch (_) {}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
app.listen(PORT, () => {
|
|
929
|
+
console.log(`\n \x1b[1mzQuery Dev Server\x1b[0m`);
|
|
930
|
+
console.log(` \x1b[2m${'─'.repeat(40)}\x1b[0m`);
|
|
931
|
+
console.log(` Local: \x1b[36mhttp://localhost:${PORT}/\x1b[0m`);
|
|
932
|
+
console.log(` Root: ${path.relative(process.cwd(), root) || '.'}`);
|
|
933
|
+
console.log(` Live Reload: \x1b[32menabled\x1b[0m (SSE)`);
|
|
934
|
+
console.log(` Watching: ${WATCH_EXTS.size} file types in ${watchDirs.length} director${watchDirs.length === 1 ? 'y' : 'ies'}`);
|
|
935
|
+
console.log(` \x1b[2m${'─'.repeat(40)}\x1b[0m`);
|
|
936
|
+
console.log(` Press Ctrl+C to stop\n`);
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
// Graceful shutdown
|
|
940
|
+
process.on('SIGINT', () => {
|
|
941
|
+
console.log('\n Shutting down...');
|
|
942
|
+
watchers.forEach(w => w.close());
|
|
943
|
+
for (const sse of sseClients) { try { sse.close(); } catch (_) {} }
|
|
944
|
+
app.close(() => process.exit(0));
|
|
945
|
+
setTimeout(() => process.exit(0), 1000);
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
|
|
748
950
|
// ---------------------------------------------------------------------------
|
|
749
951
|
// Help
|
|
750
952
|
// ---------------------------------------------------------------------------
|
|
751
953
|
|
|
752
954
|
function showHelp() {
|
|
753
955
|
console.log(`
|
|
754
|
-
zQuery CLI — build &
|
|
956
|
+
zQuery CLI — build, bundle & dev tool
|
|
755
957
|
|
|
756
958
|
COMMANDS
|
|
757
959
|
|
|
@@ -761,7 +963,9 @@ function showHelp() {
|
|
|
761
963
|
bundle [entry] Bundle app ES modules into a single file
|
|
762
964
|
--out, -o <path> Output directory (default: dist/ next to index.html)
|
|
763
965
|
--html <file> Use a specific HTML file (default: auto-detected)
|
|
764
|
-
|
|
966
|
+
|
|
967
|
+
dev [root] Start a dev server with live-reload
|
|
968
|
+
--port, -p <number> Port number (default: 3100)
|
|
765
969
|
|
|
766
970
|
SMART DEFAULTS
|
|
767
971
|
|
|
@@ -788,11 +992,14 @@ function showHelp() {
|
|
|
788
992
|
|
|
789
993
|
DEVELOPMENT
|
|
790
994
|
|
|
791
|
-
|
|
792
|
-
|
|
995
|
+
zquery dev start a dev server with live-reload (port 3100)
|
|
996
|
+
zquery dev --port 8080 custom port
|
|
793
997
|
|
|
794
998
|
EXAMPLES
|
|
795
999
|
|
|
1000
|
+
# Start dev server with live-reload
|
|
1001
|
+
cd my-app && zquery dev
|
|
1002
|
+
|
|
796
1003
|
# Build the library only
|
|
797
1004
|
zquery build
|
|
798
1005
|
|
|
@@ -805,9 +1012,6 @@ function showHelp() {
|
|
|
805
1012
|
# Custom output directory
|
|
806
1013
|
zquery bundle -o build/
|
|
807
1014
|
|
|
808
|
-
# Watch mode
|
|
809
|
-
zquery bundle --watch
|
|
810
|
-
|
|
811
1015
|
The bundler walks the ES module import graph starting from the entry
|
|
812
1016
|
file, topologically sorts dependencies, strips import/export syntax,
|
|
813
1017
|
and concatenates everything into a single IIFE with content-hashed
|
|
@@ -827,6 +1031,8 @@ if (!command || command === '--help' || command === '-h' || command === 'help')
|
|
|
827
1031
|
buildLibrary();
|
|
828
1032
|
} else if (command === 'bundle') {
|
|
829
1033
|
bundleApp();
|
|
1034
|
+
} else if (command === 'dev') {
|
|
1035
|
+
devServer();
|
|
830
1036
|
} else {
|
|
831
1037
|
console.error(`\n Unknown command: ${command}\n Run "zquery --help" for usage.\n`);
|
|
832
1038
|
process.exit(1);
|
package/dist/zquery.dist.zip
CHANGED
|
Binary file
|
package/dist/zquery.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* zQuery (zeroQuery) v0.2.
|
|
2
|
+
* zQuery (zeroQuery) v0.2.7
|
|
3
3
|
* Lightweight Frontend Library
|
|
4
4
|
* https://github.com/tonywied17/zero-query
|
|
5
5
|
* (c) 2026 Anthony Wiedman — MIT License
|
|
@@ -2576,7 +2576,7 @@ $.session = session;
|
|
|
2576
2576
|
$.bus = bus;
|
|
2577
2577
|
|
|
2578
2578
|
// --- Meta ------------------------------------------------------------------
|
|
2579
|
-
$.version = '0.2.
|
|
2579
|
+
$.version = '0.2.7';
|
|
2580
2580
|
$.meta = {}; // populated at build time by CLI bundler
|
|
2581
2581
|
|
|
2582
2582
|
$.noConflict = () => {
|
package/dist/zquery.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* zQuery (zeroQuery) v0.2.
|
|
2
|
+
* zQuery (zeroQuery) v0.2.7
|
|
3
3
|
* Lightweight Frontend Library
|
|
4
4
|
* https://github.com/tonywied17/zero-query
|
|
5
5
|
* (c) 2026 Anthony Wiedman — MIT License
|
|
@@ -13,5 +13,5 @@ class Router { constructor(config = {}) { this._el = null; const isFile = typeof
|
|
|
13
13
|
class Store { constructor(config = {}) { this._subscribers = new Map(); this._wildcards = new Set(); this._actions = config.actions || {}; this._getters = config.getters || {}; this._middleware = []; this._history = []; this._debug = config.debug || false; const initial = typeof config.state === 'function' ? config.state() : { ...(config.state || {}) }; this.state = reactive(initial, (key, value, old) => { const subs = this._subscribers.get(key); if (subs) subs.forEach(fn => fn(value, old, key)); this._wildcards.forEach(fn => fn(key, value, old)); }); this.getters = {}; for (const [name, fn] of Object.entries(this._getters)) { Object.defineProperty(this.getters, name, { get: () => fn(this.state.__raw || this.state), enumerable: true }); } } dispatch(name, ...args) { const action = this._actions[name]; if (!action) { console.warn(`zQuery Store: Unknown action "${name}"`); return; } for (const mw of this._middleware) { const result = mw(name, args, this.state); if (result === false) return; } if (this._debug) { console.log(`%c[Store] ${name}`, 'color: #4CAF50; font-weight: bold;', ...args); } const result = action(this.state, ...args); this._history.push({ action: name, args, timestamp: Date.now() }); return result; } subscribe(keyOrFn, fn) { if (typeof keyOrFn === 'function') { this._wildcards.add(keyOrFn); return () => this._wildcards.delete(keyOrFn); } if (!this._subscribers.has(keyOrFn)) { this._subscribers.set(keyOrFn, new Set()); } this._subscribers.get(keyOrFn).add(fn); return () => this._subscribers.get(keyOrFn)?.delete(fn); } snapshot() { return JSON.parse(JSON.stringify(this.state.__raw || this.state)); } replaceState(newState) { const raw = this.state.__raw || this.state; for (const key of Object.keys(raw)) { delete this.state[key]; } Object.assign(this.state, newState); } use(fn) { this._middleware.push(fn); return this; } get history() { return [...this._history]; } reset(initialState) { this.replaceState(initialState); this._history = []; }
|
|
14
14
|
const _config = { baseURL: '', headers: { 'Content-Type': 'application/json' }, timeout: 30000,
|
|
15
15
|
function debounce(fn, ms = 250) { let timer; const debounced = (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; debounced.cancel = () => clearTimeout(timer); return debounced;
|
|
16
|
-
function $(selector, context) { if (typeof selector === 'function') { query.ready(selector); return; } return query(selector, context);
|
|
16
|
+
function $(selector, context) { if (typeof selector === 'function') { query.ready(selector); return; } return query(selector, context);
|
|
17
17
|
})(typeof window !== 'undefined' ? window : globalThis);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zero-query",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7",
|
|
4
4
|
"description": "Lightweight modern frontend library — jQuery-like selectors, reactive components, SPA router, and state management with zero dependencies.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "node build.js",
|
|
21
|
-
"dev": "
|
|
22
|
-
"serve": "node examples/starter-app/local-server.js",
|
|
21
|
+
"dev": "node cli.js dev examples/starter-app",
|
|
23
22
|
"dev-lib": "node build.js --watch",
|
|
24
23
|
"bundle": "node cli.js bundle",
|
|
25
24
|
"bundle:app": "node cli.js bundle examples/starter-app/scripts/app.js"
|