Repository: remix-run/remix
Pull request #3188 (2022-05-13 19:49:40)

feat(remix-dev): add `watchPaths` config option
<!--

👋 Hey, thanks for your interest in contributing to Remix!

If this is a simple docs change, go ahead and delete all this.

**Please ask first before starting work on any significant new features.**

It's never a fun experience to have your pull request declined after investing a
lot of time and effort into a new feature. To avoid this from happening, we
request that contributors create a
[Feature Request discussion](https://github.com/remix-run/remix/discussions/new?category=ideas)
to first discuss any significant new features.

https://github.com/remix-run/remix/blob/main/CONTRIBUTING.md

Please fill in or delete each item below:

-->
Support to watch directories other then remixes default directories. Will help integration with mono repos like NX/TurboRepo.

Closes: #2983
Agreed upon replacement of: https://github.com/remix-run/remix/pull/2985

- [ x ] Docs
- [ x ] Tests

Testing Strategy:

<!--
Please explain how you tested this. For example:

> This test covers this code: <link to test>

Or

> I opened up my windows machine and ran this script:
>
> ```
> npx create-remix@0.0.0-experimental-7e420ee3 --template remix my-test
> cd my-test
> npm run dev
> ```
-->


remix-cla-bot[bot]: Hi @christophertrudel,

Welcome, and thank you for contributing to Remix!

Before we consider your pull request, we ask that you sign our **Contributor License Agreement** (CLA). We require this only once.

You may [review the CLA](https://github.com/remix-run/remix/blob/main/CLA.md) and sign it by [adding your name to contributors.yml](https://github.com/christophertrudel/remix/blob/feat/watchDirectories/contributors.yml).

Once the CLA is signed, the `CLA Signed` label will be added to the pull request.

If you have already signed the CLA and received this response in error, or if you have any questions, please contact us at [hello@remix.run](mailto:hello@remix.run?subject=CLA%20for%20open%20source%20contributions).

Thanks!

\- The Remix team
remix-cla-bot[bot]: Thank you for signing the Contributor License Agreement. Let's get this merged! 🥳
jdnichollsc: Thanks for your contribution mate!
ggaulard: Thanks for that we really need it :) 

Patch:
diff --git a/contributors.yml b/contributors.yml
index a708c85da..1aaefc480 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -62,6 +62,7 @@
 - chenxsan
 - chiangs
 - christianhg
+- christophertrudel
 - christophgockel
 - clarkmitchell
 - cliffordfajardo
diff --git a/docs/api/conventions.md b/docs/api/conventions.md
index ef7a9028e..7ededcc00 100644
--- a/docs/api/conventions.md
+++ b/docs/api/conventions.md
@@ -158,6 +158,18 @@ module.exports = {
 };
 ```
 
+### watchPaths
+
+A function for defining custom directories to watch while running [remix dev](https://remix.run/docs/en/v1/other-api/dev#remix-dev), in addition to [`appDirectory`](#appDirectory).
+
+```tsx
+exports.watchPaths = async () => {
+  return [
+      "/some/path/*"
+  ];
+};
+```
+
 ## File Name Conventions
 
 There are a few conventions that Remix uses you should be aware of.
diff --git a/packages/remix-dev/compiler.ts b/packages/remix-dev/compiler.ts
index 39209f2bc..61b828427 100644
--- a/packages/remix-dev/compiler.ts
+++ b/packages/remix-dev/compiler.ts
@@ -221,6 +221,10 @@ export async function watch(
   if (config.serverEntryPoint) {
     toWatch.push(config.serverEntryPoint);
   }
+  
+  config.watchPaths?.forEach((watchPath) => {
+    toWatch.push(watchPath);
+  });
 
   let watcher = chokidar
     .watch(toWatch, {
diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts
index fae6c171b..4318375d7 100644
--- a/packages/remix-dev/config.ts
+++ b/packages/remix-dev/config.ts
@@ -147,6 +147,14 @@ export interface AppConfig {
    * in a CJS build.
    */
   serverDependenciesToBundle?: Array<string | RegExp>;
+
+  /**
+   * A function for defining custom directories to watch while running `remix dev`, in addition to `appDirectory`.
+   */
+  watchPaths?:
+    | string
+    | string[]
+    | (() => Promise<string | string[]> | string | string[]);
 }
 
 /**
@@ -250,6 +258,11 @@ export interface RemixConfig {
    * in a CJS build.
    */
   serverDependenciesToBundle: Array<string | RegExp>;
+
+  /**
+   * A list of directories to watch.
+   */
+  watchPaths: string[];
 }
 
 /**
@@ -395,6 +408,20 @@ export async function readConfig(
     }
   }
 
+  let watchPaths: string[] = [];
+  if (typeof appConfig.watchPaths === "function") {
+    let directories = await appConfig.watchPaths();
+    watchPaths = watchPaths.concat(
+      Array.isArray(directories) ? directories : [directories]
+    );
+  } else if (appConfig.watchPaths) {
+    watchPaths = watchPaths.concat(
+      Array.isArray(appConfig.watchPaths)
+        ? appConfig.watchPaths
+        : [appConfig.watchPaths]
+    );
+  }
+
   let serverBuildTargetEntryModule = `export * from ${JSON.stringify(
     serverBuildVirtualModule.id
   )};`;
@@ -421,6 +448,7 @@ export async function readConfig(
     serverEntryPoint: customServerEntryPoint,
     serverDependenciesToBundle,
     mdx,
+    watchPaths,
   };
 }
 


Test patch:
diff --git a/packages/remix-dev/__tests__/readConfig-test.ts b/packages/remix-dev/__tests__/readConfig-test.ts
index 92af7767d..5164cc960 100644
--- a/packages/remix-dev/__tests__/readConfig-test.ts
+++ b/packages/remix-dev/__tests__/readConfig-test.ts
@@ -48,6 +48,7 @@ describe("readConfig", () => {
         "serverMode": "production",
         "serverModuleFormat": "cjs",
         "serverPlatform": "node",
+        "watchPaths": Array [],
       }
     `
     );