Note: html-dist
is being completely rewritten. If you want the old version, install html-dist@0.1.0
and read this README.
Easily manipulate HTML files by removing and inserting elements.
VERY WIP! Until V1.0.0 you should expect breaking changes in minor versions. EG: 0.2 -> 0.3 may include breaking changes
npm install --save-dev html-dist@0.3.1
The problem that lead to me creating html-dist was deploying front-end only projects. In development mode I tend to have an HTML file set up for development. For example, an HTML file for a jspm project might look like so:
<!DOCTYPE html>
<html>
<head>
<title>My Project</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('app/main');
</script>
</head>
<body>
</body>
</html>
JSPM provides a tool to bundle all my JavaScript into one file, but I'm left to deal with my HTML file. I could manually edit it each time, but that gets boring quickly. This is why I built html-dist
. I can create a configuration file that tells html-dist
how to manipulate the HTML and it will produce the new HTML file. In this instance I want to remove all script
tags and insert one new one to bundle.js
. Additionally I'd like to add the Google Analytics script.
Here's how I would do that with html-dist
:
- Install
html-dist
:npm install --save-dev html-dist
- Create a
html-dist.config.js
file (with full ES2015 support):
var { script, googleAnalytics } = require('html-dist');
module.exports = {
// where to write to
outputFile: 'dist/index.html',
// minify the HTML
minify: true,
head: {
// in the <head>, remove any elements matching the 'script' CSS selector
remove: 'script'
},
body: {
// append the following things to the body
appends: [
script({
src: 'bundle.js'
}),
googleAnalytics('UA-1234')
]
}
}
Note that the configuration file is not parsed with Babel. You may use whatever set of ES features your Node version supports.
- Run
html-dist
:
html-dist --config html-dist.config-js --input index.html
Which will produce the following:
<html><head><title>My Project</title><link rel="stylesheet" type="text/css" href="style.css"></head><body><script src="bundle.js"></script><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-1234', 'auto'); ga('send', 'pageview');</script></body></html>
- Deploy
dist/index.html
to production.
Under the hood html-dist uses the virtual-dom library to manipulate all the HTML. It parses your HTML into a Virtual DOM tree which it then allows you to manipulate, before generating HTML from that virtual dom tree at the end of the process.
This means if you want you can harness the full power of the virtual DOM to manipulate your HTML. However, for most use cases html-dist will provide helpers to make it easy for you. It's possible to use html-dist without ever dealing with the virtual DOM.
As of V0.3.0, the configuration file is NOT transpiled with Babel.
The configuration object must be the default export:
module.exports = {
// configuration here
}
Using a .js
file rather than JSON also enables you to leave comments as you wish.
The top level keys you can specify are:
outputFile
: the path to write the generated HTML to. If not given the output will be printed to STDOUT.minfiy
: if set totrue
, the generated HTML will be minified. Else it will be formatted nicely.head
: an object of manipulations to make to the<head>
element.body
: an object of manipulations to make to the<body>
element.
The object given as head
or body
also must specify certain keys.
The recommended way to use html-dist that should satisfy most use cases is through the keys appends
, prepends
and remove
:
remove: 'cssSelector'
removes any elements that match the given selector.prepends: [...]
prepend the given elements.appends: [...]
append the given elements.
For example, given:
head: {
remove: 'script'
prepends: [
script({ src: 'bundle.js' })
],
appends: [
script({ src: 'other-bundle.js' })
]
}
The <head>
element will first have all script
tags removed (remove
is always called first), it will then have <script src='bundle.js'></script>
prepended and <script src='other-bundle.js'></script>
appended.
### Full control with tree
If you'd like full control over the manipulations, you should define the tree
function:
head: {
tree: function(head) {
// manipulate head here
}
}
When the tree
function is given it is the only function called. It will be passed an object that you can use to manipulate the element. See "Manipulating Trees" below for the full documentation.
When you define a tree
function in a manipulation object that function will be given an instance of TreeManipulator
, which allows you to manipulate the tree as you like:
head: {
tree: function(head) {
// head is an instance of `TreeManipulator`
}
}
The following methods are available:
remove(cssSelector)
removes all elements that match the given CSS selector. For example:head.remove('script')
.append(node)
appends the new node as a child element. For example:head.append(script({ src: 'test.js' }))
.prepend(node)
same as append, but prepends rather than appends.replaceWith(childrenArray)
replace the entire contents of the node with the new ones. For example:
head: {
tree: function(head) {
return head.replaceWith([
script({ src: 'test.js' }),
googleAnalytics('UA-1234-1')
]);
}
}
That would replace the contents of your <head>
with a script tag and the Google Analytics snippet.
Additionally, remove
, append
and prepend
are chainable:
head.remove('script').append(...).prepend(...);
The most common elements that need to be inserted are made easier by html-dist's helpers. You can import them into your configuration file:
var { link, script, googleAnalytics } = require('html-dist');
Creates a new link
element:
var link = require('html-dist').link;
link({ rel: 'stylesheet', type: 'text/css', href: 'style.css' })
Creates a new script
element:
var script = require('html-dist').script;
script({ type: 'text/javascript', src: 'bundle.js' });
Additionally it can take a special contents
property to be used to create a script
tag with JS inside it:
var script = require('html-dist').script;
script({ contents: 'console.log("hello world")' });
//=> <script>console.log("hello world")</script>
Takes your GA user agent and produces the Google Analytics snippet:
var googleAnalytics = require('html-dist').googleAnayltics;
googleAnalytics('UA-1234-X');
If html-dist
doesn't provide a suitable helper, and you think it should, please raise an issue!
There are two ways to create custom HTML:
You can use the fromHtml
helper from html-dist/lib/html
:
var fromHtml = require('html-dist/html');
fromHtml('<div>HELLO</div>');
This will cause a new div
to be inserted into the final HTML.
You can use h
to create custom DOM elements:
var h = require('html-dist').h;
h('div#foo', 'hello');
Will create a div
with an id of foo
and the contents hello
inside. This function is provided by virtual-DOM, so refer to its documentation to see how to use it.
Sometimes you'll need to pass html-dist
some extra information, such as the location of your JavaScript file, so html-dist
can insert a script
tag with the right src
attribute.
The CLI lets you pass in any arbitrary arguments:
./html-dist --config my.config.js --input index.html --output dist/index.html --jsFile "bundle-1234.js"
In my.config.js
, I can import args
and have access to them:
var { script, args } = require('html-dist');
module.exports = {
outputFile: 'dist/index.html',
minify: true,
head: {
remove: 'script'
},
body: {
appends: [
script({
src: args.jsFile
})
]
}
}
The resulting dist/index.html
will contain <script src='bundle-1234.js'></script>
within it.