Pug templates for React Presentation Components

Nishant Singh
3 min readMar 4, 2018

--

This post is about using pug templates for writing presentational components with ReactJS .

ReactJS and Redux are really easy to learn. Though learning how to write some components and share state is pretty straightforward, how to organize codebase and responsibility is something that takes time to understand.

I find my codebase with React+Redux was much more harder to read, more verbose, lacking clear separation of concerns.

With angular(1.x) I could achieve lean, neat, minimal components using factories (to decorate scopes), pug (templates), lightweight controllers (that simply binds services and models to scope) and directives (only when DOM elements need to be manipulated).

So as part of an experiment, I decided to re-write one of my experimental angular app with react to compare and figure out some of my answers on how to have a lean, codebase with React + Redux.

Experimental app with alien theme and gaming experience

Here is the angular codebase, that looks pretty neat to me : https://github.com/nishants/star-wars (188KB).

This is react versions of the same functionality which has 53% larger codebase: https://github.com/nishants/star-wars-react. (287KB)

I figured out there were two sources of verbosity in the react app

  • Reducer-Action way of Redux over setter getter of angular services
  • JSX instead of template language like slim, jade etc.

There seems to be hardly anything that we can do for reducer-action boilerplate. But what about JSX ? Can we replace it with a template like pug ?

So trying to figure out a solution, I found this project in very early phase of its development : https://github.com/bluewings/pug-as-jsx-loader. It lets you write your dumb (presentation) react components as pug templates.The only JSX functionality it currently supports are iterating and conditional if. Which seems good enough for writing most of the dumb components.

Apart from dealing with verbosity of JSX, it also help establish clear responsibility for smart and dumb components. Container components will be a function or class, and all presentational component as pug templates.

Here are the steps I took me to quickly setup my create-react-app generate project to use pug :

  1. Install pug-as-jsx-loader
npm install pug-as-jsx-loader --save-dev

2. Eject project (sadly so)

yarn eject

3. Tell webpack how to handle pug templates.

In your webpack.config.dev.js,

{ test: /\.pug$/, use: [require.resolve('babel-loader'), require.resolve('pug-as-jsx-loader')] },

4. Define the smart container component

import React from 'react';
import {connect} from 'react-redux';
import {removeMission} from './missions-actions';
import missionsComponent from './missions.pug'

const
ListMissions = ({missions, removeMission})=> {
return missionsComponent.call({}, {
missions,
removeMission
});
};

const mapStateToProps = ({missions})=> ({missions: missions});

const mapDispatchToProps = (dispatch)=> ({
removeMission: mission => dispatch(removeMission(mission))
});

export default connect(mapStateToProps, mapDispatchToProps)(ListMissions);

3. Write a dumb component with pug

#missions-selected
ul
.missions
li(key='{mission.id}', @repeat='missions as mission')
div(className='planet') {mission.planetName}
div
(className='vehicle') {mission.vehicleName}
div
(className='overview') {mission.distanceInMegaMiles} Megagmiles in {mission.missionTime} days
div
(className='cancel', onClick='{()=> removeMission(mission)}')
div(className='no-mobile fa fa-remove')
div(className='mobile-only') Delete

Thats it!

--

--