Webpack html-webpack-plugin load favicons in template
Asked Answered
C

8

27

I'm using Webpack with html-webpack-plugin and their provided template. I want to add a list of favicons in the header:

<link rel="apple-touch-icon" sizes="57x57" href="<%= htmlWebpackPlugin.extraFiles.apple-touch-icon-57x57 %>">
<link rel="apple-touch-icon" sizes="60x60" href="<%= htmlWebpackPlugin.extraFiles.favicons.fav60%>">
<link rel="apple-touch-icon" sizes="72x72" href="<%= htmlWebpackPlugin.extraFiles.favicons.fav72%>">
<link rel="apple-touch-icon" sizes="76x76" href="favicons/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="favicons/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="favicons/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="favicons/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="favicons/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="favicons/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="favicons/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="favicons/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="favicons/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="favicons/manifest.json">
<link rel="mask-icon" href="favicons/safari-pinned-tab.svg" color="#e53935">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="favicon/mstile-144x144.png">
<meta name="theme-color" content="#e53935">

How can I include all the favicons in my webpack build, with or without html-webpack-plugin?

I tried adding them as extraFiles like the docs say, but they don't end up in my build folder.

Note: The first 3 was me trying to something that didn't work.

Carvajal answered 6/2, 2016 at 10:4 Comment(3)
Still no answers? I have the same questions here.Lycopodium
Yup. I ended up hard coding it and copying the files manually.Carvajal
I've used favicons-webpack-plugin and works like charm!Grange
C
8

After numerous trials...still didn't manage to make it work with html-webpack-plugin, I did find a new library that helps with everything relating to titles, descriptions, keywords,...and almost any kind of header called react-helmet

You can find it here: https://github.com/nfl/react-helmet

Basically you add something like this in your main component

<Helmet
    link={[
        {"rel": "apple-touch-icon", "href": require('apple-touch-icon-57x57.png'), "sizes": "57x57"}
     ]}
 />

Hope this helps others.

Carvajal answered 10/3, 2016 at 19:2 Comment(2)
Using something react-specific to a generic webpack problem does not seem like a real solution to me. :) Although in the end it does exactly the same way, what I am proposing it...Fluttery
so, were you able to get away without html-webpack-plugin and only use react-helmet, or did you require both? if only react-helmet, can you share a basic example of setup?Davenport
C
22

With Webpack v4.17.2, and html-webpack-plugin v3.2.0, I only had to do:

new HtmlWebPackPlugin({
  favicon: "./path/to/favicon",
  filename: "index.html",
  template: "./path/to/index.html",
}),

in the plugins section of the webpack config.

Craftwork answered 14/9, 2018 at 8:13 Comment(1)
Confirmed with Webpack 4.43.0 and html-webpack-plugin 4.3.0Eleni
F
21

You need to make sure, that the Images are processed by WebPack and thus that a matching loader exists for them (such as the file-loader).

For that to work, you have to explicitly require the files in the corresponding attributes. To be able to explicitly require files in the index.html you have to use a loader in turn for index.html itself, that allows for processing JS inline.

This one really depends on your setup (i.e. whether you have setup html-webpack-loader); have a look at the FAQ, explaining the basics.

So assuming, you have somewhat along this:

//somewhere in your webpack config.js

plugins: [

  new HtmlWebpackPlugin({
    template: 'index.html',
    inject: 'head',
  }) //..
]

You can require in your index.html images like that:

<link rel="apple-touch-icon" sizes="120x120" href="${require('./favicons/apple-touch-icon-120x120.png')}">

This will try to load apple-touch-icon-120x120.png via WebPack, so you must make sure that there is a loader for it and the html-loader needs to be configured as well:

//somewhere in your webpack.config.js
module: {
  loaders: [
    {
      test: /\.png$/,
      loader: 'file?name=assets/icons/[name].[hash].[ext]'
    },

    {
      test: /\.html$/,
      loader: 'html',
      query: {
        interpolate: 'require'
      }
    } //..

   ] //..
}

You only have to use require for images that are not inside <img> - tags, those will get picked up automagically by html-webpack-loader.

Future versions of html-loader might change this behaviour -> https://github.com/webpack/html-loader/issues/17

Fluttery answered 14/1, 2017 at 17:56 Comment(2)
Will try it out soon and update the answer if it works as this is more relevant (ie not react specific) to the question.Carvajal
Not sure if due to a recent change, but using href="<%= require('path/to/file.jpg') %>" (<% instead of ${) seemed to work fine w/out needing html-loader. Example here: github.com/jantimon/html-webpack-plugin/tree/master/examples/…Stablish
M
11

following up on this for anyone who comes across this in the future.

you'll need this in your template:

<link href="{%=o.htmlWebpackPlugin.files.favicon%}" rel="shortcut icon">

and its corresponding definition:

new HtmlWebpackPlugin({ favicon: "path/to/favicon" }),

in the plugins of your webpack config.

Marva answered 1/4, 2018 at 5:21 Comment(3)
Nice! I think the syntax may have been updated. This worked for me - <link rel="shortcut icon" type="image/x-icon" href="<%=htmlWebpackPlugin.files.favicon%>">Rallentando
this makes no sens since that very plugin is supposed to add many linksMag
Looks like you don't need to add anything to your template now. It seems to inject the favicon for youGnosticize
C
8

After numerous trials...still didn't manage to make it work with html-webpack-plugin, I did find a new library that helps with everything relating to titles, descriptions, keywords,...and almost any kind of header called react-helmet

You can find it here: https://github.com/nfl/react-helmet

Basically you add something like this in your main component

<Helmet
    link={[
        {"rel": "apple-touch-icon", "href": require('apple-touch-icon-57x57.png'), "sizes": "57x57"}
     ]}
 />

Hope this helps others.

Carvajal answered 10/3, 2016 at 19:2 Comment(2)
Using something react-specific to a generic webpack problem does not seem like a real solution to me. :) Although in the end it does exactly the same way, what I am proposing it...Fluttery
so, were you able to get away without html-webpack-plugin and only use react-helmet, or did you require both? if only react-helmet, can you share a basic example of setup?Davenport
A
3

For anyone who is looking for the solution,

You can use copy-webpack-plugin, that will simply copy the files you specify to the output folder.

To copy all the assets from '../src/assets/favicons' to 'favicons' output folder do:

      plugins: [
        new CopyWebpackPlugin([
          { from: `${__dirname}/../src/assets/favicons`, to: 'favicons' }
        ])
      ]

Note: ${__dirname} will resolve to the folder containing the webpack config file.

Apophthegm answered 1/5, 2019 at 22:6 Comment(0)
C
1

For anyone still struggling with this issue, I've tested here basically everything said here, and found a quite simple and clean solution:

First, use the HtmlWebpackPlugin, simple and straight. Don't need to specify the favicon option in its configuration.

Second, declare your list of icons in the template <head>. Here is the "trick": when specifying the href for each icon, write as a require, like this: href="${require('./favicon16.ico')}". This way, you can put as many favicon options as you want in your template.

Explanation: I'm not 100% sure about this, but it seems that HtmlWebpackPlugin now (tested at 3.2.0) handles interpolated requires in the HTML automatically, without requiring from developers to reconfigure the html-loader plugin.

Crevice answered 8/8, 2019 at 14:53 Comment(0)
M
1

Best solution for me: favicons-webpak-plugin

webpack config:

const path = require('path');
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

...
  plugins: [
    new HtmlWebpackPlugin({
      filename: path.resolve(__dirname, 'dist/index.html'),
      template: 'index.html',
    }),
    new FaviconsWebpackPlugin({
      logo: path.resolve(__dirname, 'src/img/icons/favicon-512.png'),
      prefix: '',
      publicPath: '../favicons',
      outputPath: path.resolve(__dirname, 'dist/favicons'),
      inject: (htmlPlugin) => 
        path.basename(htmlPlugin.options.filename) === 'index.html',
    }),
  ],
  

Result:

  • logl src => src/img/icons/favicon-512.png
  • output files => dist/favicons/
  • include to index.htm => dist/index.html
  • it looks like => <link rel="shortcut icon" href="favicons/favicon.ico"><link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">...
Munn answered 27/8, 2021 at 10:45 Comment(1)
This is the best solution for me too, thanks!Catherincatherina
B
0

If you're using HtmlWebpackPlugin's advanced config using template and templateParameters as a function, you might find it hard to achieve as we did, specifically if you're using inject: false.

resource for advanced config setup

The point was to pass favicon to HtmlWebpackPlugin itself and then use it inside templateParameters() as an argument coming from assets.favicon:

new HtmlWebpackPlugin({
  // 1. Your favicon goes here
  favicon: "path/to/favicon.ico",

  inject: false,
  template: "path/to/index.html",
  templateParameters: (compilation, assets, assetTags, options) => {
    // Compute stuff to be used as template parameters..
    const foo = "bar";

    return {
      compilation,
      webpackConfig: compilation.options,
      htmlWebpackPlugin: {
        tags: assetTags,
        files: assets,
        options,
      },

      // 2. Take 'favicon' from 'assets' so webpack
      // will be aware of its relative location
      favicon: assets.favicon,

      // This is why you used advanced settings...
      // You needed something custom
      foo,
    };
  },
})
Byrne answered 17/5, 2023 at 18:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.