Hackernoon logoUsing Pug (Jade) with Angular (with CLI) by@jecelynyeen

Using Pug (Jade) with Angular (with CLI)

Jecelyn Yeen Hacker Noon profile picture

@jecelynyeenJecelyn Yeen

Software Architect, Frontend

I love Pug. Pug allow me to write cleaner HTML.

From HTML like this:-

<!DOCTYPE html>
<html>
  <head>
<meta charset="utf-8">
<title>my portal</title>
</head>
  <body>
    <app-root>
<div class="root-spinner">
<img class="loading" src="assets/images/logo.png">
</div>
</app-root>
</body>
</html>

To Pug, so much cleaner.

doctype html
html
head
meta(charset="utf-8")
title my portal
  body
app-root
div.root-spinner
img.loading(src="assets/images/logo.png")

However, if you are using Angular (version 2 or 4) & the de-facto Angular-CLI, the pug option is not out of the box, probably yet. There is a discussion here: https://github.com/angular/angular-cli/issues/1886.

How we can use it now?

We can use pug-cli now. Pug CLI allows you to compile pug with command like pug [dir,file]` and watch the changes.

npm install pug-cli --save-dev

After installation, we create two scripts in package.json`:

"pug-it": "pug src",
"pug-it:w": "pug src -P -w"

The first command `pug-it` will compile all the .pug files under `src` directory to .html file in same directory.

The second command did exactly the same thing with additional file watching. We use this command during development to watch the file changes and recompile automatically.

Here are some other scripts we have.

"ng": "ng",
"start": "run-p pug-it:w server",
"server": "ng serve --port 4210",
"prebuild": "yarn run pug-it",
"build": "ng build",

Please notes that:-

  1. When running npm start, we will start the dev server and and the pug watch tasks concurrently.
  2. Before we run build, we run pug before that (during prebuild`).

Side notes on concurrent tasks

If you want to run multiple tasks concurrently cross platforms (mac, windows, etc), 3rd party packages like concurrently and npm-run-all are helpful. We use npm-run-all. The run-p command is provided by the package. You can install it:

npm install npm-run-all --save-dev

However, if all your developers are on Linux or Mac, then you don’t need any 3rd party packages, just replace start command withnpm run pug-it:w & npm run server will do.

Git Ignore HTML files

If you are using pug, you might not want to check in the generated HTML files. Exclude them in your git. Add this line to your .gitignore file.

#pug
/src/**/*.html

Please notes that in your component typescript, you still refer to .html, there’s no need to change this.

@Component({
selector: 'my-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {}

Woala, everything up and running.

Trade-offs

There are a few tradeoffs using this approach.

1. No auto watching for new files

When adding any new pug file after npm start, the new file is not watched. You need to restart dev server (stop and rerun npm start).

2. Fail silently when hitting pug syntax error

Since we start pug watch and dev-server concurrently, when there’s pug syntax error happens during development, you will see errors in terminal, but not on screen or browser console. Please beware of this, sometimes you got syntax error without knowing it, and spend hours to debug other area (you know what I mean).

3. Need to manually create pug file if you use ng generate

By default, angular-cli ng generate will generate HTML file for component. You need to rename or delete/create the HTML to pug file.

Some captcha when using pug with Angular

Let’s be honest, Angular template syntax looks different from normal HTML. When using it with Pug, you need to surround all attribute with single quote.

my-top-bar(
'[(ngModel)]'="myModel"
'[propA]'="myPropA"
'(actionA)'="handle($event)"
)

This will generate the following HTML.

<my-top-bar 
[(ngModel)]="myModel"
[propA]="myPropA"
(actionA)="handle($event)">
</my-top-bar>

If you somehow forgot to put single quote on the attributes, congratulation. No error will be notify in terminal. The HTML generated will be

<my-top-bar>
</my-top-bar>

All fields will be omitted. If you realise about that after an hour of debugging, please don’t cry. Heh.

Please note that

Other alternatives

There are some other alternatives.

  1. First one, the simplest one, don’t use pug, use HTML.
  2. Run ng eject to eject the angular-cli. You’ll get back all your webpack config that angular-cli generated for you. Then add your pug-loader.
  3. Use other angular boilerplate that you can make changes easier. E.g. Angular Seed.
  4. Create a pug plugin or angular-cli or wait for one.
  5. Read the discussion https://github.com/angular/angular-cli/issues/1886, probably you can dig out some gold there.

Conclusion

Our team found the option we chose and the tradeoffs bearable. We’ve use this in our v2 project now upgrade to v4.

Let me know if you have better way of doing this.

That’s it. Hopefully you find this helpful. Happy coding!

Tags

Join Hacker Noon

Create your free account to unlock your custom reading experience.