online demo for server side render
gem 'webpacker'
gem 'vue_rails'
$ bundle install
$ rails webpacker:install
$ rails webpacker:install:vue
$ rails generate vue:install
|-- app
|-- javascript
|-- packs
|-- application.js
|-- vue_server_render.js
|-- vue_components
|-- hello.vue
|-- rails_vue_ujs.js
1. add javascript_pack_tag to application.html
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
2. generate a controller and view
example:
$ rails generate controller home index
and don't forget the router config!
3. add vue_components in your home/index.html
<%= vue_component("hello") %>
multiple components render is also work!
<%= vue_component("hello") %>
<%= vue_component("hello") %>
<%= vue_component("hello") %>
4. open the browser and check it, it should been works!
/vue_components/hello.vue
-> vue_component('hello')
/vue_components/post/index.vue
-> vue_component('post/index')
/vue_components/post/edit/index.vue
-> vue_component('post/edit/index')
<%= vue_component("hello", {foo: 'bar'}) %>
in your component hello.vue:
<template>
<div id="app">
<p>{{ outside.foo }}</p>
</div>
</template>
<script>
export default {
props: ['outside'],
data: function () {
return {
message: "Hello Vue!"
}
}
}
</script>
hash or array is also works
<%= vue_component("hello", {foo: {name: 'Peter'}}) %>
<template>
<div id="app">
<p>{{ outside.foo.name }}</p>
</div>
</template>
<script>
export default {
props: ['outside'],
data: function () {
return {
message: "Hello Vue!"
}
}
}
</script>
<%= vue_component("hello", {foo: [1,2,3]}) %>
<template>
<div id="app">
<template v-for="i in outside.foo">
<div>{{i}}</div>
</template>
<p>{{ outside.foo.name }}</p>
</div>
</template>
<script>
export default {
props: ['outside'],
data: function () {
return {
message: "Hello Vue!"
}
}
}
</script>
If you're just a component for rendering small parts, you should not use server side render!
with options prerender
, server side will prerender a dom before vue components initialize in client side
<%= vue_component("hello", {foo: [1,2,3]}, {prerender: true}) %>
distinguish ssr and csr ,use props env_ssr
Adjust the order of asset_tags
<!DOCTYPE html>
<html>
<head>
<title>RailsVueSsr</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_pack_tag 'application' %>
</head>
<body>
<%= yield %>
</body>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</html>
javascript_pack_tag should under the body
$ yarn add vue-router
in both application.js and vue_server_render.js
import VueRouter from 'vue-router';
RailsVueUJS.use(VueRouter);
and your vue component
<template>
<div class="container">
<div class="content">
<router-view :outside="outside" :env_ssr="env_ssr"></router-view>
</div>
</div>
</template>
<script>
import VueRouter from 'vue-router';
import PostList from './posts/index';
import PostDetail from './posts/show';
import newPost from './posts/new';
import EditPost from './posts/edit';
const routes = [
{
path: '/',
component: PostList,
name: 'post_index',
props: true
},
{
path: '/posts/new',
component: newPost,
name: 'new_post'
},
{
path: '/posts/edit/:id',
component: EditPost,
name: 'edit_post'
},
{
path: '/posts/:id',
component: PostDetail,
name: 'post_detail'
}
];
const router = new VueRouter({
mode: 'history',
routes
});
export default {
props: ['outside', 'env_ssr'],
router
};
</script>
option prerender can receive a path for vue router
<%= vue_component("hello", {foo: [1,2,3]}, {prerender: request.path}) %>
in your routes.rb
get '*path', to: 'home#index'
$ yarn add vuex
initialize a store
import Vue from 'vue'
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
currentUser: {},
hasLogin: false
}
});
export default store;
in both application.js and vue_server_render.js
import VueRouter from 'vue-router';
import Vuex from 'vuex';
import store from "../vue_components/store";
RailsVueUJS.use(VueRouter, Vuex);
RailsVueUJS.initializeVuexStore(store);
...
in your html file
<%= vue_component("hello", {foo: [1,2,3]}, {prerender: true, state: {
hasLogin: true
}}) %>
with option state
, it will replace your vuex state, for more information see the doc with vuex
in your component
...
<div v-if="$store.state.hasLogin">
<a href="/users/logout">logout</a>
</div>
...
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the VueRails project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.