Skip to content

Commit

Permalink
Rename links to cssAssets and improve test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
jharris4 committed Apr 13, 2019
1 parent 97ac502 commit 7e78bec
Show file tree
Hide file tree
Showing 5 changed files with 671 additions and 133 deletions.
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ The available options are:

By default the assets will be included in all files. If files are defined, the assets will only be included in specified file globs (uses the [minimatch](https://github.com/isaacs/minimatch) package).

- `cssAssets`: `array`

Optional shortcut for adding css assets. An array of css asset objects.

See the cssAssets example below for the syntax of css asset object.

Example
-------
Using `HtmlWebpackIncludeAssetsPlugin` and `CopyWebpackPlugin` to include assets to `html-webpack-plugin` template :
Expand Down Expand Up @@ -300,7 +306,7 @@ plugins: [
]
```

Sepcifying `links`
Specifying `cssAssets` (a shortcut for specifying assets of type css)

```javascript
output: {
Expand All @@ -315,15 +321,19 @@ plugins: [
new HtmlWebpackIncludeAssetsPlugin({
assets: [],
append: true,
links: [
cssAssets: [
{
rel: 'icon',
href: 'asset/path'
href: 'asset/path',
attributes: {
rel: 'icon'
}
},
{
rel: 'manifest',
href: '/absolute/asset/path',
asset: false
asset: false,
attributes: {
rel: 'manifest'
}
}
]
})
Expand All @@ -340,4 +350,4 @@ Will append the following link elements into the index template html
</head>
```

Note that the second link's href was not prefixed with the webpack `publicPath` because `link.asset` was set to `false`.
Note that the second cssAsset's href was not prefixed with the webpack `publicPath` because `csAsset.asset` was set to `false`.
168 changes: 78 additions & 90 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function extend (target, source) {
function HtmlWebpackIncludeAssetsPlugin (options) {
assert(isObject(options), 'HtmlWebpackIncludeAssetsPlugin options are required');
var assets;
var links;
var cssAssets;
if (options.resolvePaths !== undefined) {
assert(isBoolean(options.resolvePaths), 'HtmlWebpackIncludeAssetsPlugin options should specify a resolvePaths that is a boolean');
}
Expand All @@ -89,16 +89,27 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
assets = options.assets;
}
assert(isArray(assets), 'HtmlWebpackIncludeAssetsPlugin options must have an assets key with an array or string value');
if (options.links !== undefined) {
links = options.links;
assert(isArray(links), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array');
links.forEach(function (link) {
assert(isObject(link), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects');
assert(isString(link.href), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects with string href');
assert(isString(link.rel), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects with string rel');
});
if (options.cssAssets !== undefined) {
cssAssets = options.cssAssets;
assert(isArray(cssAssets), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array');
if (isArray(cssAssets)) {
cssAssets.forEach(function (cssAsset) {
assert(isObject(cssAsset), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects');
assert(isString(cssAsset.href), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with string href');
if (cssAsset.attributes !== undefined) {
assert(isObject(cssAsset.attributes), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with undefined or object attributes');
} else {
cssAsset.attributes = {};
}
if (cssAsset.asset !== undefined) {
assert(isBoolean(cssAsset.asset), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with undefined or boolean asset');
} else {
cssAsset.asset = true;
}
});
}
} else {
links = [];
cssAssets = [];
}
var jsExtensions;
if (options.jsExtensions !== undefined) {
Expand Down Expand Up @@ -170,9 +181,11 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
}
if (asset.attributes !== undefined) {
assert(isObject(asset.attributes), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object');
forOwn(asset.attributes, function (value) {
assert(isString(value) || isBoolean(value), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object with string or boolean values');
});
if (isObject(asset.attributes)) {
forOwn(asset.attributes, function (value) {
assert(isString(value) || isBoolean(value), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object with string or boolean values');
});
}
}
} else {
assert(false, 'HtmlWebpackIncludeAssetsPlugin options assets key array must contain only strings and objects (' + asset + ')');
Expand Down Expand Up @@ -212,7 +225,7 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
}
this.options = {
assets: assets,
links: links,
cssAssets: cssAssets,
jsExtensions: jsExtensions,
cssExtensions: cssExtensions,
append: options.append,
Expand Down Expand Up @@ -247,6 +260,11 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
return self.options.resolvePaths ? path.resolve(assetPath) : assetPath;
};

var jsAssetAttributes = [];
var jsAssetStrings = [];
var cssAssetAttributes = [];
var cssAssetStrings = [];

function onBeforeHtmlGeneration (htmlPluginData, callback) {
if (shouldSkip(htmlPluginData)) {
if (callback) {
Expand All @@ -270,25 +288,27 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
};

var includeAssets = self.options.assets;
var includeCssAssets = self.options.cssAssets;
var jsExtensions = self.options.jsExtensions;
var cssExtensions = self.options.cssExtensions;
var appendAssets = self.options.append;
var assets = htmlPluginData.assets;

defaultPublicPath = assets.publicPath;

var includeAsset;
var includeAssetString;
var includeAssetPaths;
var includeAssetAttributes;
var includeAssetCount;
var includeAssetPath;
var includeAssetType;
var includeAssetsLength = includeAssets.length;
var jsAssets = [];
var cssAssets = [];
var assetPromises = [];

for (var i = 0; i < includeAssetsLength; i++) {
includeAsset = includeAssets[i];
includeAssetAttributes = {};
if (isObject(includeAsset)) {
includeAssetType = includeAsset.type;
if (includeAsset.glob === undefined) {
Expand All @@ -305,31 +325,44 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
if (includeAsset.assetPath !== undefined) {
assetPromises.push(addAsset(includeAsset.assetPath));
}
if (includeAsset.attributes !== undefined) {
includeAssetAttributes = includeAsset.attributes;
}
} else {
includeAssetType = null;
includeAssetPaths = [includeAsset];
}

includeAssetCount = includeAssetPaths.length;
for (var a = 0; a < includeAssetCount; a++) {
includeAssetPath = includeAssetPaths[a];
includeAssetString = getAssetPath(includeAssetPath);
if ((includeAssetType && includeAssetType === 'js') || hasExtensions(includeAssetString, jsExtensions)) {
if (assets.js.indexOf(includeAssetString) === -1 && jsAssets.indexOf(includeAssetString) === -1) {
jsAssets.push(includeAssetString);
}
jsAssetStrings.push(includeAssetString);
jsAssetAttributes.push(includeAssetAttributes);
} else if ((includeAssetType && includeAssetType === 'css') || hasExtensions(includeAssetString, cssExtensions)) {
if (assets.css.indexOf(includeAssetString) === -1 && cssAssets.indexOf(includeAssetString) === -1) {
cssAssets.push(includeAssetString);
}
cssAssetStrings.push(includeAssetString);
cssAssetAttributes.push(includeAssetAttributes);
}
}
}
if (includeCssAssets) {
var includeCount = includeCssAssets.length;
for (var j = 0; j < includeCount; j++) {
if (includeCssAssets[j].asset !== false) {
cssAssetStrings.push(defaultPublicPath + includeCssAssets[j].href);
} else {
cssAssetStrings.push(includeCssAssets[j].href);
}
cssAssetAttributes.push(includeCssAssets[j].attributes || {});
}
}
if (appendAssets) {
assets.js = assets.js.concat(jsAssets);
assets.css = assets.css.concat(cssAssets);
assets.js = assets.js.concat(jsAssetStrings);
assets.css = assets.css.concat(cssAssetStrings);
} else {
assets.js = jsAssets.concat(assets.js);
assets.css = cssAssets.concat(assets.css);
assets.js = jsAssetStrings.concat(assets.js);
assets.css = cssAssetStrings.concat(assets.css);
}
Promise.all(assetPromises).then(
function () {
Expand All @@ -350,16 +383,6 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
}

function onAlterAssetTag (htmlPluginData, callback) {
var tags;
var tagCount;
var tag;
var headers;
var includeAssets = self.options.assets;
var includeLinks = self.options.links;
var includeLinksLength = includeLinks.length;
var includeLink;
var assetAttributes;

if (shouldSkip(htmlPluginData)) {
if (callback) {
return callback(null, htmlPluginData);
Expand All @@ -368,62 +391,27 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
}
}

var findAttributesForAsset = function (assets, href) {
var assetCount = assets.length;
var asset;
var append = self.options.append;
var pluginHead = htmlPluginData.head ? htmlPluginData.head : htmlPluginData.headTags;
var pluginBody = htmlPluginData.body ? htmlPluginData.body : htmlPluginData.bodyTags;

for (var i = 0; i < assetCount; i++) {
asset = assets[i];
if (!isString(asset) && asset.attributes && href === getAssetPath(asset.path)) {
return asset.attributes;
}
}
return null;
};

// HtmlWebpackPlugin - new
if (htmlPluginData.head) {
headers = htmlPluginData.head;
tags = htmlPluginData.head.concat(htmlPluginData.body);
} else {
// HtmlWebpackPlugin - old
headers = htmlPluginData.headTags;
tags = htmlPluginData.headTags.concat(htmlPluginData.bodyTags);
}
tagCount = tags.length;
for (var i = 0; i < tagCount; i++) {
tag = tags[i];
assetAttributes = findAttributesForAsset(includeAssets, tag.attributes && (tag.attributes.href || tag.attributes.src));
if (assetAttributes) {
extend(tag.attributes, assetAttributes);
}
}

var createLink = function (linkAttributes) {
if (linkAttributes.href !== undefined) {
var href = linkAttributes.href;
pluginHead = pluginHead.slice(
append ? pluginHead.length - cssAssetAttributes.length : 0,
append ? pluginHead.length : cssAssetAttributes.length
);

if (linkAttributes.asset !== false) {
linkAttributes = Object.assign({}, linkAttributes, {
href: defaultPublicPath + href
});
}
}
var link = {
attributes: linkAttributes,
tagName: 'link',
selfClosingTag: false,
voidTag: true
};
return link;
};
pluginBody = pluginBody.slice(
append ? pluginHead.length - jsAssetAttributes.length : 0,
append ? pluginHead.length : jsAssetAttributes.length
);

var addHeader = (self.options.append ? headers.push : headers.unshift).bind(headers);
pluginBody.forEach(function (tag, i) {
extend(tag.attributes, jsAssetAttributes[i]);
});

for (var j = 0; j < includeLinksLength; j++) {
includeLink = includeLinks[j];
addHeader(createLink(includeLink));
}
pluginHead.forEach(function (tag, i) {
extend(tag.attributes, cssAssetAttributes[i]);
});

if (callback) {
callback(null, htmlPluginData);
Expand All @@ -432,7 +420,7 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
}
}

// Webpack 4+
// Webpack >= 4
if (compilation.hooks) {
// HtmlWebPackPlugin - new
if (compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration) {
Expand All @@ -451,7 +439,7 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
}
}
} else {
// Webpack 3
// Webpack < 4
compilation.plugin('html-webpack-plugin-before-html-generation', onBeforeHtmlGeneration);
compilation.plugin('html-webpack-plugin-alter-asset-tags', onAlterAssetTag);
}
Expand Down
38 changes: 38 additions & 0 deletions spec/fixtures/index-no-inject.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>html-webpack-include-assets-plugin</title>
<!-- CSS Tags -->
<% for (var cssIndex = 0; cssIndex < htmlWebpackPlugin.files.css.length; cssIndex++) { %>
<link href="<%= htmlWebpackPlugin.files.css[cssIndex] %>">
<% } %>
</head>

<body>
<noscript>This page requires Javascript to be enabled.</noscript>
<!-- Application Root -->
<div id="root">
<!-- Loading -->
<div id="loading" class="container d-none">
Loading...
</div>
<script id="loading-script" type="text/javascript">
setTimeout(function () {
var loadingElement = document.getElementById("loading");
if (loadingElement !== undefined && loadingElement !== null) {
loadingElement.className = "container";
}
}, 750);
</script>
</div>
<!-- Script Tags -->
<% for (var jsIndex = 0; jsIndex < htmlWebpackPlugin.files.js.length; jsIndex++) { %>
<script src="<%= htmlWebpackPlugin.files.js[jsIndex] %>"></script>
<% } %>
</body>

</html>
Loading

0 comments on commit 7e78bec

Please sign in to comment.