While Nx is a really great tool to handle your monorepo builds and deployments, some of the plugins / extensions either conflict with the core packages, or pollute your workspace with boilerplate code. Third party plugins are sometimes worse regarding incompatibilities - I now tend to avoid them entirely and use plugins as little as possible.
It has cost me weeks of finding the cause of some superficial and verbose stack traces, such as
√ Installing @nx/nuxt@20.0.1...
- Initializing @nx/nuxt...
NX Generating @nx/nuxt:init
(node:8640) [DEP0180] DeprecationWarning: fs.Stats constructor is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
Convert compiler options from json failed, File '.nuxt/tsconfig.json' not found.
NX Cannot read properties of undefined (reading 'split')
Pass --verbose to see the stacktrace.
× Initializing @nx/nuxt...
Error: Command failed: pnpm exec nx g @nx/nuxt:init --keepExistingVersions --updatePackageScripts
at genericNodeError (node:internal/errors:983:15)
at wrappedFn (node:internal/errors:537:14)
at checkExecSyncError (node:child_process:890:11)
at execSync (node:child_process:962:15)
at runNxSync (C:\Users\MyPC\Workspace\myproject\node_modules\nx\src\utils\child-process.js:28:34)
at initializePlugin (C:\Users\MyPC\Workspace\myproject\node_modules\nx\src\command-line\add\add.js:106:39)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async C:\Users\MyPC\Workspace\myproject\node_modules\nx\src\command-line\add\add.js:26:9
at async handleErrors (C:\Users\MyPC\Workspace\myproject\node_modules\nx\src\utils\handle-errors.js:9:24)
at async Object.handler (C:\Users\MyPC\Workspace\myproject\node_modules\nx\src\command-line\add\command-object.js:25:22)
NX Failed to initialize @nx/nuxt. Please check the error above for more details.
Custom Shell scripts
I maintain some scripts in my .github/scripts
directory, that I frequently use in the script tags of the individual applications within.
One such example is used for Netlify deployments
The ${PROJECT_CWD}
variable will be provided by Nx and give you the workspace root.
The -s
flag controls if it's a static deployment or not
Integrating Gradle manually
I've adapted the same approach to Gradle with the simple idea to just pass the module and build command to it, and it will resolve - based on the OS - if it has to use the ./gradle.bat
(Windows) or ./gradle
(Linu😆 command, so it will work seamlessly in local environments and CI.
#!/bin/bash
# Check if a command is provided
if [ -z "$1" ]; then
echo "Usage: $0 <gradle_command>"
exit 1
fi
# Get the current workspace directory (the base directory of your Nx workspace)
WORKSPACE_DIR="$PROJECT_CWD"
# Detect OS
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
echo "Running on Windows"
GRADLE_COMMAND="./gradlew.bat"
else
echo "Not running on Windows"
GRADLE_COMMAND="./gradlew"
fi
echo "Now navigating to directory $WORKSPACE_DIR to run the Gradle command from"
# Change directory to the workspace root
cd "$WORKSPACE_DIR" || exit
# Run the specified Gradle command with the module path as an argument
eval "$GRADLE_COMMAND $1"
Similar to the previous Netlify script, I call it this way
And that's pretty much it.
Now a simple
yarn nx run @myapp/backend:build
will start the Gradle build without any additional Nx plugins.
Configured correctly, all the caching is handled by Gradle during the CI build, so you do not need any Nx specific setup.
In fact, this is now the project.json
{
"name": "@myapp/backend",
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"tags": ["staging"]
}
Which does not even contain targets anymore and is super clean, and you have as little ties as possible to the tool.