Google font loads very weirdly after the deployment to the vercel - next.js

I have deployed the next js app to the server using vercel. I have referenced the two google fonts in _document.js. While I am running the app locally both font load without any problem.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document
{
static async getInitialProps(ctx)
{
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render()
{
return (
<Html>
<Head>
<link href="https://fonts.googleapis.com/css2?family=Crete+Round&family=Work+Sans:wght#500;600&display=swap" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
index.js
import Head from "next/head";
import Script from "next/script";
import Banner from "../components/Banner";
import { fetchAPI } from "../lib/api";
import Articles from "../components/Articles";
export default function Home({ articles })
{
return (
<>
<Head>
<title>Life Sciencify - Explore the mystery of life with Science! </title>
</Head>
<Articles articles={articles} />
</>
);
}
export async function getServerSideProps()
{
const [articlesRes] = await Promise.all([
fetchAPI("/posts", { populate: ["cover", "category"] })
]);
console.log(articlesRes)
return {
props: {
articles: articlesRes.data
}
};
}
app.js
import Script from "next/script";
import "bootstrap/dist/css/bootstrap.css";
import "../styles/globals.css";
import { useEffect } from "react";
import Header from "../components/Header";
import SearchBlock from "../components/SearchBlock";
import Footer from "../components/Footer";
function MyApp({ Component, pageProps })
{
useEffect(() =>
{
import("bootstrap/dist/js/bootstrap");
}, []);
return (
<>
<Component {...pageProps} />
</>
);
}
export default MyApp;
After the deployment it is showing the weird behavior.
Initially When I am in the home page the page doesn't load any font.
Now, when I click the link Post1 or Post 2, it will be redirected to the detail page.
at first font is not loaded in this page too.
Now, after the page refresh the font gets loaded.
Now, when I go to the back page in the browser, the home page will have the font loaded. But again when the page is refreshed the font will be gone.
What is the causing the weird behavior?
I am running the application in the next js version of "12.1.6".
Referenced:
google-font-display
font-optimization

In the _document.js i used two google fonts separately and it is working now.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document
{
static async getInitialProps(ctx)
{
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render()
{
return (
<Html>
<Head>
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght#500;600&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Crete+Round&display=swap" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
and in index.js, change server side rendering to static props:
export async function getStaticProps()
{
const [articlesRes] = await Promise.all([
fetchAPI("/posts", { populate: ["cover", "category"] })
]);
console.log(articlesRes)
return {
props: {
articles: articlesRes.data
}
};
}
After this changes I deployed to vercel it worked fine, again after some time i changes to getServerSideProps, it was not working. So, the culprit was getServerSideProps with google font.

Related

Next JS server side rendering on Index.tsx with NextPage componet

tsx file having a Home component below it there is getServerSiderProps method.i want to get server side but props inside my Home component show undefined.
import type { NextPage } from 'next'
import Head from 'next/head'
import Banner from '../Components/Banner'
import Header from '../Components/Header'
import Posts from '../Components/Posts'
import { sanityClient, urlFor } from '../sanity'
const Home: NextPage = ({ posts }) => {
console.log(posts)
return (
<div>
<Head>
<title>Medium Blog</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header></Header>
<Banner></Banner>
<Posts></Posts>
</div>
)
}
export default Home
//Server Side Rendering (SSR)
export const getServerSiderProps = async () => {
const query = `*[_type=="post"]{
_id,
title,
slug,
author->{
name,
image
},
description,
mainImage,
slug
}`
//Fetch
const posts = await sanityClient.fetch(query)
return { props: { posts } }
}
I want to get server side props every time it refresh my page but it became undefined.

Dynamic component imported stuck in loading phase : next js

I am new to next js. In my project I need to display youtube videos. I have an api which provides me the video ids to show with its meta details. I wanted to create dynamic pages for each videos. I am using react-player as player.
Here is my code
[videoId].tsx
import Head from 'next/head';
import { useRouter } from 'next/router'
import Layout from '../../components/layout';
import { IVideoItem } from '../../models/videos.model';
import VideoContainer from '../../components/videos-page/video-container';
import { getVideosPaths, getVideosPageTitle, getVideosPageDescription, getVideosData } from '../../services/videos-page.services';
export default function VideoPage({videoInfo} :IVideosPageProp) {
const router = useRouter()
if (router.isFallback) {
return <div>Loading...</div>
}
return(
<>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />
<title>{getVideosPageTitle(videoInfo)}</title>
<meta name="description" content={getVideosPageDescription(videoInfo)} />
<meta property="og:title" content={getVideosPageTitle(videoInfo)} key="ogtitle" />
<meta property="og:description" content={getVideosPageDescription(videoInfo)} key="ogdesc" />
</Head>
<VideoContainer data={videoInfo} />
</>
)
}
export async function getStaticPaths() {
const paths = await getVideosPaths()
//console.log('paths: ',paths);
return {
paths,
fallback: false
}
}
export async function getStaticProps({ params }:IVideosPageStaticProp) {
const {videoId} = params;
const videoInfo = await getVideosData(videoId)
return {
props: {
videoInfo
}
}
}
interface IVideosPageProp {
videoInfo: IVideoItem
}
interface IVideosPageStaticPropParams {
videoId: string
}
interface IVideosPageStaticProp {
params: IVideosPageStaticPropParams
}
video-container.tsx
import { Row, Col } from 'react-bootstrap'
import { IVideoItem } from '../../models/videos.model';
import styles from './videos-container.module.scss';
import VideoTag from '../home/videos-block/video-tag';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faEye, faThumbsUp, faThumbsDown } from '#fortawesome/free-solid-svg-icons';
import moment from 'moment';
import dynamic from 'next/dynamic';
const ReactPlayer = dynamic(
() => import('react-player'),
{ loading: () => <p>...</p>, ssr: false }
)
export default function VideoContainer({data} :IVideosPageProp){
const videoInfo:IVideoItem = data;
const videoTag = [{"tagName": "Foo", "tagId": 1}]
const fallBackElement = () => {
return <img src={videoInfo.default_thumbnail_url} width="100%"/>
}
return (
<div className={styles['videos-container']}>
<ReactPlayer
url={`https://youtu.be/${data.video_id}`}
controls
width = "100%"
light={true}
playing={true}
fallback={fallBackElement()}
config={{
youtube: {
playerVars: { showinfo: 1 }
}
}}
/>
<div className={styles['videos-body']}>
<div className={styles['tag-list-container']}>
{videoTag.map((tag, index) =>{
return <VideoTag videoTag={tag} key={index}/>
})}
</div>
<div className={styles['video-title']}>
{videoInfo.title}
</div>
<Row className={styles['video-numbers']}>
<Col md={2} xs={2}><FontAwesomeIcon icon={faEye} className={styles['views-icon']} />{videoInfo.views_count}</Col>
<Col md={2} xs={4}>{moment(new Date(videoInfo.published_at)).format('Do MMMM YYYY')}</Col>
<Col md={4} xs={2}></Col>
<Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsUp} className={styles['views-icon']} />{videoInfo.like_count}</Col>
<Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsDown} className={styles['views-icon']} />{videoInfo.dislike_count}</Col>
</Row>
<div className={styles['video-description']}>
{videoInfo.description}
</div>
</div>
</div>
)
}
interface IVideosPageProp {
data:IVideoItem
}
When I run yarn dev the page is loading properly and the video player is rendering and working as expected. But when I run next buld and after that next start, the page is loading, but player is not loading. Insted it shows the "Loading..." message on the page, I refreshed several times, no luck. Not able to understand the issue. Can any one help?
Update 1:
The page is rendering with video title, video description etc. But the dynamically imported video player is not rendered. At the place of video player, it shows 'Loading...'.
Not sure if you can dynamically load from the node_module, like this:
const ReactPlayer = dynamic(
() => import('react-player'),
{ loading: () => <p>...</p>, ssr: false }
)
But you should be able to do this by creating a react-player component first, then dynamic import it like this:
// create a component named Player.js
import ReactPlayer from 'react-player';
const Player = props => (<ReactPlayer {...props}/>)
export default Player;
// then dynamic import it:
const Player = dynamic(
() => import('../components/Player'),
{ ssr: false }
)
// Then use <Player> with the same props

Ordering problem using css import alongside styled components in nextjs app

I am using NextJS and when I use direct css import ...css alongside a styled-component createGlobalStyle. My direct css imports are always included last in my html causing some overriding issues that I've setup in GlobalStyles.
How can I resolve this?
rendered html
<head>
<link href="/_next/static/chunks/main.js?ts=1609163560022">
<style></style> // global styled component
<style></style> // bootstrap imported after global styled component
</head>
_app.js
import { ThemeProvider } from "styled-components";
import 'bootstrap/dist/css/bootstrap.min.css' // this is always loaded last <head>
import GlobalStylesfrom 'styles/global'; // this is always loaded first in <head>
const theme = {
...
};
export default function App({ Component, pageProps }) {
return (
<ThemeProvider theme={theme}>
<GlobalStyles/>
<Component {...pageProps} />
</ThemeProvider>
)
}
_document.js
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
);
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<Html>
<Head>{this.props.styleTags}</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

How to make my scripts work on my components in next.js?

I have a problem with my script, I am using next and React in my pages / _app.js file I have the following code:
import axios from "axios";
import { $ } from "jquery";
import App from "next/app";
import Router from "next/router";
import { destroyCookie, parseCookies } from "nookies";
import Layout from "../components/_App/Layout";
import "../public/css/boot.css";
import "../public/css/icons.css";
import "../public/css/themes/style.css";
import "../public/jquery";
import "../public/scripts";
import baseUrl from "../utils/baseUrl";
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const { token } = parseCookies(ctx);
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
if (!token) {
const isProtectedRoute =
ctx.pathname === "/profile" ||
ctx.pathname === "/admin/add-product" ||
ctx.pathname === "/my-orders-history" ||
ctx.pathname === "/admin/users" ||
ctx.pathname === "/admin/dashboard";
if (isProtectedRoute) {
redirectUser(ctx, "/auth/login");
}
} else {
try {
const payload = { headers: { Authorization: token } };
const url = `${baseUrl}/api/account`;
const response = await axios.get(url, payload);
const user = response.data;
const isRoot = user.role == "root";
const isAdmin = user.role == "admin";
// if authenticated but not root or admin
const isNotPermitted =
!(isRoot || isAdmin) &&
(ctx.pathname === "/admin/add-product" ||
ctx.pathname === "/admin/customers" ||
ctx.pathname === "/admin/orders" ||
ctx.pathname === "/admin/dashboard");
if (isNotPermitted) {
redirectUser(ctx, "/products");
}
pageProps.user = user;
} catch (error) {
// console.error("Error getting current user", error);
//invalid token
destroyCookie(ctx, "token");
redirectUser(ctx, "/auth/login");
}
}
return { pageProps };
}
componentDidMount() {
window.addEventListener("storage", this.syncLogout);
require($)(window);
}
syncLogout = e => {
if (e.key === "logout") {
Router.push("/");
}
};
render() {
const { Component, pageProps } = this.props;
return (
<Layout {...pageProps}>
<Component {...pageProps} />
</Layout>
);
}
}
export default MyApp;
In my components/_App/Layouts.js tenho o seguinte codigo:
import React from "react";
import Head from "next/head";
import Footer from "./Footer";
import StaticHeader from "./StaticHeader";
const Layout = ({ children, user }) => {
return (
<React.Fragment>
<Head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>WdpShoes | Home</title>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght#400;700;800&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="./public/css/icons.css" />
<link href="https://file.myfontastic.com/gMNiHf8HU5GG4r6y622k2N/icons.css" rel="stylesheet" />
<link rel="stylesheet" href="/css/boot.css" />
<link rel="stylesheet" href="/css/themes/style.css" />
<link rel="shortcut icon" href="/css/themes/logo/favicon.png" />
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
</Head>
<body>
<StaticHeader user={user} />
{children}
<Footer />
<script src="/jquery.js"></script>
<script src="/scripts.js"></script>
<script src="/css/themes/script.js"></script>
</body>
</React.Fragment>
);
};
export default Layout;
In the Components that are in my Layout the jquery and javascript are working but in my components they are not
When I import my script into my pages / _app.js file I encounter the following error:
ReferenceError: $ is not defined
at Object../public/scripts.js (C:\Users\walter\Desktop\mystore.next\server\pages_app.js:5217:1)
I looked for some materials and I didn't find anything that could help me solve this problem that is preventing me from developing several projects
I know the purpose of the site is to answer questions but to better explain my problem I have the complete code at:
https://codesandbox.io/s/dawn-mountain-vme5e?file=/pages/_app.js
And in its current state it encounters the Internal Server Error due to the fact that the $ function is returning an undefined,Because my script and jquery are not working correctly in my components
To understand your issue, a little theory is needed. Next.js uses server-side rendering and static generation, which means the all code is initially run on the server. jQuery is a client-side library and it can't run on the server. Therefore, you need to ensure that all the jQuery code is executed only on the client side. You can do this by checking if the window object exists and only then executing jQuery. Also, you've forgotten to include jQuery in your scripts.js file.
Modify the
scripts.js file:
import $ from "jquery";
if (typeof window !== "undefined") {
$(function () {
// Rest of the code...
}
}
Next, modify the componentDidMount function in _app.js:
componentDidMount() {
window.addEventListener("storage", this.syncLogout);
}

How to disable scripts based on pathname in NEXT JS

I want to disable a chat widget on my page /embed/. The widget is loaded in _document.js. I am familiar useRoute or withRouter to disable a component. Example
import React, { Component } from "react";
import Link from "next/link";
import { withRouter } from "next/router";
class Footer extends Component {
render() {
const pathname = this.props.router.pathname;
if (pathname.startsWith("/embed/")) {
return null;
} else {
return (
<div className='footer container'>
My footer displayed on all pages expect on /embed/
</div>
);
}
}
}
export default withRouter(Footer);
But unfortunately this doesn't work in _document.js and keep getting internal error 500.
import Document, { Head, Main, NextScript } from "next/document";
import { GA_TRACKING_ID } from "../lib/gtag";
import WidgetChat from "../lib/WidgetChat";
import { withRouter } from "next/router";
class MyDocument extends Document {
render() {
const pathname = this.props.router.pathname;
if (pathname.startsWith("/embed/")) {
return null;
} else {
return (
<html>
<Head>
{/* Global Site Tag (gtag.js) - Google Analytics */}
<script
async
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
/>
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', {
page_path: window.location.pathname,
});
`,
}}
/>
</Head>
<body>
<Main />
<NextScript />
<WidgetChat />
</body>
</html>
);
}
}
}
export default withRouter(MyDocument);
Any advice?
Many thanks
Frido

Resources