Skip to content

jetthoughts/vuejs-rails-starterkit

 
 

Repository files navigation

Setting up Rails 5.2 with PWA, Turbolinks, Webpack(er) 4, Babel 7, Vue.js 2.5 and Jest.

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:

Generate Ruby on Rails Project with Vue.js (No Turbolinks included on this stage)

gem install rails -v 5.2

rails new vuejs-rails-5-starterkit -M -C -S --skip-turbolinks --webpack=vue -d postgresql
cd ./vuejs-rails-5-starterkit

bin/rails db:create db:migrate

Setup development environment:

  1. Uncomment system('bin/yarn') in bin/setup and bin/update to install new node modules.

  2. Install dependencies:

bin/setup
  1. 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.

  1. Verify that we have not broken anything
bin/webpack
bin/rails runner "exit"

Upgrade to Webpacker 4

  1. Update Gemfile to use new version:
gem 'webpacker', '>= 4.0.x'
  1. Install new Webpacker and update application
bundle update webpacker
bin/rails webpacker:install
bin/rails webpacker:install:vue
  1. Upgraded packages by Yarn too
yarn add @rails/webpacker@next
yarn upgrade webpack-dev-server --latest
yarn install
  1. Verify that everything is still working
bin/webpack
bin/rails test

Enable Vue.js single-file components to make examples works

  1. Install @vue/babel-preset-app:
yarn add @vue/babel-preset-app
  1. Replace @babel/preset-env with @vue/app in .bablerc

  2. Verify by: bin/webpack

Use Webpacker assets in the application

  1. Enable Webpacker by updating app/views/layout/application.html.erb:

Replace:

    <%= stylesheet_link_tag    'application', media: 'all' %>
    <%= javascript_include_tag 'application' %>

with:

    <%= stylesheet_pack_tag 'hello_vue', media: 'all' %>
    <%= javascript_pack_tag 'hello_vue' %>
  1. Add sample page to host Vue.js component:
bin/rails g controller Landing index --no-javascripts --no-stylesheets --no-helper --no-assets --no-fixture
  1. Setup sample page as home page by updating config/routes.rb:
  root 'landing#index'
  1. Verify locally that vue.js working
bin/rails s
open "http://localhost:3000/"

Expect to see

Install Jest for Component Unit Tests

  1. Add Jest
yarn add --dev jest vue-jest babel-jest @vue/test-utils jest-serializer-vue 'babel-core@^7.0.0-bridge' @babel/core
  1. 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"
    ]
  },
  1. Add to .babelrc:
  "env": {
    "test": {
      "presets": [
        ["@babel/preset-env", {
          "targets": {
            "node": "current"
          }
      }]]
  }},
  1. Add test/javascript/test.test.js:
test('there is no I in team', () => {
  expect('team').not.toMatch(/I/);
});
  1. Verify installation
yarn test

You should found

  1. 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()
  })
});
  1. Verify by
yarn test

You should see all tests passed

Setup Heroku and Deploy

  1. Confirm compilation is working:
RAILS_ENV=production \
NODE_ENV=production \
RAILS_SERVE_STATIC_FILES=true \
SECRET_KEY_BASE="7aa51097e982f34be02abe83528c3308768dff3837b405e0907028c750d22d067367fb79e2b223e3f223fea50ddf2d5dc9b3c933cf5bc8c7f2a3d3d75f73c4a7" \
bin/rails assets:precompile
  1. 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
  1. Deploy and verify that vue.js working on Heroku
git push heroku master

heroku apps:open

Setup basic PWA

  1. Install serviceworker-rails by adding into Gemfile:
gem 'serviceworker-rails', github: 'rossta/serviceworker-rails'
  1. By following guide: https://github.com/rossta/serviceworker-rails should get something to: https://gist.github.com/pftg/786b147eff85a6fc98bd8dc1c3c9778e

Setup Turbolinks

  1. Add node dependencies
yarn add vue-turbolinks turbolinks
yarn install
  1. Load Turbolinks by adding app/javascript/initializers/turbolinks.js:
import Turbolinks from 'turbolinks'
Turbolinks.start()
  1. Update app/javascript/packs/application.js:
import 'initializers/turbolinks.js'
  1. 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: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})
  1. Update layout with:
<div id="hello"></div>
  1. Run tests and server to verify:
bin/rails t
bin/rails s