Vueport
Single file components and SSR for Rails with Vue JS and Webpack
If I were to build this gem again, I would probably use something like mini_racer to render the Vue components on the same server, as opposed to introducing an HTTP request and infra overhead. If anyone still uses this gem and wants to do that work, it should be relatively straight forward by modifying the Renderer class.
Vueport provides your Rails app with a modern, componentized approach to UI development by using Webpack and Vue.js to enable single file, reactive components rendered on the server and the client and seamless integration with your Rails views.
Take a look at the Vue.js documentation on single file components for more information on that side of things.
Vueport piggybacks onto the WebpackRails gem to get Webpack setup with Rails, so check that out for more information.
Example Rails App
Here.
Installation
Add this line to your application's Gemfile:
gem 'vueport'
And then execute:
$ bundle
Or install it yourself as:
$ gem install vueport
Then just run
rails generate vueport:install
to bootstrap everything you need to get started (this will install WebpackRails and also everything Vueport needs on top).
To run your app, execute
bundle exec foreman start -f Procfile.dev
to boot the Webpack Dev server and your Rails app!
Production Deployment
Ensure to run npm run compile
(or yarn run compile
) as part of your deployment process to production. This compiles the production version of your client side bundle, as well as compiling the server side bundle for our Node JS app to use.
In production we send HTTP requests to a basic NodeJS server to render our content. To run the Rails app and the Node server concurrently, use Procfile
.
Usage
View Helper
Wrap your application in the vueport
helper, to render out your components. E.g. in your application.html.erb
:
<body>
<%= vueport do %>
<%= render partial: 'shared/nav' %>
<%= yield %>
<% end %>
</body>
It can also accept a single argument. E.g.:
<body>
<%= vueport yield %>
</body>
Asset Setup
Add the Webpack Rails helpers to your layout to include your Javascript and CSS (see the WebpackRails readme for more information).
Ensure you place the JS entrypoint after the Vueport helper!
E.g.:
<head>
<%= stylesheet_link_tag *webpack_asset_paths('application', extension: 'css') %>
</head>
<body>
<%= vueport do %>
<%= render partial: 'shared/nav' %>
<%= yield %>
<% end %>
<%= javascript_include_tag *webpack_asset_paths("application", extension: 'js') %>
</body>
Default config
Out of the box, Vueport expects your components to live in app/components, and compiles assets to public/webpack. To change these, you'll need to change both the Webpack config (in config/webpack.config.js and config/webpack.server.js) and the Vue gem application config. To do this, in an initializer do:
Vueport.configure do |config|
config[:server_port] = 3001
end
Check out the WebpackRails gem for information on its configuration.
How does it work?
What Vueport gives you is effectively 3 applications:
- Your base rails app
- A Node app for server side rendering in production (in /renderer)
- A Node app for running webpack in development
These have been set up so that they can be built for production completely separately to avoid complicated pipelinesโfor example, you can run these 3 application using Docker completely separately meaning you don't need Ruby and Node in a single Dockerfile.
For more information on how Webpack has been integrated with Rails, check out this section of the Webpack Rails readme.
Server Side Rendering (SSR)
To enable Server Side rendering, I created a simple NodeJS app which uses the Vue Server Renderer to render out the contents of the page on each request. To enable Client Side rehydration, we also attach the original view contents in a template for the Client Side Vue instance to pick up.
SSR is only enabled in production.
Why Vue.js?
My experience of working with many modern UI libraries, and particulary with integrating them with Rails apps (especially React and Vue JS), has lead me to the conclusion that Vue JS seems to be a more explcit and 'batteries included' library when building compnents for Rails.
I use React on a regular basis for SPAs and love its functional philosophy, but for writing components to fit into a Rails frontend, Vue seems to provide me with the least complexity, and seems to be easiest for Ruby developers to reason about.
For a Vue.js and React collaborative comparison, check this out.
FAQs
-
I get the error
Could not load compiled manifest from /app/public/webpack/manifest.json
in productionYou'll need to run
npm run compile
as part of your build process to generate the production JS bundle (this error is generated by WebpackRails)
To Do
- Handle SSR
- Make webpack config more like the config from the Vue CLI template
- Optimize SSR interaction with NodeJS
- JS Component test setup
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/samtgarson/vueport. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Thanks
- Many thanks to Evan You and the VueJS team for sustaining such a vibrant and supportive community around Vue JS
- Many thanks also to mipearson for his WebpackRails gem on which this gem relies.
License
The gem is available as open source under the terms of the MIT License.