μ€νλ§ λΆνΈ μ ν리μΌμ΄μ μ Vueμ ν¨κ» κ°λ°νκΈ°
κ΄λ ¨ μμ€μ½λλ Github spring-boot-integration-vuejs 리ν¬μ§ν 리μμ μ 곡ν©λλ€.
μ΅κ·Όμλ μ€νλ§ νλ μμν¬λ‘ μ ν리μΌμ΄μ κ°λ° μ νλ‘ νΈμλ ν΄λΌμ΄μΈνΈλ₯Ό Vueλ₯Ό νμ©νμ¬ κ°λ°νκ³ λ°°ν¬ν©λλ€. μ΄λ² κΈμμλ μ€νλ§ λΆνΈ νλ‘μ νΈλ₯Ό μμνκ³ Vue CLIλ₯Ό ν΅ν΄ νλ‘ νΈμλ ν΄λΌμ΄μΈνΈλ₯Ό κ°λ°ν λ μ΄λ»κ² μ§ννλμ§ μ€λͺ ν©λλ€. μ κ° μλ €λ리λ λ°©λ²κ³Ό ꡬ쑰λ μ νν μ λ΅μ μλμ 미리 λ°νλ λ° μ λλ€.
Spring Initializr
μ€νλ§ λΆνΈ νλ‘μ νΈλ Spring Initializrμμ μ½κ² μ¬λ¬λΆμ΄ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ μμν μ μλλ‘ μ§μν©λλ€. μ λ λ©μ΄λΈ(Maven)μ΄ μλ κ·Έλλ€(Gradle)
νλ‘μ νΈλ₯Ό μ νΈνλ©° μΈμ΄λ Java
λ‘ κ°λ°ν©λλ€.
κ·Έλ¦¬κ³ μμ κ°μ΄ νλ‘μ νΈμμ μ¬μ©ν μμ‘΄μ±(Dependencies)λ₯Ό μ°Ύμ μ νν©λλ€. μ΄λ κ² λ§λ€μ΄μ§λ μ€νλ§ λΆνΈ νλ‘μ νΈλ λ€μκ³Ό κ°μ λλ ν 리 ꡬ쑰λ₯Ό κ°μ§κ² λ©λλ€.
src
ββ main
β ββ java
β ββ resources
gradle
build.gradle
Vue CLI
μμ Spring Initializr
λ₯Ό ν΅ν΄ μ€νλ§ λΆνΈ νλ‘μ νΈλ₯Ό ꡬμ±νμμ΅λλ€. μ΄μ λ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
κ³Ό ν¨κ» κ°λ°ν Vue νλ‘μ νΈλ₯Ό ꡬμ±ν©λλ€. Vue νλ‘μ νΈλ Vue CLIλ₯Ό νμ©νμ¬ μ½κ² μμν μ μμ΅λλ€.
# Vue CLIλ NPMμΌλ‘ μ€μΉν©λλ€.
npm i -g @vue/cli
# κ·Έλ¦¬κ³ create λͺ
λ Ήμ΄λ‘ νλ‘μ νΈλ₯Ό μμν©λλ€.
vue create --preset kdevkr/vue-preset [project-name]
μ μμμ²λΌ Vue νλ‘μ νΈλ₯Ό μμν λ μμ£Ό μ¬μ©νλ νλ¬κ·ΈμΈμ ν리μ νν(preset.json)λ‘ κ΅¬μ±νμ¬ μ§μ ν μ μμ΅λλ€. μ μ kdevkr/vue-preset ν리μ μ λ€μμ λΌμ΄λΈλ¬λ¦¬λ€μ ν¬ν¨νλ Vue νλ‘μ νΈλ₯Ό ꡬμ±ν©λλ€.
- Babel
- ESLint + Prettier
- SCSS (with dart-sass)
- Vuex
- Vue Router
- Bootstrap Vue
- Fontawesome
src/main/vue
보ν΅μ νλ‘μ νΈ λ£¨νΈ κ²½λ‘μ Vue νλ‘μ νΈλ₯Ό ꡬμ±ν΄λ μκ΄μμΌλ μ λ src/main/java
μ²λΌ src/main/vue
λ‘ κ΅¬μ±νλ κ²μ μΆμ²ν©λλ€. μ΄μ src/main/vue ν΄λμμ νλ‘ νΈμλ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό κ΄λ¦¬νκ² λ©λλ€.
cd src/main
vue create --preset kdevkr/vue-preset vue
Vue CLIμ μν΄ src/main/vueμ Vue νλ‘μ νΈκ° λ§λ€μ΄μ§λλ€.
Vue Configuration
Vue νλ‘μ νΈμ λν μ€μ μ vue.config.js
λ₯Ό ν΅ν΄ λ³κ²½ν μ μμ΅λλ€. Vue νλ‘μ νΈλ λ§λ€μμ§λ§ λͺκ°μ§ μ€μ μ μ§νν΄μΌν©λλ€. κ°μ₯ λ¨Όμ Vueλ₯Ό ν΅ν΄ κ°λ°ν λλ webpack-dev-serverλ₯Ό μ€νν΄μ κ°λ°ν©λλ€.
μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ λ³λ€λ₯Έ μ€μ μ΄ μμΌλ©΄ 8080
ν¬νΈλ₯Ό μ¬μ©νκ² λ©λλ€. λ°λΌμ, Vue κ°λ°μ© μλ²λ 8081
ν¬νΈλ₯Ό μ¬μ©νλλ‘ ν©λλ€.
module.exports = {
devServer: {
port: 8081,
proxy: 'http://localhost:8080',
disableHostCheck: true
}
}
μ΄μ http://localhost:8081
μΌλ‘ μ μνμ¬ μΉ νμ΄μ§λ₯Ό κ°λ°ν μ μκ² λκ³ νλ‘μ μ€μ μ ν΅ν΄ Vue κ°λ°μ© μλ²κ° μ²λ¦¬νμ§ λͺ»νλ λͺ¨λ μμ²μ 8080 ν¬νΈλ‘ μμ²ν©λλ€. λ°λΌμ, Vue μ»΄ν¬λνΈ λ΄μμ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ΄ μ 곡νλ APIλ₯Ό νΈμΆν μ μκ² λ©λλ€.
API νΈμΆμ μν΄
jQuery.ajax
λλaxios
λ₯Ό μ¬μ©νλ κ²μ λ³Έ κΈμ μ£Όλ κ΄μ¬μ¬κ° μλλλ€.
Production build
Vue νλ‘μ νΈλ‘ κ°λ°ν νλ‘ νΈμλ ν΄λΌμ΄μΈνΈλ build
λͺ
λ Ήμ μ¬μ©νμ¬ λΉλν μ μμ΅λλ€.
npm run build
μ λͺ
λ Ήμ ν΅ν΄ λΉλλλ νμΌμ dist/
ν΄λμ μμ±λ©λλ€. λ°λΌμ, src/main/vue/dist
μ λ§λ€μ΄μ§κ² λ©λλ€. λ§μ½, μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ λΉλνμ¬ μ€ννμλ€λ©΄ ν΄λΉ νμΌλ€μ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ΄ λ¦¬μμ€λ₯Ό μ½μ΄ λ°°ν¬ν μ μκ² λ©λλ€.
μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ΄ κΈ°λ³Έμ μΌλ‘ 리μμ€λ₯Ό μ½μ΄ λ°°ν¬νλ κ²½λ‘λ spring.web.resources.static-locations
νλ‘νΌν°λ‘ νμΈν μ μμ΅λλ€. μ λ src/main/resources/static/dist
λ₯Ό Vue νλ‘μ νΈμ λΉλ κ²½λ‘λ‘ μ‘κ³ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μμ ν΄λΉ λΉλ νμΌμ λ°°ν¬ν μ μκ² μ€μ νλλ‘ νκ² μ΅λλ€.
λ¨Όμ μ ν리μΌμ΄μ
νλ‘νΌν°μ ν΄λμ€ν¨μ€λ₯Ό κΈ°μ€μΌλ‘ static/dist
μ 리μμ€λ₯Ό μ½μ μ μκ² ν©λλ€.
application.properties
spring.web.resources.static-locations=classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/, classpath:/static/dist
κ·Έλ¦¬κ³ Vue νλ‘μ νΈ λΉλ κ²½λ‘λ outputDir
λ‘ μ€μ ν μ μμ΅λλ€.
vue.config.js
const path = require('path')
module.exports = {
outputDir: path.resolve(__dirname, '../resources/static/dist')
}
Freemarker Template Engine
Vue νλ‘μ νΈλ‘ λΉλλ νλ‘ νΈμλ ν΄λΌμ΄μΈνΈλ₯Ό μν νμΌλ€μ html-webpack-plugin
μ μν΄ λ§λ€μ΄μ§λ index.html
μ μλμΌλ‘ νμΌλ€μ΄ ν¬ν¨λ©λλ€. κ·Έλ°λ° μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μμ ν
νλ¦Ώ μμ§μ μ¬μ©νμ¬ νμ΄μ§μ λν μ 보λ μΈμ
μ 보λ₯Ό μΉ νμ΄μ§μ ν¬ν¨μν€κ³ μΆμ μ μμ΅λλ€. μλ₯Ό λ€μ΄, Spring Initializrμμ ν리λ§μ»€λ₯Ό ν
νλ¦Ώ μμ§μΌλ‘ μ¬μ©νκΈ° μνμ¬ μμ‘΄μ±μ μΆκ°νμλ€λ©΄ src/main/resources/templates
νμμ μμΉν *.ftlh
μ Viewλ‘ μ 곡ν μ μμ΅λλ€.
λ°λΌμ, λ€μκ³Ό κ°μ΄ indexPath
λ₯Ό μ€μ νμ¬ index.ftlhμ΄ λ§λ€μ΄μ§λ μμΉλ₯Ό μ§μ ν μ μμ΅λλ€.
vue.config.js
module.exports = {
indexPath: '../../templates/index.ftlh'
}
html-webpack-plugin
μμ index νμΌμ html-webpack-plugin
μ μν΄ λ§λ€μ΄μ§λ€κ³ νμμ΅λλ€. μ°λ¦¬κ° μμμ indexPathλ₯Ό μ§μ ν κ²μ λ¨μν νμ₯μλ₯Ό .ftlh
λ‘ λ°κΎΌ κ²κ³Ό λ€λ₯Ό λ° μμ΅λλ€. ν
νλ¦Ώ μμ§μ μ¬μ©νλ λͺ©μ μ ν΄λΉ ν
νλ¦Ώ μμ§μμ μ§μνλ λ¬Έλ²μΌλ‘ μ 보λ₯Ό νννκΈ° μν¨μ
λλ€. μ΄λ₯Ό μν΄ νλ¬κ·ΈμΈμ λν μ΅μ
μ λ³κ²½νλλ‘ ν©λλ€.
μλ₯Ό λ€μ΄, <html> νκ·Έμ lang μμ±μ μμ²μ λ°λ₯Έ μΈμ΄κ°μ λΆμ¬νκ³ μΆμ μ μμ΅λλ€. κ·Έλ¬λ©΄ λ€μκ³Ό κ°μ΄ index.ftlhκ° λ§λ€μ΄μ ΈμΌ ν©λλ€.
<!DOCTYPE html>
<html lang="${.locale?split("_")[0]}">
</html>
μμ½κ²λ html-webpack-pluginμ μ λ΄μ©μ μ½λ€κ° κ°μ μ²λ¦¬ν μ μμ΄ μ€λ₯λ₯Ό 보μ¬μ€λλ€. λ€νμ€λ½κ²λ μ½κ°μ νΈλ¦μ μ°λ©΄μ νλ¬κ·ΈμΈ μ΅μ μ 건λλ €μ κ°λ₯νκ² ν μ μμ΅λλ€.
index.html
<!DOCTYPE html>
<html lang="<%= '\${.locale?split(\"_\")[0]}' %>">
</html>
vue.config.js
module.exports = {
chainWebpack: config => {
config.plugin('html')
.tap(args => {
args[0].minify = false
args[0].interpolate = true
return args
})
}
}
minify
μ΅μ
μ λλ κ²μ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ
μ΄ ν리λ§μ»€ ν
νλ¦Ώ μμ§μΌλ‘ index.ftlh
μ μ½μ λ λ°μνλ μ€λ₯λ₯Ό λ°©μ§νκΈ° μν¨μ
λλ€.
μ΄μ λΉλλ index.ftlhλ λ€μκ³Ό κ°μ΄ λ§λ€μ΄μ§λλ€.
<!DOCTYPE html>
<html lang="${.locale?split("_")[0]}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title></title>
<link href="/js/about.d6d714df.js" rel="prefetch"><link href="/css/app.f94ee837.css" rel="preload" as="style"><link href="/css/chunk-vendors.01c183df.css" rel="preload" as="style"><link href="/js/app.247cb7a3.js" rel="preload" as="script"><link href="/js/chunk-vendors.65fb301b.js" rel="preload" as="script"><link href="/css/chunk-vendors.01c183df.css" rel="stylesheet"><link href="/css/app.f94ee837.css" rel="stylesheet"></head>
<body>
<noscript>
<strong>We're sorry but vue doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/js/chunk-vendors.65fb301b.js"></script><script type="text/javascript" src="/js/app.247cb7a3.js"></script></body>
</html>
μ΄μ μ¬λ¬λΆλ μ€νλ§ λΆνΈ μ ν리μΌμ΄μ μ Vueμ ν¨κ» κ°λ°ν μ μκ² λμμ΅λλ€. κ°μ¬ν©λλ€. π