Multi module application

Hi,

First of all, congratulations on the 1.0 release it is awesome!

I am starting a new project and wanted to structure it a bit different. My idea is to have one single (gradle) project with several modules in it, one for the application and others for components. That is: I want to put in the same project the Jmix application and Jmix components.

My rationale is that having everything in one place at the beggining lets me move fast, but having some pieces in components very early on will force for better decoupling and make my life easier as the project grows.

The 1st thing I noticed is that Jmix documentation does not include many details about components as CUBA did (cuba docs). Not much of a problem, I cloned several of the current addons to see how they are built.

I have succeeded. I was impressed that it is not completely unexpected because the Studio addon is detecting the components and application and showing all of them!!

But I had to do it all by hand. If you tell IDEA to add a new Module to the project and select Jmix it results in an empty folder with nothing in it. So I had to create the projects and then copy over stuff to the main project amending the gradle files.

I will now drop some snippets for further reference and for anyone looking into this, any feedback is more than welcome!!

I will get to the point at the bottom!

Main project

./gradle.properties
version = 1.0.0-SNAPSHOT
jmixVersion = 1.0.0
bomVersion = 1.0.0-SNAPSHOT
./settings.gradle

This is mostly based on the datatools addon, the gradle files of the subprojects are named as the subproject instead of build.gradle, hence the bottom code block.

rootProject.name = 'mni'

include 'main'  // This is the Application module. Should be named "app" maybe.
include 'a3link-bom:a3link'  // This is the component module
include 'a3link-bom:a3link-starter' // This is the Springboot starter for the component

rootProject.children.each { p1 ->
    p1.buildFileName = "${p1.name}.gradle"
    p1.children.each {p2 ->
        p2.buildFileName = "${p2.name}.gradle"
    }
}
./build.gradle

This is also based on the datatools addon mixing parts from an empty Jmix project.

buildscript {
    repositories {
        mavenLocal()
        maven {
            url 'https://nexus.jmix.io/repository/public'
        }
        gradlePluginPortal()
    }
    dependencies {
        classpath("io.jmix.build:jmix-build:${rootProject.findProperty('jmixVersion')}")
        classpath("io.jmix.gradle:jmix-gradle-plugin:${rootProject.findProperty('jmixVersion')}")
    }
}

subprojects {
    group = 'com.company.mni'
    version = rootProject.findProperty('bomVersion')

    repositories {
        mavenLocal()
        mavenCentral()
        maven {
            url 'https://global.repo.jmix.io/repository/public'
        }
    }

    /* datatools applies jmix plugin here, but we do not as we might want different
       plugins applied for certain modules. So we do this on each module. */
    //apply plugin: 'io.jmix.build'
}

“main” module

This is the application module, it is based on an empty Jmix application project.
The src folder is copied over, and the only gradle file is main.gradle (no settings, properties, wrapper, etc).

./main/main.gradle
plugins {
    id 'io.jmix'
    id 'java'
}

apply plugin: 'org.springframework.boot'

jmix {
    bomVersion = rootProject.findProperty('jmixVersion')
    projectId = 'main'
}

dependencies {
    // here go all the jmix dependencies + spring-boot-starter-web + database driver
    // just copy that from the empty project

    // Add the components from the project
    implementation project(':a3link-bom:a3link-starter')
}

test {
    useJUnitPlatform()
}

a3link module

Here start the doubts… I created a -bom module and put both component’s modules in here (the component + starter modules) so I can keep them toghether. I could have them directly on the rootProject. I have no idea of what the implication are except that I need an extra build file (for the -bom project) and the project names are longer (:project-bom:project). Also, the a3link-bom.gradle file has some stuff that might be needed (based on a clean component build.gradle file)

./a3link-bom/a3link-bom.gradle

Mostly based on the build.gradle of and empty component project,

subprojects {
    apply plugin: 'java-library'
    apply plugin: 'io.jmix'

    jmix {
        bomVersion = rootProject.findProperty('jmixVersion')
        projectId = 'a3link'
    }

    java {
        withSourcesJar()
    }

    artifacts {
        archives sourcesJar
    }
}
./a3link-bom/a3link/a3link.gradle

Inside its module (a3link-bom/a3link)

plugins {
    id 'java'
}

archivesBaseName = 'a3link'

dependencies {
    // Jmix dependencies, copied from the empty project
}

test {
    useJUnitPlatform()
}
./a3link-bom/a3link/a3link-starter.gradle

Inside its module (a3link-bom/a3link-starter)

archivesBaseName = 'a3link-starter'

jmix {
    entitiesEnhancing {
        enabled = false
    }
}

dependencies {
    api project(':a3link-bom:a3link')

    implementation 'io.jmix.core:jmix-core'
    implementation 'io.jmix.data:jmix-data'

    implementation 'org.springframework.boot:spring-boot-autoconfigure'
}

To the point

So, now to the point:

  1. Is such a setup supported or discouraged? (having one big gradle project with application+components)
  2. If it is supported, may Jmix include such a project template in the future? (multi module application)
  3. Will Jmix documentation expand on components on future releases like CUBA did?
  4. If I had more than one application subproject, how would I tell Jmix Studio which one to run then using the “Jmix Application” configuration?
  5. If the “creating a Jmix module inside a project results in an empty folder” can be reproduced, please file and issue!

Best,
Marc

6 Likes

Hi Marc,

Sorry for the very late reply.
I hope the topic is still relevant for you, so I’ll try to answer your questions.

I think it’s a natural choice at least for reusable add-on projects. It’s very convenient to have an add-on and a demo application in a single project.
Whether to split a big project to functional modules - probably it’s highly project-specific and also depends on your team structure.

The more obvious thing for me is the need for ability to split a project to modules by layers, at least to separate UI from backend services.

At the moment, nothing prevents you from creating such project structures manually, as you have already done. But Studio has some problems with handling multi-module projects. While the Jmix tool window with the project structure works mostly correctly, there are issues with creating screens, entities, liquibase diffs and so on. So we officially don’t support multi-module projects yet, and this feature is assigned for the Feb 2022 release (see our roadmap).

We’ll add multi-module templates and documentation after implementing the full support in Studio.

Perhaps we’ll address these issues during implementation. Thanks for pointing them out!

Regards,
Konstantin

2 Likes

Thank you for your reply. It is still revelant and I’ll keep an eye on the roadmap and try to stay away of the possible problems I may run into.

@krivopustov any update on the that?

I’m facing similar issue.
I was trying to build monorepo on which I’ve tried to create 2 Jmix single projects (internal and external portals) and to have separate module for the addons which those 2 portals will share but unfortunately seems like this is not supported yet…

Do you have any suggestion on how I can achieve that or currently it is not possible?

Best Regards,
Dzhuliyan Ovcharov

@djuliqn.bg note that Jmix 1.2 (RC just released) includes support for Composite Projects aka multi-module.

What is described in this post may not be up-to-date.

1 Like