ARA MEDINA

View Original

Building a Repository Portfolio with webpack and Pug (Jade)

As part of a recent job application, I was asked to build out a project that would hit the GitHub API and render all of my current repositories onto the page. This seemed simple enough, but I was asked to do it using webpack, npm, and vanilla JavaScript. To challenge myself a little more, I also decided to use SCSS and the Pug (formerly known as Jade) templating language, which I knew the company was using in its own code. 

You can follow along by checking out the GitHub repo for this project here: https://github.com/sandramedina/repository-portfolio


Here's a little background information:

webpack

webpack: webpack is a module bundler for JavaScript, and it takes all of your separate files with their individual dependencies, and compiles them down into static files. webpack is currently on its second version, so when you're reading documentation, make sure you're going here: https://webpack.js.org/ (their old docs are hosted elsewhere, it's confusing). 

npm: npm stands for 'node package manager' and it's how you'll install of the packages you'll need for your project (including webpack!). It's also how you'll install 'loaders' for your project. Loaders are sort of like a set of instructions that tell webpack what to do when it encounters certain file types. I'll talk more about them later.

Pug (and why I'd rather not use it): Pug is a templating language. Instead of writing in HTML, you'll write in Pug, and then webpack will turn that into HTML during build time. The argument is that Pug allows teams to write cleaner, more succinct code. This is probably true, since Jade looks like shorthand HTML and it is sensitive to white-space. However, it is also super annoying. Rob Muhlestein puts it well when he says "With Jade everyone has to use Jade. While it is possible to bring in HTML it is not practical to cut and paste HTML into Jade templates. With all the valuable snippets of HTML in the world choosing a template engine that is largely incompatible with them seems less than desirable." I might be missing something that Pug is trying to do, but a better solution to me seems like giving your team a style guide for writing in HTML and enforcing it during code reviews. That way, your code is still clean but you keep it in a standard language. Another personal opinion: the hard and time-consuming part of writing code is not spelling out div and p tags, but it's making sure your code is readable, fast, elegant, modular, etc etc etc. I've never said 'wow, this project is taking a long time, I wish I had a faster way to write HTML'. 


Anyway, if you disagree with my Pug stance and have decided to build it into your project, I have some tips that might help you save some time configuring it all. This won't be a comprehensive overview, because you can find those things elsewhere (I recommend here and here), but just a quick look at how I got Pug and webpack to work together.

It seems like there are at least two popular loaders out there for using Pug with webpack. The first one is Pug-HTML-Loader, but I ended up having a bunch of miscellaneous issues with this one. Some people seem to have solved their issues by using it with HTML-Loader, but that didn't work for me, so I ended up just switching to Pug-Loader. 

See this content in the original post

In my webpack config file, I'm setting a rule that tells webpack that when it runs into a Pug file, to use Pug-Loader to handle it. 

See this content in the original post

In my JS file, I'm importing the Pug file. This is important because it lets Pug-Loader return the Pug file as a template function. You'll see this if you console.log that 'template' constant. 

See this content in the original post

In the body of your JS, you can then create a 'locals' object. Here, 'repo' is the object that I'm getting back from the GitHub API, and I'm accessing its various properties to create a new object called 'locals'. 

See this content in the original post

In Pug, 'locals' is a data object that, when called with the correct function, will return a string of HTML rendered with 'locals'.

See this content in the original post

Once you get the string of HTML (in this case called 'htmlSnippet'), you can use it to set the innerHTML of an element. In my code, I'm accessing the DOM one time in order to set the innerHTML of the '#repos' div to 'htmlSnippet'. It's important to make sure you're accessing the DOM as infrequently as possible, since doing so can slow down your application.

When you run webpack on your code, it will compile your Pug into HTML and you'll see that in the dist folder. This is what actually gets rendered in the browser. I've set my code up with the extract-text-webpack-plugin, so I can actually see an index.html file in my dist folder instead of just an app.bundle.js file where everything is bundled. The index.html file ends up looking like this (webpack removes white-space to create a smaller file):

See this content in the original post