Repository: modiimedia/arri (language: rust)

Issue:
[cli] Segmentation fault when running `arri dev` on Node v20.12.2
**Environment**
NodeJS v20.12.2
OS Linux PopOS

**Describe the bug**
When running `arri dev` in node version 20.12 you get the following error:
```
WARN  [listhen] Using experimental websocket API. Learn more: https://crossws.unjs.io                                                                                                                                                                                                                            12:34:17 PM
 
  ➜ Local:    http://localhost:3000/
  ➜ Network:  http://172.18.0.1:3000/ [QR code]
  ➜ Network:  http://172.19.0.1:3000/
  ➜ Network:  http://172.20.0.1:3000/
  ➜ Network:  http://192.168.1.175:3000/

🚀 Loading server entry ./.output/server.mjs                                                                                                                                                                                                                                                                 arri 12:34:17 PM
✅ Server initialized in 5ms                                                                                                                                                                                                                                                                                 arri 12:34:17 PM
Segmentation fault (core dumped)
 ELIFECYCLE  Command failed with exit code 139.
```

**Additional context**
Downgrading back to Node version 20.11 makes the error go away.

`Esbuild` seems to be the culprit

Potentially related issues:
https://github.com/evanw/esbuild/issues/3720
https://github.com/evanw/esbuild/issues/2485
https://github.com/evanw/esbuild/issues/3287


Discussion / hints:

Fix patch:
diff --git a/packages/arri/package.json b/packages/arri/package.json
index 41b1c35c..4b9ce306 100644
--- a/packages/arri/package.json
+++ b/packages/arri/package.json
@@ -25,13 +25,13 @@
     "arri": "./dist/cli.mjs"
   },
   "dependencies": {
-    "@joshmossas/listhen": "1.8.0",
+    "@joshmossas/listhen": "1.10.0",
+    "@parcel/watcher": "^2.4.1",
     "arri-codegen-dart": "workspace:*",
     "arri-codegen-ts": "workspace:*",
     "arri-codegen-utils": "workspace:*",
     "arri-validate": "workspace:*",
     "c12": "^1.10.0",
-    "chokidar": "^3.6.0",
     "citty": "^0.1.6",
     "consola": "^3.2.3",
     "crossws": "^0.2.4",
diff --git a/packages/arri/src/cli/_common.ts b/packages/arri/src/cli/_common.ts
index 97396a27..54972fe4 100644
--- a/packages/arri/src/cli/_common.ts
+++ b/packages/arri/src/cli/_common.ts
@@ -191,5 +191,6 @@ export async function transpileFiles(config: ResolvedArriConfig) {
         format: "esm",
         target: "node20",
         platform: "node",
+        allowOverwrite: true,
     });
 }
diff --git a/packages/arri/src/cli/dev.ts b/packages/arri/src/cli/dev.ts
index 9d231338..eee8f6c2 100644
--- a/packages/arri/src/cli/dev.ts
+++ b/packages/arri/src/cli/dev.ts
@@ -1,9 +1,10 @@
 import { existsSync } from "node:fs";
 import fs from "node:fs/promises";
 import { listenAndWatch } from "@joshmossas/listhen";
+import watcher from "@parcel/watcher";
+import type ParcelWatcher from "@parcel/watcher";
 import { isAppDefinition } from "arri-codegen-utils";
 import { loadConfig } from "c12";
-import chokidar from "chokidar";
 import { defineCommand } from "citty";
 import * as esbuild from "esbuild";
 import { ofetch } from "ofetch";
@@ -73,7 +74,7 @@ export default app.h3App;`;
         path.resolve(config.rootDir, ".output", OUT_SERVER_ENTRY),
         serverContent,
     );
-    return await esbuild.context({
+    await esbuild.build({
         ...config.esbuild,
         entryPoints: [
             path.resolve(config.rootDir, config.buildDir, GEN_APP_FILE),
@@ -82,22 +83,22 @@ export default app.h3App;`;
         format: "esm",
         bundle: true,
         sourcemap: true,
-        target: "node18",
+        target: "node20",
         platform: "node",
         packages: "external",
+        allowOverwrite: true,
     });
 }
 
 async function startDevServer(config: ResolvedArriConfig) {
     await setupWorkingDir(config);
-    let fileWatcher: chokidar.FSWatcher | undefined;
+    let fileWatcher: ParcelWatcher.AsyncSubscription | undefined;
     await Promise.all([
         createEntryModule(config),
         createAppWithRoutesModule(config),
         transpileFiles(config),
     ]);
-    const bundleFiles = await bundleFilesContext(config);
-    await bundleFiles.rebuild();
+    await bundleFilesContext(config);
     const listener = await startListener(config, true);
     setTimeout(async () => {
         await generateClients(config);
@@ -108,35 +109,43 @@ async function startDevServer(config: ResolvedArriConfig) {
     process.on("exit", async () => {
         await Promise.allSettled([
             listener.close(),
-            fileWatcher?.close(),
-            bundleFiles.dispose(),
+            fileWatcher?.unsubscribe(),
         ]);
     });
     process.on("SIGINT", cleanExit);
     process.on("SIGTERM", cleanExit);
     async function load(isRestart: boolean, reason?: string) {
-        try {
-            if (fileWatcher) {
-                await fileWatcher.close();
+        if (fileWatcher) {
+            await fileWatcher.unsubscribe();
+        }
+        const srcDir = path.resolve(config.rootDir ?? "", config.srcDir);
+        const dirsToWatch = [srcDir];
+        if (config.esbuild.alias) {
+            for (const key of Object.keys(config.esbuild.alias)) {
+                const alias = config.esbuild.alias[key];
+                if (alias) {
+                    dirsToWatch.push(alias);
+                }
             }
-            const srcDir = path.resolve(config.rootDir ?? "", config.srcDir);
-            const dirsToWatch = [srcDir];
-            if (config.esbuild.alias) {
-                for (const key of Object.keys(config.esbuild.alias)) {
-                    const alias = config.esbuild.alias[key];
-                    if (alias) {
-                        dirsToWatch.push(alias);
+        }
+        const buildDir = path.resolve(config.rootDir, config.buildDir);
+        const outDir = path.resolve(config.rootDir, ".output");
+        fileWatcher = await watcher.subscribe(
+            srcDir,
+            async (err, events) => {
+                if (err) {
+                    logger.error(err);
+                    return;
+                }
+                let doNothing = true;
+                for (const event of events) {
+                    if (event.type === "create") {
+                        continue;
                     }
+                    doNothing = false;
+                    break;
                 }
-            }
-            const buildDir = path.resolve(config.rootDir, config.buildDir);
-            const outDir = path.resolve(config.rootDir, ".output");
-            fileWatcher = chokidar.watch(dirsToWatch, {
-                ignored: [buildDir, outDir],
-                ignoreInitial: true,
-            });
-            fileWatcher.on("all", async (event, file) => {
-                if (event === "add" || event === "addDir") {
+                if (doNothing) {
                     return;
                 }
                 await createAppWithRoutesModule(config);
@@ -146,7 +155,7 @@ async function startDevServer(config: ResolvedArriConfig) {
                         "Change detected. Bundling files and restarting server....",
                     );
                     await transpileFiles(config);
-                    await bundleFiles.rebuild();
+                    await bundleFilesContext(config);
                     bundleCreated = true;
                 } catch (err) {
                     logger.error("ERROR", err);
@@ -158,8 +167,11 @@ async function startDevServer(config: ResolvedArriConfig) {
                         bundleCreated = false;
                     }, 1000);
                 }
-            });
-        } catch (err) {}
+            },
+            {
+                ignore: [buildDir, outDir],
+            },
+        );
     }
     await load(false);
 }
diff --git a/playground/src/app.ts b/playground/src/app.ts
index b3a79835..6c1282fd 100644
--- a/playground/src/app.ts
+++ b/playground/src/app.ts
@@ -1,5 +1,4 @@
 import { ArriApp } from "arri";
 
 const app = new ArriApp({});
-
 export default app;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b9ba0e5c..4cc86f9e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -142,8 +142,11 @@ importers:
   packages/arri:
     dependencies:
       '@joshmossas/listhen':
-        specifier: 1.8.0
-        version: 1.8.0
+        specifier: 1.10.0
+        version: 1.10.0
+      '@parcel/watcher':
+        specifier: ^2.4.1
+        version: 2.4.1
       arri-codegen-dart:
         specifier: workspace:*
         version: link:../arri-codegen/dart
@@ -159,9 +162,6 @@ importers:
       c12:
         specifier: ^1.10.0
         version: 1.10.0
-      chokidar:
-        specifier: ^3.6.0
-        version: 3.6.0
       citty:
         specifier: ^0.1.6
         version: 0.1.6
@@ -1341,8 +1341,8 @@ packages:
     resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
     engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
 
-  '@joshmossas/listhen@1.8.0':
-    resolution: {integrity: sha512-zu6sLLv7RKThPqaJBwHsgnAXuSzbtvuVVRqLfViD4ejsWDXglZfJzdWHaPG8CGmraUAnzysEKi//kxnkpWIKug==}
+  '@joshmossas/listhen@1.10.0':
+    resolution: {integrity: sha512-DnVlguupg5vl3eslE38OWfGTnxRAwQnoOqlHGv+5BzCm0a6TpKN0QoQuibzfkiWmIXTSZ5b4Kkh6rU6Rk3Xa+Q==}
     hasBin: true
 
   '@jridgewell/gen-mapping@0.3.5':
@@ -6219,7 +6219,7 @@ snapshots:
     dependencies:
       '@sinclair/typebox': 0.27.8
 
-  '@joshmossas/listhen@1.8.0':
+  '@joshmossas/listhen@1.10.0':
     dependencies:
       '@parcel/watcher': 2.4.1
       '@parcel/watcher-wasm': 2.4.1


Test patch: