Frontend: Composition
Pakyow lets you define frontend view templates and assets in separate parts that are composed together to build a complete interface. This guide explores the various types of view and asset templates and how they're composed together to build a complete view.
Pakyow implements a dynamic templating engine using native HTML. This means that you're to create complete interfaces just by defining templates. There's no coding required—in fact you'll never leave the frontend
folder!
Organizing view templates
Pakyow builds the content, or view, for a request based on the request path. Frontend view templates, along with assets, are defined in a structure mirroring the request paths that your application will serve content for. These paths are called presentation paths.
For example, a simple chat app might have two presentation paths:
Index, which presents a list of messages.
Show, which presents a single message and its details.
Here's how the view templates for this application would be organized:
frontend/
layouts/
default.html
pages/
index.html
messages/
show.html
There are three types of view templates: pages, layouts, and partials.
Pages, located in the frontend/pages
folder, define content for a specific page in your application. When the application receives a request, the page matching the request path is chosen for composition.
For example, a request to http://your-app.com/
will match the index page located at frontend/pages/index.html
. When a matching page is found, it's composed with a layout to form a complete view.
Layouts, located in the frontend/layouts
folder, define the common elements that are used across several pages—such as a header, footer, or sidebar. The default.html
layout is used by default, or pages can define a specific layout to use (this is discussed more below).
Each layout defines one or more containers, each one defining where content from a page should be mixed in. Below is the default.html
layout that you'll find in a generated project:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<!-- @container -->
</body>
</html>
This layout defines a single, unnamed container. During composition, the <!-- @container -->
comment, or directive is replaced with content from the matching page. Let's step through a complete example to be more clear about how.
Pakyow receives a request at http://your-site.com/
and chooses the frontend/pages/index.html
page based on the presentation path. Here's the page content:
<h1>
Hello Web
</h1>
The fully composed view would look like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>
Hello Web
</h1>
</body>
</html>
The <!-- @container -->
directive in the layout was replaced with the page content just as we expected. Pakyow sends the fully composed view in the response, which is presented in the user's web browser.
Advanced presentation paths
Presentation at nested paths are also supported. Looking at the previous example, requests to http://your-site.com/messages/show would match the frontend/pages/messages/show.html
page. This page would be composed into the layout and then rendered as before.
In reality, the request path for a page like this will be based on the message that was to be presented. For example, the full url look like this:
In cases like this it's typical for same underlying template to be rendered for multiple requests, with only the data changing between requests. We'll cover this type of dynamic presentation in the next guide on data bindings.
Reusing content with partials
Partials are the third type of view template designed to break your frontend templates into even smaller, more reusable pieces. Using partials, you can move the common parts of a view template into its own file and then include it whenever you need it.
Partials are placed alongside pages in the frontend/pages
folder, but are prefixed with an underscore. Here's an example view structure that contains a layout, page, and a partial named _messages.html
:
frontend/
layouts/
default.html
pages/
_messages.html
index.html
Here's the content of the _messages.html
partial:
<article>
<h1>this is a message</h1>
</article>
Partials are included into other view templates using the @include
directive. For example, the index.html
page can include the partial like this:
<h1>
Here are your messages:
</h1>
<!-- @include messages -->
The composed view would look like this:
<h1>
Here are your messages:
</h1>
<article>
<h1>this is a message</h1>
</article>
Partials can be included into any view template—pages, layouts, or even other partials. This simple feature gives you a lot of power to build a flexible frontend while reducing duplication.
Defining partials for nested presentation paths
Partials can be defined at any presentation path, including nested paths. More specific presentation paths will inherit partials from parent paths and can override specific partials as necessary.
The _messages.html
partial from above can be redefined at the show
path, making it available to any view template within the show
path. Let's build up a complete example, starting with one top-level partial:
frontend/
layouts/
default.html
pages/
_messages.html
show/
index.html
The show
path inherits the messages
partial and can include it:
<!-- @include messages -->
The show
path can override the inherited partial by defining a view template at show/_messages.html
. This more specific partial will be used when included by templates within the frontend/pages/show
presentation path, while other presentation paths will include the frontend/pages/_messages.html
partial.
Defining global partials
Partials can also be defined globally, making them includable into any view template, including layouts. Global partials are defined by creating a view template in the frontend/includes
folder:
frontend/
includes/
messages.html
layouts/
default.html
pages/
index.html
Unlike other partials, filenames for global includes are not prefixed with an underscore. But otherwise they behave just like other partials and can be included with the same @include
directive:
<!-- @include messages -->
Composing assets for view templates
Stylesheets and Scripts can be added to the frontend folder and composed together just like layouts, pages, and partials. Let's revisit the example from above and add in a few assets to illustrate how asset composition works:
frontend/
layouts/
default.html
default.css
pages/
index.html
messages/
show.html
show.js
Here we define two stylesheets, along with a single messages/show.js
script. The default.css
stylesheet will automatically be included into any page that uses the default
layout. The show.js
script will be included into the the messages/show.html
page when rendered.
Composed assets are automatically included as an asset pack in the <head>
section of the composed view.
Using multiple named containers
Layouts can define any number of containers, each with a unique name. Here's a layout that defines a footer
container to go along with the standard default
container:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<!-- @container -->
<footer>
<!-- @container footer -->
</footer>
</body>
</html>
Defining content for a named container happens with the @within
directive in a page:
<h1>
Hello Web
</h1>
<!-- @within footer -->
Custom Footer Content
<!-- /within -->
The composed view looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>
Hello Web
</h1>
<footer>
Custom Footer Content
</footer>
</body>
</html>
Specifying the layout for a page
In cases where you want to use a layout other than default.html
, the page can specify the layout in its front-matter. For example, here's how to use a layout named other.html
for a page:
---
layout: other
---
...
Directive reference
Here's a full list of frontend directives you'll use in your view templates:
@container
: Defines a default or named container in a layout.@within
: Defines content for a named container in a page.@include
: Includes a partial into another view template.
Each directive is placed inside an HTML comment, like this:
<!-- @container -->