a boiler built with Vue (client) and Sinata (server).
The server uses faye-websockets and maps connected sockets to logged in users via a token passed to the connect request. It includes Github oAuth, ActiveRecord, a Crud generator for sinatra, and a server-push library to alert clients of DB updates.
The client uses Vuex, a redux-like library with mutations/actions/store and such. Since this type of thing generally requires a lot of boiler, there's a Crud generator here too. It uses webpack to compile NPM deps, coffeescript, sass, and slim code into Javascript objects that can be run from the client. Webpack has built-in hot reloading and runs the front-end as a static server for development.
Out the box, this boiler provides a basic collaborative Todo app with 3-way data binding. In other words, any connected clients will see the todo list update in realtime, even if the action was called by a different client. Anyone can see the todos list, but only authenticated users can update/destroy/create.
demo
see https://maxpleaner.github.io/vue-sinatra-boiler (the backend is on heroku)
-
First of all, make sure you have at least the current LTS version of Node (right now it's 6.10.0), Ruby 2.3 or newer, and a Unix environment.
-
clone the repo and change the origin to something beloning to you (or fork)
git clone https://github.com/MaxPleaner/vue-sinatra-boiler cd vue-sinatra-boiler git remote set-url origin git@github.com:<username>/<repo>.git -
Create a new oAuth account on Github developer console
-
Configure the server
cd server bundle install bundle exec rake db:create db:migrate cp .env.example .env nano .env # add the Github credentials here -
Start the server
bundle exec thin start -
Configure the client
cd ../client npm install -
Start the client
npm run dev -
Visit the app at localhost:8080
Some important concepts to keep in mind:
- all the coffee, slim, and sass files get compiled into
bundle.jswhich is loaded byindex.html - the slim-lang-loader used by webpack is somethin I authored. It allows .slim files to be passed through the HTML loader to become strings in Javascript.
├── client.coffee ------------------ The core of the client side code, required by loader.coffee
├── components --------------------- Contains a folder for each component (some are omitted here)
│ ├── components.coffee ---------- Manifest of components - requires each component
│ ├── navbar --------------------- Each component has two files:
│ │ ├── navbar.coffee ---------- coffee file for module definition
│ │ └── navbar.slim ------------ slim file for HTML template
│ ├── root ----------------------- Layout component that is always visible (along with navbar)
│ │ ├── root.coffee
│ │ └── root.slim
│ └── todos
│ ├── todos.coffee
│ └── todos.slim
├── Gemfile ------------------------ Ruby deps for client (it's only slim)
├── Gemfile.lock
├── index.html --------------------- Entry point of the app, served statically
├── lib
│ ├── crud_mapper.coffee --------- A generator for Vuex mutations/actions and server-push listeners
│ ├── jquery_extensions.coffee --- Helper methods for $.put and $.delete
│ ├── router.coffee -------------- Client side router
│ ├── store
│ │ ├── actions.coffee --------- Vuex actions make requests to server, and then commit mutations with the response
│ │ ├── mutations.coffee ------- Atomic actions to change the client state
│ │ └── state.coffee ----------- Initial client state
│ └── store.coffee --------------- Vuex store is available to all components
├── loader.coffee ------------------ Loaded by webpack.config.js, this the entry point of the client code.
├── package.json
├── style
│ └── app.sass ------------------- Not really used here but set up for hot reloading
└── webpack.config.js -------------- Webpack configuration
for more in-depth docs see sinatra_sockets
├── config.ru ---------------------- Entry point to server, run by "bundle exec thin start"
├── crud_generator.rb -------------- Sinatra plugin to generate CRUD routes for a resource
├── db
│ ├── migrate
│ │ └── 20170312215739_create_todos.rb
│ └── schema.rb
├── Gemfile ------------------------ Server dependencies
├── Gemfile.lock
├── models.rb ---------------------- ActiveRecord models (only Todo for now)
├── Rakefile ----------------------- Loads tasks from sinatra-activerecord
├── README.md
├── server_push.rb ----------------- Module which can be included in models to push updates to clients
├── server.rb ---------------------- Core of the Server, definition of Sinatra app
└── ws.rb -------------------------- The websocket APIFirst of all, you should decide what the production urls are going to be for the front-end and server. Then do a search and replace in the codebase for the following strings:
vue-sinatra-boiler-demo.herokuapp.com(replace with your server url) _used by client forwss://andhttps://maxpleaner.github.io(replace with your front-end host only, not including path) used by server for CORS
The front end is easy to deploy to Github pages or another host like that.
cd clientnpm run deploy- this will generateclient-dist/prod-bundle.js- commit changes
sh push_client_dist_to_gh_pageswill push theclient-dist/folder to the gh-pages branch of whatever origin the repo points to.
The server includes a Procfile so it's easy to deploy to heroku.
heroku create --app <some app name>sh push_server_to_herokuheroku run rake db:migrate- use
heroku config:setto copy over the GitHub credentials in.env - Make sure to re-configure the Github application on their developer console
so that it redirects to
https://<your url>/auth/github/callback
Extract the Crud generators and server push into their own libraries
Why does refreshing the demo twice cause a logout?
If you are interested in using this boiler but are having a hard time making sense of it, I'll be happy to help if you reach out to maxpleaner@gmail.com