Refactoring a Static HTML Site Into Typescript, Part 1 of 2: The Content

Simon Lutterbie
The Startup
Published in
5 min readJan 31, 2021

--

The contents of index.ts, the entrypoint to my source code, after the updates in this two-part series.

This article chronicles a small part of my journey towards creating a full website that can be rendered in three parallel frameworks and three parallel design systems (React + Material UI; Angular + Clarity; “Vanilla” JS + Carbon).

← Previous article: Setting up a simple Typescript project

→ Next article: Refactoring an HTML site into Typescript: Part 2 of 2

I recently discussed creating a simple “Hello, World!” website in Typescript. Now that the basic tools are in place, I want to:

  • Add some more content, at first as static HTML
  • Render the content using Typescript, rather than static HTML

Once I achieve this, I’ll have in place the skeleton of a modern web application. It will be tiny, creaky, and far from optimized, but the core ideas will be in place, and I can build from there.

If I were building a sports car from the ground up, this would roughly be the stage at which I’ve bolted four wheels onto a wooden shipping palette. Sure, it’s a laughably far cry from the finished product, but it does technically have four wheels and rolls forward (…on a downslope).

Converting from a static HTML site with multiple templates to a Typescript-powered “single page application” (SPA) is not too complex, but it is somewhat involved. There are two big pieces of work:

  1. Converting the content from static HTML to Typescript functions.
  2. Converting the navigation from href linkto onClick ventHandlers.

I’ve therefore divided this work into two articles, of which this is Part 1. If you want, you can skip to Part 2: The Navigation (…coming soon!). In order to provide a working site, I’ve combined the two pieces of work into a single commit, which you can view on GitHub.

Let’s begin!

At the start, my site just had a single “Hello, World!” page, which was rendered via my helloWorld() function, outlined in this article. To make the refactoring more interesting and meaningful, I first created some additional content as static HTML pages, with navigation links between them.

I ended up creating three pages, about-this-site.html, about-simon.html, and technology-used.html, all of which shared the same basic structure:

<html>
<body>
<div>
<a href="...">Links to other pages</a>
</div>
... Page content
</body>
</html>

I put each of these files into my project’s public directory, which gets copied into dist when the project is built. Here’s my project structure, at this point:

Project file tree, listing several static HTML files

And here’s what the “technology used” page looks like:

A screenshot of a very basic web page

It’s nothing much, but it works; you can view my repository code at this point in time at this commit on GitHub.

Now the refactoring work can begin!

While the above structure works, I don’t want to use static templates for my content, and I certainly don’t want them rendered from separate files. Static files are inflexible, and maintaining navigation between them quickly becomes impractical. They also don’t follow the “single page application” (SPA) architecture used by modern frameworks, in which a single HTML template serves as a canvas, and the application handles rendering (almost) all content. As this project’s ultimate destination is a set of parallel SPAs, I want to adopt this structure early on.

The first refactor is to rebuild the pages as Typescript functions. I create Typescript files for each of my new functions, in a new views directory within my source code:

mkdir src/views
touch src/views/{about-this-site,about-simon,technology-used}.ts

You’ll notice I chose views instead of pages. A “page” was a good description for the early days of the Web, when content was published in static pages, like I implemented above. But it doesn’t capture the dynamic nature of the modern web, where various parts of a “page” will appear on most, or even all, pages. “View” is a more flexible term, as it limits the scope to how one “views” a certain piece of information.

For example, consider my navigation menu. One of the things that makes static pages cumbersome is maintaining navigation between them as new content is added. This becomes much easier when thinking of views — a navigation menu is the view of where you can go on a site. In Part 2, I’ll create a dedicated view for my navigation menu, and the same content will appear on every “page” of my site. But first, the content.

The core pattern for one of my makeView functions is as follows:

makeView() creates a “wrapper element”, creates one or more “content elements” and attaches them to the wrapper element as its children, then returns the single wrapper element to be displayed.

To speed up the content creation process, and to make my code more readable (one of my core coding principles!), I created several “helper functions” to create basic content elements. For example makeParagraph(text: string):

Screenshot of my makeParagraph helper function, and a sample implementation

The makeView() function has become much more readable. I ended up creating several helper functions, including makeList, makeLink, and makeSpan, all of which I placed in src/views/views.utils.ts, so they could be more easily shared between my various view functions.

A little bit of coding later, and my initial refactoring is complete. The image below shows a before & after of my project structure. It contains a single index.html template, and the content is all contained in __.view.ts files:

File trees, from one based on static HTML files to one based on Typescript functions

You’ll notice I also created src/views/navigation.view.ts — the contents of this file is covered in Part 2.

This new architecture allowed me to greatly simplify my index.html template. Rather than providing any content directly, it now simply contains placeholders — one to hold my navigation view , and one to hold whichever content view I wish to render. It then calls my source code entrypoint, ./src/index.js, which handles the actual rendering.

My index.html template, which just has to placeholder divs, and a script tag that loads the entrypoint to my source code.

In the next article, I’ll discuss how I refactored my site’s navigation from a series of hyperlinks to a series of event listeners. If you want to view the source code developed in this article (including the navigation from the next article), you can view it in this commit on GitHub.

--

--

Simon Lutterbie
The Startup

Senior Frontend Engineer committed to creating value and being a force-multiplier. Typescript, React, GraphQL, Cypress, and more. Also: PhD in Social Psychology