diff --git a/.vitepress/config.mts b/.vitepress/config.mts index 1a04231..c050c9d 100644 --- a/.vitepress/config.mts +++ b/.vitepress/config.mts @@ -11,46 +11,14 @@ export default defineConfig({ ], sidebar: [ { - text: "Getting Started", + text: "Guide", items: [ { text: "Intro", link: "/guide/" }, - { text: "Setup", link: "/guide/setup" } - ] - }, - { - text: "Rails", - items: [ - { text: "Views", link: "/guide/rails/views" }, - { text: "Generators" }, - { text: "Migrating to Phlex" }, - ], - }, - { - text: "HTML", - collapsed: false, - items: [ - { text: "Introduction" }, - { text: "Elements" }, - { text: "Attributes" }, - { text: "Comments" }, - { text: "Helpers" }, - { text: "Whitespace" }, + { text: "Setup", link: "/guide/setup" }, + { text: "Your first component", link: "/guide/first-component" }, + { text: "Under the hood", link: "/guide/under-the-hood" }, ], }, - { - text: "SVG", - collapsed: false, - items: [ - { text: "Introduction" }, - { text: "Elements" }, - { text: "Attributes" }, - ], - }, - { - text: "CSV", - collapsed: false, - items: [{ text: "Introduction" }, { text: "CSV Injection" }], - }, ], socialLinks: [ @@ -61,4 +29,4 @@ export default defineConfig({ message: "Released under the MIT License.", }, }, -}) +}); diff --git a/guide/first-component.md b/guide/first-component.md new file mode 100644 index 0000000..3384f30 --- /dev/null +++ b/guide/first-component.md @@ -0,0 +1 @@ +# Building your first component in Phlex diff --git a/guide/setup.md b/guide/setup.md index f292a21..eb84b66 100644 --- a/guide/setup.md +++ b/guide/setup.md @@ -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. diff --git a/guide/under-the-hood.md b/guide/under-the-hood.md new file mode 100644 index 0000000..bbfa9cf --- /dev/null +++ b/guide/under-the-hood.md @@ -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 `
` and we can add a few more later. + +```ruby +def div + @buffer << "
" + yield(self) if block_given? + @buffer << "
" +end +``` + +Our `div` method first pushes an opening `
` tag onto the buffer, then yields itself to the block if a block is given. Finally, it pushes a closing `
` 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 << "
" + yield if block_given? + @buffer << "
" + 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 +
+``` + +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.