I like to use Nx workspace to manage my projects. I don't put all my projects in one workspace but I use one workspace per multi-module project.
It works nicely with node frameworks like angular, react, nest... But when its come to other languages and frameworks, we need to use custom plugins.
In this article I will use my plugin @jnxplus/nx-gradle
to add support of spring boot and Gradle multi-project builds to Nx workspace.
@jnxplus/nx-gradle
add to the Spring Boot world, an opinionated way to integrate Spring Boot apps/libs inside Nx workspace using Gradle multi-project builds.
Let's show you how to use it.
We start by creating a workspace :
Open a terminal and run this command to create a new workspace :
npx create-nx-workspace@latest
When asked provide my-org as name and choose an empty workspace :
devs> npx create-nx-workspace@latest
npx: installed 48 in 3.278s
√ Workspace name (e.g., org name) · my-org
√ What to create in the new workspace · empty
√ Use Nx Cloud? (It's free and doesn't require registration.) · No
> NX Nx is creating your workspace.
Now and in the same terminal go inside my-org folder :
cd my-org
1. Install the plugin
In the workspace root run this command to install the plugin :
npm install --save-dev @jnxplus/nx-gradle
2. Add Spring boot and Gradle wrapper support
The following command adds Spring boot and Gradle support (Gradle wrapper and config files) to the workspace. This only needs to be performed once per workspace.
nx generate @jnxplus/nx-gradle:init
I choose the version of Java supported by my operating system and the default value for Gradle root project:
my-org> nx generate @jnxplus/nx-gradle:init
√ Which version of Java would you like to use? · 11
√ What rootProjectName would you like to use? · boot-multiproject
CREATE checkstyle.xml
CREATE gradle/wrapper/gradle-wrapper.jar
CREATE gradle/wrapper/gradle-wrapper.properties
CREATE gradle.properties
CREATE gradlew
CREATE gradlew.bat
CREATE settings.gradle
UPDATE nx.json
UPDATE .gitignore
As you see, the command added the following files :
-
checkstyle.xml
for linting. - Gradle wrapper and Gradle executables for windows and Linux : Using Gradle Wrapper we can distribute/share a project to everybody to use the same version and Gradle's functionality(compile, build, install...) even if it has not been installed
-
gradle.properties
: This file contain Java, Spring Boot and dependency management versions that we will use for all apps and libs inside Nx worspace. -
settings.gradle
: Here we will add our apps and libs later so Gradle will be able to perform its tasks.
We also updated nx.json
file to add the plugin for dep-graph feature and .gitignore
so we can ignore Gradle build and cache folders.
3. Usage
Generate an application
nx generate @jnxplus/nx-gradle:application my-app
When asked, provide answers or choose default :
my-org> nx generate @jnxplus/nx-gradle:application my-app
√ What groupId would you like to use? · com.example
√ What version would you like to use? · 0.0.1-SNAPSHOT
√ Which packaging would you like to use? · jar
UPDATE workspace.json
UPDATE nx.json
CREATE apps/my-app/build.gradle
CREATE apps/my-app/src/main/java/com/example/myapp/HelloController.java
CREATE apps/my-app/src/main/java/com/example/myapp/MyAppApplication.java
CREATE apps/my-app/src/main/resources/application.properties
CREATE apps/my-app/src/test/java/com/example/myapp/HelloControllerTests.java
CREATE apps/my-app/src/test/resources/application.properties
UPDATE settings.gradle
Check the settings.gradle
, here we added a entry for my-app :
rootProject.name = 'boot-multiproject'
include('apps:my-app')
Build the app
nx build my-app
If you look carefully to the console, you will see that we run the command :
Executing command: gradlew.bat :apps:my-app:bootJar
Since we choose a jar
packaging, we run this command.
For war packaging, we run bootWar
.
Serve the app
nx serve my-app
Here under the hood we run the command : bootRun
.
Open http://localhost:8080 to see app working:
Test the app
To test the app run this command :
nx test my-app
What I like to do to see if test command is really working is breaking a test, and run it again :
So change the test and add a comma between Hello and World :
@Test
public void shouldReturnHelloWorld() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
Now rerun the same command :
Perfect, now the test target is failing.
Revert change and let's generate this time a library.
To generate a library use this command :
nx generate @jnxplus/nx-gradle:library my-lib
When asked, provide answers or choose default :
my-org> nx generate @jnxplus/nx-gradle:library my-lib
√ What groupId would you like to use? · com.example
√ What version would you like to use? · 0.0.1-SNAPSHOT
UPDATE workspace.json
UPDATE nx.json
CREATE libs/my-lib/build.gradle
CREATE libs/my-lib/src/main/java/com/example/mylib/HelloService.java
CREATE libs/my-lib/src/test/java/com/example/mylib/HelloServiceTests.java
CREATE libs/my-lib/src/test/java/com/example/mylib/TestConfiguration.java
UPDATE settings.gradle
Check the settings.gradle
, here we added a entry for my-lib :
rootProject.name = 'boot-multiproject'
include('libs:my-lib')
include('apps:my-app')
Like an app, we can build it and test it :
Build :
nx build my-lib
Test :
nx test my-lib
But we can't run it with serve target :
my-org> nx serve my-lib
> NX ERROR Cannot find target 'serve' for project 'my-lib'
Hope you like this article, and give this plugin a try :)
You can find the Github code here :
https://github.com/khalilou88/my-org
Top comments (2)
Thank you!
That's quite useful, the stack Java + JS is pretty common and monorepos are getting more attention as the time goes on 😁
that github url is 404. would you mind making it public again? thanks for the interesting article!