Add Favicon with React and Webpack
Asked Answered
S

18

124

I am attempting to add a favicon to a React-based website that I made using webpack. It has been a total nightmare to add a favicon and I have tried many solutions to no avail. The latest solution that has been recommended to me is called 'favicons-webpack-plugin' which can be found here: https://github.com/jantimon/favicons-webpack-plugin.

If anyone can tell me what I am doing wrong, your assistance would be greatly appreciated.

I get the following error when I run 'npm run start'

enter image description here

This is my directory structure:

enter image description here

This is my webpack.config.js file:

const path = require('path');
const merge = require('webpack-merge');
const webpack = require('webpack');
const NpmInstallPlugin = require('npm-install-webpack-plugin');
const TARGET = process.env.npm_lifecycle_event;
const FaviconsWebpackPlugin = require('favicons-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanPlugin = require('clean-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
var favicons = require('favicons'),
    source = 'my-logo.png',           // Source image(s). `string`, `buffer` or array of `{ size: filepath }`
    configuration = {
        appName: null,                  // Your application's name. `string`
        appDescription: null,           // Your application's description. `string`
        developerName: null,            // Your (or your developer's) name. `string`
        developerURL: null,             // Your (or your developer's) URL. `string`
        background: "#fff",             // Background colour for flattened icons. `string`
        path: "/",                      // Path for overriding default icons path. `string`
        url: "/",                       // Absolute URL for OpenGraph image. `string`
        display: "standalone",          // Android display: "browser" or "standalone". `string`
        orientation: "portrait",        // Android orientation: "portrait" or "landscape". `string`
        version: "1.0",                 // Your application's version number. `number`
        logging: false,                 // Print logs to console? `boolean`
        online: false,                  // Use RealFaviconGenerator to create favicons? `boolean`
        icons: {
            android: true,              // Create Android homescreen icon. `boolean`
            appleIcon: true,            // Create Apple touch icons. `boolean`
            appleStartup: true,         // Create Apple startup images. `boolean`
            coast: true,                // Create Opera Coast icon. `boolean`
            favicons: true,             // Create regular favicons. `boolean`
            firefox: true,              // Create Firefox OS icons. `boolean`
            opengraph: true,            // Create Facebook OpenGraph image. `boolean`
            twitter: true,              // Create Twitter Summary Card image. `boolean`
            windows: true,              // Create Windows 8 tile icons. `boolean`
            yandex: true                // Create Yandex browser icon. `boolean`
        }
    },
    callback = function (error, response) {
        if (error) {
            console.log(error.status);  // HTTP error code (e.g. `200`) or `null`
            console.log(error.name);    // Error name e.g. "API Error"
            console.log(error.message); // Error description e.g. "An unknown error has occurred"
        }
        console.log(response.images);   // Array of { name: string, contents: <buffer> }
        console.log(response.files);    // Array of { name: string, contents: <string> }
        console.log(response.html);     // Array of strings (html elements)
    };

favicons(source, configuration, callback);
const pkg = require('./package.json');

const PATHS = {
  app: path.join(__dirname, 'app'),
  build: path.join(__dirname, 'build')
};

process.env.BABEL_ENV = TARGET;

const common = {
  entry: {
    app: PATHS.app
  },
  // Add resolve.extensions
  // '' is needed to allow imports without an extension
  // note the .'s before the extension as it will fail to load without them
  resolve: {
    extensions: ['', '.js', '.jsx', '.json']
  },
  output: {
    path: PATHS.build,
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        // Test expects a RegExp! Notethe slashes!
        test: /\.css$/,
        loaders: ['style', 'css'],
        //Include accepts either a path or an array of paths
        include: PATHS.app

      },
      //set up JSX. This accepts js too thanks to RegExp
      {
      test: /\.(js|jsx)$/,
      //enable caching for improved performance during development
      //It uses default OS directory by default. If you need something more custom,
      //pass a path to it. ie: babel?cacheDirectory=<path>
      loaders: [
        'babel?cacheDirectory,presets[]=es2015'
    ],
      //parse only app files Without this it will go thru the entire project.
      //beside being slow this will likely result in an error
      include: PATHS.app
      }
    ]
  }
};

// Default configuration. We will return this if
// Webpack is called outside of npm.
if(TARGET === 'start' || !TARGET){
  module.exports = merge(common, {
    devtool: 'eval-source-map',
    devServer: {
      contentBase: PATHS.build,

      //enable history API fallback so HTML5 HISTORY API based
      // routing works. This is a good default that will come in handy in more
      // complicated setups.
      historyApiFallback: true,
      hot: true,
      inline: true,
      progress: true,

      //display only errors to reduce output amount
      stats: 'errors only',

      //Parse host and port from env so this is easy to customize
      host: process.env.HOST,
      port: process.env.PORT

},

plugins: [
  new webpack.HotModuleReplacementPlugin(),
  new NpmInstallPlugin({
    save: true //--save
  }),
  new FaviconsWebpackPlugin('my-logo.png')

]
});
}

if(TARGET === 'build' || TARGET === 'stats') {
  module.exports = merge(common, {
    entry: {
      vendor: Object.keys(pkg.dependencies).filter(function(v) {
        return v !== 'alt-utils';
      }),
      style: PATHS.style
    },
    output: {
      path: PATHS.build,
      // Output using entry name
      filename: '[name].[chunkhash].js',
      chunkFilename: '[chunkhash].js'
    },
    module: {
      loaders: [
        // Extract CSS during build
        {
          test: /\.css$/,
          loader: ExtractTextPlugin.extract('style', 'css'),
          include: PATHS.app
        }
      ]
    },
    plugins: [
      // Output extracted CSS to a file
      new ExtractTextPlugin('[name].[chunkhash].css'),
      // Extract vendor and manifest files
      new webpack.optimize.CommonsChunkPlugin({
        names: ['vendor', 'manifest']
      }),
      // Setting DefinePlugin affects React library size!
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': '"production"'
      }),
      new webpack.optimize.UglifyJsPlugin({
        compress: {
          warnings: false
        }
      })
    ]
  });
}

This is my server.js file:

/* Global Requires */

const express    = require('express');
const logger     = require('morgan');
const bodyParser = require('body-parser');
const path       = require('path');
const app        = express();
const ReactDOM = require('react-dom')
var favicon = require('serve-favicon');


if(process.env.NODE_ENV === 'development') {
  console.log('in development.');
  require('dotenv').config();
} else {
  console.log('in production.');
}

/* App Config */
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'build')));
app.use(favicon(__dirname + '/public/favicon.ico'));

app.use(logger('dev'));

/* Server Initialization */
app.get('/', (req, res) => res.sendFile('index.html'));
var port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Server initialized on // ${new Date()}`));
Seditious answered 18/5, 2016 at 11:25 Comment(3)
just make sure its at least 16x16... and favicons vary from browsers - some won't show up unless its exactly 16x16 some 32x32, oh, and use png not jpg..Gladdie
Is your issue that webpack isn't bundling your ico file? or is it that the page isn't displaying it. You can use file-loader to have wepack load the file to your bundle and then just call it in your html page.Overmantel
Hey @CodeYogi, if my solution worked for you, would you want to mark it as the correct answer?Highgrade
K
218

Here is all you need:

add this to the plugins:[] section of your webpack.config.js

new HtmlWebpackPlugin({
    favicon: "./src/favicon.gif"
})

That is definitely after adding "favicon.gif" to the folder "src".

This will transfer the icon to your build folder and include it in your tag like this <link rel="shortcut icon" href="favicon.gif">. This is safer than just importing with copyWebpackPLugin

Koala answered 14/1, 2019 at 9:12 Comment(5)
This is the most simple and secure way than other response. Good point to you.Butlery
Adding some details to this answer would be helpful, in which file do I add the new HtmlWebpackPlugin code? which plugin do I need to install? what config is needed to use this?Matrices
@Matrices You will need 'html-webpack-plugin'. You can look at their documentation for more details. The example above does not work out of the box, you need to add at least template and filename options.Syman
Badass solution.Jobber
I see the favicon on my desktop web browser but it is not shown on my web browser on Android, is this expected? Do I need any particular size or something? I am using a 64x64 pngMucilage
B
38

Adding your favicon simply into to the public folder should do. Make sure the favicon is named as favicon.ico.

Brindled answered 12/4, 2017 at 5:23 Comment(0)
F
37

For future googlers: You can also use copy-webpack-plugin and add this to webpack's production config:

plugins: [
  new CopyWebpackPlugin({ 
    patterns: [ 
     // relative path is from src
     { from: './static/favicon.ico' }, // <- your path to favicon
    ]
 })
]
Fifty answered 7/12, 2017 at 11:7 Comment(4)
Hands down the best and most consise solution so far. Mind that my webpack.config.js resides in the root directory so I had to use ./src/favicon.ico to target the correct path.Torritorricelli
Note that you need to do: $ npm install copy-webpack-plugin --save-dev Then at the top of your webpack.config.js add: const CopyWebpackPlugin = require('copy-webpack-plugin');Botts
API changed. Now should be: new CopyWebpackPlugin({ patterns: [ { from: './static/favicon.ico' }, ]}),Convulsive
Thanks for the notice, I've just updated my answer ⬆️Oletaoletha
N
22

Here is how I did.

public/index.html

I have added the generated favicon links.

...
<link rel="icon" type="image/png" sizes="32x32" href="%PUBLIC_URL%/path/to/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/path/to/favicon-16x16.png" />
<link rel="shortcut icon" href="%PUBLIC_URL%/path/to/favicon.ico" type="image/png/ico" />

webpack.config.js

new HTMLWebpackPlugin({
   template: '/path/to/index.html',
   favicon: '/path/to/favicon.ico',
})

Note

I use historyApiFallback in dev mode, but I didn't need to have any extra setup to get the favicon work nor on the server side.

Nievelt answered 14/11, 2018 at 5:17 Comment(0)
A
12

Another alternative is

npm install react-favicon

And in your application you would just do:

   import Favicon from 'react-favicon';
   //other codes

    ReactDOM.render(
        <div>
            <Favicon url="/path/to/favicon.ico"/>
            // do other stuff here
        </div>
        , document.querySelector('.react'));
Acrolein answered 10/1, 2018 at 6:50 Comment(2)
This is a great answer when a favicon is derived from variables in the DOM, thanks for your answer.Rooseveltroost
Failing now on safariLimelight
W
11

The correct answers:

If you are using webpack directly:

new HtmlWebpackPlugin({
   favicon: "./public/fav-icon.ico"
})

If you use CRA(create-react-app) then you can modificate the manifest.json in the public directory

Woollen answered 17/7, 2020 at 19:18 Comment(0)
H
9

Browsers look for your favicon in /favicon.ico, so that's where it needs to be. You can double check if you've positioned it in the correct place by navigating to [address:port]/favicon.ico and seeing if your icon appears.

In dev mode, you are using historyApiFallback, so will need to configure webpack to explicitly return your icon for that route:

historyApiFallback: {
    index: '[path/to/index]',
    rewrites: [
        // shows favicon
        { from: /favicon.ico/, to: '[path/to/favicon]' }
    ]
}

In your server.js file, try explicitly rewriting the url:

app.configure(function() {
    app.use('/favicon.ico', express.static(__dirname + '[route/to/favicon]'));
});

(or however your setup prefers to rewrite urls)

I suggest generating a true .ico file rather than using a .png, since I've found that to be more reliable across browsers.

Highgrade answered 1/12, 2016 at 18:56 Comment(0)
A
6

It's the same as adding any other external script or stylesheet. All you have to do is focus on giving the correct path and rel and type.

Note: When my favicon image was in the assets folder, it was not displaying the favicon. So I copied the image to the same folder as of my index.html and it worked perfectly as it should.

<head>
    <link rel="shortcut icon" type="image/png/ico" href="/favicon.png" />
    <title>SITE NAME</title>
</head>

It worked for me. Hope it works for you too.

Accalia answered 20/8, 2018 at 6:26 Comment(0)
A
3

I use favicons-webpack-plugin

const FaviconsWebpackPlugin = require("favicons-webpack-plugin");

module.exports={
plugins:[
    new FaviconsWebpackPlugin("./public/favicon.ico"),
//public is in the root folder in this app. 

]
}
Arjun answered 19/6, 2020 at 3:34 Comment(0)
A
3

This worked for me. Add the following in index.html (inside src folder along with favicon.ico)

<link rel="icon" href="/src/favicon.ico" type="image/x-icon" />

Within webpack.config.js add to your plugins

 plugins: [
     new HtmlWebpackPlugin({
         template: './src/index.html'
     })
 ],
Ashaashamed answered 25/8, 2020 at 9:25 Comment(1)
this implementation is wrong. Should have added favicon inside HtmlWebpackPluginDodecasyllable
R
2

Use the file-loader for that:

{
    test: /\.(svg|png|gif|jpg|ico)$/,
    include: path.resolve(__dirname, path),
    use: {
        loader: 'file-loader',
        options: {
            context: 'src/assets',
            name: 'root[path][name].[ext]'
        }
    }
}
Rigi answered 7/1, 2018 at 8:48 Comment(1)
You should also add the favicon with HtmlWebpackPlugin for work correctly, not only that.Butlery
A
2

I will give simple steps to add favicon :-)

  • Create your logo and save as logo.png
  • Change logo.png to favicon.ico

    Note : when you save it is favicon.ico make sure it's not favicon.ico.png

  • It might take some time to update

    change icon size in manifest.json if you can't wait

Apology answered 14/2, 2019 at 7:14 Comment(1)
Instead of modify manifest.json, you should clear the cache on the browser. On Chrome it's cmd + shift + r/ctrl + shift + r.Butlery
S
2

Replace the favicon.ico in your public folder with yours, that should get you going.

Scrouge answered 4/12, 2020 at 16:46 Comment(0)
I
1

In my case -- I am running Visual Studio (Professional 2017) in debug mode with webpack 2.4.1 -- it was necessary to put the favicon.ico into the root directory of the project, right where the folder src is rather than in a folder public, even though according to https://create-react-app.dev/docs/using-the-public-folder the latter should be the official location.

Ictus answered 15/8, 2019 at 7:54 Comment(0)
M
1

Ctrl+f5 clear your browser cache

Milstone answered 22/3, 2021 at 23:34 Comment(0)
S
0

For anyone still searching... I managed to import the favicon in my index.html once I ran
npm install html-loader
And included the following in my webpack.config.js:

// ... Other config options.
{
  test: /\.html$/,
  include: path.resolve(__dirname, 'public'), // Your path may be different.
  use: [
      {
          loader: 'html-loader',
      },
  ],
},

The file paths need to be relative to your source code, not the production code. To check if the your build includes the favicon you can look up the production path in the url like this: localhost:xxxxx/path/to/favicon.png

Spherical answered 30/9, 2021 at 4:37 Comment(0)
C
0

I believe the answers mentioning CopyWebpackPlugin and HtmlWebpackPlugin are both adequate.

However, it is worth noting two things:

  1. CopyWebpackPlugin is a "third-party package maintained by community members, it potentially does not have the same support, security policy or license as webpack, and it is not maintained by webpack." - Hence why there are comments saying it is less safe.

  2. The benefit of using CopyWebpackPlugin is that you can specify the output folder (i.e. /public/images - This will place your favicon in dist/public/images and your HTML file can access it there). HtmlWebpackPlugin will put the favicon in the root of the dist folder, meaning less flexibility in your input of how the dist folder is structured.

Clan answered 25/5, 2022 at 7:15 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Arose
B
0

I. Add this in file webPack.config.js

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      favicon: './src/favicon.ico'
    })
  ]    
}

II. You did everything right, but nothing works

Just clear the cookies

  1. Press F12
  2. Open Application tab, expand Cookies in left menu, right click on localhost and click Clear

enter image description here

  1. Close the browser tab from localhost
  2. Then open it and you will see a favicon
Blakey answered 22/4, 2024 at 12:35 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.