Skip to content

Template structure

This section is about the file structure. You will learn how the different files are organized, but most important of all, how to manage your project with Gulp. Let's dive into the folder structure.

Global structure

my-project/
├── src/
│   ├── font/
│   ├── img/
│   ├── js/
│   │   ├── libs/
│   │   ├── store/
│   │   └── main.js
│   ├── sass/
│   ├── scss/
│   │   ├── abstracts/
│   │   ├── components/
│   │   ├── forms/
│   │   ├── layout/
│   │   ├── pages/
│   │   ├── utilities/
│   │   └── main.scss
│   ├── data/
│   ├── layouts/
│   ├── pages/
│   └── partials/
├── gulpfile.js
├── package.json
└── package-lock.json

The directory structure can seem unusual for someone who is not used to build tools. We will break each part of it, so you understand how everything works.

Assets

my-project/
├── src/
│   ├── font/
│   ├── img/
│   ├── js/
│   │   ├── libs/
│   │   ├── store/
│   │   └── main.js
│   ├── sass/
│   ├── scss/
│   │   ├── abstracts/
│   │   ├── components/
│   │   ├── forms/
│   │   ├── layout/
│   │   ├── libs/
│   │   ├── pages/
│   │   ├── utilities/
│   │   └── main.scss

The main reason we are working with npm and gulp is that we want to keep our development process clean, as well as our dependencies management. This kind of setup highly increases the project's code maintainability and scalability. Always prefer the npm method when adding new assets. Project assets are all the files needed for the project to run properly, like CSS files, images and javascript files.

Bulma folder

my-project/
├── sass/
│   ├── sass/
│   └── bulma.sass

When you installed the project by doing npm install, you also installed Bulma 0.9.1 as a project dependency. All bulma framework Sass source files are there. You can customize bulma by changing the values of the default bulma variables. You do not have to edit the source directly. Just declare the bulma variables you want to override in scss/abstracts/_variables.scss.

WARNING

Edit the Bulma source files only if you know what you are doing as any faulty customization may completely break the layout.

Layouts folder

my-project/
├── src/
│   └── layouts/

All the html layouts resides in this folder. For a more concise code, this project uses a flat file compiler named Panini, by Zurb. Panini makes it easy to break your layouts into several reusable components, preventing you to go through every page to make your changes. You can find more information about zurb/panini by visiting the official repository. The project follows the panini pattern for the html file structure.

The layouts folder holds all the template layouts. It is mandatory to have at least one layout, and it should always be named default.html. Additional layouts can have the names you want, but don't forget the .html extension. A layout acts as container providing the same base for a set of similar pages. Finally notice the {{> body}} call that is present in each layout file. This is a reference to append the rest of the page content.

Layout files

The layouts/ folder generally holds 1 layout file, but there are cases where there can be more than 1:

  • default.html : The default layout generally used by all the project pages.

Pages folder

my-project/
├── src/
│   └── pages/

The pages folder holds all the template pages. Pages are focused on content. They are related to a layout and automatically appended to it by panini when the page is served. You will always find the same statement at the top of each page's code :

---
layout: default
title: This is the page title
---

The layout statement tells panini wich layout to use to serve the page. The title element is a string that gets inserted as the page title when panini has finished assembling the page parts together. Now that we had a look to panini's basic features let's dive into the other html files :

Page files

All html pages live in this folder. Each one of this pages is linked ot one of the existing layouts and makes use of partials living in the src/partials/ folder.

Partials folder

my-project/
├── src/
│   └── partials/

The partials folder holds all your html partials. Partials are chunks of code that you want to reuse as is accross your application : it can be a button, a navbar, a content section or whatever you want. Note that you can create as many subfolders as you want to organize your partials. You simply have to make sure that your partial names are unique. Partials are named like html files : navbar.html. When you want to call a partial in one of your layouts or pages use the following expression : {{> partial-name}}. You don't have to mention the path, even if it is nested in several subfolders, panini will find it. Also note that you don't have to add the html extension in your partial call.

Partial files

my-project/
├── src/
│   ├── partials/
│   │   ├── partial1/
│   │   ├── partial2/
│   │   └── partial3/

Images

my-project/
├── src/
│   └── img/

All the project images live in this folder. It can have as many subfolders as you want. When you build the projects, all these images are automatically transfered to the right location by Gulp.

Js

my-project/
├── src/
│   ├── js/
│   │   ├── libs/
│   │   ├── store/
│   │   └── main.js

All javascript files live in the js folder. We recently dropped jQuery support and are now using the ES6 syntax to handle javascript functions. You should be familiar with the bare bones of ES6 when working with this template. Dropping jQuery doesn't mean we didn't replace it with something else. In fact we did, we are now using Alpine JS, a powerful dependency free javascript declarative framework, similar to Vue, but with less complexity. You can learn the basics of Alpine JS by reading the documentation. Alpine works very well in a simple setup where you declare your scripts in the same HTML page. It's a little bit more complex in this projects since we are importing functions from separated JS files. The only thing you need to now when importing an Alpine JS function in your main.js file is that you need to add it to the window object for it to work properly. Otherwise, you'll get undefined. Here is a practical example:

import 'alpinejs';
import { initNavbar } from './libs/components/navbar';
window.initNavbar = initNavbar;

There are 2 subfolders inside the js folder:

  • /libs : Holds all the functions that are used accross the template, inside separate files.
  • /store : For more complex state management we included a Spruce JS store, a small state management library that works very well with Alpine JS. Learn more about Spruce by readinf its online documentation.

Scss

my-project/
├── src/
│   ├── scss/
│   │   ├── abstracts/
│   │   ├── components/
│   │   ├── forms/
│   │   ├── layout/
│   │   ├── libs/
│   │   ├── pages/
│   │   ├── utilities/
│   │   └── main.scss

This template relies on the powerful Sass features, letting you handle complex styles in a breeze. The project relies on a modular scss structure. You need to import all the SCSS partials into your main SCSS stylesheet.

File Types

There are two main types of SCSS files : Core and Partials.

Partial files

Partial SCSS file names always start with an underscore like this: _variables.scss . They act as chunks of code that are imported into a core SCSS file. Not only this gives you great control over your code, but it also greatly enhances it's maintainability.

Core file

The main.scss file centralizes all the project styles. Every time you make a change in a partial file, it impacts the outputed dist/css/main.css file resulting from the compilation process (wich is handled by Gulp, as we saw above). The main SCSS file starts by importing all the needed SCSS partials. Here is an example statement:


/* ==========================================================================
Example imports
========================================================================== */

@import "abstracts/variables";
@import "abstracts/brands";
@import "abstracts/shadows";
@import "abstracts/typography";

@import "../sass/bulma";

@import "utilities/utilities";

@import "abstracts/animations";
@import "abstracts/helpers";

@import "components/pageloader";
@import "components/navbar";
@import "components/hamburger";
@import "components/button";
@import "components/card";
@import "components/table";
@import "components/tabs";
@import "components/image";
@import "components/video";
@import "components/tag";
@import "components/pricing";
@import "components/map";

@import "forms/input";
@import "forms/toggle";

@import "layout/hero";
@import "layout/section";
@import "layout/footer";

Notice how partials are imported. Whereas the actual partial file name starts with an underscore and ends with a .scss extension, when you write imports inside your main.scss file, you have to remove the undescore and the .scss extension.

Root files

There also a few files sitting at the root of the project that we need to discuss before getting into serious business:

  • gulpfile.js : Gulp will use this file to perform all the tasks it is supposed to accomplish.
  • package.json : Lists all your project's dependencies and gives useful metadata.
  • package-lock.json : Automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.