-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a037510
commit b24b80b
Showing
4 changed files
with
106 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Building your first component in Phlex |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,23 @@ | ||
# Setup | ||
# Up and running 🏃➡️ | ||
|
||
## Setting up Phlex with Rails | ||
Before we get too far, let’s get Phlex up and running in your app. | ||
|
||
Let’s be honest, most of us are going to be using this with Rails so we’ll start there. | ||
Phlex is a standalone Ruby library with zero dependencies, but most folks will want to use it with [Ruby on Rails](https://rubyonrails.org) so let’s start there for the sake of this guide. | ||
|
||
First, add `phlex-rails` to your Gemfile. The quickest way to do this is to run: | ||
It’s possible to use Phlex with [Sinatra](https://sinatrarb.com), [Roda](https://github.com/jeremyevans/roda), [Hanami](https://hanamirb.org), and any other Ruby web framework, but you’ll need to kick off the rendering yourself. | ||
|
||
## Installing Phlex in a Rails app | ||
|
||
To install Phlex in a Rails app, you’ll need to add the `phlex-rails` gem to your `Gemfile`. The `phlex-rails` gem includes the `phlex` gem as a dependency, so you won’t need to add that separately. `phlex-rails` also includes a generator to help you get started. | ||
|
||
Start by running: | ||
|
||
``` | ||
bundle add phlex-rails | ||
``` | ||
|
||
This will add the latest version of `phlex` and `phlex-rails` and run `bundle install` for you. Now that the gem is installed, you’ll want to run the install geneartor: | ||
This will install the latest version of `phlex` and `phlex-rails` and add `phlex-rails` to your `Gemfile`. Once that’s finished, you’ll want to run the install geneartor to kick things off: | ||
|
||
``` | ||
bundle exec rails generate phlex:install | ||
``` | ||
|
||
## Setting up Phlex without Rails | ||
|
||
Phlex is actually a standalone library with zero dependencies. You can use it in any Ruby project, but you’ll need to kick off the rendering yourself. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Under the hood | ||
|
||
You’ve successfully installed Phlex and rendered your first component. Now let’s take a moment to understand what’s happening behind the scenes. To do this, we’re going to build a mineature version of Phlex from scratch. | ||
|
||
It won’t have advanced features, performance optimizations or HTML safety, but I think it’ll give you a good sense of things. | ||
|
||
## Buffers and hirearchy | ||
|
||
We’ll start by creating a `Component` class with a `@buffer` instance variable. Phlex uses a mutible String for its buffer, but we’ll use an Array since it’s easier to debug. | ||
|
||
```ruby | ||
class Component | ||
def initialize | ||
@buffer = [] | ||
end | ||
end | ||
``` | ||
|
||
Now we want to be able to render HTML tags. Let’s start with `<div>` and we can add a few more later. | ||
|
||
```ruby | ||
def div | ||
@buffer << "<div>" | ||
yield(self) if block_given? | ||
@buffer << "</div>" | ||
end | ||
``` | ||
|
||
Our `div` method first pushes an opening `<div>` tag onto the buffer, then yields itself to the block if a block is given. Finally, it pushes a closing `</div>` tag onto the buffer. | ||
|
||
Let’s add one more method so we can render our components to a string. | ||
|
||
```ruby | ||
def call | ||
view_template | ||
@buffer.join | ||
end | ||
``` | ||
|
||
This method, `call`, first calls the `view_template` method (which we haven’t defined yet) then it joins the buffer into a single string and returns it. | ||
|
||
The whole class should look like this: | ||
|
||
```ruby | ||
class Component | ||
def initialize | ||
@buffer = [] | ||
end | ||
|
||
def call | ||
view_template | ||
@buffer.join | ||
end | ||
|
||
def div | ||
@buffer << "<div>" | ||
yield if block_given? | ||
@buffer << "</div>" | ||
end | ||
end | ||
``` | ||
|
||
Now we’re ready to create a component. Let’s make a simple `HelloWorld` component — though we’re not quite ready to say `"Hello World"` just yet. Instead, we’ll render a couple of nested divs. | ||
|
||
```ruby | ||
class HelloWorld < Component | ||
def view_template | ||
div { | ||
div | ||
} | ||
end | ||
end | ||
``` | ||
|
||
This `HelloWorld` component inherits from our abstract `Component` class and implements the `view_template` method that we called from the `call` method before. | ||
|
||
Let’s see what it looks like when we `call` our `HelloWorld` component to render it: | ||
|
||
```ruby | ||
puts HelloWorld.new.call | ||
``` | ||
|
||
You should see the following output with one div nested inside another: | ||
|
||
```html | ||
<div><div></div></div> | ||
``` | ||
|
||
Ruby handled the hierarchy for us. We got part way into the first div when we _yielded_ to the block which started a new div. Since there was no block given to this inner div, it closed immediately yielding control back to the original outer div, which then closed. |