- ์ปดํ์ผ๊ณผ ๋ฒ๋ค๋ง์ด ์๋์ผ๋ก ๋๋ค(webpack ๊ณผ babel)
nextjs 12๋ฒ์ ๋ถํฐ๋ SWC ๋ผ๋ ์ปดํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ๋ค.
(TMI
swc๋ ํ๊ตญ์ธ ๊ฐ๋ฐ์๊ฐ ๊ฐ๋ฐํ๋คํจ.. ๐respect)- ์๋ ๋ฆฌํ๋ ์ฌ ๊ธฐ๋ฅ์ผ๋ก ์์ ํ๋ฉด ํ๋ฉด์ ๋ฐ๋ก ๋ฐ์๋๋ค.
- ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง์ด ์ง์๋๋ค.
- ์คํํฑ ํ์ผ์ ์ง์ํ๋ค.
ํ์ด์ง๊ฐ ssr ์ด๋ผ๋ฉด Network ์๋จ ๋ชฉ๋กํ์ผ์ ์ด์์๋ index ํ์ผ์ ํ์ธ ํ ์ ์๋ค.
๋ฐ๋๋ก csr ํ์ด์ง ๋ผ๋ฉด ์๋์ ๊ฐ์ ๊ฒฝ๊ณ ๋ฌธ์ ํ์ธ ํ ์ ์๋ค.
nextjs๊ฐ ๋ฒ์ 12๋ก ์ ๊ทธ๋ ์ด๋ ๋๋ฉด์ ๋ค์๊ณผ ๊ฐ์ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ๋ค.
failed to load SWC binary, ...
Next.js now uses Rust-based compiler SWC to compile JavaScript/TypeScript.
- babelrc ์ค์ ํด์ฃผ๊ธฐ!
{
"presets": ["next/babel"]
}
๋ ์ด์์
์ ์ ์ง ํ ์ ์๋ค.์ํ๊ฐ
์ ์ ์งํ ์ ์๋ค.componentDidCatch
๋ฅผ ์ด์ฉํด์ ์ปค์คํ
์๋ฌ ํธ๋ค๋ง
์ ํ ์ ์๋ค.CSS
๋ฅผ ์ด๊ณณ์ ์ ์ธํ๋ค.next ์์ ์ ๊ณตํ๋ document์ ์ ์ฉํ๋ฉด
๋งํฌ์ ์ ์ปค์คํ
ํ ์์๋ค.
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 />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
pages/view/[id].js
import { useRouter } from "next/router";
export default function Post() {
const router = useRouter();
const { id } = router.query;
return (
<div>Post</div>
);
}
next/link
์์ ๊ฐ์ ธ์จ Link
๋ a
ํ๊ทธ์ ํจ๊ป ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํ์ฌ id๊ฐ์ผ๋ก ๋์ ๋ผ์ฐํ
์ ์ ์ฉ ํ ์ ์๋ค.
import Link from "next/link";
export default function ItemList({ list }) {
return (
<>
{list.map((item) => {
return (
<Link key={item.id} href={`/view/${item.id}`}>
<a>
<div className="image">
<img src={item.image_link} alt={item.name} />
</div>
</a>
</Link>
);
})}
</>
);
}
Nextjs ๋ ๋ชจ๋ ํ์ด์ง๋ฅผ ์ฌ์ ๋ ๋๋ง(htmlํ์ผ์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ค)์ ํฉ๋๋ค.
์ฅ์
์ ์
์์ฑSSR
, Dymanic Rendering)๋์ ์ฐจ์ด์ ์ ์ธ์ html ํ์ผ์ ์์ฑํ๋๊ฐ?
์ ์ ์์ฑ
๋น๋ํ๋ ์์
์ htmlํ์ผ ์์ฑ์ ์ ์์ฑ
์ ๊ถ๊ณ ํจCDN์ ์บ์
์๋ฒ์ฌ์ด๋ ๋ ๋๋ง
์ ๋งค ์์ฒญ๋ง๋ค html์ ์์ฑ
์ ์ ์์ฑ๊ณผ ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง์ ์ฐจ์ด๋ ์ธ์
HTMLํ์ผ์ ๋ง๋๋์ง
1. ์ ์ ์์ฑ์ ๋น๋์ html์ ์์ฑ, ์ดํ ์์ฒญํ ๋๋ง๋ค ์ด๋ฏธ ์ ์ฅ๋์ด ์๋ Html ํ์ผ์ ๋ณด์ฌ์ค (์ ์ ์์ฑ)
2. ์๋ฒ์ฌ์ด๋ ๋ ๋๋ง ๊ฐ์ ๊ฒฝ์ฐ ์์ฒญ์ ํ ํ html์ ๋ง๋ค์ด ๋ณด์ฌ์ค๋ค.(๋์ ์์ฑ)
๋ชฉ์
์ ์๋ง๊ฒ ์ฌ์ฉ ๋ ์ ์๋ค.
์ ์ ์์ฑ
์๋ฒ์ฌ์ด๋ ๋ ๋๋ง
๊ธฐ๋ณธ react(csr)์ ๊ฐ์ด pre-rendering๋ ํ์ด์ง๊ฐ ์๋ ๊ฒฝ์ฐ JSload์ ์๋ฌด๋ฐ ์ฝ๋๊ฐ ๋ํ๋์ง ์๋๋ค.
nextjs์ ๊ฐ์ด pre-rendering ๋ ํ์ด์ง ๊ฐ์ ๊ฒฝ์ฐ JSload์ ์ด๋ฏธ html์ด ๊ตฌ์ฑ๋์ด ์๋ค (head, meta etc...)
๊ธฐ์กด์ฝ๋
export default function Home() {
const [list, setList] = useState([]);
const [isLoading, setIsLoading] = useState(true);
// ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์ด๋ผ next_public_ ๋ฅผ ๋ถ์
const API_URL = process.env.NEXT_PUBLIC_API_URL;
function getDate() {
axios.get(API_URL).then((res) => {
setList(res.data);
setIsLoading(false);
});
}
useEffect(() => {
getDate();
}, []);
return (
<div className={styles.container}>
<Head>
<title>HOME | ํ๋ก ํธ๋ชฝํค</title>
<meta name="description" content="ํ๋ก ํธ๋ชฝํค ํ ์
๋๋ค."></meta>
</Head>
{isLoading && (
<div style={{ padding: "300px 0" }} className="ui segment">
<div className="ui active inverted dimmer">
<div className="ui text loader">Loading</div>
</div>
<p></p>
</div>
)}
{!isLoading && (
<>
<Header as="h3" style={{ paddingTop: 40 }}>
๋ฒ ์คํธ์ํ
</Header>
<Divider />
<ItemList list={list.slice(0, 6)} />
<Header as="h3" style={{ paddingTop: 40 }}>
์ ์ํ
</Header>
<Divider />
<ItemList list={list} />
</>
)}
</div>
);
}
์ ์ ์์ฑ ์ฝ๋ ์ ์ฉ
export default function Home({ list }) {
// ํ์ด์ง๊ฐ ๋ฐ๋ก ๋ํ๋๊ธฐ ๋๋ฌธ์ loading ํ๋ฉด์ด ํ์ํ์ง ์์
return (
<div className={styles.container}>
<Head>
<title>HOME | ํ๋ก ํธ๋ชฝํค</title>
<meta name="description" content="ํ๋ก ํธ๋ชฝํค ํ ์
๋๋ค."></meta>
</Head>
<>
<Header as="h3" style={{ paddingTop: 40 }}>
๋ฒ ์คํธ์ํ
</Header>
<Divider />
<ItemList list={list.slice(0, 6)} />
<Header as="h3" style={{ paddingTop: 40 }}>
์ ์ํ
</Header>
<Divider />
<ItemList list={list} />
</>
</div>
);
}
export async function getStaticProps() {
// ํด๋ผ์ด์ธํธ ํ๊ฒฝ์ด ์๋๊ธฐ ๋๋ฌธ์ NEXT_PUBLIC ์ ๋ถํ ํ์ ์์
const apiUrl = process.env.apiUrl;
const res = await axios.get(apiUrl);
const data = res.data;
return {
props: {
list: data,
name: process.env.name,
},
};
}
๊ธฐ์กด์ฝ๋
export default function Post() {
const router = useRouter();
const [item, setItem] = useState();
const [isLoading, setIsLoading] = useState(true);
const { id } = router.query;
const API_URL = `http://makeup-api.herokuapp.com/api/v1/products/${id}.json`;
function getDate() {
axios.get(API_URL).then((res) => {
setItem(res.data);
setIsLoading(false);
});
}
useEffect(() => {
if (id && id > 0) {
getDate();
}
}, [id]);
return (
<>
{isLoading ? (
<div style={{ padding: "300px 0" }} className="ui segment">
<div className="ui active inverted dimmer">
<div className="ui text loader">Loading</div>
</div>
<p></p>
</div>
) : (
<Item item={item} />
)}
</>
);
}
์๋ฒ์ฌ์ด๋ ๋ ๋ ์ ์ฉ
export default function Post({ item }) {
return (
<>
<Head>
<title>{item.name}</title>
<meta name="description" content={item.description}></meta>
</Head>
{item && <Item item={item} />}
</>
);
}
export async function getServerSideProps(context) {
const id = context.params.id;
const apiUrl = `http://makeup-api.herokuapp.com/api/v1/products/${id}.json`;
const res = await axios.get(apiUrl);
const data = res.data;
return {
props: {
item: data,
},
};
}
๊ธฐ์กด์ฝ๋
export default function Post({ item, name }) {
return (
<>
<Head>
<title>{item.name}</title>
<meta name="description" content={item.description}></meta>
</Head>
{name} ํ๊ฒฝ์
๋๋ค.
{item && <Item item={item} />}
</>
);
}
export async function getServerSideProps(context) {
const id = context.params.id;
const apiUrl = `http://makeup-api.herokuapp.com/api/v1/products/${id}.json`;
const res = await axios.get(apiUrl);
const data = res.data;
return {
props: {
item: data,
name: process.env.name,
},
};
}
๋์ ๋ผ์ฐํธ ํ์ผ์ ์ ์ ์์ฑ ์ ์ฉ
const Post = ({ item, name }) => {
return (
<>
{item && (
<>
<Head>
<title>{item.name}</title>
<meta name="description" content={item.description}></meta>
</Head>
{name} ํ๊ฒฝ์
๋๋ค.
<Item item={item} />
</>
)}
</>
);
};
export default Post;
export async function getStaticPaths() {
return {
paths: [
{ params: { id: "740" } },
{ params: { id: "730" } },
{ params: { id: "729" } },
],
// false ์ค์ ์ ๋์๋์ง ์๋ ํ์ด์ง๋ ๋ชจ๋ 404Error ์ฒ๋ฆฌ
// true ์ค์ ์ ๋ชจ๋ ๋ผ์ฐํธํ์ด์ง์ ์ ์ ํ์ผ์ด ์์ฑ๋จ (์ด๊ธฐ๋น๋์๊ฐ์ด ์ค๋๊ฑธ๋ฆผ)
fallback: true,
};
}
export async function getStaticProps(context) {
const id = context.params.id;
const apiUrl = `http://makeup-api.herokuapp.com/api/v1/products/${id}.json`;
const res = await axios.get(apiUrl);
const data = res.data;
return {
props: {
item: data,
name: process.env.name,
},
};
}
ํ๋ก๋์
์ผ๋ก ์คํํ์๋ ๋น๋ํ์ผ
์ ์ดํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ ์ html
ํ์ผ์ด ์์ฑ๋์ด ์๋ ๊ฑธ ํ์ธ ํ ์ ์๋ค.
https://nextjs.org/docs
์ฝ๋ฉ์๋ง๋์ ์ ํ๋ธ ๊ฐ์ข