WebフレームワークでWebpackを使ってみよう〜SpringBoot+Webpack+Vue.js編〜
第4回目です
Laravel、Django、Railsときて最終回はSpringBootです
作るものはお約束のこれです
jp.vuejs.org
環境
nodeやWebpackは今までと同じなので省略します
SpringBootはリリースされたばかりの2.0です
特に意識したわけではございませんw
ボケーとIntellijでポチポチとSpringBootプロジェクト作ったら2.0だった
— てっしー🐝🍯🐻 (@chichi1091) 2018年3月1日
- Java@1.8
- SpringBoot@2.0.0
SpringBootプロジェクトの作成
僕はIntellij IDEAユーザなので新規プロジェクト作成でポチポチと作りました
作れたらnpmでモジュールをインストールしていきます
npm init -f npm install --save-dev webpack webpack-cli wevpack-dev-server vue style-loader css-loader
webpackの設定
今までのフレームワークはwebpack用のモジュールが用意されていたのでコマンドで準備ができていましたが、SpringBootやGradleにはありませんので手動で準備をしてきます
webpack.config.js
コンパイルの入出力やcssの組み込み、wevpack-dev-serverの設定を記載します
コメントになっている output
ですが、ここが悩ましかった。。
resources/static
にすることでSpringBootのポートでJavaScriptにアクセスできますが、build
配下だと wevpack-dev-server
を起動しないとJavaScriptにアクセスできません
どちらが正解なのか悩ましいところですが自分はwevpack-dev-server
を起動しないSpringBoot経由を選びました。。
var path = require('path') var webpack = require('webpack') var fs = require('fs') const vendor = { vendor: ['vue'] } const entries = fs.readdirSync('./src/main/js') .filter(a => /\.js$/.test(a)) .reduce((acc, x) => { acc[x.slice(0, -3)] = './src/main/js/' + x return acc }, vendor) module.exports = { entry: entries, output: { // path: path.resolve(__dirname, './build/classes/main/static/js'), path: path.resolve(__dirname, './src/main/resources/static/js'), publicPath: '/js/', filename: '[name].js', }, module : { rules: [ { test: /\.css/, use: [ 'style-loader', { loader: 'css-loader', options: { url: false, sourceMap: true, }, }, ], }, ] }, resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' } }, devServer: { historyApiFallback: true, noInfo: true, contentBase: path.join(__dirname, "./bin/static"), }, performance: { hints: false }, devtool: '#eval-source-map' }
package.json
Gradleから呼び出されるwebpackコマンドをscriptsに記載します
{ "private": true, "name": "springboot-webpack-vue", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack-dev-server --inline --hot", "build": "webpack", "watch": "webpack --progress --watch" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^0.28.10", "style-loader": "^0.20.2", "vue": "^2.5.13", "webpack": "^4.0.1", "webpack-cli": "^2.0.9", "webpack-dev-server": "^3.1.0" } }
Gradleの設定
SpringBootのrunやコンパイルでJavaScriptのビルドも行えるようにします
この辺の情報がググっても錯綜していて難しかった。。
build.gradle
buildscript { ext { springBootVersion = '2.0.0.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' tasks.withType(JavaCompile) { sourceCompatibility = '1.8' targetCompatibility = '1.8' options.encoding = 'UTF-8' } repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-thymeleaf') compile('org.springframework.boot:spring-boot-starter-web') runtime('org.springframework.boot:spring-boot-devtools') testCompile('org.springframework.boot:spring-boot-starter-test') } bootJar { launchScript() } task npmRunBuild { doLast { def npm = System.getProperty('os.name').contains('Windows') ? 'cmd /c npm' : 'npm' if (file('./node_modules').exists() == false) { "${npm} install".execute().waitForProcessOutput(System.out, System.err) } "${npm} run build".execute().waitForProcessOutput(System.out, System.err) } } processResources.dependsOn npmRunBuild
SpringBootの起動スクリプト化は2.0でかわったぽいです
SpringBoot2の起動スクリプトはこう書くのか
— てっしー🐝🍯🐻 (@chichi1091) 2018年3月1日
bootJar {
launchScript()
}
コントローラーや画面、Vue.jaの組み込み
ここからはよくあるSpringBootやサンプルVue.jsなので細かい説明は省きます
IndexController.java
@Controller public class IndexController { @GetMapping("/") public String index() { return "index"; } }
src/main/resources/templates/index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>springboot-webpack-vue</title> </head> <body> <!-- item template --> <script type="text/x-template" id="item-template"> <li> <div :class="{bold: isFolder}" @click="toggle" @dblclick="changeType"> {{ model.name }} <span v-if="isFolder">[{{ open ? '-' : '+' }}]</span> </div> <ul v-show="open" v-if="isFolder"> <item class="item" v-for="(model, index) in model.children" :key="index" :model="model"> </item> <li class="add" @click="addChild">+</li> </ul> </li> </script> <p>(You can double click on an item to turn it into a folder.)</p> <!-- the demo root element --> <ul id="demo"> <item class="item" :model="treeData"> </item> </ul> <script src="/js/vendor.js"></script> <script src="/js/index.js"></script> </body> </html>
src/main/js/index.js
import '../css/index.css'; import Vue from 'vue' // demo data var data = { name: 'My Tree', children: [ { name: 'hello' }, { name: 'wat' }, { name: 'child folder', children: [ { name: 'child folder', children: [ { name: 'hello' }, { name: 'wat' } ] }, { name: 'hello' }, { name: 'wat' }, { name: 'child folder', children: [ { name: 'hello' }, { name: 'wat' } ] } ] } ] } // define the item component Vue.component('item', { template: '#item-template', props: { model: Object }, data: function () { return { open: false } }, computed: { isFolder: function () { return this.model.children && this.model.children.length } }, methods: { toggle: function () { if (this.isFolder) { this.open = !this.open } }, changeType: function () { if (!this.isFolder) { Vue.set(this.model, 'children', []) this.addChild() this.open = true } }, addChild: function () { this.model.children.push({ name: 'new stuff' }) } } }) // boot up the demo var demo = new Vue({ el: '#demo', data: { treeData: data } })
src/main/css/index.css
body { font-family: Menlo, Consolas, monospace; color: #444; } .item { cursor: pointer; } .bold { font-weight: bold; } ul { padding-left: 1em; line-height: 1.5em; list-style-type: dot; }
動作確認
gradlew bootrun
をしてもらえればJavaScriptのコンパイルが行われSpringBootが起動します
まとめ
4つのフレームワークの中でwebpackのモジュールが用意されていなかったので準備することは多かったSpringBootでした
あと情報も意外と少なかったように思います
結構悩みました...
今回もソースはGitHubにあげてあります
webpack組み込みの参考になれば幸いです(^^)