Skip to content

Commit 7e78bec

Browse files
committed
Rename links to cssAssets and improve test coverage
1 parent 97ac502 commit 7e78bec

File tree

5 files changed

+671
-133
lines changed

5 files changed

+671
-133
lines changed

README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ The available options are:
9090

9191
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).
9292

93+
- `cssAssets`: `array`
94+
95+
Optional shortcut for adding css assets. An array of css asset objects.
96+
97+
See the cssAssets example below for the syntax of css asset object.
98+
9399
Example
94100
-------
95101
Using `HtmlWebpackIncludeAssetsPlugin` and `CopyWebpackPlugin` to include assets to `html-webpack-plugin` template :
@@ -300,7 +306,7 @@ plugins: [
300306
]
301307
```
302308

303-
Sepcifying `links`
309+
Specifying `cssAssets` (a shortcut for specifying assets of type css)
304310

305311
```javascript
306312
output: {
@@ -315,15 +321,19 @@ plugins: [
315321
new HtmlWebpackIncludeAssetsPlugin({
316322
assets: [],
317323
append: true,
318-
links: [
324+
cssAssets: [
319325
{
320-
rel: 'icon',
321-
href: 'asset/path'
326+
href: 'asset/path',
327+
attributes: {
328+
rel: 'icon'
329+
}
322330
},
323331
{
324-
rel: 'manifest',
325332
href: '/absolute/asset/path',
326-
asset: false
333+
asset: false,
334+
attributes: {
335+
rel: 'manifest'
336+
}
327337
}
328338
]
329339
})
@@ -340,4 +350,4 @@ Will append the following link elements into the index template html
340350
</head>
341351
```
342352

343-
Note that the second link's href was not prefixed with the webpack `publicPath` because `link.asset` was set to `false`.
353+
Note that the second cssAsset's href was not prefixed with the webpack `publicPath` because `csAsset.asset` was set to `false`.

index.js

Lines changed: 78 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function extend (target, source) {
7979
function HtmlWebpackIncludeAssetsPlugin (options) {
8080
assert(isObject(options), 'HtmlWebpackIncludeAssetsPlugin options are required');
8181
var assets;
82-
var links;
82+
var cssAssets;
8383
if (options.resolvePaths !== undefined) {
8484
assert(isBoolean(options.resolvePaths), 'HtmlWebpackIncludeAssetsPlugin options should specify a resolvePaths that is a boolean');
8585
}
@@ -89,16 +89,27 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
8989
assets = options.assets;
9090
}
9191
assert(isArray(assets), 'HtmlWebpackIncludeAssetsPlugin options must have an assets key with an array or string value');
92-
if (options.links !== undefined) {
93-
links = options.links;
94-
assert(isArray(links), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array');
95-
links.forEach(function (link) {
96-
assert(isObject(link), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects');
97-
assert(isString(link.href), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects with string href');
98-
assert(isString(link.rel), 'HtmlWebpackIncludeAssetsPlugin options link key should be an array of objects with string rel');
99-
});
92+
if (options.cssAssets !== undefined) {
93+
cssAssets = options.cssAssets;
94+
assert(isArray(cssAssets), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array');
95+
if (isArray(cssAssets)) {
96+
cssAssets.forEach(function (cssAsset) {
97+
assert(isObject(cssAsset), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects');
98+
assert(isString(cssAsset.href), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with string href');
99+
if (cssAsset.attributes !== undefined) {
100+
assert(isObject(cssAsset.attributes), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with undefined or object attributes');
101+
} else {
102+
cssAsset.attributes = {};
103+
}
104+
if (cssAsset.asset !== undefined) {
105+
assert(isBoolean(cssAsset.asset), 'HtmlWebpackIncludeAssetsPlugin options cssAsset key should be an array of objects with undefined or boolean asset');
106+
} else {
107+
cssAsset.asset = true;
108+
}
109+
});
110+
}
100111
} else {
101-
links = [];
112+
cssAssets = [];
102113
}
103114
var jsExtensions;
104115
if (options.jsExtensions !== undefined) {
@@ -170,9 +181,11 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
170181
}
171182
if (asset.attributes !== undefined) {
172183
assert(isObject(asset.attributes), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object');
173-
forOwn(asset.attributes, function (value) {
174-
assert(isString(value) || isBoolean(value), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object with string or boolean values');
175-
});
184+
if (isObject(asset.attributes)) {
185+
forOwn(asset.attributes, function (value) {
186+
assert(isString(value) || isBoolean(value), 'HtmlWebpackIncludeAssetsPlugin options assets key array objects attributes property should be an object with string or boolean values');
187+
});
188+
}
176189
}
177190
} else {
178191
assert(false, 'HtmlWebpackIncludeAssetsPlugin options assets key array must contain only strings and objects (' + asset + ')');
@@ -212,7 +225,7 @@ function HtmlWebpackIncludeAssetsPlugin (options) {
212225
}
213226
this.options = {
214227
assets: assets,
215-
links: links,
228+
cssAssets: cssAssets,
216229
jsExtensions: jsExtensions,
217230
cssExtensions: cssExtensions,
218231
append: options.append,
@@ -247,6 +260,11 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
247260
return self.options.resolvePaths ? path.resolve(assetPath) : assetPath;
248261
};
249262

263+
var jsAssetAttributes = [];
264+
var jsAssetStrings = [];
265+
var cssAssetAttributes = [];
266+
var cssAssetStrings = [];
267+
250268
function onBeforeHtmlGeneration (htmlPluginData, callback) {
251269
if (shouldSkip(htmlPluginData)) {
252270
if (callback) {
@@ -270,25 +288,27 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
270288
};
271289

272290
var includeAssets = self.options.assets;
291+
var includeCssAssets = self.options.cssAssets;
273292
var jsExtensions = self.options.jsExtensions;
274293
var cssExtensions = self.options.cssExtensions;
275294
var appendAssets = self.options.append;
276295
var assets = htmlPluginData.assets;
296+
277297
defaultPublicPath = assets.publicPath;
278298

279299
var includeAsset;
280300
var includeAssetString;
281301
var includeAssetPaths;
302+
var includeAssetAttributes;
282303
var includeAssetCount;
283304
var includeAssetPath;
284305
var includeAssetType;
285306
var includeAssetsLength = includeAssets.length;
286-
var jsAssets = [];
287-
var cssAssets = [];
288307
var assetPromises = [];
289308

290309
for (var i = 0; i < includeAssetsLength; i++) {
291310
includeAsset = includeAssets[i];
311+
includeAssetAttributes = {};
292312
if (isObject(includeAsset)) {
293313
includeAssetType = includeAsset.type;
294314
if (includeAsset.glob === undefined) {
@@ -305,31 +325,44 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
305325
if (includeAsset.assetPath !== undefined) {
306326
assetPromises.push(addAsset(includeAsset.assetPath));
307327
}
328+
if (includeAsset.attributes !== undefined) {
329+
includeAssetAttributes = includeAsset.attributes;
330+
}
308331
} else {
309332
includeAssetType = null;
310333
includeAssetPaths = [includeAsset];
311334
}
335+
312336
includeAssetCount = includeAssetPaths.length;
313337
for (var a = 0; a < includeAssetCount; a++) {
314338
includeAssetPath = includeAssetPaths[a];
315339
includeAssetString = getAssetPath(includeAssetPath);
316340
if ((includeAssetType && includeAssetType === 'js') || hasExtensions(includeAssetString, jsExtensions)) {
317-
if (assets.js.indexOf(includeAssetString) === -1 && jsAssets.indexOf(includeAssetString) === -1) {
318-
jsAssets.push(includeAssetString);
319-
}
341+
jsAssetStrings.push(includeAssetString);
342+
jsAssetAttributes.push(includeAssetAttributes);
320343
} else if ((includeAssetType && includeAssetType === 'css') || hasExtensions(includeAssetString, cssExtensions)) {
321-
if (assets.css.indexOf(includeAssetString) === -1 && cssAssets.indexOf(includeAssetString) === -1) {
322-
cssAssets.push(includeAssetString);
323-
}
344+
cssAssetStrings.push(includeAssetString);
345+
cssAssetAttributes.push(includeAssetAttributes);
346+
}
347+
}
348+
}
349+
if (includeCssAssets) {
350+
var includeCount = includeCssAssets.length;
351+
for (var j = 0; j < includeCount; j++) {
352+
if (includeCssAssets[j].asset !== false) {
353+
cssAssetStrings.push(defaultPublicPath + includeCssAssets[j].href);
354+
} else {
355+
cssAssetStrings.push(includeCssAssets[j].href);
324356
}
357+
cssAssetAttributes.push(includeCssAssets[j].attributes || {});
325358
}
326359
}
327360
if (appendAssets) {
328-
assets.js = assets.js.concat(jsAssets);
329-
assets.css = assets.css.concat(cssAssets);
361+
assets.js = assets.js.concat(jsAssetStrings);
362+
assets.css = assets.css.concat(cssAssetStrings);
330363
} else {
331-
assets.js = jsAssets.concat(assets.js);
332-
assets.css = cssAssets.concat(assets.css);
364+
assets.js = jsAssetStrings.concat(assets.js);
365+
assets.css = cssAssetStrings.concat(assets.css);
333366
}
334367
Promise.all(assetPromises).then(
335368
function () {
@@ -350,16 +383,6 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
350383
}
351384

352385
function onAlterAssetTag (htmlPluginData, callback) {
353-
var tags;
354-
var tagCount;
355-
var tag;
356-
var headers;
357-
var includeAssets = self.options.assets;
358-
var includeLinks = self.options.links;
359-
var includeLinksLength = includeLinks.length;
360-
var includeLink;
361-
var assetAttributes;
362-
363386
if (shouldSkip(htmlPluginData)) {
364387
if (callback) {
365388
return callback(null, htmlPluginData);
@@ -368,62 +391,27 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
368391
}
369392
}
370393

371-
var findAttributesForAsset = function (assets, href) {
372-
var assetCount = assets.length;
373-
var asset;
394+
var append = self.options.append;
395+
var pluginHead = htmlPluginData.head ? htmlPluginData.head : htmlPluginData.headTags;
396+
var pluginBody = htmlPluginData.body ? htmlPluginData.body : htmlPluginData.bodyTags;
374397

375-
for (var i = 0; i < assetCount; i++) {
376-
asset = assets[i];
377-
if (!isString(asset) && asset.attributes && href === getAssetPath(asset.path)) {
378-
return asset.attributes;
379-
}
380-
}
381-
return null;
382-
};
383-
384-
// HtmlWebpackPlugin - new
385-
if (htmlPluginData.head) {
386-
headers = htmlPluginData.head;
387-
tags = htmlPluginData.head.concat(htmlPluginData.body);
388-
} else {
389-
// HtmlWebpackPlugin - old
390-
headers = htmlPluginData.headTags;
391-
tags = htmlPluginData.headTags.concat(htmlPluginData.bodyTags);
392-
}
393-
tagCount = tags.length;
394-
for (var i = 0; i < tagCount; i++) {
395-
tag = tags[i];
396-
assetAttributes = findAttributesForAsset(includeAssets, tag.attributes && (tag.attributes.href || tag.attributes.src));
397-
if (assetAttributes) {
398-
extend(tag.attributes, assetAttributes);
399-
}
400-
}
401-
402-
var createLink = function (linkAttributes) {
403-
if (linkAttributes.href !== undefined) {
404-
var href = linkAttributes.href;
398+
pluginHead = pluginHead.slice(
399+
append ? pluginHead.length - cssAssetAttributes.length : 0,
400+
append ? pluginHead.length : cssAssetAttributes.length
401+
);
405402

406-
if (linkAttributes.asset !== false) {
407-
linkAttributes = Object.assign({}, linkAttributes, {
408-
href: defaultPublicPath + href
409-
});
410-
}
411-
}
412-
var link = {
413-
attributes: linkAttributes,
414-
tagName: 'link',
415-
selfClosingTag: false,
416-
voidTag: true
417-
};
418-
return link;
419-
};
403+
pluginBody = pluginBody.slice(
404+
append ? pluginHead.length - jsAssetAttributes.length : 0,
405+
append ? pluginHead.length : jsAssetAttributes.length
406+
);
420407

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

423-
for (var j = 0; j < includeLinksLength; j++) {
424-
includeLink = includeLinks[j];
425-
addHeader(createLink(includeLink));
426-
}
412+
pluginHead.forEach(function (tag, i) {
413+
extend(tag.attributes, cssAssetAttributes[i]);
414+
});
427415

428416
if (callback) {
429417
callback(null, htmlPluginData);
@@ -432,7 +420,7 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
432420
}
433421
}
434422

435-
// Webpack 4+
423+
// Webpack >= 4
436424
if (compilation.hooks) {
437425
// HtmlWebPackPlugin - new
438426
if (compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration) {
@@ -451,7 +439,7 @@ HtmlWebpackIncludeAssetsPlugin.prototype.apply = function (compiler) {
451439
}
452440
}
453441
} else {
454-
// Webpack 3
442+
// Webpack < 4
455443
compilation.plugin('html-webpack-plugin-before-html-generation', onBeforeHtmlGeneration);
456444
compilation.plugin('html-webpack-plugin-alter-asset-tags', onAlterAssetTag);
457445
}

spec/fixtures/index-no-inject.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
8+
<title>html-webpack-include-assets-plugin</title>
9+
<!-- CSS Tags -->
10+
<% for (var cssIndex = 0; cssIndex < htmlWebpackPlugin.files.css.length; cssIndex++) { %>
11+
<link href="<%= htmlWebpackPlugin.files.css[cssIndex] %>">
12+
<% } %>
13+
</head>
14+
15+
<body>
16+
<noscript>This page requires Javascript to be enabled.</noscript>
17+
<!-- Application Root -->
18+
<div id="root">
19+
<!-- Loading -->
20+
<div id="loading" class="container d-none">
21+
Loading...
22+
</div>
23+
<script id="loading-script" type="text/javascript">
24+
setTimeout(function () {
25+
var loadingElement = document.getElementById("loading");
26+
if (loadingElement !== undefined && loadingElement !== null) {
27+
loadingElement.className = "container";
28+
}
29+
}, 750);
30+
</script>
31+
</div>
32+
<!-- Script Tags -->
33+
<% for (var jsIndex = 0; jsIndex < htmlWebpackPlugin.files.js.length; jsIndex++) { %>
34+
<script src="<%= htmlWebpackPlugin.files.js[jsIndex] %>"></script>
35+
<% } %>
36+
</body>
37+
38+
</html>

0 commit comments

Comments
 (0)