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:migrate
This 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/setup
andbin/update
to install new node modules. -
Install dependencies:
bin/setup
- Enable content_security_policy in the
config/initializers/content_security_policy.rb
with 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.erb
to:
<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.js
to:
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
SplitChunks
with 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
SplitChunks
is 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 test
You 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/nodejs
Use 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-rails
by 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 defined
andFailed to register a ServiceWorker...
. To fix that add following line toconfig/webpack/environment.js
as 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.js
to:
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.js
initializer:
import '../assets/adminlte.scss'
import('./plugins') // () needed for async loading
- Add
app/javascript/initializers/plugins.js
file 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.js
pack:
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 addyield
in div withcontent
class:
<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 s
To 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-pr
You should see a list of the linters that were running.