Skip to content

Instantly share code, notes, and snippets.

@jhesgodi
Last active February 25, 2022 10:15
Show Gist options
  • Save jhesgodi/2d530753c551ace665a8c3010d3a719c to your computer and use it in GitHub Desktop.
Save jhesgodi/2d530753c551ace665a8c3010d3a719c to your computer and use it in GitHub Desktop.
Nx Plugin - nx-watch | Run given 'commands' on every change on a watched 'sources' directory

Nx Plugin - nx-watch

Given a list of watched directories run given commands everytime there are changes.

Handy in cases when needed to run an app in watch mode to build direct/implicit dependencies on changes.

Options

  • @sources = string[] List of directories to watch

  • @commands = string[] List of taks to execute everytime (ie. nx build)

Usage

Install

Copy it

Place plugin files under "./tools/executors/nx-watch/, and

Compile it

Must be complieed before use, or if changes are made to the source imple.ts file.

tsc --project tools/executors/nx-watch/tsconfig.json

Usage

Simply add a new task entry to workspace.json under the project's target.

The following task will re-build ui-tokens for ui-kit everytime on changes:

// workspace.json

  "version": 2,
  //   ...
  "projects": {
      "ui-kit": {
        "watch": {
          "executor": "./tools/executors/nx-watch:run",
          "options": {
            "sources": ["libs/ui-tokens"],
            "commands": [
              "nx build ui-tokens",
              "echo rebulding cause of changes"
            ]
          }
        },
      },
      "ui-tokens": {
          "build": {
            //   do build taks ...
          }
      },
    //   ...
  }

Can also be combined with other nx task, like serving ui-kit storybook while watching for changes on the buildable dependency ui-tokens:

// workspace.json

  "version": 2,
  //   ...
  "projects": {
      "ui-kit": {
        "watch": {
            //   watch task ...
        },
        "serve": {
          "builder": "@nrwl/workspace:run-commands",
          "options": {
            "commands": [
              {
                "command": "nx watch ui-kit"
              },
              {
                "command": "nx storybook ui-kit"
              }
            ]
          }
        },
      },
      "ui-tokens": {
          "build": {
            //   do build taks ...
          }
      },
    //   ...
  }
{
"builders": {
"run": {
"implementation": "./__generated__/impl",
"schema": "./schema.json",
"description": "Watch for changes on given source directories and executes given command everytime"
}
}
}
import { execSync } from 'child_process';
const watch = require('node-watch');
const treekill = require('tree-kill');
import { output } from '@nrwl/workspace/src/utils/output';
import { ExecutorContext } from '@nrwl/devkit';
const NAME = 'nx-watch';
const getTitle = (key: string = '') => [NAME, key].filter(Boolean).join(': ')
const registerWatchers = (sources = [], callback: () => void)=> {
const options = { recursive: true };
const handler = function () {
callback();
};
for (const source of sources) {
watch(source, options, handler);
}
};
export type Json = { [k: string]: any };
interface NxWatchExecutorOptions extends Json {
sources: string[];
commands: string[];
}
interface Output {
success: boolean;
}
export default async function tsNodeExecutor(
_options: NxWatchExecutorOptions,
_context: ExecutorContext
): Promise<{ success: boolean }> {
return new Promise<Output>(() => {
const { sources, commands } = _options;
const title = getTitle('')
let changed = true
const setChanged = () => {
console.log('setChanged: ');
output.note({ title: getTitle('rebuild')})
changed = true
}
registerWatchers(sources, setChanged);
function run() {
if (changed) {
changed = false
for (const command of commands) {
execSync(command, {
stdio: [0, 1, 2],
env: { ...process.env, FORCE_COLORS: 'true' },
});
}
}
setTimeout(() => run(), 1000);
}
run();
output.success({ title });
});
}
process.on('exit', (s) => {
treekill(s);
});
{
"builders": "./builder.json"
}
{
"$schema": "http://json-schema.org/schema",
"type": "object",
"cli": "nx",
"properties": {
"sources": {
"type": "array",
"description": "Source directories to watch for changes",
"items": {
"oneOf": [
{
"type": "string"
}
]
}
},
"commands": {
"type": "array",
"description": "Commands to run in child process",
"items": {
"oneOf": [
{
"type": "string"
}
]
}
}
},
"required": ["sources", "commands"]
}
{
"compilerOptions": {
"outDir": "__generated__/",
"rootDir": ".",
"module": "commonjs",
"target": "es2015",
"types": [
"node"
],
"esModuleInterop": true
},
"include": [
"impl.ts"
]
}
@jhesgodi
Copy link
Author

Thank you @hevans90. I just catch up with this. Im glad it served your project too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment