Dynamic start_url - reactjs

I'm fairly new to next.js, and I'm trying to create a PWA using Next.js.
The goal is to make the start_url of my pwa to be: "/recipes/:recipe_id"
I cloned this repo: https://github.com/mvllow/next-pwa-template.
Then I updated the _app.tsx file:
import type { AppProps } from 'next/app'
import { ThemeProvider } from 'next-themes'
import Meta from '#/components/meta'
import '#/styles/globals.css'
import manifest from "../public/manifest.json";
import {useEffect} from "react";
const App = ({ Component, pageProps }: AppProps) => {
useEffect(() => {
const manifestElement = document.getElementById("manifest");
const manifestString = JSON.stringify({
...manifest,
start_url: `${window.location.href}`,
});
manifestElement?.setAttribute(
"href",
"data:application/json;charset=utf-8," + encodeURIComponent(manifestString)
);
});
return (
<ThemeProvider
attribute='class'
defaultTheme='system'
disableTransitionOnChange
>
<Meta />
<Component {...pageProps} />
</ThemeProvider>
)
}
export default App
And the _document.tsx file :
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html lang='en'>
<link href="/manifest.json" rel="manifest" id="manifest" />
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
But the following errors occur:
anifest: property 'start_url' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'scope' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
It seems like updating the file doesn't set the right format but I'm not sure.
Here are some of the links I used to update my code :
https://stackoverflow.com/a/68511528/8995872
https://medium.com/#stefanfrancis/nextjs-dynamic-manifest-be8b804ceb92
I tried updating the above code without success.

try this
start_url: `${window.location.href}`

Related

document is not defined when creating new portal in Nextjs

in my project I want to separate section like menu in header tag, content in main tag and contact in footer tag _document.js file, for this I created a new portal but I get an error document is not defined in my Header.js file.
I trying to create new portal in nextjs like this:
import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import NavigationBar from "./NavigationBar";
import classes from "./header.module.css";
const Header = (props) => {
return (
<Fragment>
{ReactDOM.createPortal(
<NavigationBar>{props.children}</NavigationBar>,
document.getElementById("header")
)}
</Fragment>
);
};
export default Header;
I created _document.js:
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 lang="en" dir="ltr">
<Head />
<body>
<header id="header"></header>
<Main />
<footer id="_footer"></footer>
<div id="_modal"></div>
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
The error is thrown because document is only available inside the browser and not on the server. Next js executes this code on the server side and that's why the error is thrown.
You can wrap our code inside an if statement. If you check on the console the type of window it returns object. The following code illustrates this:
if (typeof window === 'object') {
// Check if document is finally loaded
}
Use React portal maker:
import React from "react";
import reactDom from "react-dom";
const Header = (props) => {
const content = <NavigationBar>{props.children}</NavigationBar>;
if (typeof window === "object") {
return reactDom.createPortal(content, document.getElementById("__header"));
}
return null;
};
export default Header ;

error in _document.js when run build next js

I'm getting two errors when I try to yarn run build my nextJS project:
3:1 Error: next/document should not be imported outside of pages/_document.js.
See https://nextjs.org/docs/messages/no-document-import-in-page. #next/next/no-document-import-in-page
13:38 Error: Component definition is missing display name react/display-name
the first error doesn't make sense to me, see the path of my _document.js:
the second, doesn'nt uderstand, my _document.js:
import Document, { Head, Main, NextScript } from "next/document";
// Import styled components ServerStyleSheet
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
// Step 1: Create an instance of ServerStyleSheet
const sheet = new ServerStyleSheet();
// Step 2: Retrieve styles from components in the page
const page = renderPage(
(App) => (props) => sheet.collectStyles(<App {...props} />)
);
// Step 3: Extract the styles as <style> tags
const styleTags = sheet.getStyleElement();
// Step 4: Pass styleTags as a prop
return { ...page, styleTags };
}
render() {
return (
<html>
<Head>
<title>My app</title>
{/* Step 5: Output the styles in the head */}
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
I already tried to install the canary new version (npm install next#11.1.3-canary.15), (saw this solution in another post) but doesn't work.
any tip, please?

Storybook MDX: Dynamic Meta Title

How can I set a dynamic title property on a Storybook Meta component in a Markdown Extended *.stories.mdx file?
import { Meta } from '#storybook/addon-docs/blocks';
// displays title as 'undefined' in sidebar nav
<Meta title={conditionalValue ? 'foo' : 'bar'} />
I also tried wrapping Meta in a higher-order component, which triggers an error: Unexpected default export without title
import { Meta } from '#storybook/addon-docs/blocks';
export const MetaCustom = (props) => {
const title = conditionalValue ? props.foo : props.bar;
return <Meta title={title} />;
};
// mdx stories file
<MetaCustom foo="foo" bar="bar" />
I tried creating a util function and import into the mdx and seems like it is working.
utils.js
export function generateTitle (condition) {
return condition ? 'foo' : 'bar'
}
Component.stories.mdx
import { generateTitle } from './utils.js';
<Meta
title={generateTitle(true)}
/>
Hope that helps!

Only load Snipcart on specific page in Gatsby

I'm using Snipcart Plugin in Gatsby but the script gets loaded everywhere. Is is it possible with some sort of function to trigger the script on only 1 specific page and not entirely?
Below are the options I'm using in my Gatsby-config.js file
{
resolve: "gatsby-plugin-snipcart",
options: {
apiKey: process.env.SNIPCART_API,
autopop: true,
js: "https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.js",
styles: "https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.css",
jquery: false,
},
},
You should take a look at gatsby-plugin-snipcartv3. I believe the gatsby-plugin-snipcart is deprecated and is not working with Snipcart v3.
But as far as I know, there's no way to tell the plugin to load the script only on specific pages.
You could use Snipcart directly, not using the plugin, to have more control over it.
Let's say you have a layout.js file, wrapping content for your page, you can have a loadSnipcart flag that will load Snipcart files only when you need them.
Here's an example:
layout.js
import React from "react"
import Helmet from "react-helmet"
export default ({ loadSnipcart, children }) => {
const Snipcart = () => {
if (!loadSnipcart) return null
return (
<Helmet>
<script
src="https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.js"
type="text/javascript"
/>
<link
href="https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.css"
rel="stylesheet"
/>
</Helmet>
)
}
return (
<div id="main-content">
<Snipcart />
{children}
</div>
)
}
shop.js
import React from "react"
import Layout from "./layout"
export default () => {
return (
<Layout loadSnipcart>
<h1>Welcome to my shop !</h1>
</Layout>
)
}
index.js
import React from "react"
import Layout from "./layout"
export default () => {
return (
<Layout>
<h1>This page doesn't load Snipcart</h1>
</Layout>
)
}

Intense FOUC when using Next.js 8 and styled-jsx

I have recently upgraded to Next.js 8.0.3 from 6.1.1 and I am now encountering a very intense flash of un-styled content (FOUC) for my header content which is using styled-jsx. It loaded just fine before updating Next.js.
The header code that is flashing is a custom built npm module that uses styled-jsx (but not next) and is being imported and placed into a layout page that is rendered with every next page.
This was the implementation in the _document.js file before updating next and it was working:
import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet, injectGlobal } from 'styled-components'
import styledNormalize from 'styled-normalize'
import flush from 'styled-jsx/server'
injectGlobal`
${styledNormalize}
`
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()
const styles = flush()
return { ...page, styleTags, styles }
}
render() {
return (
<html>
<Head>
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
Based on the docs I have also tried this (where I wait for the initial props):
import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet, injectGlobal } from 'styled-components'
import styledNormalize from 'styled-normalize'
import flush from 'styled-jsx/server'
injectGlobal`
${styledNormalize}
`
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const page = ctx.renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
)
const initialProps = await Document.getInitialProps(ctx)
const styleTags = sheet.getStyleElement()
const styles = flush()
return { ...initialProps, ...page, styles, styleTags }
}
render() {
return (
<html>
<Head>
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
The flash might be a result of where I am implementing the module but not sure.
It seems like the code coming in from the module is not being properly bundled with the rest of the pages and thus giving the page flash. Any thoughts or feedback would be appreciated.
I ended up fixing the issue by refactoring the custom npm module to not use styled-jsx but instead use styled-components. Not really a fix but more of a work around

Resources