HTML includes with Gulp.js
Tags: html, gulp, javascript, frontend
Published: 2020-06-01 15:44:38

How beautiful it would be if HTML had the option of including repeating blocks, right?

Using Gulp.js and some packages, we can make that dream come true!

This tutorial uses Gulp 4.0. This is the most recent stable version and the current default on [npm](https://www.npmjs.com/package/gulp).


##Let's get started!
First of all let's create our project and the html files that will be used for this tutorial.

```zsh
mkdir myproject && cd myproject
touch index.html header.html footer.html
```
**header.html** and **footer.html** will be the files that we will include in our **index.html**.

####Our index.html example
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Gulp Html Include Boilerplate</title>
  </head>
  <body>
    <!-- Content -->
    <section>
      <h1>Hello world</h1>
    </section>
  </body>
</html>
```

####Our include files example
#####header.html
```html
<!-- Header -->
<header>
  My Header
</header>
```

#####footer.html
```html
<!-- Footer -->
<footer>
  My Footer
</footer>
```


##Add packages
For this tutorial we will use [Yarn](https://yarnpkg.com/) as a package manager. (You can use npm if you prefer)

Starting a new project
```zsh
yarn init
```

Install the [gulp-file-include](https://www.npmjs.com/package/gulp-file-include) plugin
```
yarn add gulp gulp-file-include -D
```


##gulpfile
Let's create our gulpfile to be able to create our tasks with Gulp
```zsh
touch gulpfile.js
```

Import **gulp** and **gulp-file-include**. We will also create a variable **paths** to define the path of our source and the destination path (where the static html files will be after the build).
```javascript
const gulp        = require('gulp');
const fileinclude = require('gulp-file-include');

const paths = {
  scripts: {
    src: './',
    dest: './build/'
  }
};
```

In our gulpfile.js file we will create a task function that will be responsible for including our html files and returning static files.
```javascript
async function includeHTML(){
  return gulp.src([
    '*.html',
    '!header.html', // ignore
    '!footer.html' // ignore
    ])
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(paths.scripts.dest));
}
```

For now we will set our function as default and we will test our script.
```javascript
exports.default = includeHTML;
```


##Add the include tags to index.html
```html
@@include('./header.html')

<!-- Content -->
<section>
  <h1>Hello world</h1>
</section>

@@include('./footer.html')
```


##Run the gulp command
```zsh
yarn gulp
```

The build folder will be created with our **index.html** file inside

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zxujdbxqnsh477kiph27.png)

We can see the content of **header.html** and **footer.html** have been included into our index.html
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Gulp Html Include Boilerplate</title>
  </head>
  <body>

    <!-- Header -->
    <header>
      My Header
    </header>
    
    <!-- Content -->
    <section>
      <h1>Hello world</h1>
    </section>

    <!-- Footer -->
    <footer>
      My Footer
    </footer>
  </body>
</html>
```

But it can be a little tiring to run the gulp command every time we modify our files, let's automate this task.


##Bonus #1: Live Browser Reload 
Add the [browser-sync](https://www.browsersync.io/docs/gulp) plugin
```zsh
yarn add browser-sync -D
```

Let's load the plugin and the [watch](https://gulpjs.com/docs/en/api/watch/)/[series](https://gulpjs.com/docs/en/api/series/) methods inside our gulpfile.js
```javascript
const server = require('browser-sync').create();
const { watch, series } = require('gulp');
```

Add the reload function
```javascript
// Reload Server
async function reload() {
  server.reload();
}
```

If you have assets you will need this function to move them to the build folder.
```javascript
// Copy assets after build
async function copyAssets() {
  gulp.src(['assets/**/*'])
    .pipe(gulp.dest(paths.scripts.dest));
}
```

Let's create a function that includes our files and then reload the server.
```javascript
// Build files html and reload server
async function buildAndReload() {
  await includeHTML();
  await copyAssets();
  reload();
}
```

We will need our default gulp function, so we will have to rename the current one to:
```javascript
exports.includeHTML = includeHTML;
```

Now that we have all the functions, we will recreate the default function of our gulp script by inserting the following code:
```javascript
exports.default = async function() {
  // Init serve files from the build folder
  server.init({
    server: {
      baseDir: paths.scripts.dest
    }
  });
  // Build and reload at the first time
  buildAndReload();
  // Watch task
  watch(["*.html","assets/**/*"], series(buildAndReload));
};
```

###Our final gulpfile.js file
```javascript
const gulp        = require('gulp');
const fileinclude = require('gulp-file-include');
const server = require('browser-sync').create();
const { watch, series } = require('gulp');

const paths = {
  scripts: {
    src: './',
    dest: './build/'
  }
};

// Reload Server
async function reload() {
  server.reload();
}

// Copy assets after build
async function copyAssets() {
  gulp.src(['assets/**/*'])
    .pipe(gulp.dest(paths.scripts.dest));
}

// Build files html and reload server
async function buildAndReload() {
  await includeHTML();
  await copyAssets();
  reload();
}

async function includeHTML(){
  return gulp.src([
    '*.html',
    '!header.html', // ignore
    '!footer.html' // ignore
    ])
    .pipe(fileinclude({
      prefix: '@@',
      basepath: '@file'
    }))
    .pipe(gulp.dest(paths.scripts.dest));
}
exports.includeHTML = includeHTML;

exports.default = async function() {
  // Init serve files from the build folder
  server.init({
    server: {
      baseDir: paths.scripts.dest
    }
  });
  // Build and reload at the first time
  buildAndReload();
  // Watch task
  watch(["*.html","assets/**/*"], series(buildAndReload));
};
```

Start your server in localhost and see the autoreload working. 🎉🎉🎉
```zsh
yarn gulp
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mqpc35u2v8vxwcfzfnwb.png)

Each time the file is saved, Gulp follow the flow of tasks making the files and refreshing the page.

##Bonus #2: Sass Compiler
Let's create our scss file inside the sass folder
```zsh
mkdir sass && touch sass/style.scss
```

Add the [gulp-sass](https://www.npmjs.com/package/gulp-sass) plugin
```zsh
yarn add node-sass gulp-sass -D
```

Open the gulpfile.js file and insert the following lines to load the plugin
```zsh
const sass = require('gulp-sass');
sass.compiler = require('node-sass');
```

Now let's create the function that will help us to compile scss files into css:
```zsh
// Sass compiler
async function compileSass() {
  gulp.src('./sass/**/*.scss')
    .pipe(sass().on('error', sass.logError))
    .pipe(gulp.dest('./assets/css'));
}
```
The destination folder will be "/assets/css" because later our build will move all the contents of assets folder to the build folder.

Let's add a watch to compile our css each time we make a modification inside the scss file

Before the buildAndReload watch add:
```zsh
// Watch Sass task
watch('./sass/**/*.scss',  series(compileSass));
```

We must not forget to load the css file that will be loaded after the build
```html
<link rel="stylesheet" type="text/css" href="css/style.css">
```

And now, just start the gulp and make changes to the scss file:
```zsh
yarn gulp
```

Change the color of the body
![Style.scss file](https://dev-to-uploads.s3.amazonaws.com/i/t69f55xsa6x9wc2uvm25.png)

And... 💥
![Screenshot](https://dev-to-uploads.s3.amazonaws.com/i/7n3twsw94hvo051wdixi.png)

##Link to Code
You can find the final code [here](https://github.com/caiojhonny/gulp-html-include-boilerplate)

Hope it's helpful some of you 🙂