NOTE: For Rails 5.2, please check https://github.com/jetthoughts/vuejs-rails-starterkit/tree/rails-5-latest
A quick and easy way to setup Rails + PWA + Turbolinks + Webpacker + Bootstrap with AdminLTE theme + Vue + Jest. If your team is considering or has already decided to use Vue, this is the right for you. As an additional review of how to setup PWA, Turbolinks, CSS frameworks, Storybook.
- Step 1. Generate Ruby on Rails Project with Vue.js
- Step 2. Setup development environment
- Step 3. Add sample page to host Vue.js component
- Step 4. Use Webpacker assets in the application
- Step 5. Install Jest for Component Unit Tests
- Step 6. Setup Heroku and Deploy
- Step 7. Setup basic PWA
- Step 8. Setup Turbolinks
- Step 9. Installs UI Kit - AdminLTE
- Step 10. Configure continuous integration and other services for static code analysis
- Optimized for peformance Webpacker with Vue.js: Lazy Load, Split Chunks
- Turbolinks
- PWA
- Backend Unit and System Tests with coverage
- Vue.js Unit Tests with coverage
- Deployable to Heroku
- Pre-setup for services:
- GitHub
- Heroku (Heroku Reviews Apps)
- CircleCI
- Codecov and Simplecov
- Dependabot
- Static Code Analyzers:
- Pronto
- Rubocop
- ESLint
- EditorConfig
- Ruby on Rails version 6
- Vue.js version 2 with Vue Test Utils
- Webpacker 5 with Webpack 4
- Bootstrap 4 with AdminLTE Template
- Babel 7
- Ruby 3.0
- Node.js 14
- Yarn
- PostgreSQL 12
- Heroku CLI
gem install rails
rails new vuejs-rails-starterkit --force --database=postgresql \
--skip-action-mailer --skip-action-cable --skip-sprockets --skip-turbolinks \
--webpack=vue
cd ./vuejs-rails-starterkit
bin/rails db:create db:migrateThis generates Rails project with:
- Vue component in
app/javascript/app.vue - Example entry file
app/javascript/packs/hello_vue.js
-
Uncomment
system('bin/yarn')inbin/setupandbin/updateto install new node modules. -
Install dependencies:
bin/setup- Enable content_security_policy in the
config/initializers/content_security_policy.rbwith the following configuration:
Rails.application.config.content_security_policy do |policy|
policy.script_src :self, :https
if Rails.env.development? || Rails.env.test?
policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035'
end
end- Verify that we have not broken anything
bin/webpack
bin/rails runner "exit"- Generate controller and view:
bin/rails generate controller Landing index --no-javascripts --no-stylesheets --no-helper --no-assets --no-fixture- Update
app/views/landing/index.html.erbto:
<h1>Landing#index</h1>
<p>Find me in app/views/landing/index.html.erb</p>
<div id='hello_vue_app'></div>- Change
app/javascript/packs/hello_vue.jsto:
import Vue from 'vue'
import App from '../app.vue'
document.addEventListener('DOMContentLoaded', () => {
const app = new Vue({
render: h => h(App),
el: '#hello_vue_app'
}).$mount()
})- Setup a sample page as a home page by updating
config/routes.rb:
root 'landing#index'-
Enable Webpacker with
SplitChunks:-
Enable
SplitChunkswith default config by adding toconfig/webpack/environment.js:environment.splitChunks()
-
Enable Webpacker by updating
app/views/layouts/application.html.erb:Change:
<%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_pack_tag 'application' %>
to:
<%= stylesheet_packs_with_chunks_tag 'application', 'hello_vue', media: 'all' %> <%= javascript_packs_with_chunks_tag 'application', 'hello_vue' %>
-
-
Verify locally that vue.js is working and
SplitChunksis enabled
bin/rails s
open "http://localhost:3000/"The javascript_packs_with_chunks_tag and stylesheet_packs_with_chunks_tag helpers split assets
into small size chunks and create html tags for them:
<script src="/packs/js/runtime~hello_vue-818eba5af0151079cb6c.js"></script>
<script src="/packs/js/1-7b962b4481d6abff6c2b.chunk.js"></script>
<script src="/packs/js/hello_vue-bc0218ac204eff3ff742.chunk.js"></script>- Add Jest with required dependencies
yarn add --dev jest @vue/test-utils vue-jest babel-core@^7.0.0-bridge.0 babel-jest jest-serializer-vue- Configure Jest in
package.json(including the Coverage enabling):
"scripts": {
"test": "jest"
},
"jest": {
"verbose": true,
"testURL": "http://localhost/",
"roots": [
"test/javascript"
],
"moduleDirectories": [
"node_modules",
"app/javascript"
],
"moduleNameMapper": {
"^@/(.*)$": "<rootDir>/app/javascript/$1"
},
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
".+\\.js$": "babel-jest",
".+\\.vue$": "vue-jest"
},
"testPathIgnorePatterns": [
"<rootDir>/config/webpack/"
],
"snapshotSerializers": [
"jest-serializer-vue"
],
"collectCoverage": true,
"collectCoverageFrom": [
"**/*.{js,vue}",
"!**/node_modules/**"
]
},- Add
test/javascript/test.test.js:
test('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});- Verify installation
yarn test- Add component test for App in
test/javascript/app.test.js:
import { mount, shallowMount } from '@vue/test-utils'
import App from 'app';
describe('App', () => {
test('is a Vue instance', () => {
const wrapper = mount(App)
expect(wrapper.vm).toBeTruthy()
})
test('matches snapshot', () => {
const wrapper = shallowMount(App)
expect(wrapper.html()).toMatchSnapshot()
})
});- Verify by
yarn testYou should see all tests passed
- Confirm compilation is working:
RAILS_ENV=production \
NODE_ENV=production \
RAILS_SERVE_STATIC_FILES=true \
SECRET_KEY_BASE="7aa51097e982f34be02abe83528c3308768dff3837b405e0907028c750d22d067367fb79e2b223e3f223fea50ddf2d5dc9b3c933cf5bc8c7f2a3d3d75f73c4a7" \
bin/rails assets:precompile- Create a Heroku App and provision it
Requirements: Heroku CLI.
NOTE: Do not forget to commit all your changes: git add . && git commit -m "Generates Ruby on Rails application with Vue.js onboard"
heroku create
heroku addons:create heroku-postgresql:hobby-dev
heroku buildpacks:add heroku/ruby
heroku config:set RAILS_ENV=production NODE_ENV=production YARN_PRODUCTION=true MALLOC_ARENA_MAX=2- Setup Node.js for Heroku
heroku buildpacks:add --index 1 heroku/nodejsUse the engines section of the package.json to specify the version of Node.js to use on Heroku.
Drop the ‘v’ to save only the version number:
{
"engines": {
"node": ">= 12.x"
}
}- Deploy and verify that vue.js is working on Heroku
git push heroku master
heroku apps:open- Install
serviceworker-railsby adding intoGemfile:
gem 'serviceworker-rails', github: 'rossta/serviceworker-rails'-
Following the guide: https://github.com/rossta/serviceworker-rails you should get something like: https://gist.github.com/pftg/786b147eff85a6fc98bd8dc1c3c9778e
-
There'll be an issue with service worker registration on the page saying:
Uncaught ReferenceError: window is not definedandFailed to register a ServiceWorker.... To fix that add following line toconfig/webpack/environment.jsas suggested here:
environment.config.set('output.globalObject', 'this')- Add node dependencies
yarn add vue-turbolinks turbolinks- Load Turbolinks by adding to
app/javascript/initializers/turbolinks.js:
import Turbolinks from 'turbolinks'
Turbolinks.start()- Add to
app/javascript/packs/application.js:
import 'initializers/turbolinks.js'- Change
app/javascript/packs/hello_vue.jsto:
import TurbolinksAdapter from 'vue-turbolinks'
import Vue from 'vue'
import App from '../app.vue'
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
render: h => h(App),
el: '#hello_vue_app'
}).$mount()
})- Update layout
app/views/layouts/application.html.erb:
<%= javascript_packs_with_chunks_tag 'hello_vue', 'application', 'data-turbolinks-track': 'reload' %>- Run tests and server to verify:
bin/rails t
bin/rails s- Add node dependencies
yarn add admin-lte bootstrap jquery popover @fortawesome/fontawesome-free- Add
app/javascript/initializers/adminlte.jsinitializer:
import '../assets/adminlte.scss'
import('./plugins') // () needed for async loading- Add
app/javascript/initializers/plugins.jsfile with plugin importing:
import '@fortawesome/fontawesome-free'
import 'jquery/src/jquery.js'
import 'popper.js'
import 'bootstrap'
import 'admin-lte/build/js/AdminLTE'- Import admin lte initializer in
app/javascript/packs/application.jspack:
import 'initializers/adminlte'- Next step is updating main layout
app/views/layouts/application.html.erb. Code for layout you can find here. Also don't forget to addyieldin div withcontentclass:
<div class="content">
<%= yield %>
</div>- Add styles to
app/javascript/assets/adminlte.scss:
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/solid';
@import '~@fortawesome/fontawesome-free/scss/regular';
@import '~@fortawesome/fontawesome-free/scss/brands';
@import "~admin-lte/build/scss/adminlte";- Run tests and server to verify:
yarn test
bin/rails test
bin/rails test:system
bin/rails sTo be able to automatically analyze the quality of the code, let's install the jt_tools gem.
- Add this line to your application's Gemfile:
gem 'jt_tools', groups: [:development]- Next step is running bundle install and generator:
bin/bundle
bin/rails jt_tools:install- Run linters to verify
bin/lint-prYou should see a list of the linters that were running.


