Laravel + Vue look like SPA

2019-02-11

Server-side apps with client-side rendering - Jonathan Reinink

  1. blade 템플릿 + 각 기능별 vue 컴포넌트 : 너무 난해짐
  2. 빈 html + 1개의 단일 vue 컴포넌트 : api가 많아짐
  3. vue 컴포넌트 모두 등록후 controller에서 response::make를 통해 app.blade.php에 사용할 컴포넌트 이름과 데이타(props)를 넘겨 주는 방식 장점: API 없이 시작할 수 있다. 구조가 단순해진다.
// SPA처럼 작동하게 해준다.
npm install --save-dev turbolinks
// AppServiceProvider::boot 등록  
use Illuminate\View\Factory as ViewFactory;

ViewFactory::macro('component', function ($name, $data = []) {
    return View::make('app', ['name' => $name, 'data' => $data]);
});
<!-- app.blade.php -->
<!DOCTYPE html> 
<html>
<head>
    <meta charset="utf-8">
    <link href="{{ mix('/css/app.css') }}" rel="stylesheet">
    <script src="{{ mix('/js/manifest.js') }}" defer></script>
    <script src="{{ mix('/js/vendor.js') }}" defer></script>
    <script src="{{ mix('/js/app.js') }}" defer></script>
    <meta name="turbolinks-cache-control" content="no-cache">
    <!-- turbolinks 비활성화. 브라우저 이동시 vue 인스턴스를 만들어야함 -->
</head>
<body>

<div id="app" data-component="{{ $name }}" data-props="{{ json_encode($data) }}"></div>

</body>
</html>
// Controller
$events = Event::oldest('start_date')
    ->get()
    ->map->only('id', 'title', 'start_date');

return View::component('Events', ['events' => $events]);
// app.js
import Vue from 'vue'

// 모든 컴포넌트 등록
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))

// Start Turbolinks
require('turbolinks').start()

// Boot the Vue component
document.addEventListener('turbolinks:load', (event) => {
    const root = document.getElementById('app')

    if (window.vue) {
        window.vue.$destroy(true)
    }
    //vue runtime만 사용
    window.vue = new Vue({
        render: h => h(
            Vue.component(root.dataset.component), {
                props: JSON.parse(root.dataset.props)
            }
        )
    }).$mount(root)
})
//webpack.mix.js - vue runtime만 사용
mix.js('resources/js/app.js', 'public/js')
   .sass('resources/sass/app.scss', 'public/css')
   .extract(['vue', 'lodash', 'popper.js', 'axios'])
   .webpackConfig({
       resolve: {
           alias: { 'vue$': 'vue/dist/vue.runtime.js' }
       }
   })
   .version()