Comparing HTML Preprocessor Features

(This is a sponsored post.)

Of the languages that browsers speak, I’d wager that the very first one that developers decided needed some additional processing was HTML. Every single CMS in the world (aside from intentionally headless-only CMSs) is essentially an elaborate HTML processor: they take content and squoosh it together with HTML templates. There are dozens of other dedicated HTML processing languages that exist today.

The main needs of HTML processing being:

  • Compose complete HTML documents from parts
  • Template the HTML by injecting variable data

There are plenty of other features they can have, and we’ll get to that, but I think those are the biggies.

This research is brought to you by support from Frontend Masters, CSS-Tricks’ official learning partner.

Need front-end development training?

Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies, from React to CSS, from Vue to D3, and beyond with Node.js and Full Stack.

Diagram showing partials and {{ data }} turning into a complete HTML document.

Consider PHP. It’s literally a “Hypertext Preprocessor.” On this very website, I make use of PHP in order to piece together bits of templated HTML to build the pages and complete content you’re looking at now.

<h2>
  <?php the_title(); // Templating! ?>
</h2>

<?php include("metadata.php"); // Partials! ?>

In the above code, I’ve squooshed some content into an HTML template, which calls another PHP file that likely contains more templated HTML. PHP covers the two biggies for HTML processing and is available with cost-friendly hosting — I’d guess that’s a big reason why PHP-powered websites power a huge chunk of the entire internet.

But PHP certainly isn’t the only HTML preprocessor around, and it requires a server to work. There are many others, some designed specifically to run during a build process before the website is ever requested by users.

Let’s go language-by-language and look at whether or not it supports certain features and how. When possible the link of the preprocessor name links to relevant docs.

Does it allow for templating?

Can you mix in data into the final HTML output?

ProcessorExample
Pug
- var title = "On Dogs: Man's Best Friend";
- var author = "enlore";
h1= title
p Written with love by #{author}
ERB
<%= title %>
<%= description %>

<%= @logged_in_user.name %>
Markdown
PHP
<?php echo $post.title; ?>
<?php echo get_post_description($post.id) ?>
Also has HEREDOC syntax.
Slim
tr
td.name = item.name
Haml
<h1><%= post.title %></h1>
<div class="subhead"><%= post.subtitle %></div>
Liquid
Hello {{ user.name }}!
Go html/template
{{ .Title }}
{{ $address }}
Handlebars
{{firstname}} {{lastname}}
Mustache
Hello {{ firstname }}!
Twig
{{ foo.bar }}
Nunjucks
<h1>{{ title }}</h1>
Kit
<!-- $myVar = We finish each other's sandwiches. -->
<p> <!-- $myVar --> </p>
Sergey

Does it do partials/includes?

Can you compose HTML from smaller parts?

ProcessorExample
Pug
include includes/head.pug
ERB
<%= render 'includes/head' %>
Markdown
PHP
<?php include 'head.php'; ?>
<?php include_once 'meta.php'; ?>
Slim⚠️
If you have access to the Ruby code, it looks like it can do it, but you have to write custom helpers.
Haml
.content
=render 'meeting_info'
Liquid{% render head.html %}
{% render meta.liquid %}
Go html/template{{ partial "includes/head.html" . }}
Handlebars⚠️
Only through registering a partial ahead of time.
Mustache{{> next_more}}
Twig{{ include('page.html', sandboxed = true) }}
Nunjucks{% include "missing.html" ignore missing %}
{% import "forms.html" as forms %}
{{ forms.label('Username') }}
Kit<!-- @import "someFile.kit" -->
<!-- @import "file.html" -->
Sergey<sergey-import src="header" />

Does it do local variables with includes?

As in, can you pass data to the include/partial for it to use specifically? For example, in Liquid, you can pass a second parameter of variables for the partial to use. But in PHP or Twig, there is no such ability—they can only access global variables.

ProcessorExample
PHP
ERB<%= render(
partial: "card",
locals: {
title: "Title"
}
) %>
Markdown
Pug⚠️
Pug has mixins that you can put in a separate file and call. Not quite the same concept but can be used similarly.
Slim
Haml.content
= render :partial => 'meeting_info', :locals => { :info => @info }
Liquid{% render "name", my_variable: my_variable, my_other_variable: "oranges" %}
Go html/template{{ partial "header/site-header.html" . }}
(The period at the end is “variable scoping.”)
Handlebars{{> myPartial parameter=favoriteNumber }}
Mustache
Twig
{% include 'template.html' with {'foo': 'bar'} only %}
Nunjucks{% macro field(name, value='', type='text') %}
<div class="field">
<input type="{{ type }}" name="{{ name }}" value="{{ value | escape }}" />
</div>
{% endmacro %}
Kit
Sergey

Does it do loops?

Sometimes you just need 100 <div>s, ya know? Or more likely, you need to loop over an array of data and output HTML for each entry. There are lots of different types of loops, but having at least one is nice and you can generally make it work for whatever you need to loop.

ProcessorExample
PHPfor ($i = 1; $i <= 10; $i++) {
echo $i;
}
ERB<% for i in 0..9 do %>
<%= @users[i].name %>
<% end %>
Markdown
Pugfor (var x = 1; x < 16; x++)
div= x
Slim- for i in (1..15)
div #{i}
Haml(1..16).each do |i|
%div #{i}
Liquid{% for i in (1..5) %}
{% endfor %}
Go html/template{{ range $i, $sequence := (seq 5) }}
{{ $i }}: {{ $sequence }
{{ end }}
Handlebars{{#each myArray}}
<div class="row"></div>
{{/each}}
Mustache{{#myArray}}
{{name}}
{{/myArray}}
Twig{% for i in 0..10 %}
{{ i }}
{% endfor %}
Nunjucks{% set points = [0, 1, 2, 3, 4] %}
{% for x in points %}
Point: {{ x }}
{% endfor %}
Kit
Sergey

Does it have logic?

Mustache is famous for philosophically being “logic-less.” So sometimes it’s desirable to have a templating language that doesn’t mix in any other functionality, forcing you to deal with your business logic in another layer. Sometimes, a little logic is just what you need in a template. And actually, even Mustache has some basic logic.

ProcessorExample
Pug#user
if user.description
h2.green Description
else if authorised
h2.blue Description
ERB<% if show %>
<% endif %>
Markdown
PHP<?php if (value > 10) { ?>
<?php } ?>
Slim- unless items.empty?If you turn on logic less mode:
- article
h1 = title
-! article
p Sorry, article not found
Hamlif data == true
%p true
else
%p false
Liquid{% if user %}
Hello {{ user.name }}!
{% endif %}
Go html/template{{ if isset .Params "title" }}
<h4>{{ index .Params "title" }}</h4>
{{ end }}
Handlebars{{#if author}}
{{firstName}} {{lastName}}
{{/if}}
Mustache
It’s kind of ironic that Mustache calls itself “Logic-less templates”, but they do kinda have logic in the form of “inverted sections.”
{{#repo}}
{{name}}
{{/repo}}
{{^repo}}
No repos :(
{{/repo}}
Twig{% if online == false %}
Our website is in maintenance mode.
{% endif %}
Nunjucks{% if hungry %}
I am hungry
{% elif tired %}
I am tired
{% else %}
I am good!
{% endif %}
Kit
It can output a variable if it exists, which it calls “optionals”:
<dd class='<!-- $myVar? -->'> Page 1 </dd>
Sergey

Does it have filters?

What I mean by filter here is a way to output content, but change it on the way out. For example, escape special characters or capitalize text.

ProcessorExample
Pug⚠️
Pug thinks of filters as ways to use other languages within Pug, and doesn’t ship with any out of the box.
ERB
Whatever Ruby has, like:
"hello James!".upcase #=> "HELLO JAMES!"
Markdown
PHP$str = "Mary Had A Little Lamb";
$str = strtoupper($str);
echo $str; // Prints MARY HAD A LITTLE LAMB
Slim⚠️
Private only?
Haml⚠️
Very specific one for whitespace removal. Mostly for embedding other languages?
Liquid
Lots of them, and you can use multiple.
{{ "adam!" | capitalize | prepend: "Hello " }}
Go html/template⚠️
Has a bunch of functions, many of which are filter-like.
Handlebars⚠️
Triple-brackets do HTML escaping, but otherwise, you’d have to register your own block helpers.
Mustache
Twig{% autoescape "html" %}
{{ var }}
{{ var|raw }} {# var won't be escaped #}
{{ var|escape }} {# var won't be doubled-escaped #}
{% endautoescape %}
Nunjucks{% filter replace("force", "forth") %}
may the force be with you
{% endfilter %}
Kit
Sergey

Does it have math?

Sometimes math is baked right into the language. Some of these languages are built on top of other languages, and thus use that other language to do the math. Like Pug is written in JavaScript, so you can write JavaScript in Pug, which can do math.

ProcessorSupport
PHP<?php echo 1 + 1; ?>
ERB<%= 1 + 1 %>
Markdown
Pug- const x = 1 + 1
p= x
Slim- x = 1 + 1
p= x
Haml%p= 1 + 1
Liquid{{ 1 | plus: 1 }}
Go html/template
{{add 1 2}}
Handlebars
Mustache
Twig{{ 1 + 1 }}
Nunjucks{{ 1 + 1 }}
Kit
Sergey

Does it have slots / blocks?

The concept of a slot is a template that has special areas within it that are filled with content should it be available. It’s conceptually similar to partials, but almost in reverse. Like you could think of a template with partials as the template calling those partials to compose a page, and you almost think of slots like a bit of data calling a template to turn itself into a complete page. Vue is famous for having slots, a concept that made its way to web components.

ProcessorExample
PHP
ERB
Markdown
Pug
You can pull it off with “mixins”
Slim
Haml
Liquid
Go html/template
Handlebars
Mustache
Twig{% block footer %}
© Copyright 2011 by you.
{% endblock %}
Nunjucks{% block item %}
The name of the item is: {{ item.name }}
{% endblock %}
Kit
Sergey<sergey-slot />

Does it have a special HTML syntax?

HTML has <angle> <brackets> and while whitespace matters a little (a space is a space, but 80 spaces is also… a space), it’s not really a whitespace dependant language like Pug or Python. Changing these things up is a language choice. If all the language does is add in extra syntax, but otherwise, you write HTML as normal HTML, I’m considering that not a special syntax. If the language changes how you write normal HTML, that’s special syntax.

ProcessorExample
PHP
ERBIn Ruby, if you want that you generally do Haml.
Markdown
This is pretty much the whole point of Markdown.
# Title
Paragraph with [link](#link).

- List
- List

> Quote
Pug
Slim
Haml
Liquid
Go html/template
Handlebars
Mustache
Twig
Nunjucks
Kit⚠️
HTML comment directives.
Sergey⚠️
Some invented HTML tags.

Wait wait — what about stuff like React and Vue?

I’d agree that those technologies are component-based and used to do templating and often craft complete pages. They also can do many/most of the features listed here. Them, and the many other JavaScript-based-frameworks like them, are also generally capable of running on a server or during a build step and producing HTML, even if it sometimes feels like an afterthought (but not always). They also have other features that can be extremely compelling, like scoped/encapsulated styles, which requires cooperation between the HTML and CSS, which is an enticing feature.

I didn’t include them because they are generally intentionally used to essentially craft the DOM. They are focused on things like data retrieval and manipulation, state management, interactivity, and such. They aren’t really focused on just being an HTML processor. If you’re using a JavaScript framework, you probably don’t need a dedicated HTML processor, although it absolutely can be done. For example, mixing Markdown and JSX or mixing Vue templates and Pug.

I didn’t even put native web components on the list here because they are very JavaScript-focused.

Other considerations

  • SpeedHow fast does it process? Do you care?
  • Language — What was in what is it written in? Is it compatible with the machines you need to support?
  • Server or Build — Does it require a web server running to work? Or can it be run once during a build process? Or both?

Superchart

TemplatingIncludesLocal VariablesLoopsLogicFiltersMathSlotsSpecial Syntax
PHP
ERB⚠️
Markdown
Pug⚠️
Slim⚠️⚠️
Haml⚠️
Liquid
Go html/template⚠️
Handlebars⚠️
Mustache
Twig
Nunjucks
Kit⚠️
Sergey⚠️

The post Comparing HTML Preprocessor Features appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

Why Parcel Has Become My Go-To Bundler for Development

Today we’re gonna talk about application bundlers — tools that simplify our lives as developers. At their core, bundlers pick your code from multiple files and put everything all together in one or more files in a logical order that are compiled and ready for use in a browser. Moreover, through different plugins and loaders, you can uglify the code, bundle up other kinds of assets (like CSS and images), use preprocessors, code-splitting, etc. They manage the development workflow.

There are lots of bundlers out there, like Browserify and webpack. While those are great options, I personally find them difficult to set up. Where do you start? This is especially true for beginners, where a "configuration file" might be a little scary.

That’s why I tend to reach for Parcel. I stumbled upon it accidentally while watching a tutorial on YouTube. The speaker was talking about tips for faster development and he heavily relied on Parcel as part of his workflow. I decided to give it a try myself.

What makes Parcel special

The thing I love the most about this bundler: it doesn’t need any configuration. Literally, none at all! Compare that to webpack where configuration can be strewn across several files all containing tons of code… that you may have picked up from other people’s configurations or inherited from other projects. Sure, configuration is only as complex as you make it, but even a modest workflow requires a set of plugins and options.

We all use different tools to simplify our job. There are things like preprocessors, post-processors, compilers, transpilers, etc. It takes time to set these up, and often a pretty decent amount of it. Wouldn’t you rather spend that time developing?

That’s why Parcel seems a good solution. Want to write your styles in SCSS or LESS? Do it! Want to use the latest JavaScript syntax? Included. Need a server for development? You got it. That’s barely scratching the surface of the large list of other features it supports.

Parcel allows you to simply start developing. That’s the biggest advantage of using it as a bundler — alongside its blazing fast compiling that utilizes multicore processing where other bundlers, including webpack, work off of complex and heavy transforms.

Where using Parcel makes sense

Parcel, like any tool, is not a golden pill that’s designed as a one-size-fits-all solution for everything. It has use cases where it shines most.

I’ve already mentioned how fast it is to get a project up and running. That makes it ideal when working with tight deadlines and prototypes, where time is precious and the goal is to get in the browser as quickly as possible.

That’s not to say it isn’t up to the task of handling complex applications or projects where lots of developers might be touching code. It’s very capable of that. However, I realize that those projects may very well benefit from a hand-rolled workflow.

It’s sort of like the difference between driving a car with an automatic transmission versus a stick shift. Sometimes you need the additional control and sometimes you don’t.

I’ve been working on a commercial multi-page website with a bunch of JavaScript under the hood, and Parcel is working out very well for me. It’s providing my server, it compiles my Sass to CSS, it adds vendor prefixes when needed, and it allows me to use import and export in my JavaScript files out of the box without any configuration. All of this allowed me to get my project up and running with ease.

Let’s create a simple site together using Parcel

Let’s take Parcel for a test drive to see how relatively simple it is to make something with it.

We’re going to build a simple page that uses Sass and a bit of JavaScript. We’ll fetch the current day of the week and a random image from Unsplash Source.

The basic structure

There's no scaffolding we’re required to use or framework needed to initialize our project. Instead, we’re going to make three files that ought to look super familiar: index.html, style.scss and index.js. You can set that up manually or in Terminal:

mkdir simple-site
cd simple-site
touch index.html && touch style.scss && touch index.js

Let’s sprinkle some boilerplate markup and the basic outline into our HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link href="https://fonts.googleapis.com/css?family=Lato&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.scss">
  <title>Parcel Tutorial</title>
</head>
<body>
  <div class="container">
    <h1>Today is:</h1>
    <span class="today"></span>
    <h2>and the image of the day:</h2>
    <img src="https://source.unsplash.com/random/600x400" alt="unsplash random image">
</div>
<script src="index.js"></script>
</body>
</html>

You may have noticed that I’m pulling in a web font (Lato) from Google, which is totally optional. Otherwise, all we’re doing is linking up the CSS and JavaScript files and dropping in the basic HTML that will display the day of the week and a link from Unsplash that will serve a random image. This is all we really need for our baseline.

Marvel at Parcel’s quick set up!

Let’s run the application using with Parcel as the bundler before we get into styling and scripts. Installing Parcel is like any thing:

npm install -g parcel-bundler
# or
yarn global add parcel-bundler

Let’s also create a package.json file should we need any development dependencies. This is also where Parcel will include anything it needs to work out of the box.

npm init -y
# or
yarn init -y

That’s it! No more configuration! We only need to tell Parcel which file is the entry point for the project so it knows where to point its server. That’s going to be our HTML file:

parcel index.html

If we open the console we’ll see something like this indicating that the server is already running:

Server running at http://localhost:1234

Parcel’s server supports hot reloading and rebuilds the app as change are saved.

Now, heading back to our project folder, we’ll see additional stuff,that Parcel created for us:

What’s important for us here is the dist folder, which contains all our compiled code, including source maps for CSS and JavaScript.

Now all we do is build!

Let’s go to style.scss and see how Parcel handles Sass. I’ve created variables to store some colors and a width for the container that holds our content:

$container-size: 768px;
$bg: #000;
$text: #fff;
$primary-yellow: #f9f929;

Now for a little styling, including some nested rulesets. You can do your own thing, of course, but here’s what I cooked up for demo purposes:

*, *::after, *::before {
  box-sizing: border-box;
}

body {
  background: $bg;
  color: $text;
  font-family: 'Lato', sans-serif;
  margin: 0;
  padding: 0;
}

.container {
  margin: 0 auto;
  max-width: $container-size;
  text-align: center;

  h1 {
    display: inline-block;
    font-size: 36px;
  }

  span {
    color: $primary-yellow;
    font-size: 36px;
    margin-left: 10px;
  }
}

Once we save, Parcel’s magic is triggered and everything compiles and reloads in the browser for us. No command needed because it’s already watching the files for changes.

This is what we’ve got so far:

Webpage with black background, a heading and an image

The only thing left is to show the current day of the week. We’re going to use imports and exports so we get to see how Parcel allows us to use modern JavaScript.

Let’s create a file called today.js and include a function that reports the current day of the week from an array of days:

export function getDay() {
  const today = new Date();
  const daysArr = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
  return daysArr[today.getDay()];
}

💡 It’s worth a note to remember that the getDay function returns Sunday as the first day of the week.

Notice we’re exporting the getDay function. Let’s go into our index.js file and import it there so it gets included when compiling happens:

import { getDay } from './today';

We can import/export files, because Parcel supports ES6 module syntax right out of the box — again, no configuration needed!

The only thing left is to select the <span> element and pass the value of the getDay function to it:

const day = document.querySelector('.today');
day.innerHTML = getDay();

Let’s see the final result:

Webpage with black background, heading that includes the day of the week, and an image below.

Last thing is to build for production

We’ve created the app, but we want to serve it somewhere — whether it’s your personal server or some zero-configuration deployment like Surge or Now — and we want to serve compiled and minified code.

Here’s the one and only command we need:

parcel build index.js
Terminal output after a successful build.

This gives us all of the production-ready assets for the app. You can read more about Parcel’s product mode for some tips and tricks to get the most from your environment.


I’ve said it several times and I’ll say it again: Parcel is a great tool. It bundles, it compiles, it serves, it pre- and post-processes, it minifies and uglifies, and more. We may have looked at a pretty simple example, but hopefully you now have a decent feel for what Parcel offers and how you might start to use it in your own projects.

I’m interested if you’re already using Parcel and, if so, how you’ve been using it. Have you found it works better for some things more than others? Did you discover some neat trick that makes it even more powerful? Let me know in the comments!

The post Why Parcel Has Become My Go-To Bundler for Development appeared first on CSS-Tricks.

Split

Jeremy on the divide between the core languages of the web, and all the tooling that exists to produce code in those languages:

On the one hand, you’ve got the raw materials of the web: HTML, CSS, and JavaScript. This is what users will ultimately interact with.

On the other hand, you’ve got all the tools and technologies that help you produce the HTML, CSS, and JavaScript: pre-processors, post-processors, transpilers, bundlers, and other build tools.

Jeremy likes the raw materials side the best but acknowledges a healthy balance of both worlds is a healthy mix.

I think a great front-end developer is hyper-aware of this split. Every choice we make is a trade-off between developer productivity and complexity management and the user's experience. The trick is to punish the user as little as possible while giving yourself as much as you can.

Direct Link to ArticlePermalink

The post Split appeared first on CSS-Tricks.