Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Bridgetown::Component class with a ViewComponent-ish API #268

Merged
merged 28 commits into from
Apr 25, 2021

Conversation

jaredcwhite
Copy link
Member

@jaredcwhite jaredcwhite commented Mar 31, 2021

Resolves #140 (!!). Touches upon #251

Breaking Change ⚠️ – This retools the ERB template engine to provide automatic HTML escaping along with html_safe functionality courtesy of ActiveSupport. This means that when referencing front matter data or outside API sources, you'll need to use <%== value %> (double-equals), or the safehelper or html_safe string method if you want actual HTML injected. The one exception is rendered template content (aka content or yield in layouts), so bear that in mind when considering XSS vectors. Obviously escaping does not apply when using render/partial/liquid_render helpers (so remember it's possible somewhere in there also lurks an XSS vector).


This PR adds a bona fide Ruby component/template layer to Bridgetown, with an API very much inspired by GitHub's ViewComponent library for Rails. This is no accident! I have a "shim" in the works to support ViewComponent in Bridgetown directly—however, it brings with it additional complexity, more Rails gem dependencies, and a few less-than-desirable workarounds. That's acceptable for "component design systems" you'd like to use across both Bridgetown and Rails.

But for just Bridgetown sites with minimal overhead, I've been thinking for a while now we probably need our own simple component base class. I prefer this to partials, and while I don't plan on deprecating partials, our primary "Ruby templates" story will heavily revolve around real components. Components are isolated from global values/view state (other than site) and can be more easily tested and reused—basically all the same reasons ViewComponent is preferable to partials in Rails.

Here's what a Bridgetown Component looks like:

# src/_components/birthday_greeting.rb
class BirthdayGreeting < Bridgetown::Component
  def initialize(name:, age:)
    @name = name
    @age = age
  end

  def greeting
    "Hello #{@name}"
  end
end
<!-- src/_components/birthday_greeting.erb -->

<p><%= greeting %>! Happy Birthday! You're <%= @age %> today.</p>
<!-- Now let's use our component! -->
<!-- src/birthday.erb -->

<h1>Surprise!</h1>

<%= render BirthdayGreeting.new(name: "Pascal", age: "42") %>

Pretty standard stuff. Content blocks are supported, nested components within components work fine, helpers are delegated to the initial view class, multiple template engines are supported (currently ERB, Serbea, Slim, and Haml)—or you can define a template or call method (roughly equivalent) on the Ruby file directly and return a string (via heredoc, tag builder DSL, whatever) and not even need a template file.

There's also a before_render hook and a render? conditional just like ViewComponent. However, I don't think I'll tackle a "Slottable" API this go around…a possible V2 for the future?

  • Tests
  • Documentation

@jaredcwhite
Copy link
Member Author

Figured out a way to isolate site as well, so now Ruby components are pretty much globals-free just like Liquid components. But you can add @site = Bridgetown::Current.site to your component initializer if you want to and then site will work in the template without having pass site in as an argument.

@render
Copy link

render bot commented Apr 3, 2021

@render
Copy link

render bot commented Apr 3, 2021

@jaredcwhite
Copy link
Member Author

There are a few changes in here to support the ViewComponent library as well…and in fact I've tested calling ViewComponents from BridgetownComponents and visa-versa all in the same project with both ERB and Serbea templates back and forth. Took a ridiculous amount of trial-and-error, but I think I've finally cracked this nut. :shipit:

@jaredcwhite
Copy link
Member Author

FYI: the amount of shim code for VC required has become fairly minimal thanks to recent upstream improvements. https://github.com/bridgetownrb/bridgetown-view-component/blob/cc98b3963b4baa81263e4bf189ca5889a993f36e/lib/bridgetown-view-component.rb

@jaredcwhite jaredcwhite changed the base branch from main to 0-21-beta April 12, 2021 16:41
@jaredcwhite jaredcwhite added this to the 0.21 "Broughton Beach" milestone Apr 12, 2021
@jaredcwhite
Copy link
Member Author

jaredcwhite commented Apr 16, 2021

OK, I think the code and tests are in pretty good shape. On to massive updates to the documentation! 😱

@render
Copy link

render bot commented Apr 17, 2021

@jaredcwhite jaredcwhite merged commit 12ed5fb into 0-21-beta Apr 25, 2021
@jaredcwhite jaredcwhite deleted the builtin-component branch April 25, 2021 19:37
jaredcwhite added a commit that referenced this pull request Jun 1, 2021
* Welcome to 0.21 "Broughton Beach"

* Highlight Render as a hosting provider

* Relations for resources (belongs_to, has_many, etc.) (#261)

* Relations for resources (belongs_to, has_many, etc)

* improve resource type comments

* Make relations available to Liquid templates

* remove stray p methods

* Add test for resource relationships

* Support pluralized belongs_to keys

* make cop happy

* Use model origin id for resource id

* Add documentation and Liquid test for resource relations

* use newer feed gem

* Use list for relation accessor examples

* Fix nil bug in relations schema

* New `Bridgetown::Component` class with a ViewComponent-ish API (#268)

* New Component class with a ViewComponent-ish API

* Isolate site in components and improve link helpers

* Remove unnecessary special render case for ViewComponent

* Fix missing variables

* Relocate markdownify to Helpers class

* Switch to new Rails-like OutputBuffer, more VC support

* Support clean render interop between builtin Component and VCs

* Add several common Liquid filters in as Ruby helpers

Also add output_safety dependency

* Additional html_safe usage

* Match Rails' capture escaping logic

* Change before_render behavior to match latest VC

* Add tests and code comments for Bridgetown::Component

* Couple of YARD updates

* fix cop offense

* Fix bug with url_for helper

* Correct failing ERB feature test

* Use new SEO and feed helpers for the website

* Fix odd cop errors

* Convert website navbar to ERB component

* fix is-active class name

* Use resource variable in default website layout

* Update documentation (WIP) on components subsystem

Also change all occurences of Javascript to JavaScript

* Add lint-html addition

* Add documentation regarding ViewComponent

* Make linthtml happy

* Fix typos

* Add link to components docs from the ERB page

* Add section on ERB output safety to the docs

* End-to-end Ruby front matter, templates, and data files (#285)

* Major feature addition for Ruby Front Matter and raw templates

Also additional work to normalize Liquid & ERB template APIs

* Improve docs

* improve error messages, support Ruby data files

* Add to_json support for Resources

* Improve code quality and test rbfm

* Refactor front matter importing and add rbfm to layouts

* Revert and use regex capture

* Remove logging around rbfm

* Lots of Ruby files and rbfm documentation, couple of fixes

* Better to_json compat

* Fix Liquid error on website build

* Fix erb render bug in docs

* Update Changelog with 0.21 beta details

* Fix dotfiles or multiple extension permalinks (resource engine) (#292)

* Fix bug which was swallowing dotfiles and multiple extensions

* Revert tag refactoring

* Remove sassify/scssify filters, html_safe the obfuscate link

* Refactor old TODOs and deprecations

* Release 0.21 beta 2

* Bugfix for `previous_resource` method

* Ensure resources with no output are still transformed

* Remove a bunch of global config accessors on site

* Switch `plugins new` command to MiniTest in repo

* Release Bridgetown 0.21.0.beta3

* Webiste: use proper metadata title for Index page

* Add I18n file reloader to the watcher process

* Add prototype page warnings of bad configs

* Add note to Resources docs about require prototype page collection key

* Add CLI command to update webpack config (#270)

* Install required packages in webpack enable postcss tool (#319)

* Add config directory and move webpack defaults into it (#316)

* Add confirmation for overwriting postcss config in tailwindcss and bt-postcss bundled configurations (#317)

* Add Bridgetown version to webpack defaults (#322)

* Resolve issue with zombie templates in Pagination/Prototype logic

* Add layout method to resource and label method to layout (#324)

* Add memoization to cache templates in `Bridgetown::Component` (#326)

* Fix the Bridgetown logger and other test improvements (#328)

* Release 0.21.0.beta4

* Release v0.21.0

Co-authored-by: Ayush Newatia <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: Additional Ruby template helpers
1 participant