この記事ではSpring BootとVue.js (SPA)アプリの構築方法を紹介したいと思います。本アプリはAPIサーバーとフロントエンドは同一サーバーで稼働する構成を想定しています。
アプリケーション全体のソースコードはこちら
環境
Spring Boot | 2.5.4 |
Java | 16 |
Kotlin | 1.5.30 |
Vue CLI | 4.5.13 |
Vue | 3.2.6 |
vue-router | 4.0.11 |
TypeScript | 4.3.5 |
spring initializrで以下の構成で作成されたアプリケーションを前提としています。

設定
それでは順に設定を進めていきましょう!
Vueのソースコードの追加
まずはVue関連のソースコードを追加していきましょう。
本アプリではVueのソースコードをsrc/main/vue以下に配置し、package.jsonなどの設定ファイルはプロジェクト直下に配置するようにします。
babel.config.js
babel.config.jsをプロジェクト直下に配置します。
module.exports = {
presets: [
"@vue/cli-plugin-babel/preset"
]
}
package.json
package.jsonをプロジェクト直下に追加します。
{
"name": "spring-boot-vue",
"version": "1.0.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.21.1",
"core-js": "^3.17.2",
"vue": "^3.2.6",
"vue-router": "^4.0.11",
"vuex": "^4.0.2"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.30.0",
"@typescript-eslint/parser": "^4.30.0",
"@vue/cli-plugin-babel": "~4.5.13",
"@vue/cli-plugin-eslint": "~4.5.13",
"@vue/cli-plugin-router": "~4.5.13",
"@vue/cli-plugin-typescript": "~4.5.13",
"@vue/cli-plugin-vuex": "~4.5.13",
"@vue/cli-service": "~4.5.13",
"@vue/compiler-sfc": "^3.2.6",
"@vue/eslint-config-standard": "^5.1.2",
"@vue/eslint-config-typescript": "^7.0.0",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^7.17.0",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"typescript": "~4.3.5"
}
}
tsconfig.json
tsconfig.jsonをプロジェクト 直下に追加します。
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env"
],
"paths": {
"@/*": [
"src/main/vue/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/main/vue/**/*.ts",
"src/main/vue/**/*.tsx",
"src/main/vue/**/*.vue",
"src/test/vue/**/*.ts",
"src/test/vue/**/*.tsx",
"src/test/vue/**/*.vue",
],
"exclude": [
"node_modules"
]
}
paths及びincludeの設定部分でVueのソースファイルの位置を指定しています。
vue.config.js
vue.config.jsをプロジェクト 直下に追加します。
vue.config.jsはVue CLIの設定を行うための設定ファイルとなります。
const path = require("path")
module.exports = {
configureWebpack: {
resolve: {
alias: {
"@": path.join(__dirname, "/src/main/vue"), // (1) エイリアスの設定
},
},
},
outputDir: "src/main/resources/static", // (2) ビルド結果の出力先
pages: {
index: {
entry: "src/main/vue/main.ts",
template: "src/main/vue/public/base.html",
filename: "index.html",
},
},
// (3) 開発サーバーの設定
devServer: {
proxy: {
"/api": {
target: "http://localhost:8080",
},
},
port: 8090,
},
}
(1) ではimport文等で使用可能なエイリアスの参照先を設定しています。
(2)は非常に重要な設定なのですが、Vue CLIのビルドの出力先を指定しています。出力先をsrc/main/resources/staticにすることによりSpring Bootアプリの静的ファイルとして公開されます。
(3)では開発サーバーの設定をしています。
Vue CLIでは開発用のサーバーが内蔵されており、開発時はそちらを使用することでソースコードの変更を即時反映することができます。Spring Bootサーバのポートと重複しないように8090ポートで起動するように設定しています。
また、開発環境では”api”で始まるURIの通信はSpring BootのRestControllerにリクエストを送れるようにプロキシ設定を行っています。
SPA用の画面遷移設定
本アプリケーションはVueのrouterを使用しており、いわゆるSPA(Single Page Application)の構成になっているため、サーバーサイド(Spring Boot)ではページ要求に対して常にindex.htmlを返す必要があります。
index.html遷移用のコントローラーの設定
package com.example.springbootvue.controller
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
@Controller
class ForwardController {
@GetMapping("/")
fun index() = "forward:/index.html"
}
ResourceHandlerの設定
次に/以外のパスでアクセスがあった場合もindex.htmlを返せるようにします。
まずはSpring MVCの設定を行います。
WebMvcConfigurerを継承した設定クラスを作成し、addResourceHandlersメソッドをオーバーライドし、SPA用のResourceResolverを登録します。
package com.example.springbootvue.config
import org.springframework.boot.autoconfigure.web.WebProperties
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
class WebMvcConfig(
private val resources: WebProperties.Resources,
private val spaPageResourceResolver: SpaPageResourceResolver,
) : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/**")
.addResourceLocations(*resources.staticLocations)
.resourceChain(resources.chain.isCache)
.addResolver(spaPageResourceResolver)
}
}
package com.example.springbootvue.config
import org.springframework.core.io.Resource
import org.springframework.stereotype.Service
import org.springframework.web.servlet.resource.PathResourceResolver
@Service
class SpaPageResourceResolver: PathResourceResolver() {
override fun getResource(resourcePath: String, location: Resource): Resource? {
val resource = super.getResource(resourcePath, location)
return resource ?: super.getResource("index.html", location)
}
}
上記の設定ではresourcePathで渡されたパスが存在しない場合にindex.htmlを返すようにしています。
次にcssやjsなどの静的リソースはSPA用のResourceResolverが適用されないようにapplication.ymlで静的リソースのパスパターンを登録します。
spring:
mvc:
static-path-pattern: /**/*.* # 拡張子付きのものは静的リソースとして扱う
build.gradleの設定
ビルド設定を行います。
本アプリではVueのアプリケーションの構築にVue CLIを使用しており、Vue CLIではアプリケーションのビルドにWebpackというビルドツールを使用しています。上記の設定ではGradle Plugin for Nodeというプラグインを使用し、gradleのビルドプロセスにVue CLIのビルドプロセスを組み込んでいます。
plugins {
id "org.springframework.boot" version "2.5.4"
id "io.spring.dependency-management" version "1.0.11.RELEASE"
id "org.jetbrains.kotlin.jvm" version "1.5.30"
id "org.jetbrains.kotlin.plugin.spring" version "1.5.30"
id "com.github.node-gradle.node" version "3.1.0" // (1) Gradle Plugin for Nodeを追加
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_16
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "16"
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ["-Xjsr305=strict"]
jvmTarget = "16"
}
}
test {
useJUnitPlatform()
}
// (2)
node {
version = "14.17.6"
npmVersion = "7.13.0"
download = true
workDir = file("${project.projectDir}/node_runtimes/nodejs")
npmWorkDir = file("${project.projectDir}/node_runtimes/npm")
nodeModulesDir = file("${project.projectDir}")
}
// (3)
processResources.dependsOn npm_run_build
(1) Gradle Plugin for Nodeをプラグインとして追加
(2) Vue CLIで使用するNode.jsを設定
downloadをtrueにすることでNode.jsやnpmがインストールされていない環境でも自動的にランタイムをダウンロードし、実行されます。
(3) gradleのリソースプロセスにVue CLIのビルドプロセスを組み込む
上記の設定ではprocessResourcesの実行前に npm_run_buildタスクが実行されます。
Gradle Plugin for Nodeではスネークケースでnpmのコマンドを実行できますので、npm_run_buildと指定することで、npm run buildが実行されます。
まとめ
今回はSpring BootとVue.js (SPA)アプリの構築方法を紹介しました。機会があれば、React (Create React Appベース)のアプリの構築方法もご紹介できればと思います。
最後までお読みいただき、ありがとうございました。
コメント