spring.svg

Spring Boot + NuxtJSによるSPA構築

SpringBoot
Nuxt2

はじめに

この記事では、各プロジェクトの作成方法などについては触れません。 NuxtJS で生成した SPA をどのようにしたら Spring Boot でホスティングできるのかという説明になります。

各バージョンにより設定が異なる(変わってくる)可能性があります。 この記事では以下のバージョンで検証しています。

  • Spring Boot 2.5.5
  • NuxtJS 2.5.17

NuxtJS

SPA を構築するため、nuxt.config.jsssrtargetが以下であることが前提です。

nuxt.config.js
export default {
  ssr: false,
  target: 'static',
  //...
}

Spring Boot 側でコンテキストパスを設定する場合は、以下で同じものを設定します。

nuxt.config.js
export default {
  //...
  router: {
    base: '/context-path',
  },
  //...
}

あとは以下コマンドで、ビルドして SPA を生成します。 デフォルトだとdistフォルダに生成されます。

$ npm run generate

今回は仮に、ホーム(/)と About(/about)のページがあることとします。

Spring Boot

生成した SPA をsrc/main/resources/staticに配置します。

サーバーを起動してルートパスにアクセスすれば、ホームのページが表示されると思います。 ページリンク(<nuxt-link>)であれば、About ページも表示されます。

問題はページリロードです。 About ページでリロードすると、404として「Whitelabel Error Page」が表示されるかと思います。

ページリンクでは、SPA のためあくまで JavaScript でページを構築したに過ぎません。 つまり、サーバー側にリクエストを送信していません。

一方ページリロードは、/aboutに対してリクエストを送信するため、対象のリソースがないと判断されています。

これを解決するために、以下の設定クラスを作成します。

@Configuration
public class SpaResourceConfig implements WebMvcConfigurer {

  @Autowired
  private Resources resource;

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
      .addResourceHandler("/**")
      .addResourceLocations(resource.getStaticLocations())
      .resourceChain(false)
      .addResolver(new SpaPageResourceResolver());
  }

  private static class SpaPageResourceResolver extends PathResourceResolver {
    @Override
    protected Resource getResource(String resourcePath, Resource location) throws IOException {
      Resource resource = super.getResource(resourcePath, location);
      return resource != null ? resource : super.getResource("index.html", location);
    }
  }
}

細かい説明は省きますが、リクエストした際に対象のリソースがない場合、ホームのページ(src/main/resrouces/static/index.html)を表示するような設定になります。 例えば/aboutにリクエストを送信した場合、リソースとしてはindex.htmlが返ってきますが、/aboutというパスはそのまま残るため、パスから SPA が対象のページを構築します。

注意点として、@EnableMvcを付与した@Configurationクラスが存在するとルートパスでホームページが表示されません。 なぜそのようなことが起こるかまではわかりませんが、ご参考までに。