I am trying to change the favicon dynamically on all browsers, I get a response from the backend containing an https link to the icon, I am using react-helmet to change the favicon but it only works on chrome and android and doesnt work on safari, any ideas? please check out the code below:
import React from "react";
import { Helmet } from "react-helmet";
import { FavIconProps } from "./FavIconProps.types";
export const FavIcon = (props: FavIconProps) => {
const { faviconLink } = props;
console.log(faviconLink);
return (
<Helmet>
<meta name="favicon" />
<meta data-react-helmet="true" content="yes" name="apple-mobile-web-app-capable" />
<meta
data-react-helmet="true"
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<link id="favicon" rel="icon" data-react-helmet="true" href={faviconLink} />
<link
rel="apple-touch-icon"
data-react-helmet="true"
sizes="180x180"
href={faviconLink} />
</Helmet>
);
};
export default FavIcon;
Related
I am having the Nextjs-based Web App for my Portfolio Website, where I've defined some common meta tags in the _document.jsx file and I have a few static pages in which in the browser tab I can see the title, but when I open the Page Source those titles are missing.
My _document.jsx file code are below:
// Next
import Document, { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';
// styled-components
import { ServerStyleSheet } from 'styled-components';
const APP_NAME = `Dhaval Vira Resume | CV | Portfolio`;
const APP_DESC = `A skilled full-stack developer who has worked on projects ranging from small personal sites to large enterprise systems.`;
const APP_URL = `https://dhavalvira.com`;
class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (Component) => (props) =>
sheet.collectStyles(<Component {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: [initialProps.styles, sheet.getStyleElement()],
};
} finally {
sheet.seal();
}
}
render() {
return (
<Html lang='en-US'>
<Head>
{/* General Meta Tags */}
<meta charSet='utf-8' />
<meta httpEquiv='X-UA-Compatible' content='IE=edge' />
<link rel='icon' href='/favicon.ico' />
{/* Meta Tags */}
<meta name='application-name' content={APP_NAME} />
<meta name='description' content={APP_DESC} />
<meta name='author' content='Dhaval Vira' />
<meta name='robots' content='index, follow' />
<meta name='rating' content='general' />
<link rel='canonical' href={APP_URL} />
<meta httpEquiv='Content-Type' content='text/html; charset=utf-8' />
<meta name='language' content='English' />
<meta name='revisit-after' content='1 day' />
<meta name='creationdate' content='14-Feb-2022' />
<meta name='distribution' content='global' />
<meta
name='keywords'
content='CV, resume, online cv, online resume, professional resume, portfolio, next js developer, nextjs developer, freelance developer, full stack developer, full-stack developer, freelance full stack developer, freelance full-stack developer, freelance next js developer, freelance next.js developer, freelance nextjs developer'
/>
{/* Open Graph */}
<meta property='og:url' content={APP_URL} />
<meta property='og:type' content='website' />
<meta property='og:title' content={APP_NAME} />
<meta property='og:description' content={APP_DESC} />
<meta property='og:image' content='/D_V_Cropped.png' />
{/* Twitter Meta Tags */}
<meta name='twitter:card' content='summary_large_image' />
<meta property='twitter:domain' content={APP_URL} />
<meta property='twitter:url' content={APP_URL} />
<meta name='twitter:title' content={APP_NAME} />
<meta name='twitter:description' content={APP_DESC} />
<meta name='twitter:image' content='/D_V_Cropped.png' />
{/* Some Extra Tags */}
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta
name='apple-mobile-web-app-status-bar-style'
content='default'
/>
<meta name='apple-mobile-web-app-title' content={APP_NAME} />
<meta name='description' content={APP_DESC} />
<meta name='format-detection' content='telephone=no' />
<meta name='mobile-web-app-capable' content='yes' />
<meta name='theme-color' content='#000000' />
<link rel='manifest' href='/manifest.json' />
<link rel='apple-touch-icon' href='/D_V_Cropped.png' />
{/* Icons */}
<link
rel='apple-touch-icon'
sizes='57x57'
href='/icons/apple-icon-57x57.png'
/>
<link
rel='apple-touch-icon'
sizes='60x60'
href='/icons/apple-icon-60x60.png'
/>
<link
rel='apple-touch-icon'
sizes='72x72'
href='/icons/apple-icon-72x72.png'
/>
<link
rel='apple-touch-icon'
sizes='76x76'
href='/icons/apple-icon-76x76.png'
/>
<link
rel='apple-touch-icon'
sizes='114x114'
href='/icons/apple-icon-114x114.png'
/>
<link
rel='apple-touch-icon'
sizes='120x120'
href='/icons/apple-icon-120x120.png'
/>
<link
rel='apple-touch-icon'
sizes='144x144'
href='/icons/apple-icon-144x144.png'
/>
<link
rel='apple-touch-icon'
sizes='152x152'
href='/icons/apple-icon-152x152.png'
/>
<link
rel='apple-touch-icon'
sizes='180x180'
href='/icons/apple-icon-180x180.png'
/>
<link
rel='apple-touch-icon'
sizes='192x192'
href='/icons/apple-icon-precomposed.png'
/>
<link
rel='icon'
type='image/png'
sizes='192x192'
href='/icons/android-icon-192x192.png'
/>
<link
rel='icon'
type='image/png'
sizes='32x32'
href='/icons/favicon-32x32.png'
/>
<link
rel='icon'
type='image/png'
sizes='96x96'
href='/icons/favicon-96x96.png'
/>
<link
rel='icon'
type='image/png'
sizes='16x16'
href='/icons/favicon-16x16.png'
/>
<meta name='msapplication-TileColor' content='#54ca95' />
<meta name='msapplication-TileImage' content='/ms-icon-144x144.png' />
<meta name='msapplication-TileImage' content='/ms-icon-150x150.png' />
<meta name='msapplication-TileImage' content='/ms-icon-310x310.png' />
<meta name='theme-color' content='#54ca95' />
{/* Google Tag Manager */}
// GTM iFrame Tag
{/* LinkedIn Insight Tags */}
// LinkedIn Insight Scrip Tags
{/* Google Tag Manager */}
// Google Tag Manager Script Tag
</Script>
{/* Schema.org */}
// Schema.org Script Tag
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
Below code is from blogs.jsx in which the title inside the <Head></Head> tag remains static <Head><title>Blog :: Dhaval Vira Resume</title></Head>. this title is visible in the Chrome Tab, but when I open the Page Source, that time it's missing.
Below is the code from pages/blog/[index].js Page, and when I open the below Page Source - all those Meta Tags are missing.
const BlogPost = (props) => {
const router = useRouter();
useEffect(() => {
Prism.highlightAll();
}, []);
// destructuring props
const { singleData, ...other } = props;
return (
<Fragment>
<Head>
<title>{singleData[0].blogTitle} :: Dhaval Vira Resume</title>
<meta name='description' content={singleData[0].seoDescription} />
<meta name='keywords' content={singleData[0].tags.map((tag) => tag)} />
{/* OG Meta Tags */}
<meta property='og:title' content={singleData[0].seoTitle} />
<meta
property='og:description'
content={singleData[0].seoDescription}
/>
<meta property='og:type' content='article' />
<meta
property='og:url'
content={`${process.env.SHARE_URL}${router.asPath}`}
/>
<meta
name='image'
property='og:image'
content={singleData[0].displayImageUrl}
/>
{/* Twitter Meta Tags */}
<meta property='twitter:title' content={singleData[0].seoTitle} />
<meta
property='twitter:description'
content={singleData[0].seoDescription}
/>
<meta
property='twitter:image'
content={singleData[0].displayImageUrl}
/>
<link
rel='canonical'
href={`${process.env.SHARE_URL}${router.asPath}`}
/>
</Head>
<div>{/* HTML Code goes here */}</div>
</Fragment>
);
};
export default BlogPost;
export const getServerSideProps = async (context) => {
const { index } = context.params;
const response = await axios({
url: `${process.env.SERVER_URL}/api/get-single-blog-detail?slug=${index}`,
method: 'GET',
validateStatus: function (status) {
return status >= 200 && status < 599;
},
});
switch (response.status) {
case 200:
return {
props: {
singleData: response.data.comments,
},
};
case 500:
return {
redirect: {
destination: '/500',
permanent: false,
},
};
default:
return {
redirect: {
destination: '/404',
permanent: false,
},
};
}
};
Also, if I'm sharing the link of my Portfolio Site with anyone (WhatsApp or LinkedIn) at that place also when the title is coming up, it's coming from either Static Page or Dynamic Page, it's coming from _document.jsx file.
Below is the _app.jsx code:
// React
import React, { Fragment, useEffect, useState } from 'react';
// next component
import Head from 'next/head';
import Router from 'next/router';
// Preloader Component
import Loader from '../Loader/loader';
// react-hot-toast
import { Toaster } from 'react-hot-toast';
// NProgress Package & CSS
import NProgress from 'nprogress';
import '../styles/nprogress.css';
Router.events.on('routeChangeStart', NProgress.start);
Router.events.on('routeChangeError', NProgress.done);
Router.events.on('routeChangeComplete', NProgress.done);
import '../styles/globals.css';
// Google Firebase - Analytics - SDK
import { getAnalytics, logEvent } from 'firebase/analytics';
// Utils Func for Firebase
import { app } from '../utils/firebase';
function MyApp(props) {
const { Component, pageProps } = props;
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 4000);
}, []);
if (loading) {
return (
<Fragment>
<Head>
<title>Dhaval Vira Resume</title>
<meta
name='description'
content='online resume website of Dhaval Vira, cv of Dhaval Vira, portfolio of Dhaval Vira'
/>
<link rel='icon' href='/favicon.ico' />
</Head>
<Loader />
</Fragment>
);
} else {
return (
<Fragment>
<Head>
<title>Dhaval Vira Resume</title>
<meta
name='description'
content='online resume website of Dhaval Vira, cv of Dhaval Vira, portfolio of Dhaval Vira'
/>
<link rel='icon' href='/favicon.ico' />
</Head>
<Component {...pageProps} />
{/* react-hot-toast */}
<Toaster position='top-right' reverseOrder={false} />
</Fragment>
);
}
}
export default MyApp;
In _app.jsx, you're forcing client-side rendering of your pages content after 4s have passed due the the loading logic you have there. This means that when the pages gets pre-rendered on the server you're only getting the Loader component in the HTML sent from the server.
Remove the loading logic entirely so that your pages can be server-side rendered properly.
function MyApp({ Component, pageProps }) {
return (
<Fragment>
<Head>
<title>Dhaval Vira Resume</title>
<meta
name='description'
content='online resume website of Dhaval Vira, cv of Dhaval Vira, portfolio of Dhaval Vira'
/>
<link rel='icon' href='/favicon.ico' />
</Head>
<Component {...pageProps} />
{/* react-hot-toast */}
<Toaster position='top-right' reverseOrder={false} />
</Fragment>
);
}
I have tried to share images on facebook with React. I have dynamically added og:image tags using react-helmet npm and also pre-rendered the build using react-snapshot. while view the source the og:image URL's are present but when I try to share the image it won't share.
if I provide the static og:image URL in index.html the facebook works as expected. I have tried the pre-render with react-snapshot and add meta tags
import {Helmet} from "react-helmet";
fbshare1 = () => {
window.open(
'https://www.facebook.com/sharer.php?u='+encodeURIComponent(window.location.href),
'facebook-share-dialog',
'width=626,height=436');
return false;
}
<Helmet>
<title>About us Title</title>
<meta property="og:url" content="https://little-parrot-19.localtunnel.me" />
<meta property="og:title" content="Welcome to Passup" />
<meta property="og:description" content="A URL with no session id or extraneous parameters. All shares on Facebook will use this as the identifying URL for this article." />
<meta property="og:image" content="https://external-preview.redd.it/QB5Nv2dee5NmtpgFOxdjBrfp4MitMx_7OPoYVOLceVk.jpg?width=960&crop=smart&auto=webp&s=1fb548e43b8e5fe9b2fd7ba26af6da4221efcddb" />
<meta property="og:image:type" content="image/png" />
<meta property="og:type" content="Free Web" />
<meta property="fb:app_id" content="12345678900" />
<meta property="article:author" content="Passup" />
<meta property="article:publisher" content="Passup trioangle" />
<meta property="og:image:secure_url" content="https://external-preview.redd.it/QB5Nv2dee5NmtpgFOxdjBrfp4MitMx_7OPoYVOLceVk.jpg?width=960&crop=smart&auto=webp&s=1fb548e43b8e5fe9b2fd7ba26af6da4221efcddb" />
<meta property="og:image:width" content="400" />
<meta property="og:image:height" content="300" />
</Helmet>
<a href="#" onClick={this.fbshare1}> Share on Facebook without sharer fb2 </a>
on the otherhand my server side rendering looks like this with express
import path from 'path';
import fs from 'fs';
import React from 'react';
import express from 'express';
import ReactDOMServer from 'react-dom/server';
import {StaticRouter} from "react-router-dom";
import { Helmet } from 'react-helmet';
import App from '../src/App';
const PORT = 3006;
const app = express();
app.use(express.static('./build'));
app.get('/*', (req, res) => {
const app = ReactDOMServer.renderToString(<StaticRouter location=
{req.url}><App /></StaticRouter>);
const helmet = Helmet.renderStatic();
const indexFile = path.resolve('./build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
return res.status(500).send('Oops, better luck next time!');
}
res.send(formatHTML(app, helmet));
});
});
const formatHTML = (appStr, helmet) => {
return `
<!doctype html>
<html prefix="og: http://ogp.me/ns#"
${helmet.htmlAttributes.toString()}>
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
<div id="app">
${appStr}
</div>
</body>
</html>
`
}
app.listen(PORT, () => {
console.log(`😎 Server is listening on port ${PORT}`);
});
Check next framework. It have server side rendering for react. It is very easy to setup and use it. They have pretty good documentation. Read the documentation and see how _document.js works in this framework it will do the job. Good luck :)
More info about the next server side rendering here
Try using react-helmet-async, which was a fork of react-helmet developed to solve such issues.
Just don't forget to wrap your application inside a HelmetProvider which is used to manage Helmet's state using React's context API.
You'll need react 16+ to use this package.
I'm trying to use graphquery with react and gatsby but I can't get the data. I could get the data if it's written in js. How can I fix it? Thanks.
I started it from gatsby typesript starter but it doesn't work properly.
Uncaught ReferenceError: gatsby_1 is not defined
at ./src/templates/index-page.tsx.exports.IndexPageTemplate (index-page.tsx:56)
index.js:2177 The above error occurred in the <TemplateWrapper> component:
in TemplateWrapper (created by IndexPage)
React will try to recreate this component tree from scratch using the error boundary you provided, AppContainer.
I changed sitemetadata file from js to tsx and then the error happeend
SiteMetaData.tsx
import { graphql, useStaticQuery } from "gatsby";
const useSiteMetadata = () => {
const { data } = useStaticQuery(
graphql`
query GetSiteMetaData{
site {
siteMetadata {
title
description
}
}
}
`
);
return data.siteMetaData;
};
export default useSiteMetadata;
Layout.tsx
import * as React from "react";
import Helmet from "react-helmet";
import Footer from "../Organisms/Footer";
import Navbar from "../Organisms/Navbar";
import useSiteMetadata from "../Organisms/SiteMetadata";
interface TemplateWrapperProps {
children: React.ReactChild;
}
const TemplateWrapper: React.SFC<TemplateWrapperProps> = ({ children }) => {
const { title, description }: any = useSiteMetadata();
return (
<div>
<Helmet>
<html lang="ja" />
<title>{title}</title>
<meta name="description" content={description} />
<meta name="theme-color" content="#fff" />
<meta property="og:type" content="business.business" />
{/**<meta property="og:title" content={title} /> */}
<meta property="og:url" content="/" />
<meta property="og:image" content="/img/og-image.jpg" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</Helmet>
<Navbar />
<div>{children}</div>
<Footer />
</div>
);
};
export default TemplateWrapper;
Try to separate graphql import into his own line, worked for me:
import { graphql } from 'gatsby';
import { Link, useStaticQuery } from 'gatsby';
There seem to be an issue open about it on gatsby-plugin-ts-loader repository: https://github.com/AdamLeBlanc/gatsby-plugin-ts-loader/issues/1#issuecomment-453876850
When I ran npm run build for nextjs it does build in windows but it won't build on linux server. The problem is that build process cant resolve relative paths of my components.
import React, { Component } from "react";
import { connect } from "react-redux";
import Layout from "components/Layout";
import WithAuth from "components/WithAuth";
import Head from "next/head";
class Profile extends Component {
render() {
return (
<React.Fragment>
<Head>
<title>TripeMa</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<link
rel="shortcut icon"
type="image/x-icon"
href="/static/images/tripe-ma-app-icon-rec.ico"
/>
<meta charSet="UTF-8" />
<meta name="theme-color" content="#d0f4f0" />
</Head>
<Layout Component={WithAuth} />
</React.Fragment>
);
}
}
export default connect()(Profile);
1.0.0 build /home/user/site
next build
Using external babel configuration
Location: "/home/user/site/.babelrc.js"
Failed to build
{ Error: (client) ./pages/profile.js
Module not found: Error: Can't resolve '../components/WithAuth' in '/home/useri/site/pages'
# ./pages/profile.js 20:0-46
I am using react-helmet and on the client all is good in the inspect window and the tags are being outputted correctly. However, when I boot up in production and the SSR kicks in the tags aren't shown in the source and I'm getting no errors at all.
I tried logging the 'stringified' title tag too and got:
<title data-react-helmet="true"></title>
Here is some code:
This is one of the page components where I'm setting the tags from, the 3 page components are all set up identically to this. (I've simplified the components render function and data object as they are quite large and I'm sure these aren't at fault.)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet';
// Components
import WorkGrid from 'universal/components/Grid';
import Wrapper from 'universal/components/Wrapper';
import Container from 'universal/components/Container';
import Hero from 'universal/components/Hero';
import PageWrapper from 'universal/components/PageWrapper';
import GridHeader from 'universal/components/GridHeader';
const data = {};
class Work extends PageComponent {
render () {
return (
<PageWrapper ref="root">
<Helmet>
<title>Work</title>
<meta name="description" content="Work Description" />
</Helmet>
<h1>Work Page</h1>
</PageWrapper>
);
}
}
export default connect(state => ({
theme: state.ui.theme
}), { changeTheme }, null, { withRef: true })(Work);
This is some of the server code, specifically where the SSR goes down and I'm calling Helmet.renderStatic();
// Node Modules
import fs from 'fs';
import {basename, join} from 'path';
// Libraries
import React from 'react';
import {StaticRouter} from 'react-router';
import {renderToString} from 'react-dom/server';
// styled-components
import { ServerStyleSheet, ThemeProvider } from 'styled-components';
import { theme } from '../universal/constants';
// Redux
// import {push} from 'react-router-redux';
import createStore from 'data/redux/createStore.js';
import createHistory from 'history/createMemoryHistory';
import { Provider } from 'react-redux';
// Third Party Scripts
import * as thirdPartyScripts from './thirdPartyScripts.js';
// Helmet
import {Helmet} from 'react-helmet';
function renderApp(url, res, store, assets) {
const PROD = process.env.NODE_ENV === 'production';
const context = {};
const {
manifest,
app,
vendor
} = assets || {};
let state = store.getState();
const stylesheet = new ServerStyleSheet();
const initialState = `window.__INITIAL_STATE__ = ${JSON.stringify(state)}`;
const Layout = PROD ? require( '../../build/prerender.js') : () => {};
const root = PROD && renderToString(
stylesheet.collectStyles(
<Provider store={store}>
<ThemeProvider theme={theme}>
<StaticRouter location={url} context={context}>
<Layout />
</StaticRouter>
</ThemeProvider>
</Provider>
)
);
const styleTags = stylesheet.getStyleTags();
const seo = Helmet.renderStatic();
console.log(seo.title.toString());
const html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
${seo.title.toString()}
${seo.meta.toString()}
${seo.link.toString()}
<link rel="shortcut icon" href="/favicon.ico">
<link rel="icon" sizes="16x16 32x32 64x64" href="/favicon.ico">
<link rel="apple-touch-icon" href="/favicon-57.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon-114.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon-72.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon-144.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon-60.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon-120.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon-76.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon-152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon-180.png">
<meta name="msapplication-TileColor" content="#FFFFFF">
<meta name="msapplication-TileImage" content="/favicon-144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
${ styleTags }
${PROD ? '<link rel="stylesheet" href="/static/prerender.css" type="text/css" />' : ''}
<link href="${thirdPartyScripts.googleFont}" rel="stylesheet" type="text/css">
<script>${thirdPartyScripts.googleAnalytics}</script>
</head>
<body>
<script>${initialState}</script>
${PROD ? `<div id="root">${root}</div>` : '<div id="root"></div>'}
${PROD ? `<script>${manifest.text}</script>` : ''}
<script>${thirdPartyScripts.facebookPixel}</script>
<script async src="${thirdPartyScripts.googleAnalyticsSrc}"></script>
${PROD ? `<script src="${vendor.js}"></script>` : ''}
<script src="${PROD ? app.js : './static/app.js'}"></script>
</body>
</html>`;
res.send(html);
}
Also, I am using React Router v4 if that's of any help.
I found the solution to this the other week and thought I may as well update this so it can help anyone else having this problem...
Good news is it was surprisingly simple!
For me anyway it was down to the fact that I separate webpack bundles for the client and the server. So in layman's terms it was including react-helmet twice, once for the client and once for the server, meaning all the state holding the meta tags in the client side code didn't exist in the .rewind() call on the server.
Just add this to your server webpack config file
externals: ['react-helmet']