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
How to Compose Next 13 Link and MUI Link
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>
Way #2 - Using the component Property of MuiLink
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.
Way #3 - Modifying NextLink href Property
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