Setting up Rails 6 with PWA, Turbolinks, Webpack(er) 4, Babel 7, Vue.js 2 and Jest.
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 + Vue + Jest. If your team is considering, or has already decided, to use Vue, this is the right for you. As extra review how to setup PWA, Turbolinks, CSS frameworks, Storybook.
Things you may want to cover:
-
Ruby version: 2.7.0
-
System dependencies: Node.js, Yarn, PostgreSQL, Heroku CLI
-
Key Dependencies: Ruby on Rails version 6, Vue.js version 2, Webpacker with Webpack 4 and Babel 7
Generate Ruby on Rails Project with Vue.js (No Turbolinks included on this stage)
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
Setup development environment:
-
Uncomment
system('bin/yarn')
inbin/setup
andbin/update
to install new node modules. -
Install dependencies:
bin/setup
- Enable unsafe-eval rule to support runtime-only build and webpacker-dev-server
This can be done in the config/initializers/content_security_policy.rb
with the following
configuration:
Rails.application.config.content_security_policy do |policy|
if Rails.env.development?
policy.script_src :self, :https, :unsafe_eval
policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035'
else
policy.script_src :self, :https
end
end
You can learn more about this from: Vue.js Docs and Webpacker/Vue Docs.
- Verify that we have not broken anything
bin/webpack
bin/rails runner "exit"
Use Webpacker assets in the application
- Enable Webpacker by updating
app/views/layout/application.html.erb
:
Add after:
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
inlcude of vue example:
<%= stylesheet_pack_tag 'hello_vue', media: 'all' %>
<%= javascript_pack_tag 'hello_vue' %>
- Add sample page to host Vue.js component:
bin/rails generate controller Landing index --no-javascripts --no-stylesheets --no-helper --no-assets --no-fixture
- Setup sample page as home page by updating
config/routes.rb
:
root 'landing#index'
- Verify locally that vue.js working
bin/rails s
open "http://localhost:3000/"
Install Jest for Component Unit Tests
- Add Jest
yarn add --dev jest vue-jest babel-jest @vue/test-utils jest-serializer-vue 'babel-core@^7.0.0-bridge' @babel/core
- Add to
package.json
:
"scripts": {
"test": "jest"
},
"jest": {
"verbose": true,
"testURL": "http://localhost/",
"roots": [
"test/javascript"
],
"moduleDirectories": [
"node_modules",
"app/javascript"
],
"moduleNameMapper": {
"^@/(.*)$": "app/javascript/$1"
},
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
},
- 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.isVueInstance()).toBeTruthy()
})
test('matches snapshot', () => {
const wrapper = shallowMount(App)
expect(wrapper.html()).toMatchSnapshot()
})
});
- Verify by
yarn test
You should see all tests passed
Setup Heroku and Deploy
- Confirm compilation is working:
RAILS_ENV=production \
NODE_ENV=production \
RAILS_SERVE_STATIC_FILES=true \
SECRET_KEY_BASE="7aa51097e982f34be02abe83528c3308768dff3837b405e0907028c750d22d067367fb79e2b223e3f223fea50ddf2d5dc9b3c933cf5bc8c7f2a3d3d75f73c4a7" \
bin/rails assets:precompile
- Create 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 buildpacks:add heroku/ruby
heroku config:set RAILS_ENV=production NODE_ENV=production
- Deploy and verify that vue.js working on Heroku
git push heroku master
heroku apps:open
Setup basic PWA
- Install
serviceworker-rails
by adding intoGemfile
:
gem 'serviceworker-rails', github: 'rossta/serviceworker-rails'
- By following guide: https://github.com/rossta/serviceworker-rails should get something to: https://gist.github.com/pftg/786b147eff85a6fc98bd8dc1c3c9778e
Setup Turbolinks
- Add node dependencies
yarn add vue-turbolinks turbolinks
yarn install
- Load Turbolinks by adding
app/javascript/initializers/turbolinks.js
:
import Turbolinks from 'turbolinks'
Turbolinks.start()
- Add to
app/javascript/packs/application.js
:
import 'initializers/turbolinks.js'
- Uncomment in
hello_vue.js
:
import TurbolinksAdapter from 'vue-turbolinks'
import Vue from 'vue/dist/vue.esm'
import App from '../app.vue'
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
const app = new Vue({
el: '#hello',
data: () => {
return {
message: "Can you say hello?"
}
},
components: { App }
})
})
- Update layout with:
<div id="hello"></div>
- Run tests and server to verify:
bin/rails t
bin/rails s