bekwam courses

Using Vue.js In A Static Website

February 11, 2019

Usually, when you think of Vue.js, you think of a dynamic, rich internet application. This article shows how Vue.js can be used in a static website to maintain commons elements that appear throughout a set of pages. This is not a single-page application. Rather, the demo is a collection of .html pages that share an app instance definition to allow the maintenance of a header and a footer at a single point.

This screenshot shows Page A in a file. This is an HTML file, pageA.html. Without Vue.js, there would be a header, followed by content, followed by a footer. The colored header and footer bands sppear throughout the site.

Browser Screenshot
Page A with Shared Header and Footer

There is an HTML file, pageB.html, with a similar structure. The content in pageA.html differs from that in pageB.html, but there common elements like the header and the footer which are duplicated. This presents a maintenance problem as additional pages (pageC.html, pageD.html) will require editing multiple documents to affect the same change. The screenshot from Page B is below.

Browser Screenshot
Page B with Shared Header and Footer

To view the pages for yourself, visit http://www.bekwam.org/slot-demo-project/pageA.html.

In the Vue.js version, the common header and footer are factored out and put into Vue.js. Changing these elements -- things like the brand logo and copyright notice -- site-wide now involves a single edit to a single file (main.js). Moreover, the header can slightly vary between pages. This is parameterized using a <slot>.

Javascript

The following pair of component definitions and Vue app instance are in a single main.js file.

The HeaderComponent contains a shared top-level page header, a shared navigation, and a page-specific sub-header. The page-specific sub-header is parameterized with a Vue <slot> tag. This will swap in the contents of the <header-component> tag in the individual pages (pageA.html and pageB.html). For help during debugging, you might specify a default value within the slot tag. However, I feel that this is more fault tolerant because if it is omitted, the <h2;> will be empty.


const HeaderComponent = {
    template : `
    <header>
        <h1>My Site Brand</h1>
        <nav>
            <ul>
                <li><a href="pageA.html">Page A</a></li>
                <li><a href="pageB.html">Page B</a></li>
            </ul>
        </nav>
        <h2><slot></slot></h2>
    </header>`
}

The FooterComponent is will be exactly the same for each page. There's no need for the slot tag.

    
const FooterComponent = {
    template: `
    <div id="ftr">
        <hr>
        <footer>
            <p>© 2019 My Site Brand, Inc</p>
            <p>Questions? 
            Contact the <a href="mailto:webmaster@example.com">
            webmaster@example.com</a>.
            </p>
        </footer>
    </div>
        `
}    
    

The Vue app instance registers a pair of component, HeaderComponent and FooterComponent. These are aliased to kebab-case to keep the names readable in the W3C case insensitivity guidelines.


const app = new Vue({
    el: '#app',
    components : {
        'header-component': HeaderComponent,
        'footer-component': FooterComponent
    }
})

HTML

pageA.html builds out the document in the "app" div which is bound to the Vue app instance. It uses the header-component and footer-component tags. header-component has a title that will be used in the HeaderComponent definition. Notice that the <head> title and keywords are also fixed in this page.


<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="pagea">
<title>Slot Demo - Page A</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
    <div id="app">
    
        <header-component>Page A</header-component>
        <p>AAAA AAAA AAAA AAAA</p>
        <p>My Content for Page A</p>
        <footer-component></footer-component>

    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="main.js"></script>
</body>
</html>

Page B has an identical structure but has its own values in the head content in the body.


<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="pageb">
<title>Slot Demo - Page B</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
    <div id="app">

        <header-component>Page B</header-component>
        <h2>Page B</h2>
        <p>BBBB BBBB BBBB BBBB</p>
        <p>My Content for Page B</p>
        <footer-component></footer-component>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="main.js"></script>
</body>
</html>

CSS

There are some minor CSS styles used in the presentation to highlight the shared elements.


header {
    background-color: lightcoral
}

#ftr {
    background-color: lightblue
}

When you have a large web site, you should consider a Content Management System (CMS). The CMS provides a streamlined workflow for managing content. However, a static website is easy to set up and will be more secure because there's no back-end to compromise. Additionally the static site is very scalable with services like CloudFlare able to replicate the static content around the globe. If you find yourself maintaining a static site, the ideas in this article may help you deal with shared items so that maintenance can be kept to a minimum by cutting down on duplication.


Headshot of Carl Walker

By Carl Walker

President and Principal Consultant of Bekwam, Inc