Skip to content

Commit

Permalink
Merge pull request #17 from drolsen/dev
Browse files Browse the repository at this point in the history
Dev 1.3.8 Release
  • Loading branch information
drolsen authored Jan 31, 2022
2 parents a97d0cf + 84d5b7e commit f1d12eb
Show file tree
Hide file tree
Showing 13 changed files with 293 additions and 84 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ No, you should checkout https://github.com/jantimon/favicons-webpack-plugin for
By tapping into the Webpack 5's latest hooks, WebackFavicon digs into a given build to search for any instances of HTML file assets.
While doing that, it leverages the favicon (https://github.com/itgalaxy/favicons) module to generate configured favicons off your provided source file.

Once done, you will have device or browser specific generated favicons written to disk while HTML files (with a `<head>` tag) will have corresponding `<link />` tags injected.
Once done, you will have device or browser specific generated favicons written to disk while HTML files (with a `<head>` tag) will have corresponding `<link>` tags injected.

### Does this work with CopyWebpackPlugin?
Yep! While it is more common to see a Webpack configuration using `HtmlWebpackPlugin` in order to process HTML files; WebpackFavicons will inject `<link>` tags into HTML documents found being copied by `CopyWebpackPlugin` and/or `HtmlWebpackPlugin`.

---
## Install
```
npm i --save webpack-favicons
npm i --save-dev webpack-favicons
```
or
```
yarn add --dev webpack-favicons
```
Expand Down
Binary file removed assets/favicon.png
Binary file not shown.
Binary file modified assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
91 changes: 74 additions & 17 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const fs = require('fs');
const path = require('path');
const { sources } = require('webpack');

const getAttributes = (markup) => markup.match(/([^\r\n\t\f\v= '"]+)(?:=(["'])?((?:.(?!\2?\s+(?:\S+)=|\2))+.)\2?)?/g).slice(1, -1);

class WebpackFavicons {
constructor(options, callback) {
Expand Down Expand Up @@ -32,7 +35,7 @@ class WebpackFavicons {
appleIcon: false, // Create Apple touch icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
appleStartup: false, // Create Apple startup images. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
coast: false, // Create Opera Coast icon. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
favicons: false, // Create regular favicons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
favicons: true, // Create regular favicons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
firefox: false, // Create Firefox OS icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
windows: false, // Create Windows 8 tile icons. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
yandex: false // Create Yandex browser icon. `boolean` or `{ offset, background, mask, overlayGlow, overlayShadow }` or an array of sources
Expand All @@ -56,34 +59,88 @@ class WebpackFavicons {
{
name: 'WebpackFavicons',
stage: compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, // see below for more stages
additionalAssets: true
additionalAssets: false
},
(assets) => import('favicons').then((module) => module.favicons(
this.options.src,
this.options,
(error, response) => {
// If we have parsing error lets stop
if (error) { console.error(error.message); return; }
// Clean favicon <link href=".*" /> pathing
if (compiler.options.output.publicPath !== 'auto') {
response.html = Object.keys(response.html).map((i) => response.html[i].replace(/href="(.*?)"/g, (match, p1, string) => {
return `href="${path.normalize(`${compiler.options.output.publicPath}/${p1}`)}"`.replace(/\\/g, '/')
}));
}

// Run callback
// Check/Run plugin callback
if (typeof this.callback === 'function') {
response = Object.assign({ ...response }, this.callback(response));
}

// Adds favicon markup to any html documents
//////// if HtmlWebpackPlugin found //////////
try {
require('html-webpack-plugin/lib/hooks').getHtmlWebpackPluginHooks(compilation).alterAssetTags.tapAsync(
{ name: 'WebpackFavicons' },
(data, callback) => {
// Loop over favicon's response HTML <link> tags
Object.keys(response.html).map((i) => {
// Collect <link> HTML attributes into key|value object
let attrs = getAttributes(response.html[i]);
const attributes = {};

Object.keys(attrs).map((j) => {
const parts = attrs[j].split('=');
const key = parts[0];
const value = parts[1].slice(1, -1);

attributes[key] = value;

if (
key === 'href'
&& compiler.options.output.publicPath !== 'auto'
) {
attributes[key] = path.normalize(`${compiler.options.output.publicPath}/${value}`).replace(/\\/g, '/');
}
});

// Push <link> HTML object data into HtmlWebpackPlugin meta template
data.assetTags.meta.push({
tagName: 'link',
voidTag: true,
meta: { plugin: 'WebpackFavicons' },
attributes
});
});

// Run required callback with altered data
callback(null, data);
}
);
} catch (err) { }

//////// if CopyWebpackPlugin found //////////
Object.keys(assets).map((i) => {
// limit assets to only .html files
if (i.indexOf('.html') !== -1) {
// get .html file's source out of buffer and into string
let HTML = assets[i]._value.toString();
assets[i]._value = HTML.replace(/<head>([\s\S]*?)<\/head>/, `<head>$1\r${response.html.join('\r')}</head>`);
// Only alter .html files
if (i.indexOf('.html') === -1) { return false; }

// Prepend output.plublicPath to favicon href paths by hand
if (compiler.options.output.publicPath !== 'auto') {
response.html = Object.keys(response.html).map(
(i) => response.html[i].replace(
/href="(.*?)"/g,
(match, p1, string) => `href="${path.normalize(`${compiler.options.output.publicPath}/${p1}`)}"`.replace(/\\/g, '/')
)
);
}
});

// Inject favicon <link> into .html document(s)
let HTML = compilation.getAsset(i).source.source().toString();
compilation.updateAsset(
i,
new sources.RawSource(
HTML.replace(
/<head>([\s\S]*?)<\/head>/,
`<head>$1\r ${response.html.join('\r ')}\r </head>`
)
)
);
});

// Adds generated images to build
if (response.images) {
Expand All @@ -110,7 +167,7 @@ class WebpackFavicons {
return assets;
}
))
);
);
});
}
}
Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"webpack html favicon",
"webpack favicons"
],
"version": "1.3.4",
"version": "1.3.8",
"description": "Webpack plugin to generate favicons for devices and browsers",
"repository": "drolsen/webpack-favicons",
"bugs": {
Expand All @@ -17,14 +17,16 @@
"author": "Devin R. Olsen <[email protected]> (http://devinrolsen.com)",
"license": "MIT",
"scripts": {
"test": "npm run basic-test && npm run nested-test && npm run public-test && npm run mixed-test && npm run default-test && npm run callback-test && npm run full-test && npm run ava-test",
"test": "npm run basic-test && npm run nested-test && npm run public-test && npm run mixed-test && npm run minimal-test && npm run callback-test && npm run copy-test && npm run hybrid-test && npm run full-test && npm run ava-test",
"basic-test": "webpack --config ./test/basic.config.js --mode production",
"nested-test": "webpack --config ./test/nested.config.js --mode production",
"public-test": "webpack --config ./test/public-path.config.js --mode production",
"mixed-test": "webpack --config ./test/mixed-path.config.js --mode production",
"full-test": "webpack --config ./test/full.config.js --mode production",
"callback-test": "webpack --config ./test/callback.config.js --mode production",
"default-test": "webpack --config ./test/default.config.js --mode production",
"minimal-test": "webpack --config ./test/minimal.config.js --mode production",
"copy-test": "webpack --config ./test/copy.config.js --mode production",
"hybrid-test": "webpack --config ./test/hybridcopy.config.js --mode production",
"ava-test": "ava ./test/ava.test.js"
},
"engines": {
Expand All @@ -33,6 +35,7 @@
"devDependencies": {
"ava": "4.0.1",
"clean-webpack-plugin": "4.0.0",
"copy-webpack-plugin": "^10.2.3",
"html-loader": "3.1.0",
"html-webpack-plugin": "5.5.0",
"webpack": "5.66.0",
Expand Down
Loading

0 comments on commit f1d12eb

Please sign in to comment.