Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): add watch command (#13664)
- Loading branch information
Showing
8 changed files
with
526 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
--- | ||
title: 'watch - CLI command' | ||
description: 'Watch for changes within projects, and execute commands' | ||
--- | ||
|
||
# watch | ||
|
||
Watch for changes within projects, and execute commands | ||
|
||
## Usage | ||
|
||
```terminal | ||
nx watch | ||
``` | ||
|
||
Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. | ||
|
||
### Examples | ||
|
||
Watch the "app" project and echo the project name and the files that changed: | ||
|
||
```terminal | ||
nx watch --projects=app -- echo \$NX_PROJECT_NAME \$NX_FILE_CHANGES | ||
``` | ||
|
||
Watch "app1" and "app2" and echo the project name whenever a specified project or its dependencies change: | ||
|
||
```terminal | ||
nx watch --projects=app1,app2 --includeDependencies -- echo \$NX_PROJECT_NAME | ||
``` | ||
|
||
Watch all projects (including newly created projects) in the workspace: | ||
|
||
```terminal | ||
nx watch --all -- echo \$NX_PROJECT_NAME | ||
``` | ||
|
||
## Options | ||
|
||
### all | ||
|
||
Type: `boolean` | ||
|
||
Watch all projects. | ||
|
||
### help | ||
|
||
Type: `boolean` | ||
|
||
Show help | ||
|
||
### includeDependentProjects | ||
|
||
Type: `boolean` | ||
|
||
When watching selected projects, include dependent projects as well. | ||
|
||
### projects | ||
|
||
Type: `string` | ||
|
||
Projects to watch (comma delimited). | ||
|
||
### verbose | ||
|
||
Type: `boolean` | ||
|
||
Run watch mode in verbose mode, where commands are logged before execution. | ||
|
||
### version | ||
|
||
Type: `boolean` | ||
|
||
Show version number |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { | ||
cleanupProject, | ||
createFile, | ||
newProject, | ||
runCLI, | ||
uniq, | ||
getPackageManagerCommand, | ||
tmpProjPath, | ||
getStrippedEnvironmentVariables, | ||
updateJson, | ||
isVerbose, | ||
} from '@nrwl/e2e/utils'; | ||
import { exec, spawn } from 'child_process'; | ||
|
||
describe('Nx Commands', () => { | ||
let proj1 = uniq('proj1'); | ||
let proj2 = uniq('proj2'); | ||
let proj3 = uniq('proj3'); | ||
beforeAll(() => { | ||
newProject({ packageManager: 'npm' }); | ||
runCLI(`generate @nrwl/workspace:lib ${proj1}`); | ||
runCLI(`generate @nrwl/workspace:lib ${proj2}`); | ||
runCLI(`generate @nrwl/workspace:lib ${proj3}`); | ||
}); | ||
|
||
afterAll(() => cleanupProject()); | ||
|
||
it('should watch for project changes', async () => { | ||
const getOutput = await runWatch( | ||
`--projects=${proj1} -- echo \\$NX_PROJECT_NAME` | ||
); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`libs/${proj3}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([proj1]); | ||
}); | ||
|
||
it('should watch for all projects and output the project name', async () => { | ||
const getOutput = await runWatch(`--all -- echo \\$NX_PROJECT_NAME`); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`libs/${proj3}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([proj1, proj2, proj3]); | ||
}); | ||
|
||
it('should watch for all project changes and output the file name changes', async () => { | ||
const getOutput = await runWatch(`--all -- echo \\$NX_FILE_CHANGES`); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([ | ||
`libs/${proj1}/newfile.txt libs/${proj1}/newfile2.txt libs/${proj2}/newfile.txt`, | ||
]); | ||
}); | ||
|
||
it('should watch for global workspace file changes', async () => { | ||
const getOutput = await runWatch( | ||
`--all --includeGlobalWorkspaceFiles -- echo \\$NX_FILE_CHANGES` | ||
); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([ | ||
`libs/${proj1}/newfile.txt libs/${proj1}/newfile2.txt libs/${proj2}/newfile.txt newfile2.txt`, | ||
]); | ||
}); | ||
|
||
it('should watch selected projects only', async () => { | ||
const getOutput = await runWatch( | ||
`--projects=${proj1},${proj3} -- echo \\$NX_PROJECT_NAME` | ||
); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`libs/${proj3}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([proj1, proj3]); | ||
}); | ||
|
||
it('should watch projects including their dependencies', async () => { | ||
updateJson(`libs/${proj3}/project.json`, (json) => { | ||
json.implicitDependencies = [proj1]; | ||
return json; | ||
}); | ||
|
||
const getOutput = await runWatch( | ||
`--projects=${proj3} --includeDependentProjects -- echo \\$NX_PROJECT_NAME` | ||
); | ||
createFile(`libs/${proj1}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj2}/newfile.txt`, 'content'); | ||
createFile(`libs/${proj1}/newfile2.txt`, 'content'); | ||
createFile(`libs/${proj3}/newfile2.txt`, 'content'); | ||
createFile(`newfile2.txt`, 'content'); | ||
|
||
expect(await getOutput()).toEqual([proj3, proj1]); | ||
}); | ||
}); | ||
|
||
async function wait(timeout = 200) { | ||
return new Promise<void>((res) => { | ||
setTimeout(() => { | ||
res(); | ||
}, timeout); | ||
}); | ||
} | ||
|
||
async function runWatch(command: string) { | ||
const output = []; | ||
const pm = getPackageManagerCommand(); | ||
const runCommand = `npx -c 'nx watch --verbose ${command}'`; | ||
isVerbose() && console.log(runCommand); | ||
return new Promise<(timeout?: number) => Promise<string[]>>((resolve) => { | ||
const p = spawn(runCommand, { | ||
cwd: tmpProjPath(), | ||
env: { | ||
CI: 'true', | ||
...getStrippedEnvironmentVariables(), | ||
FORCE_COLOR: 'false', | ||
}, | ||
shell: true, | ||
stdio: 'pipe', | ||
}); | ||
|
||
p.stdout?.on('data', (data) => { | ||
const s = data.toString().trim(); | ||
isVerbose() && console.log(s); | ||
if (s.includes('watch process waiting')) { | ||
resolve(async (timeout = 6000) => { | ||
await wait(timeout); | ||
p.kill(); | ||
return output; | ||
}); | ||
} else { | ||
if (s.length == 0 || s.includes('NX')) { | ||
return; | ||
} | ||
output.push(s); | ||
} | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
a1d9c46
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
nx-dev – ./
nx-dev-git-master-nrwl.vercel.app
nx.dev
nx-dev-nrwl.vercel.app
nx-five.vercel.app