内容
Vue.js + Spring Boot + HerokuでSPAを作成しました。
Vue.jsとSpring Bootは同じリポジトリ上で管理し、ビルドも同時に実施します。
それにより、最低限のソースコード管理とHerokuへのデプロイ時にまとめてビルドする状態を実現しました。
本記事は第一弾として、プロジェクト作成〜ビルドまでを紹介します。
Vue.js + Spring Boot + Heroku(はじめに 兼 まとめ)
Vue.js + Spring Boot + Heroku(プロジェクト作成~ビルド)
Vue.js + Spring Boot + Heroku(Herokuへデプロイ〜環境毎プロパティファイル作成)
Vue.js + Spring Boot + Heroku(認証作成 Spring Boot編)
Vue.js + Spring Boot + Heroku(認証作成 Vue編)
Vue.js + Spring Boot + Heroku(サンプルAPI作成)
前提
・Herokuに登録済であること。
・Heroku CLIがインストール済であること。
・SprintToolSuiteがインストール済であること。(プロジェクト作るだけ)
・IntelliJがインストール済であること。(IDEとして使うだけ)
・npmが使用可能であること。
・Vue-CLIがインストール済であること。
・ポート8080と8081が使用されていないこと。
ディレクトリ構成
src配下は下記の通りです。
vue配下にソースコード管理して、ビルド時にresorce/vue配下に生成しSpringが使用される。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ├── main │   ├── java │   │   └── com │   └── resources │       ├── application.properties │       ├── static │       │   └── vue   // Springに利用される。ビルド時に生成。(git管理対象外) │       │       ├── css │       │       ├── favicon.ico │       │       ├── img │       │       ├── index.html │       │       └── js │       └── templates ├── test │   └── java │       └── com └── vue   //vueのソースコード(git管理対象)     ├── README.md     ├── babel.config.js     ├── package-lock.json     ├── package.json     ├── public     │   ├── favicon.ico     │   └── index.html     ├── src     │   ├── App.vue     │   ├── assets     │   ├── components     │   └── main.js     └── vue.config.js | 
Spring Bootプロジェクト作成
Spring Bootのプロジェクトを作成します。
IntelliJで作成したかったのですが、(コミュニティだから?)作成するものが見当たらず、STS(Spring Tool Suite)で作成しました。
新規のワークスペースを作成し、「新しいSpringスターター・プロジェクトを作成する」から作成開始。
とりあえずデフォルト設定+(java11は用意してないので)java 8を指定。

Spring webを追加して完了をクリック。


STS(というかEclipse)は使いづらいので一旦終了。IntelliJ(コミュニティ版)で開発します。
IntelliJを開き、
Open or Importからdemo(作成したプロジェクトのディレクトリ)を指定
聞かれたらMaen projectを選択

DemoApplicationを右クリックし、RunすることでSpring bootを起動できます。

以降は右上の▶︎で起動できます。

Spring Bootの作成は一旦完了です。
Vueプロジェクトを作成
Vueの作成をします。事前にVue CLIをインストールしてください。
まずはコマンドラインからVue CLI UIを起動。
| 1 | vue ui | 
Vueプロジェクトマネージャで作成をクリック
「demo(プロジェクト名)/src」を開き、「ここに新しいプロジェクトを作成する」をクリック
プロジェクトフォルダに「vue」と入力して次へをクリック

デフォルトプリセットを選択して「プロジェクトを作成する」をクリック

プロジェクト作成後はVue用のディレクトリに配置したいので、設置→Vue CLI→公開パスに「/vue」を指定して変更を保存をクリック。

設定を完了するとvue.config.jsが作成されます。
package.jsonのscriptsを修正して、ビルド時の出力先を指定。
加えて、Vue CLIのローカルサーバのポートがSpring Bootと被るため8081へ変更。
| 1 2 3 4 5 |   "scripts": {     "serve": "vue-cli-service serve --port 8081",     "build": "vue-cli-service build --dest ../../src/main/resources/static/vue",     "lint": "vue-cli-service lint"   }, | 
Spring BootのビルドでVueもビルドする
heroku gitによるソースコード管理は「.vue」ファイルのみにして、ビルドして生成される「.js」は管理せずにHerokuによるSpringのビルド時に一緒にビルドされ配置されることが理想的です。
pom.xmlへmavenでvueのビルドを追記。
参考:A Lovely Spring View: Spring Boot & Vue.js
ついでにlombokも追加
pom.xml
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 	<modelVersion>4.0.0</modelVersion> 	<parent> 		<groupId>org.springframework.boot</groupId> 		<artifactId>spring-boot-starter-parent</artifactId> 		<version>2.3.3.RELEASE</version> 		<relativePath/> <!-- lookup parent from repository --> 	</parent> 	<groupId>com.example</groupId> 	<artifactId>demo</artifactId> 	<version>0.0.1-SNAPSHOT</version> 	<name>demo</name> 	<description>Demo project for Spring Boot</description> 	<properties> 		<java.version>1.8</java.version> 	</properties> 	<dependencies> 		<dependency> 			<groupId>org.springframework.boot</groupId> 			<artifactId>spring-boot-starter-web</artifactId> 		</dependency> 		<dependency> 			<groupId>org.projectlombok</groupId> 			<artifactId>lombok</artifactId> 			<version>1.18.12</version> 			<scope>provided</scope> 		</dependency> 		<dependency> 			<groupId>org.springframework.boot</groupId> 			<artifactId>spring-boot-starter-test</artifactId> 			<scope>test</scope> 			<exclusions> 				<exclusion> 					<groupId>org.junit.vintage</groupId> 					<artifactId>junit-vintage-engine</artifactId> 				</exclusion> 			</exclusions> 		</dependency> 	</dependencies> 	<build> 		<plugins> 			<plugin> 				<groupId>com.github.eirslett</groupId> 				<artifactId>frontend-maven-plugin</artifactId> 				<version>1.10.0</version> 				<executions> 					<execution> 						<id>install node and npm</id> 						<goals> 							<goal>install-node-and-npm</goal> 						</goals> 						<configuration> 							<nodeVersion>v12.16.2</nodeVersion> 							<npmVersion>6.14.4</npmVersion> 						</configuration> 					</execution> 					<execution> 						<id>npm install --prefix ./src/vue/</id> 						<goals> 							<goal>npm</goal> 						</goals> 						<phase>generate-resources</phase> 						<configuration> 							<arguments>install --prefix ./src/vue/</arguments> 						</configuration> 					</execution> 					<execution> 						<id>npm run build --prefix ./src/vue/</id> 						<goals> 							<goal>npm</goal> 						</goals> 						<configuration> 							<arguments>run build --prefix ./src/vue/</arguments> 						</configuration> 					</execution> 				</executions> 			</plugin> 			<plugin> 				<groupId>org.springframework.boot</groupId> 				<artifactId>spring-boot-maven-plugin</artifactId> 			</plugin> 		</plugins> 	</build> </project> | 
右側のMavenタブを開き、グルグルマーク(Reload All Maven Projects)をクリック

src > main > java > com.example.demo配下にBaseController.javaを作成して設定。
BaseController.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; /**  * VueのSPAを返す。存在しないURLへのアクセス時はHtml5HistoryModeResourceConfigで返す。  */ @Controller public class BaseController {     @GetMapping(path = "/")     public String getSpa() {         return "forward:vue/index.html";     } } | 
historyモードを実現する場合、API以外のURLに対するアクセスはSPAを返却する必要があるため、存在しないULRへのアクセスは固定でファイルを返すよう指定。
参考:SPA(Nuxt.js)をSpring Bootからホストする方法
src > main > java > com.example.demo配下にHtml5HistoryModeResourceConfig.javaを作成。
Html5HistoryModeResourceConfig.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import lombok.RequiredArgsConstructor; import org.springframework.boot.autoconfigure.web.ResourceProperties; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.resource.PathResourceResolver; import java.io.IOException; /**  * 対応しないURLの場合、固定ページを返す。  * https://qiita.com/yushi_koga/items/65e94a97af1d0b0dc8b1  */ @RequiredArgsConstructor @Configuration public class Html5HistoryModeResourceConfig implements WebMvcConfigurer {     private final ResourceProperties resourceProperties;     @Override     public void addResourceHandlers(ResourceHandlerRegistry registry) {         registry.addResourceHandler("/**") // 全パスをこのリソースハンドラーの処理対象にする                 .addResourceLocations(resourceProperties.getStaticLocations()) // 静的リソース配置先のパスを指定する                 .resourceChain(resourceProperties.getChain().isCache()) // 開発時はfalse、本番はtrueが望ましい。trueにしておくとメモリ上にキャッシュされるためI/Oが軽減される                 .addResolver(new SpaPageResourceResolver()); // 拡張したPathResourceResolverを読み込ませる     }     public static class SpaPageResourceResolver extends PathResourceResolver {         @Override         protected Resource getResource(String resourcePath, Resource location) throws IOException {             Resource resource = super.getResource(resourcePath, location); // まずはPathResourceResolverで静的リソースを取得する             return resource != null ? resource : super.getResource("/vue/index.html", location); // 取得できなかった場合は、index.htmlを返す         }     } } | 
右側のmavenタブを開き、cleanとinstallを実行してVueをビルド。


【追記】windows環境の場合、npmコマンドの–prefixオプションが意図した動作をしません。手動でのビルドが必要です。
| 1 2 3 | cd src/vue npm install npm build | 
Spring Boot起動中の場合は一旦終了(■マーク)し、Spring Bootを起動(▶︎マーク)してサーバを起動。http://localhost:8080/へアクセスし、トップページを確認。

demo配下の.gitignoreへ追記
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | HELP.md target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/** !**/src/test/** .DS_Store # vue dist directory src/main/resources/static/vue # frontend-maven-plugin node/ node_modules/ ### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans .sts4-cache ### IntelliJ IDEA ### .idea *.iws *.iml *.ipr ### NetBeans ### /nbproject/private/ /nbbuild/ /dist/ /nbdist/ /.nb-gradle/ build/ ### VS Code ### .vscode/ |