March 20, 2021
Next. ๋ฆฌ์กํธ ๊ธฐ๋ฐ์ ํ๋ ์์ํฌ.
๋ฆฌ์กํธ๋ โ์ปดํฌ๋ํธโ ๋ฅผ ์ฌ์ฉํ์ฌ UI ๋ฅผ ํจ์จ์ ์ผ๋ก ๋ง๋ค๊ธฐ ์ํ ํ๋ ์์ํฌ ์ด๋ค. ๋ฆฌ์กํธ ๋ง์ผ๋ก๋ ํ๋ก ํธ๊ฐ๋ฐ์ ํ ์ ์๋๋ฐ, ์ ๊ตณ์ด
Next ๋ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ด๋ผ๋๋ ํ๋ ๊ฒ์ ์๋ ค๊ณ ํ๋ ๊ฑธ๊น?
๋จผ์ ๋ ๋๋ง์ด๋ ์๋ฒ์ ์๋ต์ ๋ฐ์ ํ๋ฉด์ (๋ธ๋ผ์ฐ์ ์) ๋์ด๋ค๋ ๊ฒ์ ์๊ฐํ๋ฉด ์ฝ๋ค.
๋ฆฌ์กํธ ์์๋ ํ์ด์ง๋ฅผ ๋ถ๋ฌ์ฌ ๋ ํ์ํ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ํ๋ฒ์ ๋ถ๋ฌ์จ๋ค.
ํ์ด์ง ์ด๋์ ํตํด ๋ฐ์์จ ํ์ผ์ ์ด์ฉํ์ฌ UI ๋ฅผ ๋ณํ์ํค๋ฉฐ ํ์ํ ๋ฐ์ดํฐ๋ ์๋ฒ์์ JSON ํํ๋ก ๋ฐ์ UI ๋ฅผ ๋น ๋ฅด๊ฒ ๋ณํ์ํฌ ์ ์๋ค.
๊ทธ๋ฐ๋ฐ ํ๋์ ํ์ด์ง๋ฅผ ๋ถ๋ฌ ์ฌ ๋๋ง๋ค ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ๋ถ๋ฌ์์ผ ํ๊ธฐ ๋๋ฌธ์ ์ฒ์ ํ์ด์ง๋ฅผ ๋ถ๋ฌ์ฌ ๋ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๊ฒ ๋๋ค๊ณ ํ๋ค.
https://d2.naver.com/helloworld/7804182
์ ๋งํฌ์ ์ข์ ๋ด์ฉ๋ค์ด ์์๋ค. ๋๋ถ์ด ๋งํฌ์ ์๋ ์ฌ์ง๋ ์ฒจ๋ถํด ๋ณธ๋ค.
๊ทธ๋ฆฌ๊ณ SPA ๋ (ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง์) ๊ฒ์ ์์ง ์ต์ ํ (SEO) ์ ์ข์ง ์๋ค๊ณ ํ๋ค.
๊ฒ์ ์์ง ์ต์ ํ(์์ด: search engine optimization, SEO)๋ ์น ํ์ด์ง ๊ฒ์์์ง์ด ์๋ฃ๋ฅผ ์์งํ๊ณ ์์๋ฅผ ๋งค๊ธฐ๋ ๋ฐฉ์์ ๋ง๊ฒ ์น ํ์ด์ง๋ฅผ ๊ตฌ์ฑํด์ ๊ฒ์ ๊ฒฐ๊ณผ์ ์์์ ๋์ฌ ์ ์๋๋ก ํ๋ ์์ ์ ๋งํ๋ค.
์ฝ๊ฒ ๋งํ๋ฉด ์์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง์ ์์๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ด๋ฏธ์ง๋ฅผ ๋ดค์ ๋, ๊ฒ์ ์์ง ๋ด์ด ์ฌ์ดํธ์ ๋ฐฉ๋ฌธํ์ ๋ ๋ก๋ฉ์ค์ธ ์ํ๋ผ์ ์ฝํ ์ธ ๋ฅผ ์ ๊ณตํ์ง ๋ชปํ๊ฒ ๋์ด,
์ฌ์ดํธ๋ฅผ ํ์ ํ๋ ๋ฐ ์ด๋ ค์์ด ์๊ธฐ๊ณ ์ผ๊ป ๊ณต๋ค์ฌ ๋ง๋ค์ด ๋์ ๋ด ํ์ด์ง๊ฐ ๊ฒ์ ์์์ ํน์ ์์ ์๋ณด์ด๊ฒ ๋๋ค๋ฉด ๋ง์์ด ์ํ์ง ์๊ฒ ๋๊ฐ?
์ด๋ฌํ ๋ฌธ์ ์ ์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง (SSR) ์ ์ฌ์ฉํจ์ผ๋ก์จ ํด๊ฒฐํ ์ ์๋ค๊ณ ํ๋ค.
์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ์ฌ์ดํธ์ ์ ์ํ ๋ ๋ ๋๋ง๋ html ์ ๋ถ๋ฌ์ค๊ฒ ๋๋ค.
ํ์ํ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ์ ๋ถ๋ฌ์ฌ ๋๊น์ง ๋ฐ์์ ํ์ง ์์ง๋ง, ๋น ๋ฅด๊ฒ ํ๋ฉด์ ๋ณด์ผ ์ ์๊ธฐ์ ์๋๊ฐ ๋นจ๋ผ ๋ณด์ด๊ฒ ๋๋ค๊ณ ํ๋ค.
๊ฒ์ ์์ง ๋ด์ ๋ ๋๋ง ๋ html ์ ์ ๊ณตํ์ฌ ๊ฒ์ ์์ง ์ต์ ํ์๋ ์ข๋ค.
ํ์ง๋ง ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ํ์ด์ง ์ด๋ ์ ์๋ก์ด ํ์ด์ง๋ฅผ ์์ฒญํ๊ธฐ ๋๋ฌธ์ ํ์ด์ง ์ด๋์์ ๊น๋ฐ์์ด ์กด์ฌํ๋ค.
๋ํ ํ์ด์ง ์ด๋ ์ ํ ํ๋ฆฟ์ ์ค๋ณตํด์ ๋ก๋ฉํ๊ณ SSR ์ ํ๋ ๊ฒ์ด ์๋ฒ์ ๋ถ๋ด์ ์ฃผ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ ์ข์ง ์๋ค๋ ๋จ์ ์ ๊ฐ์ง๊ณ ์๋ค ํ๋ค.
๋ฅ์คํธ๋ SPA ์ SSR ์ ๋จ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด์ ๋ฆฌ์กํธ ์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง ๊ธฐ๋ฅ์ ๋ํ์ฌ SPA ์ SSR ์ ์ฅ์ ์ ๊ฐ์ง ์ ์๊ฒ ๋๋ค.
๋ฆฌ์กํธ ์์ฒด์์ SSR ์ ์ถ๊ฐํ๋ ค๋ฉด ๋ณต์กํ ๊ณผ์ ์ ํ์๋ก ํ์ง๋ง ๋ฅ์คํธ ์์๋ ๋ณต์กํ ๊ณผ์ ์ ์ค์ ํ์ง ์๊ณ ์ฌ์ฉํ ์ ์์ด ๊ฐ๋ฐ ํ๊ฒฝ์ ์ค์ ํ๋ ์๊ฐ์ ์ค์ผ ์ ์๋ค.
node ์ npm ๊ทธ๋ฆฌ๊ณ ์๋ํฐ ๋ฑ์ ์ค์น๊ฐ ๋์๋ค๋ ๊ฐ์ ํ์ ์๋์ ๋ช ๋ น์ด๋ฅผ CLI ์ ์ ๋ ฅํ๋ค.
```js
npx create-next-app
```
ํ๋ก์ ํธ ์ด๋ฆ ๋ฑ์ ์ ๋ ฅํ๊ณ ํด๋๋ก ์ด๋ํ๋ฉด ์ฌ๋ฌ ํ์ผ ํธ๋ฆฌ๋ค์ด ๋ณด์ธ๋ค.
๊ทธ ์ค package.json ์ ์๋ โscriptโ ๊ฐ์ฒด ๋ถ๋ถ์ ๋ณด์๋ฉด,
```js
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
```
yarn dev ๋ฅผ ํตํด ์๋ฒ๊ฐ localhost ์ 3000๋ฒ ํฌํธ์์ ์คํ๋๋ค๋ ์ ๋ณด๊ฐ CLI ์ ์ถ๋ ฅ๋๋ค.
package.json ์ ๋ฅ์คํธ๋ฅผ ์คํํ script ๋ช ๋ น์ด ์ถ๊ฐํ๊ธฐ
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
๋ฅ์คํธ๋ ๋ฆฌ์กํธ๋ฅผ import ํ์ง ์๋๋ผ๋ ์์์ ์ผ๋ก import ํด์ค๋ค.
.eslintrc ํ์ผ ๋ด ์ถ๊ฐ์ ์ผ๋ก ๊ฐ๋ฐํ๋ฉด์ ํ์ํ ๊ท์น๋ค ์ถ๊ฐํ๊ธฐ
module.exports = {
env: {
browser: true,
es6: true,
},
extends: ["airbnb"],
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly",
},
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: "module",
},
plugins: ["react", "@typescript-eslint"],
rules: {
quotes: ["error", "double"], //๋๋ธ ์ฟผํฐ ์ฌ์ฉ
"@typescript-eslint/quotes": ["error", "double"], //๋๋ธ ์ฟผํฐ ์ฌ์ฉ
"no-unused-vars": "off", //์ฌ์ฉ์ํ ๋ณ์ ๊ฒฝ๊ณ ์ค๋ณต
"spaced-comment": "off", //์ฃผ์์ ๋ค์ ์ฐ์ง ๋ง๋ผ๋ ๊ฒฝ๊ณ
"@typescript-eslint/no-unused-vars": "warn", //์ฌ์ฉ์ํ ๋ณ์๋ ๊ฒฝ๊ณ
"jsx-a11y/control-has-associated-label": "off", // ์ํธ์์ฉํ๋ ์๋ฆฌ๋จผํธ์ label์ ๋ฃ๋๋ค
"react/no-array-index-key": "off", // key๊ฐ์ผ๋ก index๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
"comma-dangle": "off", // ๋ง์ง๋ง์ , ์ ๋ฃ์ด์ฃผ์ง ์๋๋ค.
"arrow-body-style": "off", //ํ์ดํ ํจ์ ์์ return์ ์ฌ์ฉ ํ ์ ์๋ค.
"react/no-unescaped-entities": "off", //๋ฌธ์์ด ๋ด์์ " ' > } ํ์ฉ
"react/prop-types": "off", //proptypes๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค.
"object-curly-newline": "off", // { ๋ค์ ์ค ๋ฐ๊ฟ์ ๊ฐ์ ๋ก ์ฌ์ฉํ์ง ์๋๋ค.
"react/jsx-one-expression-per-line": "off", //ํ๋ผ์ธ์ ์ฌ๋ฌ๊ฐ์ JSX๋ฅผ ์ฌ์ฉ ํ ์ ์๋ค.
"implicit-arrow-linebreak": "off", // ํ์ดํ ํจ์ ๋ค์์ ์ค ๋ฐ๊ฟ์ ์ฌ์ฉํ ์ ์๋ค.
"no-shadow": "off", //ํ์ผ ๋ด์์ ์ค๋ณต ์ด๋ฆ์ ์ฌ์ฉ ํ ์ ์๋ค.
"operator-linebreak": "off", //์ฐ์ฐ์ ๋ค์ ์ค ๋ฐ๊ฟ์ ์ฌ์ฉ ํ ์ ์๋ค.
"react/react-in-jsx-scope": "off", // jsx๋ฅผ ์ฌ์ฉํ์ฌ๋ React๋ฅผ ๊ผญ import ํ์ง ์์๋ ๋๋ค.
"react/jsx-props-no-spreading": "off", //props๋ฅผ ์คํ๋๋ ํ ์ ์๋ค.
"jsx-a11y/anchor-is-valid": "off", // next js์์๋ a์ href์์ด ์ฌ์ฉ
"global-require": "off", //ํจ์ ๋ด์์ require ์ฌ์ฉ๊ฐ๋ฅ
"no-use-before-define": "off", // ์ ์ธ์ ์ ์ฌ์ฉํ์ง ๋ง๋ผ,
"import/prefer-default-export": "off", //export default ๊ถ์ฅ
"no-param-reassign": "off", //param assign ํ์ง ์๊ธฐ
"jsx-a11y/label-has-associated-control": "off",
"no-invalid-css": "off",
"no-confusing-arrow": "off",
"react/jsx-curly-newline": "off",
indent: "off",
"react/jsx-filename-extension": [
1,
{ extensions: [".js", ".jsx", ".tsx"] }, //jsx์ฌ์ฉ๊ฐ๋ฅํ ํ์ฅ์ ์ค์
],
"import/extensions": [
"error",
"ignorePackages",
{
js: "never",
jsx: "never",
ts: "never",
tsx: "never",
}, //import ์ ํ์ฅ์๋ช
์ ์ฌ์ฉํ์ง ์๋๋ค.
],
},
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
},
},
},
};
์ด๋ ๊ฒ๋ ๋ง์ ๊ท์น๋ค์ด ์๋ค๋ ๋ฐ ๋๋๊ณ ์๊ฐ๋ณด๋ค ์์ ๋๊ฐ ๋๋ค๊ณ ๋๊ผ๋ค.