ViewComponent: How to build a library
This is the first post in a series that focuses on the ViewComponent gem by GitHub. The series will document my progress as I build a library of reusable components. All the source code used to generate this series of blog posts is on GitHub.
#Getting started
To get started, we're going to create a Rails engine. For our ViewComponent library, we can overlook most aspects of Rails and keep our setup minimal.
Make sure you have Rails installed and run rails plugin new
with the name of
your library and the options detailed below.
rails plugin new view_component_library_example \
--mountable \
--skip-action-mailer \
--skip-action-mailbox \
--skip-action-text \
--skip-active-storage \
--skip-active-record \
--skip-active-job \
--skip-action-cable \
--skip-hotwire \
--skip-jbuilder \
--skip-test \
--skip-asset-pipeline \
--dummy_path=spec/dummy \
This will create a Rails engine with a dummy app in spec/dummy
(we'll come
back to that later). As well as keeping our initial setup as slim as possible,
we can also remove unused app folders (controllers, helpers, models, views).
Since we're building an engine for ViewComponents only, we don't need to define the whole of Rails as a dependency. The gemspec can be updated to require the bare minimum dependencies.
--- a/view_component_library_example.gemspec
+++ b/view_component_library_example.gemspec
- spec.add_dependency "rails", ">= 7.0.2.3"
+ spec.add_dependency "activemodel", ">= 7.0.2.3"
+ spec.add_dependency "railties", ">= 7.0.2.3"
We can also comment out unused railties in bin/rails
.
# bin/rails
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
# require "active_job/railtie"
# require "active_record/railtie"
# require "active_storage/engine"
# require "action_controller/railtie"
# require "action_mailer/railtie"
# require "action_view/railtie"
# require "action_cable/engine"
# require "rails/test_unit/railtie"
require "rails/engine/commands"
Once the gemspec and binstub have been updated, run bundle
to install the
dependencies.
#Installing dependencies
Before we can start building components our library, we need to install a couple more dependencies — namely RSpec and ViewComponent.
#RSpec
To install RSpec, first add rspec-rails
as a development dependency in the
gemspec file.
--- a/view_component_library_example.gemspec
+++ b/view_component_library_example.gemspec
spec.add_dependency "activemodel", ">= 7.0.2.3"
spec.add_dependency "railties", ">= 7.0.2.3"
+ spec.add_development_dependency "rspec-rails"
After running bundle
again, we can run the RSpec installation generator.
bin/rails generate rspec:install
This will generate all the helper files needed to run our tests, although, we
need to make a small change to rails_helper.rb
. before we can run tests
successfully.
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
- require_relative '../config/environment'
+ require_relative 'dummy/config/environment'
#ViewComponent
Similarly, to install ViewComponent, we need to add view_component
as a
dependency in the gemspec file before running bundle
once again.
--- a/view_component_library_example.gemspec
+++ b/view_component_library_example.gemspec
spec.add_dependency "activemodel", ">= 7.0.2.3"
spec.add_dependency "railties", ">= 7.0.2.3"
+ spec.add_dependency "view_component", ">= 2.50.0"
spec.add_development_dependency "rspec-rails"
Before we can use ViewComponent, we need to require view_component
in our
library code.
--- a/lib/view_component_library_example.rb
+++ b/lib/view_component_library_example.rb
+ require "view_component"
require "example_library/version"
require "example_library/engine"
module ViewComponentExampleLibrary
# Your code goes here...
end
RSpec can also be configured to include the ViewComponent test helpers in component tests by default.
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
+ require "view_component/test_helpers"
RSpec.configure do |config|
config.use_active_record = false
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
+ config.include ViewComponent::TestHelpers, type: :component
end
#Creating the first component
Now we have configured our Rails engine and installed our library dependencies, we can start creating some components.
To begin with, let us consider a basic alert component. You're probably already familiar with the concept of flash messages in Rails. We're going to build a basic alert component that could be used to render flash messages in a Rails application.
The ViewComponent generator generates the files required for our first component.
bin/rails generate component ViewComponentLibraryExample::Alert --test-framework rspec --skip_namespace
We can write a simple test to assert that the content passed to the component is rendered.
# spec/components/view_component_library_example/alert_component_spec.rb
require "rails_helper"
module ExampleLibary
RSpec.describe AlertComponent, type: :component do
it "renders the alert content" do
alert_text = "This is an alert!"
component = AlertComponent.new
render_inline(component) do
alert_text
end
expect(rendered_component).to match(alert_text)
end
end
end
To make the test pass, all we need to do is render the component's content in the component template file.
# app/components/view_component_library_example/alert_component.html.erb
<div role="alert">
<%= content %>
</div>
And there we have it. We've created an ultra minimal ViewComponent library using a Rails 7 engine and RSpec for testing.
In future posts we'll explore the lookbook gem and ViewComponent previews, as well as how to integrate Tailwind CSS — plus deeper dives into aspects such as testing.