@olegkuibar/plunk 0.7.3 → 0.7.5-canary.28557d2
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 +27 -7
- package/dist/{chunk-XAVMCPKI.mjs → chunk-CIY4E6PA.mjs} +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{dev-QMDH32K7.mjs → dev-DBGYZOIV.mjs} +1 -1
- package/dist/index.mjs +71 -4
- package/dist/{push-AM6JDGUN.mjs → push-AUAGCBYK.mjs} +1 -1
- package/dist/vite-plugin.mjs +76 -45
- package/dist/watcher-SY45L3SS.mjs +3 -0
- package/package.json +1 -1
- package/dist/watcher-JAR4XGGM.mjs +0 -3
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Local npm package development without symlinks. Copies built files directly into
|
|
|
22
22
|
```bash
|
|
23
23
|
npx plunk init # set up your app
|
|
24
24
|
plunk add my-lib # link a package
|
|
25
|
-
plunk
|
|
25
|
+
plunk dev # watch → build → push (continuous)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
## Why plunk?
|
|
@@ -48,7 +48,7 @@ graph LR
|
|
|
48
48
|
1. `publish` copies built files to a local store at `~/.plunk/store/`
|
|
49
49
|
2. `add` copies from store into your app's `node_modules/`
|
|
50
50
|
3. `push` = publish + copy to all consumers
|
|
51
|
-
4.
|
|
51
|
+
4. `dev` = watch → build → push loop (or `push --watch`)
|
|
52
52
|
|
|
53
53
|
> Uses CoW reflinks for instant copy-on-write on APFS/btrfs/ReFS, with automatic fallback. Reflink support is probed once per volume and cached — no wasted syscalls. Only changed files are re-copied (xxhash-based diffing).
|
|
54
54
|
|
|
@@ -68,9 +68,9 @@ plunk publish
|
|
|
68
68
|
cd my-app
|
|
69
69
|
plunk add my-lib
|
|
70
70
|
|
|
71
|
-
# Continuous dev: watch → build → push
|
|
71
|
+
# Continuous dev: watch → build → push (auto-detects build command)
|
|
72
72
|
cd my-lib
|
|
73
|
-
plunk
|
|
73
|
+
plunk dev
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
## At a glance
|
|
@@ -97,9 +97,7 @@ npx @olegkuibar/plunk init # set up a consumer project
|
|
|
97
97
|
|
|
98
98
|
## Try it online
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
**[Open Playground](https://plunk-playground.vercel.app)** — Run real `plunk publish`, `plunk add`, and `plunk push` commands with live HMR preview.
|
|
100
|
+
**[Open Playground](https://plunk.olegkuibar.dev)** — run `plunk publish`, `plunk add`, and `plunk push` in the browser with live HMR preview.
|
|
103
101
|
|
|
104
102
|
## Documentation
|
|
105
103
|
|
|
@@ -121,6 +119,28 @@ Experience plunk directly in your browser with our interactive playground:
|
|
|
121
119
|
| [Playground](playground/) | Interactive browser-based playground |
|
|
122
120
|
| [Contributing](CONTRIBUTING.md) | Dev setup and guidelines |
|
|
123
121
|
|
|
122
|
+
## Acknowledgments
|
|
123
|
+
|
|
124
|
+
plunk and its playground are built on top of excellent open-source projects:
|
|
125
|
+
|
|
126
|
+
- [chokidar](https://github.com/paulmillr/chokidar) — file watching
|
|
127
|
+
- [xxhash-wasm](https://github.com/nicolo-ribaudo/xxhash-wasm-legacy) — fast file hashing for incremental sync
|
|
128
|
+
- [citty](https://github.com/unjs/citty) — CLI framework
|
|
129
|
+
- [tsup](https://github.com/egoist/tsup) — TypeScript bundler
|
|
130
|
+
- [vitest](https://github.com/vitest-dev/vitest) — test runner
|
|
131
|
+
- [WebContainers](https://webcontainers.io) — in-browser Node.js runtime (playground)
|
|
132
|
+
- [Vite](https://vite.dev) — frontend tooling
|
|
133
|
+
- [React](https://react.dev) — UI framework
|
|
134
|
+
- [Monaco Editor](https://microsoft.github.io/monaco-editor/) — code editor (playground)
|
|
135
|
+
- [xterm.js](https://xtermjs.org) — terminal emulator (playground)
|
|
136
|
+
- [Tailwind CSS](https://tailwindcss.com) — styling
|
|
137
|
+
|
|
138
|
+
Thank you to the maintainers and contributors of these projects.
|
|
139
|
+
|
|
140
|
+
<p>
|
|
141
|
+
<a href="https://tailwindcss.com"><img src="https://img.shields.io/badge/Support-Tailwind_CSS-06B6D4?style=for-the-badge&logo=tailwindcss&logoColor=white" alt="Support Tailwind CSS" /></a>
|
|
142
|
+
</p>
|
|
143
|
+
|
|
124
144
|
## License
|
|
125
145
|
|
|
126
146
|
[MIT](LICENSE)
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {createRequire}from'node:module';import {a as a$6}from'./chunk-SMIGYQFG.mjs';import {a as a$8}from'./chunk-7JG555TZ.mjs';import {a as a$7}from'./chunk-AC5FETT7.mjs';import {j,f,d as d$1}from'./chunk-LLVBXPQN.mjs';import {a as a$3}from'./chunk-PVMVWPLG.mjs';import {a as a$4}from'./chunk-HPF6K6WO.mjs';import {b as b$1}from'./chunk-EMRPZYLU.mjs';import {a as a$2}from'./chunk-MBKCCWSD.mjs';import {a as a$5}from'./chunk-OJJZ7CLB.mjs';import {a}from'./chunk-TMH7HIJ2.mjs';import {d}from'./chunk-R3RSOZXN.mjs';import {b}from'./chunk-ICCM7US5.mjs';import {a as a$1}from'./chunk-2VCW5RWI.mjs';import {readFile}from'fs/promises';import {join}from'path';globalThis.require=createRequire(import.meta.url);
|
|
3
|
-
var E=a(4);async function X(n,i={}){let a=new a$2,e=await a$3(n,{runScripts:i.runScripts,force:i.force});if(e.skipped){b.info("No changes to push");return}let t=await b$1(e.name,e.version);if(!t){a$4(`Failed to read store entry for ${e.name}@${e.version} after publish`);return}let r=await j(e.name);if(r.length===0){b.success(`Published ${e.name}@${e.version} to store`),b.info("No consumers registered yet. Run 'plunk add "+e.name+"' in a consumer project to start receiving pushes."),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:0,failedConsumers:0,copied:0,skipped:0,elapsed:a.elapsedMs()});return}let d$2=0,o=0,l=0,b$2=0,N=await Promise.all(r.map(c=>E(async()=>{let f$1=await f(c,e.name);if(!f$1)return d(`[push] No link found for ${e.name} in ${c}, skipping`),null;try{let m=await a$6(t,c,f$1.packageManager,{force:i.force});return await d$1(c,e.name,{...f$1,contentHash:t.meta.contentHash,linkedAt:new Date().toISOString(),buildId:t.meta.buildId??""}),m}catch(m){return b.warn(`Failed to push to ${c}: ${m instanceof Error?m.message:String(m)}`),null}})));for(let c of N)c?(d$2+=c.copied,o+=c.skipped,l++):b$2++;let M=e.buildId?` [${e.buildId}]`:"";b.success(`Pushed ${e.name}@${e.version}${M} to ${l} consumer(s) in ${a.elapsed()} (${d$2} files changed, ${o} unchanged)`),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:l,failedConsumers:b$2,copied:d$2,skipped:o,elapsed:a.elapsedMs()});}a$1(X,"doPush");function W(n){if(!n)return;let i=parseInt(n,10);return Number.isFinite(i)?i:void 0}a$1(W,"parseMs");async function Y(n,i,a){let{startWatcher:e}=await import('./watcher-
|
|
3
|
+
var E=a(4);async function X(n,i={}){let a=new a$2,e=await a$3(n,{runScripts:i.runScripts,force:i.force});if(e.skipped){b.info("No changes to push");return}let t=await b$1(e.name,e.version);if(!t){a$4(`Failed to read store entry for ${e.name}@${e.version} after publish`);return}let r=await j(e.name);if(r.length===0){b.success(`Published ${e.name}@${e.version} to store`),b.info("No consumers registered yet. Run 'plunk add "+e.name+"' in a consumer project to start receiving pushes."),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:0,failedConsumers:0,copied:0,skipped:0,elapsed:a.elapsedMs()});return}let d$2=0,o=0,l=0,b$2=0,N=await Promise.all(r.map(c=>E(async()=>{let f$1=await f(c,e.name);if(!f$1)return d(`[push] No link found for ${e.name} in ${c}, skipping`),null;try{let m=await a$6(t,c,f$1.packageManager,{force:i.force});return await d$1(c,e.name,{...f$1,contentHash:t.meta.contentHash,linkedAt:new Date().toISOString(),buildId:t.meta.buildId??""}),m}catch(m){return b.warn(`Failed to push to ${c}: ${m instanceof Error?m.message:String(m)}`),null}})));for(let c of N)c?(d$2+=c.copied,o+=c.skipped,l++):b$2++;let M=e.buildId?` [${e.buildId}]`:"";b.success(`Pushed ${e.name}@${e.version}${M} to ${l} consumer(s) in ${a.elapsed()} (${d$2} files changed, ${o} unchanged)`),a$5({name:e.name,version:e.version,buildId:e.buildId,consumers:l,failedConsumers:b$2,copied:d$2,skipped:o,elapsed:a.elapsedMs()});}a$1(X,"doPush");function W(n){if(!n)return;let i=parseInt(n,10);return Number.isFinite(i)?i:void 0}a$1(W,"parseMs");async function Y(n,i,a){let{startWatcher:e}=await import('./watcher-SY45L3SS.mjs'),{buildCmd:t,patterns:r}=await F(n,i),d=await e(n,{patterns:r,buildCmd:t,debounce:W(i.debounce),cooldown:W(i.cooldown)},a);await new Promise(o=>{let l=a$1(async()=>{b.info("Stopping watcher..."),await d.close(),o();},"cleanup");process.once("SIGINT",l),process.once("SIGTERM",l);});}a$1(Y,"startWatchMode");async function F(n,i){let a=i.build,e;if(!i.build){if(!i["skip-build"]){let t=await a$7(n),r=await a$8(n,t);r&&(a=r,b.info(`Auto-detected build command: ${r}`));}}if(a){let{exists:t}=await import('./fs-BUNURH4P.mjs'),r=["src","lib","source","app","pages","components"],d$1=(await Promise.all(r.map(async o=>({dir:o,exists:await t(join(n,o))})))).filter(o=>o.exists).map(o=>o.dir);e=d$1.length>0?d$1:["src","lib"],d(`[watch] Using source patterns with build command: ${e.join(", ")}`);}else {b.info("No build command detected \u2014 watching output directories directly");try{let t=JSON.parse(await readFile(join(n,"package.json"),"utf-8"));t.files&&t.files.length>0?(e=t.files,b.info(`Watching from package.json "files": ${e.join(", ")}`)):b.warn('No "files" field in package.json \u2014 falling back to watching src/ and lib/. Add a "files" field or use --build to specify a build command.');}catch(t){d(`[watch] Could not read package.json: ${t instanceof Error?t.message:String(t)}`);}}return {buildCmd:a,patterns:e}}a$1(F,"resolveWatchConfig");export{X as a,Y as b};
|
package/dist/cli.mjs
CHANGED
|
@@ -8,4 +8,4 @@ var o=c(a$1(),1);var r=`
|
|
|
8
8
|
\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557
|
|
9
9
|
\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
10
10
|
`;function a(){console.log(o.default.yellow(r)),console.log(o.default.cyan(" \u{1F4E6} Local npm package development without symlinks")),console.log(o.default.dim(` Copies built files into consumer node_modules with incremental sync
|
|
11
|
-
`));}a$2(a,"showBanner");process.env.UV_THREADPOOL_SIZE??=String(Math.max(availableParallelism(),8));a$3();var d=process.argv.slice(2),p=d.some(e=>!e.startsWith("-")&&["init","publish","add","remove","push","dev","restore","list","status","update","clean","gc","doctor","migrate"].includes(e));p||a();var u={meta:{name:"plunk",version:"0.7.
|
|
11
|
+
`));}a$2(a,"showBanner");process.env.UV_THREADPOOL_SIZE??=String(Math.max(availableParallelism(),8));a$3();var d=process.argv.slice(2),p=d.some(e=>!e.startsWith("-")&&["init","publish","add","remove","push","dev","restore","list","status","update","clean","gc","doctor","migrate"].includes(e));p||a();var u={meta:{name:"plunk",version:"0.7.5-canary.28557d2",description:"Local npm package development \u2014 copies built files into consumer node_modules"},args:{verbose:{type:"boolean",alias:"v",description:"Enable verbose debug logging",default:false},"dry-run":{type:"boolean",description:"Preview changes without writing files",default:false},json:{type:"boolean",description:"Output machine-readable JSON",default:false}},subCommands:{init:a$2(()=>import('./init-C6XCSFCU.mjs').then(e=>e.default),"init"),publish:a$2(()=>import('./publish-6A7PX5IH.mjs').then(e=>e.default),"publish"),add:a$2(()=>import('./add-GYBX4VAZ.mjs').then(e=>e.default),"add"),remove:a$2(()=>import('./remove-5DAQD627.mjs').then(e=>e.default),"remove"),push:a$2(()=>import('./push-AUAGCBYK.mjs').then(e=>e.default),"push"),dev:a$2(()=>import('./dev-DBGYZOIV.mjs').then(e=>e.default),"dev"),restore:a$2(()=>import('./restore-JVH6INAG.mjs').then(e=>e.default),"restore"),list:a$2(()=>import('./list-QSPN7FE5.mjs').then(e=>e.default),"list"),status:a$2(()=>import('./status-22YV26A3.mjs').then(e=>e.default),"status"),update:a$2(()=>import('./update-33ICRFYZ.mjs').then(e=>e.default),"update"),clean:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"clean"),gc:a$2(()=>import('./clean-F2IWAVRP.mjs').then(e=>e.default),"gc"),doctor:a$2(()=>import('./doctor-GJGAAT6J.mjs').then(e=>e.default),"doctor"),migrate:a$2(()=>import('./migrate-4TFDXO4G.mjs').then(e=>e.default),"migrate")}};a$4(u);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-
|
|
2
|
+
import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-CIY4E6PA.mjs';import'./chunk-SMIGYQFG.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
|
|
3
3
|
var u={meta:{name:"dev",description:"Watch, rebuild, and push to all consumers. Auto-detects build command."},args:{build:{type:"string",description:"Override build command (default: auto-detect from package.json)"},"skip-build":{type:"boolean",description:"Watch output dirs directly, skip build command detection",default:false},debounce:{type:"string",description:"Debounce delay in ms (default: 500)"},cooldown:{type:"string",description:"Minimum time between builds in ms (default: 500)"},"no-scripts":{type:"boolean",description:"Skip prepack/postpack lifecycle hooks",default:false}},async run({args:e}){b();let t=resolve("."),i=a(()=>a$1(t,{runScripts:!e["no-scripts"]}),"push");await i(),await b$1(t,e,i);}};export{u as default};
|
package/dist/index.mjs
CHANGED
|
@@ -659,13 +659,51 @@ var init_workspace = __esm({
|
|
|
659
659
|
|
|
660
660
|
// src/core/watcher.ts
|
|
661
661
|
import { spawn as spawn2 } from "child_process";
|
|
662
|
+
import { readdir as readdir6, stat as stat8 } from "fs/promises";
|
|
662
663
|
import { platform as platform3 } from "os";
|
|
664
|
+
import { join as join13 } from "path";
|
|
663
665
|
function killActiveBuild() {
|
|
664
666
|
if (activeChild && !activeChild.killed) {
|
|
665
667
|
activeChild.kill("SIGTERM");
|
|
666
668
|
activeChild = null;
|
|
667
669
|
}
|
|
668
670
|
}
|
|
671
|
+
async function walkDir(dir, snapshot) {
|
|
672
|
+
let entries;
|
|
673
|
+
try {
|
|
674
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
675
|
+
} catch {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
for (const entry of entries) {
|
|
679
|
+
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
680
|
+
const fullPath = join13(dir, entry.name);
|
|
681
|
+
if (entry.isDirectory()) {
|
|
682
|
+
await walkDir(fullPath, snapshot);
|
|
683
|
+
} else {
|
|
684
|
+
try {
|
|
685
|
+
const st = await stat8(fullPath);
|
|
686
|
+
snapshot.set(fullPath, st.mtimeMs);
|
|
687
|
+
} catch {
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
async function buildSnapshot(watchPaths) {
|
|
693
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
694
|
+
for (const p of watchPaths) {
|
|
695
|
+
try {
|
|
696
|
+
const st = await stat8(p);
|
|
697
|
+
if (st.isDirectory()) {
|
|
698
|
+
await walkDir(p, snapshot);
|
|
699
|
+
} else {
|
|
700
|
+
snapshot.set(p, st.mtimeMs);
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return snapshot;
|
|
706
|
+
}
|
|
669
707
|
async function startWatcher(watchDir, options, onChange) {
|
|
670
708
|
const { watch } = await import("chokidar");
|
|
671
709
|
const patterns = options.patterns ?? ["src", "lib"];
|
|
@@ -742,9 +780,9 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
742
780
|
const watcher = watch(watchPaths, {
|
|
743
781
|
ignoreInitial: true,
|
|
744
782
|
ignored: [
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
783
|
+
/[/\\]node_modules[/\\]/,
|
|
784
|
+
/[/\\]\.git[/\\]/,
|
|
785
|
+
/[/\\]\.plunk[/\\]/
|
|
748
786
|
],
|
|
749
787
|
awaitWriteFinish: awfOption,
|
|
750
788
|
usePolling,
|
|
@@ -756,9 +794,37 @@ async function startWatcher(watchDir, options, onChange) {
|
|
|
756
794
|
watcher.on("error", (err) => {
|
|
757
795
|
consola.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`);
|
|
758
796
|
});
|
|
797
|
+
let pollInterval = null;
|
|
798
|
+
if (usePolling) {
|
|
799
|
+
let lastSnapshot = await buildSnapshot(watchPaths);
|
|
800
|
+
pollInterval = setInterval(async () => {
|
|
801
|
+
if (closed) return;
|
|
802
|
+
try {
|
|
803
|
+
const current = await buildSnapshot(watchPaths);
|
|
804
|
+
for (const [path, mtime] of current) {
|
|
805
|
+
const prev = lastSnapshot.get(path);
|
|
806
|
+
if (prev === void 0 || prev !== mtime) {
|
|
807
|
+
onFileEvent(path);
|
|
808
|
+
break;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
if (!closed) {
|
|
812
|
+
for (const path of lastSnapshot.keys()) {
|
|
813
|
+
if (!current.has(path)) {
|
|
814
|
+
onFileEvent(path);
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
lastSnapshot = current;
|
|
820
|
+
} catch {
|
|
821
|
+
}
|
|
822
|
+
}, 1e3);
|
|
823
|
+
}
|
|
759
824
|
const watcherHandle = {
|
|
760
825
|
close: async () => {
|
|
761
826
|
closed = true;
|
|
827
|
+
if (pollInterval) clearInterval(pollInterval);
|
|
762
828
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
763
829
|
killActiveBuild();
|
|
764
830
|
await watcher.close();
|
|
@@ -797,13 +863,14 @@ function runBuildCommand(cmd, cwd) {
|
|
|
797
863
|
});
|
|
798
864
|
});
|
|
799
865
|
}
|
|
800
|
-
var activeChild, activeWatcher;
|
|
866
|
+
var activeChild, activeWatcher, IGNORED_DIRS;
|
|
801
867
|
var init_watcher = __esm({
|
|
802
868
|
"src/core/watcher.ts"() {
|
|
803
869
|
"use strict";
|
|
804
870
|
init_console();
|
|
805
871
|
activeChild = null;
|
|
806
872
|
activeWatcher = null;
|
|
873
|
+
IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".plunk"]);
|
|
807
874
|
}
|
|
808
875
|
});
|
|
809
876
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-
|
|
2
|
+
import {createRequire}from'node:module';import {a as a$1,b as b$1}from'./chunk-CIY4E6PA.mjs';import'./chunk-SMIGYQFG.mjs';import'./chunk-7JG555TZ.mjs';import'./chunk-AC5FETT7.mjs';import'./chunk-LLVBXPQN.mjs';import'./chunk-PVMVWPLG.mjs';import'./chunk-HPF6K6WO.mjs';import'./chunk-EMRPZYLU.mjs';import'./chunk-MBKCCWSD.mjs';import'./chunk-22YCXJTS.mjs';import {b}from'./chunk-OJJZ7CLB.mjs';import'./chunk-OL7SNXMX.mjs';import'./chunk-HW7AEGI3.mjs';import'./chunk-TMH7HIJ2.mjs';import'./chunk-R3RSOZXN.mjs';import'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {resolve}from'path';globalThis.require=createRequire(import.meta.url);
|
|
3
3
|
var u={meta:{name:"push",description:"Publish and push to all consumers. Use --watch for continuous mode."},args:{watch:{type:"boolean",description:"Watch for changes and auto-push",default:false},build:{type:"string",description:"Build command to run before publishing (watch mode)"},"skip-build":{type:"boolean",description:"Watch output dirs directly, skip build command detection",default:false},debounce:{type:"string",description:"Debounce delay in ms for watch mode (default: 500)"},cooldown:{type:"string",description:"Minimum time between builds in ms (default: 500)"},"no-scripts":{type:"boolean",description:"Skip prepack/postpack lifecycle hooks",default:false},force:{type:"boolean",alias:"f",description:"Force copy all files, bypassing hash comparison",default:false}},async run({args:e}){b();let o=resolve("."),t=a(()=>a$1(o,{runScripts:!e["no-scripts"],force:e.force}),"push");await t(),e.watch&&await b$1(o,e,t);}};export{u as default};
|
package/dist/vite-plugin.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/vite-plugin.ts
|
|
2
2
|
import { join, normalize } from "path";
|
|
3
|
-
import { readFileSync
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
4
|
function readLinkedPackagesSync(stateFile) {
|
|
5
5
|
try {
|
|
6
6
|
const content = readFileSync(stateFile, "utf-8");
|
|
@@ -12,8 +12,6 @@ function readLinkedPackagesSync(stateFile) {
|
|
|
12
12
|
}
|
|
13
13
|
function plunkPlugin() {
|
|
14
14
|
let plunkStateFile;
|
|
15
|
-
let rootDir;
|
|
16
|
-
let cacheDir;
|
|
17
15
|
let nodeModulesDir;
|
|
18
16
|
let pollTimer;
|
|
19
17
|
return {
|
|
@@ -47,8 +45,6 @@ function plunkPlugin() {
|
|
|
47
45
|
return result;
|
|
48
46
|
},
|
|
49
47
|
configResolved(config) {
|
|
50
|
-
rootDir = config.root;
|
|
51
|
-
cacheDir = config.cacheDir;
|
|
52
48
|
nodeModulesDir = join(config.root, "node_modules");
|
|
53
49
|
plunkStateFile = normalize(join(config.root, ".plunk", "state.json"));
|
|
54
50
|
console.log(`[plunk] Watching state file: ${plunkStateFile}`);
|
|
@@ -58,6 +54,7 @@ function plunkPlugin() {
|
|
|
58
54
|
let isRestarting = false;
|
|
59
55
|
let pendingRestart = false;
|
|
60
56
|
let debounceTimer = null;
|
|
57
|
+
let reloadTimer = null;
|
|
61
58
|
function syncPackageWatchers() {
|
|
62
59
|
let added = false;
|
|
63
60
|
for (const pkg of readLinkedPackagesSync(plunkStateFile)) {
|
|
@@ -67,13 +64,13 @@ function plunkPlugin() {
|
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
66
|
if (added && watchedPackages.size > 0) {
|
|
70
|
-
const escaped = [...watchedPackages].map((p) => p.replace(/[/\\.*+?^${}()|[\]]/g, "\\$&")).join("|");
|
|
67
|
+
const escaped = [...watchedPackages].sort((a, b) => b.length - a.length).map((p) => p.replace(/[/\\.*+?^${}()|[\]]/g, "\\$&")).join("|");
|
|
71
68
|
server.watcher.options = {
|
|
72
69
|
...server.watcher.options,
|
|
73
70
|
ignored: [
|
|
74
71
|
new RegExp(`node_modules\\/(?!(?:${escaped})(?:\\/|$)).*`),
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
/[/\\]\.git[/\\]/,
|
|
73
|
+
/[/\\]test-results[/\\]/
|
|
77
74
|
]
|
|
78
75
|
};
|
|
79
76
|
server.watcher._userIgnored = void 0;
|
|
@@ -82,23 +79,9 @@ function plunkPlugin() {
|
|
|
82
79
|
server.watcher.add(pkgPath);
|
|
83
80
|
console.log(`[plunk] Added watcher for package: ${pkgPath}`);
|
|
84
81
|
}
|
|
85
|
-
server.watcher.on("change", (changedPath) => {
|
|
86
|
-
const normalized = normalize(changedPath);
|
|
87
|
-
for (const pkg of watchedPackages) {
|
|
88
|
-
if (normalized.includes(join("node_modules", pkg))) {
|
|
89
|
-
console.log(`[plunk] Linked package file changed: ${changedPath}`);
|
|
90
|
-
const mods = server.moduleGraph.getModulesByFile(normalized);
|
|
91
|
-
if (mods) {
|
|
92
|
-
mods.forEach((m) => server.moduleGraph.invalidateModule(m));
|
|
93
|
-
}
|
|
94
|
-
server.hot.send({ type: "full-reload", path: "*" });
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
82
|
}
|
|
100
83
|
}
|
|
101
|
-
async function
|
|
84
|
+
async function restartServer(source) {
|
|
102
85
|
if (isRestarting) {
|
|
103
86
|
pendingRestart = true;
|
|
104
87
|
console.log(`[plunk] Restart already in progress, queued: ${source}`);
|
|
@@ -107,48 +90,80 @@ function plunkPlugin() {
|
|
|
107
90
|
isRestarting = true;
|
|
108
91
|
syncPackageWatchers();
|
|
109
92
|
console.log(`[plunk] ${source}, restarting server...`);
|
|
110
|
-
server.config.logger.info(
|
|
111
|
-
`[plunk] ${source}, restarting server...`,
|
|
112
|
-
{ timestamp: true }
|
|
113
|
-
);
|
|
114
|
-
try {
|
|
115
|
-
if (existsSync(cacheDir)) {
|
|
116
|
-
rmSync(cacheDir, { recursive: true, force: true });
|
|
117
|
-
console.log(`[plunk] Cleared cache: ${cacheDir}`);
|
|
118
|
-
}
|
|
119
|
-
} catch (err) {
|
|
120
|
-
console.error(`[plunk] Failed to clear cache:`, err);
|
|
121
|
-
}
|
|
122
93
|
try {
|
|
123
94
|
await server.restart();
|
|
124
95
|
} finally {
|
|
125
96
|
isRestarting = false;
|
|
126
97
|
if (pendingRestart) {
|
|
127
98
|
pendingRestart = false;
|
|
128
|
-
await
|
|
99
|
+
await restartServer("Queued change detected");
|
|
129
100
|
}
|
|
130
101
|
}
|
|
131
102
|
}
|
|
132
103
|
function scheduleRestart(source) {
|
|
133
|
-
if (debounceTimer)
|
|
104
|
+
if (debounceTimer) return;
|
|
134
105
|
debounceTimer = setTimeout(() => {
|
|
135
106
|
debounceTimer = null;
|
|
136
|
-
|
|
137
|
-
},
|
|
107
|
+
restartServer(source);
|
|
108
|
+
}, 1500);
|
|
109
|
+
}
|
|
110
|
+
function scheduleReload() {
|
|
111
|
+
if (reloadTimer) clearTimeout(reloadTimer);
|
|
112
|
+
reloadTimer = setTimeout(() => {
|
|
113
|
+
reloadTimer = null;
|
|
114
|
+
console.log("[plunk] Linked package updated, reloading");
|
|
115
|
+
server.hot.send({ type: "full-reload", path: "*" });
|
|
116
|
+
}, 200);
|
|
117
|
+
}
|
|
118
|
+
function invalidateAndReload(changedPath) {
|
|
119
|
+
const normalized = normalize(changedPath);
|
|
120
|
+
const mods = server.moduleGraph.getModulesByFile(normalized);
|
|
121
|
+
if (mods) {
|
|
122
|
+
mods.forEach((m) => server.moduleGraph.invalidateModule(m));
|
|
123
|
+
}
|
|
124
|
+
scheduleReload();
|
|
125
|
+
}
|
|
126
|
+
function invalidateLinkedModules() {
|
|
127
|
+
for (const [url, mod] of server.moduleGraph.urlToModuleMap) {
|
|
128
|
+
for (const pkg of watchedPackages) {
|
|
129
|
+
if (url.includes(pkg)) {
|
|
130
|
+
server.moduleGraph.invalidateModule(mod);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
scheduleReload();
|
|
138
136
|
}
|
|
139
137
|
server.watcher.add(plunkStateFile);
|
|
140
138
|
console.log(`[plunk] Added watcher for: ${plunkStateFile}`);
|
|
141
139
|
syncPackageWatchers();
|
|
142
140
|
server.watcher.on("change", async (changedPath) => {
|
|
143
141
|
const normalizedChanged = normalize(changedPath);
|
|
144
|
-
if (normalizedChanged
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
if (normalizedChanged === plunkStateFile) {
|
|
143
|
+
const currentPackages = readLinkedPackagesSync(plunkStateFile);
|
|
144
|
+
const hasNew = currentPackages.some((pkg) => !watchedPackages.has(pkg));
|
|
145
|
+
if (hasNew) {
|
|
146
|
+
scheduleRestart("New package linked");
|
|
147
|
+
} else {
|
|
148
|
+
invalidateLinkedModules();
|
|
149
|
+
}
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
151
|
-
|
|
152
|
+
const isLinkedPackage = [...watchedPackages].some(
|
|
153
|
+
(pkg) => normalizedChanged.includes(normalize(join(nodeModulesDir, pkg)))
|
|
154
|
+
);
|
|
155
|
+
if (isLinkedPackage) {
|
|
156
|
+
invalidateAndReload(changedPath);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
server.watcher.on("add", (addedPath) => {
|
|
160
|
+
const normalizedAdded = normalize(addedPath);
|
|
161
|
+
const isLinkedPackage = [...watchedPackages].some(
|
|
162
|
+
(pkg) => normalizedAdded.includes(normalize(join(nodeModulesDir, pkg)))
|
|
163
|
+
);
|
|
164
|
+
if (isLinkedPackage) {
|
|
165
|
+
invalidateAndReload(addedPath);
|
|
166
|
+
}
|
|
152
167
|
});
|
|
153
168
|
if (process.versions?.webcontainer) {
|
|
154
169
|
if (pollTimer) clearInterval(pollTimer);
|
|
@@ -168,6 +183,8 @@ function plunkPlugin() {
|
|
|
168
183
|
);
|
|
169
184
|
if (hasNew) {
|
|
170
185
|
scheduleRestart("New package linked (polling fallback)");
|
|
186
|
+
} else {
|
|
187
|
+
invalidateLinkedModules();
|
|
171
188
|
}
|
|
172
189
|
}
|
|
173
190
|
if (!lastStateContent) lastStateContent = content;
|
|
@@ -176,6 +193,20 @@ function plunkPlugin() {
|
|
|
176
193
|
}, 1e3);
|
|
177
194
|
console.log("[plunk] WebContainer polling fallback active (1s interval)");
|
|
178
195
|
}
|
|
196
|
+
server.httpServer?.on("close", () => {
|
|
197
|
+
if (pollTimer) {
|
|
198
|
+
clearInterval(pollTimer);
|
|
199
|
+
pollTimer = void 0;
|
|
200
|
+
}
|
|
201
|
+
if (debounceTimer) {
|
|
202
|
+
clearTimeout(debounceTimer);
|
|
203
|
+
debounceTimer = null;
|
|
204
|
+
}
|
|
205
|
+
if (reloadTimer) {
|
|
206
|
+
clearTimeout(reloadTimer);
|
|
207
|
+
reloadTimer = null;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
179
210
|
}
|
|
180
211
|
};
|
|
181
212
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {createRequire}from'node:module';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {spawn}from'child_process';import {readdir,stat}from'fs/promises';import {platform}from'os';import {join}from'path';globalThis.require=createRequire(import.meta.url);
|
|
3
|
+
var m=null;function j(){m&&!m.killed&&(m.kill("SIGTERM"),m=null);}a(j,"killActiveBuild");var _=new Set(["node_modules",".git",".plunk"]);async function M(o,t){let n;try{n=await readdir(o,{withFileTypes:!0});}catch{return}for(let r of n){if(_.has(r.name))continue;let u=join(o,r.name);if(r.isDirectory())await M(u,t);else try{let f=await stat(u);t.set(u,f.mtimeMs);}catch{}}}a(M,"walkDir");async function I(o){let t=new Map;for(let n of o)try{let r=await stat(n);r.isDirectory()?await M(n,t):t.set(n,r.mtimeMs);}catch{}return t}a(I,"buildSnapshot");async function q(o,t,n){let{watch:r}=await import('./chokidar-LVDD2IK4.mjs'),u=t.patterns??["src","lib"],f=u.map(e=>e.startsWith("/")||e.includes(":")?e:`${o}/${e}`),h=t.debounce??500,l=t.cooldown??500,i=null,p=false,b$1=false,w=0,v=false,P=a(async()=>{if(p||b$1)return;let e=Date.now()-w;if(!(w>0&&e<l)){b$1=true,v=false;try{if(t.buildCmd&&!await x(t.buildCmd,o)){b.warn("Build failed (see output above), skipping push");return}await n();}catch(s){b.error(`Push failed: ${s instanceof Error?s.message:String(s)}`);}finally{b$1=false,w=Date.now(),v&&!p&&(v=false,i=setTimeout(()=>{i=null,P();},l));}}},"doBuild"),g=a(e=>{if(p)return;if(b$1){v=true;return}let s=Date.now()-w;if(w>0&&s<l){i&&clearTimeout(i);let d=l-s;i=setTimeout(()=>{i=null,P();},d+h);return}i&&clearTimeout(i),i=setTimeout(()=>{i=null,P();},h);},"onFileEvent"),$=t.buildCmd?false:t.awaitWriteFinish??{stabilityThreshold:200,pollInterval:50},T=!!process.versions?.webcontainer,y=r(f,{ignoreInitial:true,ignored:[/[/\\]node_modules[/\\]/,/[/\\]\.git[/\\]/,/[/\\]\.plunk[/\\]/],awaitWriteFinish:$,usePolling:T,...T&&{interval:1e3}});y.on("change",g),y.on("add",g),y.on("unlink",g),y.on("error",e=>{b.error(`Watcher error: ${e instanceof Error?e.message:String(e)}`);});let k=null;if(T){let e=await I(f);k=setInterval(async()=>{if(!p)try{let s=await I(f);for(let[d,D]of s){let W=e.get(d);if(W===void 0||W!==D){g(d);break}}if(!p){for(let d of e.keys())if(!s.has(d)){g(d);break}}e=s;}catch{}},1e3);}let B={close:a(async()=>{p=true,k&&clearInterval(k),i&&clearTimeout(i),j(),await y.close();},"close")};return b.info(`Watching for changes in: ${u.join(", ")}`),B}a(q,"startWatcher");function x(o,t){return new Promise(n=>{let r=platform()==="win32",u=r?"cmd":"sh",f=r?"/c":"-c";b.start(`Running: ${o}`);let h=spawn(u,[f,o],{cwd:t,stdio:"inherit"});m=h,h.on("close",l=>{m=null,l===0?(b.success("Build succeeded"),n(true)):(b.error(`Build failed with code ${l}`),n(false));}),h.on("error",l=>{m=null,b.error(`Build error: ${l.message}`),n(false);});})}a(x,"runBuildCommand");export{j as killActiveBuild,q as startWatcher};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olegkuibar/plunk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5-canary.28557d2",
|
|
4
4
|
"description": "Local npm package development without symlinks. Copies built files into consumer node_modules with incremental sync and watch mode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {createRequire}from'node:module';import {b}from'./chunk-ICCM7US5.mjs';import {a}from'./chunk-2VCW5RWI.mjs';import {spawn}from'child_process';import {platform}from'os';globalThis.require=createRequire(import.meta.url);
|
|
3
|
-
var r=null;function E(){r&&!r.killed&&(r.kill("SIGTERM"),r=null);}a(E,"killActiveBuild");async function O(c,n,u){let{watch:m}=await import('./chokidar-LVDD2IK4.mjs'),h=n.patterns??["src","lib"],P=h.map(t=>t.startsWith("/")||t.includes(":")?t:`${c}/${t}`),a$1=n.debounce??500,i=n.cooldown??500,e=null,g=false,w=false,d=0,p=false,T=a(async()=>{if(g||w)return;let t=Date.now()-d;if(!(d>0&&t<i)){w=true,p=false;try{if(n.buildCmd&&!await S(n.buildCmd,c)){b.warn("Build failed (see output above), skipping push");return}await u();}catch(l){b.error(`Push failed: ${l instanceof Error?l.message:String(l)}`);}finally{w=false,d=Date.now(),p&&!g&&(p=false,e=setTimeout(()=>{e=null,T();},i));}}},"doBuild"),b$1=a(t=>{if(g)return;if(w){p=true;return}let l=Date.now()-d;if(d>0&&l<i){e&&clearTimeout(e);let C=i-l;e=setTimeout(()=>{e=null,T();},C+a$1);return}e&&clearTimeout(e),e=setTimeout(()=>{e=null,T();},a$1);},"onFileEvent"),W=n.buildCmd?false:n.awaitWriteFinish??{stabilityThreshold:200,pollInterval:50},y=!!process.versions?.webcontainer,f=m(P,{ignoreInitial:true,ignored:["**/node_modules/**","**/.git/**","**/.plunk/**"],awaitWriteFinish:W,usePolling:y,...y&&{interval:1e3}});f.on("change",b$1),f.on("add",b$1),f.on("unlink",b$1),f.on("error",t=>{b.error(`Watcher error: ${t instanceof Error?t.message:String(t)}`);});let v={close:a(async()=>{g=true,e&&clearTimeout(e),E(),await f.close();},"close")};return b.info(`Watching for changes in: ${h.join(", ")}`),v}a(O,"startWatcher");function S(c,n){return new Promise(u=>{let m=platform()==="win32",h=m?"cmd":"sh",P=m?"/c":"-c";b.start(`Running: ${c}`);let a=spawn(h,[P,c],{cwd:n,stdio:"inherit"});r=a,a.on("close",i=>{r=null,i===0?(b.success("Build succeeded"),u(true)):(b.error(`Build failed with code ${i}`),u(false));}),a.on("error",i=>{r=null,b.error(`Build error: ${i.message}`),u(false);});})}a(S,"runBuildCommand");export{E as killActiveBuild,O as startWatcher};
|