Next.js Discord

Discord Forum

Hosting requirements for a Next app?

Unanswered
American black bear posted this in #help-forum
Open in Discord
American black bearOP
Hello 👋

Please bear with me because I don't really know what I'm talking about here...

For my side projects I have always used Vercel, which obviously works flawlessly out of the box, and I've never thought to even consider how I would go about hosting a next app outside of Vercel.

However, I recently created an internal app for the company I work for as part of a hack project with another dev - There was some existing infrastructure in place, and my job was to replace the existing CRA with a better app, for which I used Nextjs (I will say the current scope of the project probably didn't need to use Next, but it'll be useful as and when the project grows)

This is where I'm out of my depth - The previous CRA was hosted using Spring and WebFlux, used to serve static html pages... Obviously, when it came time to host the app, it was abundantly clear that NONE of the Server Side stuff worked at all - Dynamic Routing, Server Actions, SSR etc...

To fix this in the interim, I've had to move all requests to the client and remove the dynamic routing so my app would build as a static site. Fortunately, using this Spring/WebFlux setup, I was able to match the URL and serve the previously dynamic route as a static page, using the route to build the URL my client-side request.

As a solution - This works fine, but obviously not as I ever intended.

My backend knowledge is incredibly minimal, and I don't know where to even start to actually fix this - Hoping someone here can point me in the right direction - I will share some of the existing code below that I had to tweak to make it work.

Thanks a lot! 🙏

2 Replies

American black bearOP
build.gradle
The comment was previously there - I don't know what WAR is, but hopefully it makes sense
frontend {
    nodeVersion = '16.18.0'
    nodeInstallDirectory = file("${project.projectDir}/frontend/node")
    packageJsonDirectory = file("${project.projectDir}/frontend")
    assembleScript = 'run build'
}

// Task to copy frontend resources into the backend build output so they are included in the WAR.
tasks.register('processFrontendResources', Copy) {
    group 'Frontend'
    description 'Process frontend resources'
    dependsOn ':assembleFrontend'
        from file("${project.projectDir}/frontend/.next")
        into file("${project.buildDir}/resources/main/public/_next")
}
tasks.named('assembleFrontend') {
    dependsOn tasks.named('installFrontend')
}
tasks.named('processResources') {
    dependsOn tasks.named('processFrontendResources')
}
AppWebFluxConfiguration.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

@Configuration
public class PricingLogUiWebFluxConfiguration {

  @Bean
  public RouterFunction<ServerResponse> indexRouter(
      @Value("classpath:/public/_next/server/app/index.html") Resource indexPage) {

    return RouterFunctions.route(
        RequestPredicates.GET("/hack"),
        request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(indexPage));
  }

  // This was the "dynamic" route with SSR - The "Seed" is a unique ID we use to request data.
  @Bean
  public RouterFunction<ServerResponse> seedRouter(
      @Value("classpath:/public/_next/server/app/seed.html") Resource seedPage) {

    return RouterFunctions.route(
        RequestPredicates.GET("/hack/*"),
        request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(seedPage));
  }

  @Bean
  public RouterFunction<ServerResponse> errorRouter(
      @Value("classpath:/public/_next/server/pages/404.html") Resource errorPage) {

    return RouterFunctions.route(
        RequestPredicates.GET("/hack/*/**"),
        request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(errorPage));
  }
}