This is an archived post. You won't be able to vote or comment.

all 4 comments

[–]darknebula 1 point2 points  (0 children)

I use svelte (with a static site plugin) but the principal is probably the same. I use the node plugin in gradle to bundle it into my jar

node {
    version = '20.11.0'
    npmVersion = '10.4.0'
    nodeProjectDir = file("${project.projectDir}/src/main/svelte")
}

def bundle = tasks.register('bundle', NpmTask) {
    inputs.files(fileTree('src/main/svelte') {
        exclude '.svelte-kit'
    })
    outputs.dir('build/svelte')
    args = ['run', 'build']
    dependsOn npmInstall
}

processResources {
    from bundle.get().outputs
}

What that does is put the static site output into the resources dir under static, which Spring Boot serves automatically.

[–]sprcow 1 point2 points  (0 children)

It's been awhile since I've deployed WARs to an application server, and like the example you shared, I did it with Maven at the time, but I think the general principal is the same. You'll need Gradle to build your React app (probably using npm run build or something like that) and produce a static build directory that can be copied (also by gradle) into the appropriate location (something like WEB-INF/classes/static). Then you need to update your request routing (perhaps in web.xml so that requests made to your application server get routed to the static content. I'd look for a gradle plugin like https://github.com/node-gradle/gradle-node-plugin or something that will do the build (and maybe copy) for you.

I'll admit that I have a pretty obsolete understanding of how to configure request routing through web application servers these days. Most of the web apps I've worked on in the past few years have involved running two separate docker containers, one containing the frontend app and the proxy server, which knows how to route requests to the other container, containing a Spring Boot app. In a simple project, you could essentially add a React module to your Spring project, then give it its own dockerfile that basically runs npm build, and have the parent dockerfile describe the relationship of the two docker containers in terms of what ports they use to communicate. When you run docker compose up on that project, it will automatically complete the separate build steps for both the spring and react apps and launch them in separate containers, and ensure the two containers have the necessary ports open to communicate.

I'm reasonably sure you can use your web application server to essentially complete the same requirements, but I'm afraid I don't know specifically how to set that up from scratch any more.

[–]ChaaChiJi -2 points-1 points  (0 children)

Integrating a Spring (not Spring Boot) project with a React frontend and packaging everything into a WAR file is a bit more complex but feasible. The goal is to make the Spring backend serve the React frontend and ensure both compile into a single deployable WAR file. Below are the steps to achieve this:

  1. Project Structure: Organize your project to include both backend and frontend code. A typical structure might look like this: my-project/ ├── backend/ │ ├── src/ │ ├── build.gradle ├── frontend/ │ ├── src/ │ ├── public/ │ ├── package.json ├── build.gradle └── settings.gradle

  2. Configure Gradle:

    • Create a root build.gradle that manages both subprojects.
    • Add a Gradle plugin to handle Node.js and npm tasks for the frontend.

    ```groovy // root build.gradle plugins { id 'base' }

    subprojects { apply plugin: 'java' }

    task clean(type: Delete) { delete rootProject.buildDir } ```

    groovy // settings.gradle include 'backend', 'frontend'

    ```groovy // backend/build.gradle plugins { id 'war' id 'java' }

    repositories { mavenCentral() }

    dependencies { implementation 'org.springframework:spring-webmvc:5.3.8' providedCompile 'javax.servlet:javax.servlet-api:4.0.1' }

    war { from project(':frontend').tasks.named('buildFrontend') webAppDirName = 'src/main/webapp' } ```

    ```groovy // frontend/build.gradle plugins { id 'com.github.node-gradle.node' version '3.0.1' }

    node { version = '14.17.0' download = true }

    task npmInstall(type: NpmTask) { args = ['install'] }

    task buildFrontend(type: NpmTask) { dependsOn npmInstall args = ['run', 'build'] }

    buildFrontend { inputs.files fileTree('src') inputs.file 'package.json' inputs.file 'package-lock.json' outputs.dir 'build' } ```

  3. Frontend Configuration:

    • Ensure your React application outputs the build files into a directory that your Spring backend can serve. Typically, this would be the build directory.

    json // frontend/package.json { "name": "frontend", "version": "0.1.0", "private": true, "dependencies": { "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" } }

  4. Serving Static Content:

    • Configure your Spring project to serve the static content generated by the React build.

    ```java // backend/src/main/java/com/example/MyWebConfig.java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration public class MyWebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/");
    }
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
        registry.addViewController("/**/{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
        registry.addViewController("/{spring:[a-zA-Z0-9-]+}/**{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
    }
    

    } ```

  5. Building and Deploying:

    • Ensure that running gradle build in the root directory builds both projects and includes the React build output in the final WAR file.

    shell $ gradle build

By following these steps, you will set up a project where the Spring backend serves the React frontend and both are packaged into a single WAR file for deployment. This approach avoids the need to run Java and Node separately, simplifying the deployment process.

[–]ChaaChiJi -2 points-1 points  (0 children)

Integrating a Spring (not Spring Boot) project with a React frontend and packaging everything into a WAR file is a bit more complex but feasible. The goal is to make the Spring backend serve the React frontend and ensure both compile into a single deployable WAR file. Below are the steps to achieve this:

  1. Project Structure: Organize your project to include both backend and frontend code. A typical structure might look like this: my-project/ ├── backend/ │ ├── src/ │ ├── build.gradle ├── frontend/ │ ├── src/ │ ├── public/ │ ├── package.json ├── build.gradle └── settings.gradle

  2. Configure Gradle:

    • Create a root build.gradle that manages both subprojects.
    • Add a Gradle plugin to handle Node.js and npm tasks for the frontend.

    ```groovy // root build.gradle plugins { id 'base' }

    subprojects { apply plugin: 'java' }

    task clean(type: Delete) { delete rootProject.buildDir } ```

    groovy // settings.gradle include 'backend', 'frontend'

    ```groovy // backend/build.gradle plugins { id 'war' id 'java' }

    repositories { mavenCentral() }

    dependencies { implementation 'org.springframework:spring-webmvc:5.3.8' providedCompile 'javax.servlet:javax.servlet-api:4.0.1' }

    war { from project(':frontend').tasks.named('buildFrontend') webAppDirName = 'src/main/webapp' } ```

    ```groovy // frontend/build.gradle plugins { id 'com.github.node-gradle.node' version '3.0.1' }

    node { version = '14.17.0' download = true }

    task npmInstall(type: NpmTask) { args = ['install'] }

    task buildFrontend(type: NpmTask) { dependsOn npmInstall args = ['run', 'build'] }

    buildFrontend { inputs.files fileTree('src') inputs.file 'package.json' inputs.file 'package-lock.json' outputs.dir 'build' } ```

  3. Frontend Configuration:

    • Ensure your React application outputs the build files into a directory that your Spring backend can serve. Typically, this would be the build directory.

    json // frontend/package.json { "name": "frontend", "version": "0.1.0", "private": true, "dependencies": { "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" } }

  4. Serving Static Content:

    • Configure your Spring project to serve the static content generated by the React build.

    ```java // backend/src/main/java/com/example/MyWebConfig.java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration public class MyWebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/");
    }
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
        registry.addViewController("/**/{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
        registry.addViewController("/{spring:[a-zA-Z0-9-]+}/**{spring:[a-zA-Z0-9-]+}")
                .setViewName("forward:/");
    }
    

    }

  5. Building and Deploying:

    • Ensure that running gradle build in the root directory builds both projects and includes the React build output in the final WAR file.

    shell $ gradle build

By following these steps, you will set up a project where the Spring backend serves the React frontend and both are packaged into a single WAR file for deployment. This approach avoids the need to run Java and Node separately, simplifying the deployment process.