Skip to main content

Next.js

Dev

npm install -g react-devtools

Initial Project

npx create-next-app@latest project-name

# Have a single command without worrying about setting or using the environment variable properly for the platform.
npm install cross-env --save

Change port

"scripts": {
"dev": "cross-env port=3261 next dev",
}

Dynamic

npm run dev -- --port 13001
npm run dev -- -p 13001

Sitemap

# Sitemap
npm install next-sitemap -D

Tailwind CSS

Install

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

tailwind.config.js

module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

tailwind.config.js

module.exports = {
plugins: {
// Use ./config.js for Tailwind config
tailwindcss: { config: './config.js' },
autoprefixer: {},
},
}

Multi theme

npm install next-themes --save

Dark Mode

Dev Emu

Chrome => Run command => Emulate CSS prefers-color-scheme: light

Tailwind

tailwind.config.js

module.exports = {
mode: "jit"
darkMode: false, // or 'media' auto or 'class' manual
}

example:

install next-themes

import { useTheme } from 'next-themes'
...
const { theme, setTheme } = useTheme();
setTheme('dark');

Base layer

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
body {
@apply dark:bg-black;
}
}

Components layer

@layer components {
@media (prefers-color-scheme: dark) {
[type="checkbox"]:checked {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%23262626' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
}

[type="checkbox"] {
@apply focus:ring-0 focus:ring-offset-0;
}
}
}

Environment Variables

If you are trying to use a variable with a $ in the actual value, it needs to be escaped like so: $.

For example, if NODE_ENV is development and you define a variable in both .env.development.local and .env, the value in .env.development.local will be used.

Exposing Environment Variables to the Browser

In order to expose a variable to the browser you have to prefix the variable with NEXT_PUBLIC_. For example:

NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk

Script tags not working. No scripts are rendered

next/script should not be wrapped in next/head

concurrently

Run multiple commands concurrently. Like npm run watch-js & npm run watch-less but better.

Upgrading from 12 to 13

npm i next@latest react@latest react-dom@latest eslint-config-next@latest --save

NextJS recently released a major update which is Next 13, It included an update to the critical next/link component. You need to customize the MUI Link component and integrate the behavior of the next/link component and fix the naming conflict of the href prop of both components.

Limit to the versions:

MUI version 5.x and up NextJS version 13.x and up

Way #1 -legacyBehavior

<NextLink key={title} href={path} passHref legacyBehavior>
<RootLinkStyle active={isActiveRoot}>
<ListItemText disableTypography primary={title} />
</RootLinkStyle>
</NextLink>

If you don't need to create a custom component you can directly use the component property of MuiLink, but it's not without its drawbacks. For example:

import { Link as MuiLink } from "@mui/material";
import NextLink from "next/link";
const Container = () => {
return (
<div>
{/* This will use "prop forwarding" and MuiLink will automatically have the props of NextLink */}
<MuiLink component={NextLink} prefetch={false} href={"/page1"}>
hello
</MuiLink>
{/* However, passing a URLObject in href results in a type error */}
<MuiLink
component={NextLink}
prefetch={false}
href={{ pathname: "/page1" }} //type error
>
hello
</MuiLink>
</div>
);
};
export default Container;

This pattern will use prop forwarding and MuiLink will automatically get the NextLink props. But since both MuiLink and NextLink have href props, this causes name collisions and results in a type error. It will use the href prop from MuiLink.

To solve the problem above, you can extend the NextLink component and rename the href prop to something else to avoid naming collisions. For example:

// components/MyLink.tsx
import { LinkProps, Link as MuiLink } from "@mui/material";
import NextLink, { LinkProps as NextLinkProps } from "next/link";
// Defining the CustomNextLink
export type CustomNextLinkProps = Omit<NextLinkProps, "href"> & {
_href: NextLinkProps["href"];
};
export const CustomNextLink = ({ _href, ...props }: CustomNextLinkProps) => {
return <NextLink href={_href} {...props} />;
};
// combine MUI LinkProps with NextLinkProps
type CombinedLinkProps = LinkProps<typeof NextLink>;
// remove both href properties
// and define a new href property using NextLinkProps
type MyLinkProps = Omit<CombinedLinkProps, "href"> & {
href: NextLinkProps["href"];
};
const MyLink = ({ href, ...props }: MyLinkProps) => {
// use _href props of CustomNextLink to set the href
return <MuiLink {...props} component={CustomNextLink} _href={href} />;
};
export default MyLink;

Explanation: Line 5-10: We define the component CustomNextLink that uses _href prop to avoid naming collisions. This is an internal component for this file and is not to be used anywhere else.

Line 12-17: We take a roundabout way to remove the href props and define a new href prop that uses the one NextLinkProps for our custom MuiLink component.

Line 20: Here's where the magic happens. We use the _href props from our CustomNextLink and pass the next href prop that we just defined on line 16.

Perhaps there's a better way of defining the MyLinkProps, but I found this to be really easy to digest.

Usage:

import MyLink from "./MyLink";
// MyLink usage
const Container2 = () => {
return (
<div>
<MyLink
prefetch={false}
scroll={false}
sx={{ color: "warning.main" }}
href={{ pathname: "/page1" }}
>
hello
</MyLink>
<MyLink
prefetch={false}
scroll={false}
sx={{ color: "warning.main" }}
href="/page2" //Both string and URLObject are accepted
>
hello
</MyLink>
</div>
);
};
export default Container2;

Here we can see that it's a very seamless integration with NextLink and MUILink. I think this is a very good pattern to know.

Usage with styled:

If you want to use styled components, you can use the new wrapper component as the base:

// components/StyledLink:
import { styled } from "@mui/material/styles";
import MyLink, { MyLinkProps } from "./MyLink";
const StyledLink = styled(MyLink)<MyLinkProps>({});
StyledLink.defaultProps = {
color: "seagreen",
underline: "hover",
};
export default StyledLink;

You can apply it in other MUI components as well.

Nextra

# Don't use like <image> {image} outside the code block

Unit Test

npm install --save-dev jest babel-jest @babel/preset-env @testing-library/react @testing-library/jest-dom jest-environment-jsdom

Troubleshooting

Exit code is 137. killed.

Maybe ram not enough. Extend swap ram or add more ram.

Disable Remote Data Collect

npx next telemetry disable