- gulp-htmlincluder
- What to use this for?
- A Brief Warning
- Install and Setup
- File Naming Requirement
- Includer Tags
- Terminology
- All Tags
- Attributes
- path
- jsonPath
- rawJson (uses eval )
- count
- Insert
- Example
- Configure insert to use other text
- Wrap
- Example
- data
- Example
- jsonInsert
- Example
- Inline json objects
- Each
- Just with a count
- each over other tags
- With an array of values in json input
- With an array of values
- Array limited by count
- With an array of objects
- Clip tops and bottoms off of files
- Example
- Clip between
- Example
- More Examples
- ToDo
- gulp-file-include
gulp-htmlincluder
This allows you to insert a special markup into your files to do a number of things:
- insert files into other files
- wrap a file with another file
- clip off certain parts of a file
- inject data for use in adding text to files
- basic control flow (if and each) to use with data
What to use this for?
This was written with the intention of working on static websites while still allowing for a component based development. It also was intended to let the individual components be testable by themselves by allowing the individual component files to include portions that would be removed on build.
It also can allow the inclusion of some dynamic content into these static sites, as long as you can wrangle said content into a json object and pass it in when you are building.
I’m sure this can be put to a much broader use than originally intended (and may do for a name change at some point, since there is no reason you couldn’t include json files into json files, or do other things.)
A Brief Warning
Certain features use eval . I have flagged these features below, but please use caution when using them so that you don’t have any untrusted data that isn’t unsanitized going into the system. It could lead to compromising the build environment or XSS attacks in the resulting html.
Install and Setup
npm install --save-dev gulp gulp-htmlincluder
const src, dest > = require('gulp'); const includer = require('gulp-htmlincluder'); // A simple method for making basic api requests. const http = require('http'); const getApiData = url => new Promise((resolve, reject) => http.get(url, resp => let data = ''; resp.on('data', chunk => data += chunk) resp.on('end', () => resolve(JSON.parse(data))) >) >) exports.includer = function(path) // optional use of json data. options object is not required const jsonInput = require('./input-file.json'); const rawJsonPlugins = getApiData >; src('./src/**/*.html') .pipe(includer( jsonInput, rawJsonPlugins >)) .pipe(dest('./dist/')) >
you can then run this with gulp includer
gulpfile.js (using earlier versions of gulp):
var gulp = require('gulp'), includer = require('gulp-htmlincluder'); gulp.task('htmlIncluder', function() // optional use of json data. options object is not required var json = require('./input-file.json'); var options = jsonInput : json, >; gulp.src('./src/**/*.html') .pipe(includer(options)) .pipe(gulp.dest('./dist/')); >); gulp.task('default', ['htmlIncluder']); gulp.task('watch', function() gulp.watch(['files/*.html'], function(event) gulp.start('default'); >); >);
File Naming Requirement
htmlincluder requires files follow a particular naming convention.
Files that you want to include in other files begin with — .
Files that you want to wrap around other files begin with _ .
Files that you want to use to build the resulting static pages can be named however you want, as long as they don’t begin with — or _ .
Right now this is necessary because the files that will ultimately exist in the build folder are those that don’t start with — or _ . I’d love to change this to determine this in another manner (for example, only files that aren’t included are finally built).
Includer Tags
It is probably best to learn from examples. These can be found in the ./test/html folder of this repository. These can be run by cloning this repository, running npm install and then npx gulp . Check the gulpfile.js for specifics if you just want to try building single files.
Terminology
All Tags
Note: * means required attribute
- Wrapping a file with another file
- Inserting a file
- Inserting Json (passed in from parent component)
- Inserting Json (from data input, or default value)
- Control Flow
- If
- Each (repeater)
- Clipping (Ignores parts of file)
Attributes
path
A relative (to current file) path to a file.
src |- components | |- -header.html |- index.html
in index.html the path for -header.html is:
jsonPath
A path to data in a json object.
rawJson (uses eval )
A string that, when converted to JavaScript and executed, produces a json object. You can access this data using your jsonPath attribute.
You can pass in a self-invoking function you can invoke this function with the arguments json and/or plugins .
json represents the json object that you may pass in to the options for htmlincluder when invoking it in your gulp task. plugins
It would even be possible to use an async function to load data from a service or CMS:
Internally eval is used so beware. But also, you could technically write a script that generates an object if you need more complicated data.
Of course, if you’re loading data from an api it could be compromised. If it contains something like:
You may have compromised your users. So beware!
count
On an #each you can tell it how many times to repeat the inner content with a count attribute
Insert
This is the simplest use case. Simply put the following html comment
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> body> html>
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> hello world body> html>
Configure insert to use other text
If you want to use ssi includes along with this, and so have the insert string follow that format there is an argument to pass into the htmlincluder in gulp.
Thanks to theSLY for suggesting this!
var gulp = require('gulp'), includer = require('gulp-htmlincluder'); gulp.task('htmlIncluder', function() var options = insertPattern: 'include virtual', >; gulp.src('files/*.html') //now looks for <!--#include virtual, instead of <!--#insert .pipe(includer(options)) .pipe(gulp.dest('dist/')); >); gulp.task('default', ['htmlIncluder']); gulp.task('watch', function() gulp.watch(['files/*.html'], function(event) gulp.start('default'); >); >);
Wrap
The middle tag must be placed in the wrap file so we know where to put the middle part of the other file
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> body> html>
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> hello world body> html>
data
Inside of wrap and insert tags that you have used the jsonPath attribute on you can use use this tag to print data that has been passed down.
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> body> html>
< "hello" : < "world" : "hello world" > >
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> div> hello world div> body> html>
jsonInsert
When using a json data file, you can pull data from it directly using this tag.
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> body> html>
< "hello" : < "world" : "hello world" > >
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> hello world body> html>
Inline json objects
Instead of using the data file, you can provide a raw json object
Each
Each can be used to iterate over a json array, or just to repeat some data a number of times.
Just with a count
div>hello worlddiv> div>hello worlddiv> div>hello worlddiv> div>hello worlddiv> div>hello worlddiv>
each over other tags
div>hello worlddiv> div>hello worlddiv> div>hello worlddiv> div>hello worlddiv> div>hello worlddiv>
With an array of values in json input
div>1div> div>2div> div>3div> div>4div>
With an array of values
div>1div> div>2div> div>3div> div>4div>
Array limited by count
With an array of objects
note: use single quotes in json objects, which means you’ll need to escape
< name: 'Tom', age: 33, bio: 'Bio for Tom' >, < name: 'Dick', age: 55, bio: 'Dick\'s bio' >, < name: 'Jane', age: 28, bio: 'Bio for Jane' >, < name: 'Harry', age: 27 >, ]» —> div>name: div> div>age: div> div>bio: div>
div>name: Tomdiv> div>age: 33div> div>bio: Bio for Tomdiv> div>name: Dickdiv> div>age: 55div> div>bio: Dick's biodiv> div>name: Janediv> div>age: 28div> div>bio: Bio for Janediv> div>name: Harrydiv> div>age: 27div> div>bio: nothing is known about themdiv>
Clip tops and bottoms off of files
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> blah body> html>
Clip between
Example
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> something a widget! something else body> html>
> html lang pl-s">en"> head> meta charset pl-s">UTF-8"> title>Documenttitle> head> body> something something else body> html>
More Examples
ToDo
- Build out more tests — consider more automated versions of them
- Implement some form of caching so only changed files need be processed
gulp-file-include
The webRoot field of the context contains the relative path from the source document to the source root (unless the value is already set in the context options).
> html> head> link type=stylesheet src=@@webRoot/css/style.css> head> body> h1>Support Contact Infoh1> footer>a href=@@webRoot>Homea>footer> body> body> html>
> html> head> link type=stylesheet src=../../css/style.css> head> body> h1>Support Contact Infoh1> footer>a href=../..>Homea>footer> body> body> html>
- If