๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

ยท ์•ฝ 2๋ถ„

Say Hello to Storybook#

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ#

  - Pure Components
  ![2020-12-04-201204-image-0](./images/2020-12-04-201204-image-0.png)


  - Container - Presenter ํŒจํ„ด
  ![2020-12-04-201204-image-1](./images/2020-12-04-201204-image-1.png)




  - Redux
  ![2020-12-04-201204-image-2](./images/2020-12-04-201204-image-2.png)


  - MobX
  ![2020-12-04-201204-image-3](./images/2020-12-04-201204-image-3.png)

๋ทฐ๊ฐ€ ๊นŠ์ˆ™ํžˆ ์ˆจ์–ด ์žˆ๋Š” ๊ฒฝ์šฐ#

  • ๊นŠ์€ ํŠธ๋ฆฌ, nullable, ๋ผ์šฐํŒ… ๋“ฑ์œผ๋กœ ์ธํ•ด ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋“ค์—ฌ์•ผํ•˜๋Š” ๋…ธ๋ ฅ์ด ๋„ˆ๋ฌด ํฌ๋‹ค.

2020-12-04-201204-image-4

์Šคํ† ๋ฆฌ๋ถ์ด ํ•˜๋Š” ์—ญํ• #

์Šคํ† ๋ฆฌ๋ถ์€ UI์ปดํฌ๋„ŒํŠธ๋ฅผ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ scaffolder์ด์ž UI ํ…Œ์ŠคํŒ… ํˆด์ด๋‹ค.

๊ฐ์ข… ๋ผ์šฐํŒ…๊ณผ state๋“ค๋กœ ์—ฐ๊ฒฐ์ด ๋˜์–ด์žˆ๋Š” React ๋ทฐ ์ปดํฌ๋„ŒํŠธ๋“ค์„ nomalize ์‹œ์ผœ isolate ์‹œ์ผœ ๋…๋ฆฝ์  ํ™˜๊ฒฝ์—์„œ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” UI scaffolding ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

  ![2020-12-04-201204-image-5](./images/2020-12-04-201204-image-5.png)


  ![2020-12-04-201204-image-6](./images/2020-12-04-201204-image-6.png)


  ![2020-12-04-201204-image-7](./images/2020-12-04-201204-image-7.png)
  • ์ž์ฒด ์›นํŒฉ์ด ์žˆ์–ด์„œ ํ•ซ ๋ฆฌ๋กœ๋”ฉ ์ง€์›

  • ๋””์ž์ด๋„ˆ์™€ ๊ฐœ๋ฐœ์ž, PM์„ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๋Š” ํ•˜๋‚˜์˜ ํˆด์ด๋‹ค.

์Šคํ† ๋ฆฌ๋ถ์€ ์•ฑ ๋ฐ–์—์„œ ๋”ฐ๋กœ ๋ˆ๋‹ค#

addons#

  • actions : ์ด๋ฒคํŠธ ์‹œ ๋กœ๊ทธ๋ฅผ ์ฐ์–ด์คŒ

  • links : ์Šคํ† ๋ฆฌ์—์„œ ๋‹ค๋ฅธ ์Šคํ† ๋ฆฌ๋กœ ์ด๋™

  • knobs : ๋™์ ์œผ๋กœ ์ƒํƒœ ๋ณ€๊ฒฝ

  • console : ์ฝ˜์†” ์ฐ์–ด์คŒ

  • notes : ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ ๋…ธํŠธ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

์„œ๋“œ ํŒŒํ‹ฐ#

  • backgrounds

  • chapters


ยท ์•ฝ 2๋ถ„

ts-node ์ ˆ๋Œ€๊ฒฝ๋กœ#

ts-node ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜

yarn add -D typescript @types/node nodemon ts-node tsconfig-paths

package.json์—์„œ nodemon์œผ๋กœ ์‹คํ–‰

"scripts": {  "dev": "nodemon -r ts-node src/index.ts" // nodemon src/index.ts๋กœ๋„ ์‹คํ–‰๋จ}

tsconfig.json์— baseUrl๊ณผ path ์„ค์ •

"baseUrl": ".","paths": {  "src/*": ["src/*"]}

โ†’ ์ด์ œ ์ปดํŒŒ์ผ์€ ๋˜์ง€๋งŒ, ์ปดํŒŒ์ผ๋œ ํŒŒ์ผ์„ node, ts-node๊ฐ€ ์ธ์‹ํ•˜์ง€ ๋ชปํ•œ๋‹ค.

โ†’ tsconfig-paths ๋ชจ๋“ˆ๋กœ ๊ฐ€๋Šฅ

"scripts": {  "dev": "nodemon --exec ts-node -r tsconfig-paths/register src/index.ts"}

๋นŒ๋“œ ํ›„์—๋„ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด

  1. ts-node ๋ชจ๋“ˆ์„ ํ†ตํ•ด ์ž‘๋™์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

    "scripts": {    "start": "ts-node -r tsconfig-paths/register dist/index.js"    // ๋˜๋Š”    // "start": "node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/index.js"}
  2. tsconfig-paths์˜ bootstrap์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•.

    // tsconfig-paths-bootstrap.jsconst tsConfigPathFile = require('./tsconfig.paths.json');const tsConfig = require('./tsconfig.json');const tsConfigPaths = require('tsconfig-paths');
    tsConfigPaths.register({    baseUrl: tsConfig.compilerOptions.outDir,    paths: tsConfigPathFile.compilerOptions.paths,});
    // package.json"scripts" {  "start": "node -r ./tsconfig-paths-bootstrap.js dist/src/index.js"}

์ฐธ๊ณ ์ž๋ฃŒ#

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์ ˆ๋Œ€๊ฒฝ๋กœ ์“ฐ๊ธฐ

typescript + node absolute path

ยท ์•ฝ 2๋ถ„

ESLint#

  • ํฌ๋งทํŒ…

  • ์ฝ”๋“œ ํ’ˆ์งˆ

๊ทœ์น™#

rules ๋กœ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

  • ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ทœ์น™๊ณผ ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ทœ์น™์ด ์žˆ์Œ.

  • ๊ทœ์น™ ๋ชฉ๋ก ์ค‘ ๋ Œ์น˜ ๊ธฐํ˜ธ๊ฐ€ ๋ถ™์€ ๊ฒƒ์ด ์ž๋™์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ทœ์น™

  • --fix ์˜ต์…˜์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

List of available rules

Extends#

  • ์—ฌ๋Ÿฌ ๊ทœ์น™์„ ๋ชจ์•„๋†“์€ ๊ฒƒ๋“ค

  • eslint:recommended , eslint-config-airbnb-base , eslint-config-standard ๋“ฑ์ด ์žˆ๋‹ค.

init#

--init ์˜ต์…˜์œผ๋กœ ๋Œ€ํ™”์‹์œผ๋กœ ์„ค์ • ๊ฐ€๋Šฅ

npx eslint --init
? How would you like to use ESLint?? What type of modules does your project use?? Which framework does your project use?? Where does your code run?? How would you like to define a style for your project?? Which style guide do you want to follow?? What format do you want your config file to be in?

Prettier์™€์˜ ํ†ตํ•ฉ#

Integrating with Linters ยท Prettier

Create-React-App with TypeScript, ESLint, Prettier, and Github Actions

ยท ์•ฝ 3๋ถ„

์ฟ ํ‚ค์™€ ์ธ์ฆ(Auth)#

์ฟ ํ‚ค๋ž€?#

๐Ÿ“Œ ์ƒํƒœ๊ฐ€ ์—†๋Š”(stateless) HTTP ํ”„๋กœํ† ์ฝœ์—์„œ ์ƒํƒœ ์ •๋ณด๋ฅผ ๊ธฐ์–ตํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ˆ 

  • ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์›น ๋ธŒ๋ผ์šฐ์ €์— ์ „์†กํ•˜๋Š” ์ž‘์€ ๋ฐ์ดํ„ฐ ์กฐ๊ฐ

  • ๋™์ผํ•œ ์„œ๋ฒ„์— ์žฌ ์š”์ฒญ ์‹œ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์ „์†ก

  • ์ฟ ํ‚ค๋Š” ๋™์ผํ•œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋“ค์–ด์™”๋Š”์ง€ ์•„๋‹Œ์ง€๋ฅผ ํŒ๋‹จํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ (์‚ฌ์šฉ์ž์˜๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€)

๋ชฉ์ #

  • ์„ธ์…˜ ๊ด€๋ฆฌ

    ์„œ๋ฒ„์— ์ €์žฅํ•ด์•ผ ํ•  ๋กœ๊ทธ์ธ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ, ๊ฒŒ์ž„ ์Šค์ฝ”์–ด ๋“ฑ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•จ

  • ๊ฐœ์ธํ™”

    ์‚ฌ์šฉ์ž ์„ ํ˜ธ, ํ…Œ๋งˆ ๋“ฑ์˜ ์„ธํŒ…

  • ํŠธ๋ž˜ํ‚น

    ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ๊ธฐ๋กํ•˜๊ณ  ๋ถ„์„ํ•˜๋Š” ์šฉ๋„

์ฟ ํ‚ค ์ƒ์„ฑํ•˜๊ธฐ#

HTTP ์‘๋‹ต ํ—ค๋”์˜ Set-Cookie key์— ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

function(req, res) {  res.writeHead(200, {    'Set-Cookie': ['yummy_cookie=choco', 'tasty_cookie=strawberry'],  })}

์ฟ ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ#

function(req, res) {  console.log(res.headers.cookie); // ['yummy_cookie=choco', 'tasty_cookie=strawberry']}

Session vs Persistent#

Session Cookie#

  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ ์‚ญ์ œ ๋จ.

session storage๋Š” ๋ธŒ๋ผ์šฐ์ € ํƒญ์ด ์ข…๋ฃŒ๋˜๋ฉด ์‚ญ์ œ๋˜๋Š” ๋ฐ˜๋ฉด, ์ฟ ํ‚ค๋Š” ๋ธŒ๋ผ์šฐ์ € ํƒญ ๊ฐ„์—๋„ ๊ณต์œ ๋˜์–ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์™„์ „ํžˆ ์ข…๋ฃŒ๋˜์–ด์•ผ ์‚ญ์ œ๋œ๋‹ค. ์ฐธ์กฐ

Persistent Cookie#

  • ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ข…๋ฃŒํ•ด๋„ ์‚ฌ์šฉ์ž์˜ ํ•˜๋“œ๋””์Šคํฌ์— ์ €์žฅ.

  • ์‚ญ์ œ ์‹œ๊ธฐ : Max-Age ์†์„ฑ์— ๋ช…์‹œ๋œ ๊ธฐ๊ฐ„ ์ดํ›„์—, ๋˜๋Š” Expires ์†์„ฑ์— ๋ช…์‹œ๋œ๋‚ ์งœ์— ์‚ญ์ œ, ๋˜๋Š” ์ง์ ‘ ์‚ญ์ œ

Secure & HttpOnly#

Secure#

'Set-Cookie': ['hello_secure_cookie=hello-secure; Secure'],

Secure ์ฟ ํ‚ค๋Š” HTTPS ํ”„๋กœํ† ์ฝœ ์ƒ์—์„œ ์•”ํ˜ธํ™”๋œ ์š”์ฒญ์ผ ๊ฒฝ์šฐ์—๋งŒ ์ „์†ก๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ดํ”Œ๋ž˜๊ทธ๊ฐ€ ์‹ค์งˆ์ ์ธ ๋ณด์•ˆ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

HttpOnly#

'Set-Cookie': ['hello_http_only=hello-http; HttpOnly'],

HttpOnly ์ฟ ํ‚ค๋Š” JavaScript์˜ document.cookie API๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค. ์„œ๋ฒ„์—๊ฒŒ ์ „์†ก๋˜๊ธฐ๋งŒ ํ•œ๋‹ค.

Path & Domain#

path#

path=/subpath ์ด๋Ÿฐ ์‹์œผ๋กœ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์š”์ฒญ๋˜๋Š” URL ๋‚ด์— ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•ด์•ผ ํ•˜๋Š” URL ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

domain#

'Set-Cookie': ['hello_domain=hello-domain; Domain=o2.org'],

์ด๋ ‡๊ฒŒ ์ง€์ •ํ•˜๋ฉด subdomain.o2.org ๋“ฑ๋“ฑ์˜ ๋ชจ๋“  ์„œ๋ธŒ ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด์„œ๋„ ์ฟ ํ‚ค๊ฐ€ ์ €์žฅ๋˜๊ฒŒ ๋œ๋‹ค.

ํƒœ๊ทธ:

ยท ์•ฝ 6๋ถ„

Narkdown ํ”„๋กœ์ ํŠธ#

  • notion-py ๋ฅผ ์‚ฌ์šฉํ•ด์„œ Python ๊ธฐ๋ฐ˜์œผ๋กœ์ง„ํ–‰ํ–ˆ์—ˆ์ง€๋งŒ Python์„ ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋‹ค๋ณด๋‹ˆ ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ ํž˜๋“ค์—ˆ๋‹ค.

  • ts ๊ธฐ๋ฐ˜ notion-api-worker ๊ฐ€ ์žˆ์–ด์„œ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค.

๋ชฉํ‘œ#

  • CLI๋กœ page url ๋˜๋Š” database url์„ ์ž…๋ ฅ ๋ฐ›๊ณ  notion์˜ ์ปจํ…์ธ ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ md ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์ž. (CMS๋ฅผ ์œ„ํ•ด)

  • ์ดํ›„ ์›น ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹์„ ๋“ฏ.

fetch vs axios#

ํ”„๋ก ํŠธ์—”๋“œ์—์„œ fetch, axios๋Š” ์ž์ฃผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, node ํ™˜๊ฒฝ์—์„œ api ์š”์ฒญ์„ ํ•ด๋ณด๋Š”๊ฒƒ์€ ์ฒ˜์Œ์ด๋ผ, ์–ด๋–ค ๊ฒƒ์„ ์‚ฌ์šฉํ• ์ง€ ๊ณ ๋ฏผํ–ˆ๋‹ค.

  • axios๋Š” node ํ™˜๊ฒฝ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

  • fetch๋Š” node-fetch ๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” NodeJS ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ window.fetch ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ๋ฅผ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.

  • ํ”„๋ก ํŠธ์—”๋“œ ํ™˜๊ฒฝ์—์„œ fetch ๊ฐ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฒŒ ์žฅ์ ์ด๋ผ๊ณ ์ƒ๊ฐํ•˜๋Š”๋ฐ, ๊ตณ์ด node-fetch๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์„ ๊ฒƒ ๊ฐ™์•„์„œ, axios๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ๊ฒฐ์ •ํ–ˆ๋‹ค. (๋ณด์•ˆ์ ์ธ ์˜ต์…˜๋„ axios๊ฐ€ ๋งŽ์ด ์ œ๊ณตํ•œ๋‹ค.)

https://www.geeksforgeeks.org/difference-between-fetch-and-axios-js-for-making-http-requests/

ts-node#

  • tsconfig ์ƒ์„ฑ ๋ช…๋ น์–ด
tsc --init
  • tsconfig ์˜ต์…˜ ์ •๋ฆฌ

8 Best Practices for Future-Proofing Your TypeScript Code

tsconfig ์ปดํŒŒ์ผ ์˜ต์…˜ ์ •๋ฆฌ

[TS / Node] TS + Node.js + Express + Babel(option) + eslint๋กœ ๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ

Node.js ์‹œ์ž‘ํ•˜๊ธฐ

notion-api-worker#

  • get page ๋ฆฌํ„ด

    • ๊ธฐ๋ณธ ํŽ˜์ด์ง€
      {    "847c0e9b-15a1-42c9-9392-ca2f817c4eac": {        "role": "editor",        "value": {            "id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",            "version": 23,            "type": "page",            "properties": {                "title": [["hello"]]            },            "content": ["cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61"],            "permissions": [                {                    "role": "editor",                    "type": "user_permission",                    "user_id": "b21a69b3-a19b-438c-b599-e850190836a3"                }            ],            "created_time": 1605604740000,            "last_edited_time": 1605604740000,            "parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",            "parent_table": "space",            "alive": true,            "created_by_table": "notion_user",            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "last_edited_by_table": "notion_user",            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "shard_id": 1004639,            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"        }    },    "cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61": {        "role": "editor",        "value": {            "id": "cc1dee2e-269d-4cd0-a5a3-b1c3d72edf61",            "version": 12,            "type": "text",            "properties": {                "title": [["1234"]]            },            "created_time": 1605604740000,            "last_edited_time": 1605604740000,            "parent_id": "847c0e9b-15a1-42c9-9392-ca2f817c4eac",            "parent_table": "block",            "alive": true,            "created_by_table": "notion_user",            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "last_edited_by_table": "notion_user",            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "shard_id": 1004639,            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"        }    }}
    • Database ํ•˜์œ„ ํŽ˜์ด์ง€
      {  "15afa14b-8f9c-4b6c-97cc-46375c775cc5": {    "role": "reader",    "value": {      "id": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",      "version": 25,      "type": "page",      "properties": [Object],      "created_time": 1605517260000,      "last_edited_time": 1605602760000,      // ๋ถ€๋ชจ Id      // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๊ฒฝ์šฐ collection_id      "parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",      // ๋ถ€๋ชจ      "parent_table": "collection",      "alive": true,      "created_by_table": "notion_user",      // user_id      "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",      "last_edited_by_table": "notion_user",      "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",      "shard_id": 1004639,      "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"    }  },
        // ๋ถ€๋ชจ๊ฐ€ space๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ ๋ถ€๋ชจ  "acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {    "role": "reader",    "value": {      "id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",      "version": 106,      "type": "collection_view_page",      "view_ids": [Array],      "collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",      "format": [Object],      "permissions": [Array],      "created_time": 1600223639505,      "last_edited_time": 1605594780000,      "parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",      "parent_table": "space",      "alive": true,      "created_by_table": "notion_user",      "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",      "last_edited_by_table": "notion_user",      "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",      "shard_id": 1004639,      "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"    }  }}
    • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€
      {    "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61": {        "role": "reader",        "value": {            "id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",            "version": 6,            "type": "page",            // ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ•˜์œ„์— ์žˆ๋Š” ํŽ˜์ด์ง€์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถ€๋ชจ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•ด์„œ ๊ฐ€์ ธ์™€์•ผ ํ•จ.            "properties": {                "RXKJ": [                    // ์—ฌ๋Ÿฌ ํƒœ๊ทธ ๋ชฉ๋ก์ด ๋ฌธ์ž์—ด ',' ๋กœ ๊ตฌ๋ถ„๋˜์–ด ์˜ด.                    ["hello,bye"]                ],                "fb_;": [["๐Ÿ›  In Progress"]],                "qS^H": [["Test"]],                "title": [["asdf"], ["์˜ ์‚ฌ๋ณธ"]]            },            // ์ „์ฒด ํŽ˜์ด์ง€, ์ž‘์€ ํŽ˜์ด์ง€ ์‚ฌ์ด์ฆˆ์ผ ๋•Œ ํ•จ๊ป˜ ์˜ด, ์—†์œผ๋ฉด ์•ˆ์˜ด.            "format": {                "page_icon": "๐Ÿšก",                // link์ธ ๊ฒฝ์šฐ๋Š” ๋งํฌ                "page_cover": "https://user-images.githubusercontent.com/1440854/79684011-6c948280-822e-11ea-9e23-1644903796fb.png",                // ์—…๋กœ๋“œ์ธ ๊ฒฝ์šฐ https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d53a69fd-a3e1-4914-b014-63158a1078a2/blue.png                // ๊ธฐ๋ณธ ์ œ๊ณต์ธ ๊ฒฝ์šฐ /images/blue.png => https://notion.so/images/blue.png๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅ                "page_cover_position": 0.5,                "page_full_width": true,                "page_small_text": true            },            "created_time": 1605594821014,            "last_edited_time": 1605603000000,            "parent_id": "e543505f-be64-46cd-9c55-07117dc85a92",            "parent_table": "collection",            "alive": true,            "copied_from": "15afa14b-8f9c-4b6c-97cc-46375c775cc5",            "created_by_table": "notion_user",            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "last_edited_by_table": "notion_user",            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "shard_id": 1004639,            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"        }    },    "acc3dfd0-339e-4cac-b5ba-ae8673fddfad": {        "role": "reader",        "value": {            "id": "acc3dfd0-339e-4cac-b5ba-ae8673fddfad",            "version": 106,            "type": "collection_view_page",            "view_ids": [                "be43c1c8-dd64-4cfb-9df9-efd97d8af60a",                "cfabb574-6051-47ed-9c14-ea3a1b6aead7",                "87cdd007-d8d6-464c-82f2-c7a4153bab0d",                "c09c2c36-0419-4bff-8195-bf6c2b897d6f",                "e0d39abd-4d7b-4c5c-9ce9-4984a3315932",                "83b3d2a6-6f63-4940-987d-1142e51da175"            ],            "collection_id": "e543505f-be64-46cd-9c55-07117dc85a92",            "format": {                "page_cover_position": 0.6            },            "permissions": [                {                    "role": "editor",                    "type": "user_permission",                    "user_id": "b21a69b3-a19b-438c-b599-e850190836a3"                },                {                    "role": "reader",                    "type": "public_permission"                }            ],            "created_time": 1600223639505,            "last_edited_time": 1605594780000,            "parent_id": "ee7c0178-18cf-474e-a665-83f2432f545f",            "parent_table": "space",            "alive": true,            "created_by_table": "notion_user",            "created_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "last_edited_by_table": "notion_user",            "last_edited_by_id": "b21a69b3-a19b-438c-b599-e850190836a3",            "shard_id": 1004639,            "space_id": "ee7c0178-18cf-474e-a665-83f2432f545f"        }    }}
  • get table ๋ฆฌํ„ด

    • table๋กœ ๋œ ํŽ˜์ด์ง€
      [    {        "id": "11acfd54-2ee8-4640-b3fb-1782ce9b8caa",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Basic Blocks"    },    {        "id": "084bbefe-7f25-481a-bfbb-e8aff2152e4f",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Copy of Basic Blocks"    },    {        "id": "24786a8a-3d7d-4dfd-854d-ac40559c9f82",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Code Blocks"    },    {        "id": "74bbb810-9a68-499f-8f12-25dcce846f02",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Embed Blocks"    },    {        "id": "2df7176f-d58f-4c42-921b-55e9bbf0e92e",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Table Blocks"    },    {        "id": "30894478-96e6-4f95-9095-d84be27a82a9",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Page Blocks"    },    {        "id": "cee84696-242a-4f6e-953a-2c7ecb8b1603",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Advanced Blocks"    },    {        "id": "64c69eaf-268a-4076-bf48-d8ee5f2ca8c8",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Linked Page"    },    {        "id": "6a8383c0-0a12-4859-9edc-2fe41e9cbe75",        "Status": "๐Ÿ–จ Published",        "Category": "Test",        "Name": "Recursive embed Image"    },    {        "id": "d10a7885-58f0-4ba9-b9a4-fb357ab796e8",        "Status": "๐Ÿ–จ Published",        "Category": "Example",        "Name": "Example Pages"    },    {        "id": "1c7c8eb6-ec3b-42fb-b950-63abd3c9bd61",        "Tags": ["hello", "bye"],        "Status": "๐Ÿ›  In Progress",        "Category": "Test",        "Name": "asdf์˜ ์‚ฌ๋ณธ"    },    // ์™„์ „ํžˆ ์•ˆ์ง€์› ์„ ๋•Œ๋Š” ๋นˆ๋ฌธ์ž์—ด๋กœ ์˜ด.    {        "id": "e8b450e4-f686-4d0b-9212-6241e6099a0b",        "Tags": [""],        "Status": "",        "Category": ""    }]
  • blocks

Accept vs Content-Type#

  • Accept : ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์‘๋‹ต ํ˜•์‹์„ ์ง€์ •ํ•จ.

  • Content-Type : ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ด๋Š” ์ฝ˜ํ…์ธ ์˜ ํ˜•์‹

ยท ์•ฝ 14๋ถ„

TypeScript#

๋ชฉํ‘œ#

  • TypeScript๋กœ ํƒ€์ดํ•‘์„ ์ž˜ํ•˜๋ฉด, ๋Ÿฐํƒ€์ž„ ์ „์— ๋ฏธ๋ฆฌ ์˜ค๋ฅ˜๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ฝ”๋“œ์˜ ๊ตฌํ˜„์ž๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜๋„๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž… ์‹œ์Šคํ…œ#

  • ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๋Š” ์‹œ์Šคํ…œ

  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ํƒ€์ž…์„ ์ถ”๋ก ํ•˜๋Š” ์‹œ์Šคํ…œ

โ˜ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ํƒ€์ž…์„ ์ถ”๋ก ํ•œ๋‹ค.


๋ช…์‹œ์  ํƒ€์ž… vs ์ถ”๋ก #

// ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ number๋กœ ์ถ”๋ก ๋œ๋‹ค.// ํ•˜์ง€๋งŒ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์•„์„œ, any๋กœ ์ถ”๋ก ๋œ๋‹ค.function f(a) {    return a * 38;}
// ์‚ฌ์šฉ์ž๋Š” a๊ฐ€ any ์ด๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ๋ฒ•์— ๋งž๊ฒŒ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ–ˆ์ง€๋งŒ, ์‚ฌ์šฉ์ž๋Š” ์˜ˆ์ธกํ•˜์ง€ ๋ชปํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ฒŒ ๋œ๋‹ค.console.log(f(10)); // 380console.log(f('Mark')); // NaN

์ด๊ฒƒ์€ noImplicitAny ์˜ต์…˜์„ ํ†ตํ•ด ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ any ๋กœ ์ถ”๋ก ๋˜๋Š” ๋ณ€์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.


// ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ–ˆ๋‹ค.// ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๋ฆฌํ„ด ํƒ€์ž…์€ number๋กœ ์ถ”๋ก ๋œ๋‹ค.function f(a: number) {    if (a > 0) {        return a * 38;    }}
// ์‚ฌ์šฉ์ž๋Š” ์‚ฌ์šฉ๋ฒ•์— ๋งž๊ฒŒ ์ˆซ์žํ˜•์„ ์‚ฌ์šฉํ•ด์„œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ–ˆ์ง€๋งŒ,// ์‹ค์ œ๋กœ๋Š” ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด์ด undefined๋กœ, undefined + 5๊ฐ€ ์‹คํ–‰๋˜์–ด NaN์ด ์ถœ๋ ฅ๋œ๋‹ค.
console.log(f(5)); // 190;console.log(f(-5) + 5); // NaN

strictNullChecks ์˜ต์…˜์„ ์ผœ๋ฉด ๋ชจ๋“  ํƒ€์ž…์— ์ž๋™์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ๋Š” null ๊ณผ undefined ๋ฅผ ์ œ๊ฑฐํ•ด์ค€๋‹ค.


// ์ด ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ number | undefined๋กœ ์ถ”๋ก ๋œ๋‹ค.function f(a: number) {    if (a > 0) {        return a * 38;    }}
// ํ•ด๋‹น ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ํƒ€์ž…์€ number | undefined ์ด๊ธฐ ๋•Œ๋ฌธ์—,// ํƒ€์ž…์— ๋”ฐ๋ฅด๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.// ์ปดํŒŒ์ผ ์—๋Ÿฌ๋ฅผ ๊ณ ์น˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ์ž์™€ ์ž‘์„ฑ์ž๊ฐ€ ์˜๋…ผํ•ด์•ผ ํ•œ๋‹ค.console.log(f(-5) + 5); // error TS2532: Object is possibly 'undefined'

ํ•˜์ง€๋งŒ ๊ฐ€๊ธ‰์ ์ด๋ฉด ๋ช…์‹œ์ ์œผ๋กœ ๋ฆฌํ„ด ํƒ€์ž…์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

noImplicitReturns ์˜ต์…˜์„ ์ผœ๋ฉด ํ•จ์ˆ˜ ๋‚ด์˜ ๋ชจ๋“  ์ฝ”๋“œ์˜ ์ค„๊ธฐ๊ฐ€ ๊ฐ’์„ ๋ฆฌํ„ดํ•˜์ง€ ์•Š์œผ๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.


// error TS7030: Not all code paths return a valuefunction f(a: number) {    if (a > 0) {        return a * 38;    }}

์ด๋กœ ์ธํ•ด ๋ฆฌํ„ด ํƒ€์ž…์„ ๋ช…์‹œํ•˜๊ณ , ๋ชจ๋“  ์ค„๊ธฐ์— return ์„ ์ง์ ‘ ํ•˜๋„๋ก ๊ตฌํ˜„์ž์—๊ฒŒ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๋‹ค.


๋งค๊ฐœ๋ณ€์ˆ˜์— object๊ฐ€ ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ#

function f(a) {  return `์ด๋ฆ„์€ ${a.name}์ด๊ณ  ์—ฐ๋ น๋Œ€๋Š” ${Math.floor(a.age / 10) * 10)}๋Œ€ ์ž…๋‹ˆ๋‹ค.`}
console.log(f({ name: 'Mark', age: 38 })); // ์ด๋ฆ„์€ Mark์ด๊ณ , ์—ฐ๋ น๋Œ€๋Š” 30๋Œ€ ์ž…๋‹ˆ๋‹ค.console.log(f('Mark')); // ์ด๋ฆ„์€ undefined์ด๊ณ , ์—ฐ๋ น๋Œ€๋Š” NaN๋Œ€ ์ž…๋‹ˆ๋‹ค.

JavaScript์—์„œ๋Š” ์ œ์•ฝ์‚ฌํ•ญ์œผ๋กœ ์•Œ๋ ค์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„์—์„œ ์˜ค๋ฅ˜๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜์žˆ๋‹ค.

  • Object literal type
function f(a: { name: string, age: number }): string {  return `์ด๋ฆ„์€ ${a.name}์ด๊ณ  ์—ฐ๋ น๋Œ€๋Š” ${Math.floor(a.age / 10) * 10)}๋Œ€ ์ž…๋‹ˆ๋‹ค.`}
  • ๋‚˜๋งŒ์˜ ํƒ€์ž…์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•
interface PersonInterface {  name: string;  age: number;}
type PersonTypeAlias = {  name: string;  age: number;}
function f1(a: PersonInterface): string {  return `์ด๋ฆ„์€ ${a.name}์ด๊ณ  ์—ฐ๋ น๋Œ€๋Š” ${Math.floor(a.age / 10) * 10)}๋Œ€ ์ž…๋‹ˆ๋‹ค.`}
function f2(a: PersonTypeAlias): string {  return `์ด๋ฆ„์€ ${a.name}์ด๊ณ  ์—ฐ๋ น๋Œ€๋Š” ${Math.floor(a.age / 10) * 10)}๋Œ€ ์ž…๋‹ˆ๋‹ค.`}

interface vs type alias#

structural vs nominal type system#

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” structural ํƒ€์ž… ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • structural type system : ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์œผ๋ฉด, ๊ฐ™์€ ํƒ€์ž…์ด๋‹ค.

  • nominal type system : ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์•„๋„ ์ด๋ฆ„์ด ๋‹ค๋ฅด๋ฉด, ๋‹ค๋ฅธ ํƒ€์ž…์ด๋‹ค.

interface IPerson {    name: string;    age: number;    speak(): string;}
type PersonType = {    name: string;    age: number;    speak(): string;};
  • typescript๋ฅผ nominal ์ฒ˜๋Ÿผ ์“ฐ๋Š” ๊ผผ์ˆ˜ ? - ์•„์ง ์ž˜ ์ดํ•ด๋ฅผ ๋ชปํ•จ
    type PersonID = string & {readonly brand: unique symbol};
    function PersonID(id: string): PersonID {    return id as PersonID;}
    function getPersonById(id: PersonID) {}
    getPersonById(PersonID('id-aaaaaa'));getPersonById('id-aaaaaa');

  • function
    type EatType = (food: string) => void;
    interface IEat {    (food: string): void;}
  • array
    type PersonList = string[];
    interface IPersonList {    [index: number]: string;}
  • intersection
    interface ErrorHandling {    success: boolean;    error?: {message: string};}
    interface ArtistsData {    artists: {name: string}[];}
    type ArtistsResponseType = ArtistsData & ErrorHandling;
    interface IArtistsResponse extends ArtistsData, ErrorHandling {}
  • union
    interface Bird {    fly(): void;    layEggs(): void;}
    interface Fish {    swim(): void;    layEggs(): void;}
    type BirdType = {    fly(): void;    layEggs(): void;};
    type FishType = {    swim(): void;    layEggs(): void;};
    // union์€ type alias๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.type PetType = Bird | Fish;
    // ์—๋Ÿฌ ๋ฐœ์ƒinterface IPet extends PetType {}class Pet implements PetType {}
    // ๊ฐ€๋Šฅinterface IBird extends BirdType {}class IFish implements FishType {}

Declaration Merging - interface#

  • ์ค‘๋ณต๋˜๋Š” ์ด๋ฆ„์œผ๋กœ ์„ ์–ธ๋˜์—ˆ์„ ๋•Œ ๋จธ์ง€๋˜๋Š” ๊ธฐ๋Šฅ์€ interface์—์„œ๋งŒ ์ œ๊ณต๋œ๋‹ค.

  • type์€ ์ค‘๋ณต์‹œ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

  • ์ด๋Š” ์™ธ๋ถ€ ์œ ํ‹ธ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

interface MergingInterface {    a: string;}
interface MergingInterface {    b: string;}
let mi: MergingInterface;// mi: { a: string, b: string }

์–ธ์ œ type์„ ์‚ฌ์šฉํ•˜๊ณ  ์–ธ์ œ interface๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€

  • ์˜๋ฏธ์ ์œผ๋กœ, ์—ญํ• ์ ์œผ๋กœ type alias๋ฅผ ํƒ€์ž…์— ๋ณ„์นญ์„ ๋ถ™์ผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์ฆ‰, ์ด๋ฏธ ์žˆ๋Š” ํƒ€์ž…์— ๋ณ„์นญ์„ ๋ถ™์—ฌ ๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ๋ถ€๋ฅด๊ณ  ์‹ถ์„ ๋•Œ, ์ด๋ฏธ ์žˆ๋Š” ํƒ€์ž…์„ union์œผ๋กœ ์กฐํ•ฉํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

  • ๊ทธ ์™ธ์— ์ƒˆ๋กœ์šด ํƒ€์ž…์„ ์ƒ์„ฑํ•  ๋•Œ interface๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

    • ์‹ค์ œ ๋™์ž‘ ์ƒ์˜ ์ฐจ์ด๋Š” Merging์—์„œ์˜ ์ฐจ์ด๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋‹ค.

์„œ๋ธŒ ํƒ€์ž…๊ณผ ์Šˆํผ ํƒ€์ž…#

์ง‘ํ•ฉ์˜ ๊ด€๊ณ„์—์„œ ํฌํ•จ๋˜๋Š” ์ชฝ์ด ์„œ๋ธŒ ํƒ€์ž…, ํฌํ•จํ•˜๋Š” ์ชฝ์ด ์Šˆํผ ํƒ€์ž…์ด๋‹ค.

let sub1: 1 = 1;let sup1: number = sub1;sub1 = sup1; // error! Type 'number' is not assignable to type '1'.
let sub2: number[] = [1];let sup2: object = sub2;sub2 = sup2; // error! Type '{}' is missing the following the properties from type 'number[]': length, pop, push, concat, and 16 more.
let sub3: [number, number] = [1, 2];let sup3: number[] = sub3;sub3 = sup3; // error! Type 'number[]' is not assignable to type '[number, number]'. Target requires 2 element(s) but source may have fewer.
let sub4: number = 1;let sup4: any = sub4;sub4 = sup4;
let sub5: never = 0 as never;let sup5: number = sub5;sub5 = sup5; // Type 'number' is not assignable to type 'never'.
class Animal {}class Dog extends Animal {    eat() {}}
let sub6: Dog = new Dog();let sup6: Animal = sub6;sub6 = sup6; // Property 'eat' is missing in type 'Animal' but required in type 'Dog'.

โ˜ any ์™€ never ๋Š” ์ถ”ํ›„์— ๋‹ค์‹œ ํ•™์Šต

๊ฐ™๊ฑฐ๋‚˜ ์„œ๋ธŒ ํƒ€์ž…์ธ ๊ฒฝ์šฐ ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค. โ‡’ ๊ณต๋ณ€#

let sub7: string = '';let sup7: string | number = sub7;
// object - ๊ฐ๊ฐ์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋Œ€์‘ํ•˜๋Š” ํ”„๋กœํผํ‹ฐ์™€ ๊ฐ™๊ฑฐ๋‚˜ ์„œ๋ธŒํƒ€์ž…์ด์–ด์•ผ ํ•œ๋‹ค.let sub8: {a: string; b: number} = {a: '', b: 1};let sup8: {a: string | number; b: number} = sub8;
// array - object์™€ ๋งˆ์ฐฌ๊ฐ€์ง€let sub9: Array<{a: string; b: number}> = [{a: '', b: 1}];let sup9: Array<{a: string | number; b: number}> = sub9;

ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…๋งŒ ๊ฐ™๊ฑฐ๋‚˜ ์Šˆํผํƒ€์ž…์ธ ๊ฒฝ์šฐ, ํ• ๋‹น์ด ๊ฐ€๋Šฅํ•˜๋‹ค โ‡’ ๋ฐ˜๋ณ‘#

class Person {}class Developer extends Person {    coding() {}}class StartupDeveloper extends Developer {    burning() {}}
function tellme(f: (d: Developer) => Developer) {}
// Developer => Developer ์—๋‹ค๊ฐ€ Developer => Developer ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐtellme(function dToD(d: Developer): Developer {    return new Developer();});
// Developer => Developer ์—๋‹ค๊ฐ€ Person => Developer ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ// ๋ฐ˜๋ณ‘tellme(function pToD(d: Person): Developer {    return new Developer();});
// Developer => Developer ์—๋‹ค๊ฐ€ StartupDeveloper => Developer ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒฝ์šฐ// strictFunctionType์œผ๋กœ ์—๋Ÿฌ ํ‘œ์‹œ ๊ฐ€๋Šฅtellme(function sToD(d: StartupDeveloper): Developer {    return new Developer();});

any#

  • ์ž…๋ ฅ์€ ๋งˆ์Œ๋Œ€๋กœ

  • ํ•จ์ˆ˜ ๊ตฌํ˜„์ด ์ž์œ ๋กญ๊ฒŒ โ‡’ ์ž์œ ๊ฐ€ ํ•ญ์ƒ ์ข‹์€ ๊ฑด ์•„๋‹ˆ๋‹ค.

unknown#

  • ์ž…๋ ฅ์€ ๋งˆ์Œ๋Œ€๋กœ

  • ํ•จ์ˆ˜ ๊ตฌํ˜„์€ ๋ฌธ์ œ ์—†๋„๋ก

ํƒ€์ž… ์ถ”๋ก  ์ดํ•ดํ•˜๊ธฐ#

  • let๊ณผ const์˜ ํƒ€์ž… ์ถ”๋ก  (+ as const)

  • as const

let a = 'Mark'; // stringconst b = 'Mark'; // 'Mark' => literal type
let c = 38; // numberconst d = 38; // 38 => literal type
let e = false; // booleanconst f = false; // false => literal type
let g = ['Mark', 'Haeun']; // string[]const h = ['Mark', 'Haeun']; // string[]
const i = ['Mark', 'Haeun', 'Bokdang'] as const; // readonly ['Mark', 'Haeun', 'Bokdang']
  • best common type (๊ฐ€์žฅ ๊ณตํ†ต์ ์ธ ํƒ€์ž…์„ ์ถ”๋ก ํ•ด๋‚ธ๋‹ค)
let j = [0, 1, null]; // (number | null)[]const k = [0, 1, null]; // (number | null)[]
class Animal {}class Rhino extends Animal {}class Elephant extends Animal {}class Snake extends Animal {}
let l = [new Rhino(), new Elephant(), new Snake()]; // (Rhino | Elephant | Snake)[]const m = [new Rhino(), new Elephant(), new Snake()]; // (Rhino | Elephant | Snake)[]const n = [new Animal(), new Rhino(), new Elephant(), new Snake()]; // Animal[]const o: Animal[] = [new Rhino(), new Elephant(), new Snake()]; // Animal[]
  • Contextual Typing - ์œ„์น˜์— ๋”ฐ๋ผ ์ถ”๋ก ์ด ๋‹ค๋ฆ„
// Parameter 'e' implicitly has an 'any' type.const click = (e) => {    e; // any};
document.addEventListener('click', click);document.addEventListener('click', (e) => {    e; // MouseEvent});

Type Guard๋กœ ์•ˆ์ „ํ•จ์„ ํŒŒ์•…ํ•˜๊ธฐ#

typeof Type Guard - ๋ณดํ†ต Primitive ํƒ€์ž…์ผ ๊ฒฝ์šฐ#

  • typeof๋กœ primitive ํƒ€์ž…์„ ๊ฑธ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
function getNumber(value: number | string): number {    value; // number | string    if (typeof value == 'number') {        return value;    }    value; // string    return -1;}

instanceof Type Guard - Error ๊ฐ์ฒด ๊ตฌ๋ถ„์— ๋งŽ์ด ์“ฐ์ธ๋‹ค.#

class NegativeNumberError extends Error {}
function getNumber(value: number): number | NegativeNumberError {    if (value < 0) return new NegativeNumberError();
    return value;}
function main() {    const num = getNumber(-10);
    if (num instanceof NegativeNumberError) {        return;    }
    num; // number}

in operator Type Guard - object์˜ ํ”„๋กœํผํ‹ฐ ์œ ๋ฌด๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ#

interface Admin {    id: string;    role: string;}
interface User {    id: string;    emain: string;}
function redirect(user: Admin | User) {    if ('role' in user) {        routeToAdminPage(user.role);    } else {        routeToHomePage(user.email);    }}

literal Type Guard - object์˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๊ฐ™๊ณ , ํƒ€์ž…์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ#

interface IMachine {    type: string;}
class Car implements IMachine {    type: 'CAR';    wheel: number;}
class Boat implements IMachine {    type: 'BOAT';    motor: number;}
function getWheelOrMotor(machine: Car | Boat): number {    if (machine.type === 'CAR') {        return machine.wheel;    } else {        return machine.motor;    }}

custom Type Guard#

function getWheelOrMoter(machine: any): number {    if (isCar(machine)) {        return machine.wheel;    } else if (isBoat(machine)) {        return machine.motor;    } else {        return -1;    }}
function isCar(arg: any): arg is Car {    return arg.type === 'CAR';}
function isBoat(arg: any): arg is Boat {    return arg.type === 'BOAT';}

Conditional Type#

  • `Item T`
    interface StringContainer {    value: string;    format(): string;    split(): string[];}
    interface NumberContainer {    value: number;    nearestPrime: number;    round(): number;}
    type Item1<T> = {    id: T;    container: any;};
    const item1: Item1<string> = {    id: 'aaaaaa',    container: null, // container type์— any๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— null์„ ๋„ฃ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.};
  • `Item T` - T๊ฐ€ string์ด๋ฉด StringContainer, ์•„๋‹ˆ๋ฉด NumberContainer
    type Item2<T> = {    id: T;    container: T extends string ? StringContainer : NumberContainer;};
    const item2: Item2<string> = {    id: 'aaaaaa',    container: null, // Type 'null' is not assignable to type 'StringContainer'.};
  • `Item T` - T๊ฐ€ string์ด๋ฉด StringContainer, number๋ฉด NumberContainer, ์•„๋‹ˆ๋ฉด ์‚ฌ์šฉ ๋ถˆ๊ฐ€
    type Item3<T> = {    id: T extends string | number ? T : never;    container: T extends string        ? StringContainer        : T extends number        ? NumberContainer        : never;};
    const item3: Item3<boolean> = {    id: true, // Type 'boolean' is not assignable to type 'never'.    container: null, // Type 'null' is not assignable to type 'never'.};
  • `ArrayFilter T`
    type ArrayFilter<T> = T extends any[] ? T : never;type StringsOrNumbers = ArrayFilter<string | number | string[] | number[]>;

1:11:12 ๊นŒ์ง€ ์‹œ์ฒญ ...


ยท ์•ฝ 4๋ถ„

SSR and Next.js#

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์ด๋ž€ ์„œ๋ฒ„์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

2020-11-11-201112-image-0

๋‹ค์Œ์˜ ์žฅ์ ์„ ๊ฐ€์ง„๋‹ค.

  • ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™”(SEO)

  • ๋น ๋ฅธ ์ฒซ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง

์งง์€ ํžˆ์Šคํ† ๋ฆฌ#

  • (AJAX๊ฐ€ ์—†๋˜ ์‹œ์ ˆ) ์„œ๋ฒ„์—์„œ ์ „์ฒด HTML์„ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹

  • AJAX์˜ ๋“ฑ์žฅ

    • ๋น„๋™๊ธฐ์ ์œผ๋กœ ์„œ๋ฒ„์™€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•˜์—ฌ ํŽ˜์ด์ง€ ์ „์ฒด๋ฅผ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ , ๊ฐฑ์‹ ์ด ํ•„์š”ํ•œ ์ผ๋ถ€๋งŒ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ.

    • ๋™์ ์œผ๋กœ HTML์„ ๋งŒ๋“ค๋ฉด์„œ JavaScript์˜ ์—ญํ• ์ด ๋Š˜์–ด๋‚˜๊ฒŒ ๋จ.

  • SPA๋กœ..

  • JavaScript MVC Framework์˜ ๋“ฑ์žฅ

    • Backbone.js, Ember, Knockout ...

    • MVC Framework์˜ ๋ํŒ์™• AngularJS

  • React์˜ ๋“ฑ์žฅ

    • Virtual DOM์„ ์ด์šฉ

    • Flux ์•„ํ‚คํ…์ณ

    • ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง ์ง€์›

      • (๋ฐฐ๊ฒฝ) V8 ์—”์ง„, Node.js ๋“ฑ์œผ๋กœ ์„œ๋ฒ„์—์„œ๋„ JS ๊ธฐ๋ฐ˜์˜ ํด๋ผ์ด์–ธํŠธ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ์Œ

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์€ ๋‘ ๋ฒˆ ๋ Œ๋”๋ง ํ•œ๋‹ค. ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์ƒ์„ฑ๋œ HTML์—๋Š” ์ด๋ฒคํŠธ ์†์„ฑ์ด ์—†๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ Œ๋”๋งํ•  ๋•Œ ์ด๋ฏธ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์ด ๋˜์–ด ์žˆ๋‹ค๋ฉด, ์ƒ์„ฑ๋œ DOM์— ์˜ค์ง ์ด๋ฒคํŠธ ์†์„ฑ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค.

์™œ React์™€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์ธ๊ฐ€?

๋ฆฌ์•กํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง#

  • renderToString : ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ HTML์— DOM์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

  • hydrate : ๋” ์š”์†Œ์— ํ•„์š”ํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.

๐Ÿ“Œ ๋‚˜์ค‘์— ์ง์ ‘ ํ•ด๋ด์•ผ๊ฒ ๋‹ค..!

Next.js#

Next๋Š” ์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์— ํŠนํ™”๋œ ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค.

  • ์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง์˜ ์žฅ์ 

    • SEO

    • ์ดˆ๊ธฐ ๋กœ๋”ฉ ์„ฑ๋Šฅ ๊ฐœ์„ 

  • ์ด๋ฏธ์ง€ ๋ฆฌ์†Œ์Šค ์ตœ์ ํ™”

  • ์ •์  ํŒŒ์ผ ์„œ๋น™

    • ๋ฐฐ๋„ˆ ์ด๋ฏธ์ง€, ์•„์ด์ฝ˜ ๋“ฑ๋“ฑ์—์„œ ์‚ฌ์šฉํ•จ
  • ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ… ์ž๋™ํ™”

  • ์›นํŒฉ ๊ธฐ๋ฐ˜ ํ™˜๊ฒฝ (create-react-app๊ณผ ๋‹ฌ๋ฆฌ ์›นํŒฉ ์„ค์ • ๋ณ€๊ฒฝ์ด ์‰ฝ๋‹ค.)

์„œ๋ฒ„์—์„œ ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๊ธฐ#

  • getInitialProps : ๊ตฌ๋ฒ„์ „์—์„œ ์‚ฌ์šฉํ•œ data fetching ๋ฐฉ์‹

  • getStaticProps : ๋นŒ๋“œ ์‹œ ๊ณ ์ •๋˜๋Š” ๊ฐ’์œผ๋กœ ๋นŒ๋“œ ์ดํ›„์—๋Š” ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

    • static data๋ฅผ ์œ„ํ•ด (๋ณ€๊ฒฝ๋˜์ง€ ์•Š์„ ๋ฐ์ดํ„ฐ. ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ๋“ฑ๋“ฑ ...)
  • getServerSideProps : ๋นŒ๋“œ์™€ ์ƒ๊ด€์—†์ด ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜จ๋‹ค.

    • ๋งค๋ฒˆ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•ด (์ƒํ’ˆ ๋ชฉ๋ก. ์‹ค์‹œ๊ฐ„ ๋‰ด์Šค ๋“ฑ๋“ฑ ...)
  • getStaticPaths : ๋นŒ๋“œ ํƒ€์ž„ ๋•Œ ์ •์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ๊ฒฝ๋กœ ์„ค์ •.


ยท ์•ฝ 12๋ถ„

๋ชจ๋ฐ”์ผ ์‚ฌํŒŒ๋ฆฌ ๋””๋ฒ„๊น…#

  • ์•„์ดํฐ์„ ๋งฅ๋ถ์— ์—ฐ๊ฒฐํ•œ๋‹ค.

  • ์•„์ดํฐ์—์„œ ๋””๋ฒ„๊น…ํ•˜๊ณ ์ž ํ•˜๋Š” ์›นํŽ˜์ด์ง€๋ฅผ Safari์— ๋„์šด๋‹ค.

  • ๋งฅ๋ถ์—์„œ Safari๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

  • ๊ฐœ๋ฐœ์ž์šฉ > iPhone > Safari ์›น ํŽ˜์ด์ง€ ์„ ํƒ

    2020-11-10-201110-image-0

  • ์š”์†Œ, ์ฝ˜์†”, ์†Œ์Šค, ๋„คํŠธ์›Œํฌ ๋“ฑ ์‚ฌํŒŒ๋ฆฌ์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋กœ ๋””๋ฒ„๊น…ํ•  ์ˆ˜ ์žˆ๋‹ค.

    2020-11-10-201110-image-1

Debugging Your iPhone Mobile Web App With Safari Dev Tools

๋ชจ๋ฐ”์ผ ์‚ฌํŒŒ๋ฆฌ๋ฅผ ๋งฅ์˜ Chrome์—์„œ ๋””๋ฒ„๊น…ํ•˜๊ธฐ#

๋ชจ๋ฐ”์ผ Safari๋ฅผ ๋งฅ์˜ Chrome์—์„œ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์— ์•Œ์•„๋ด์•ผ๊ฒ ๋‹ค.

Jon Sadka - How to debug an issue in Chrome for iOS using remote debugging

๋ฆฌ์•กํŠธ#

  • ๋ฆฌ์•กํŠธ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ํŠธ๋ฆฌ ํ˜•ํƒœ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ํ‘œํ˜„ํ•œ๋‹ค.

  • ์ด๋ฅผ Virtual-DOM์œผ๋กœ ๋ถ€๋ฅด๋Š”๋ฐ, ์ด๋Š” JavaScript ์ผ๋ฐ˜ ๊ฐ์ฒด์ด๋‹ค. (Plain Object)

  • ๊ธฐ์กด VanillaJS๋Š” UI๋ฅผ ๋ช…๋ นํ˜•์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜์ง€๋งŒ, React๋Š” ์„ ์–ธํ˜•์œผ๋กœ UI๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ#

  • ์ปดํฌ๋„ŒํŠธ๋Š” ๋‚ด๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ์ƒํƒœ ๊ฐ’์ธ state ์™€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‚ด๋ ค ์ฃผ๋Š”์†์„ฑ ๊ฐ’ props ๋ฅผ ๊ฐ€์ง„๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ๋Š” state , props ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด render() ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์–ด ํ™”๋ฉด์„ ๊ฐฑ์‹ ํ•œ๋‹ค.

  • UI ๋ฐ์ดํ„ฐ(์ƒํƒœ๊ฐ’๊ณผ ์†์„ฑ๊ฐ’)๋กœ ๋ทฐ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์ด ๋ฆฌ์•กํŠธ์˜ ํ•ต์‹ฌ์ด๋‹ค.

  • setState ๋Š” ๋น„๋™๊ธฐ๋กœ ๋™์ž‘ํ•œ๋‹ค.

๋ฆฌ์•กํŠธ์˜ ๋ Œ๋”๋ง ๊ณผ์ •#

  • ์ปดํฌ๋„ŒํŠธ์˜ Props๋‚˜ State์˜ ๋ณ€๊ฒฝ์ด ์žˆ์„ ๋•Œ, ์ปดํฌ๋„ŒํŠธ์˜ ์ด์ „ ์ƒํƒœ ์—˜๋ฆฌ๋จผํŠธ์™€ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง„ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋น„๊ตํ•˜๊ณ  ์‹ค์ œ DOM์˜ ์—…๋ฐ์ดํŠธ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. ๋น„๊ตํ•˜์—ฌ์ฐพ์€ ๋ณ€๊ฒฝ ์ ์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฐฑ์‹ ํ•œ๋‹ค.

  • ์ปดํฌ๋„ŒํŠธ์˜ setState ๋ฉ”์„œ๋“œ๊ฐ€ ์ˆ˜ํ–‰๋˜๋ฉด, ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ Dirty ์ฒดํฌํ•˜๊ณ , ๋‹ค์Œ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ๋ฐฐ์น˜ ์ž‘์—…์œผ๋กœ ๋Œ€์ƒ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ๋‹ค. (๋น„๋™๊ธฐ )

  • ์ด๋Ÿฌํ•œ ๋ฆฌ์•กํŠธ์˜ ๋ Œ๋”๋ง ๊ณผ์ •์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ชผ๊ฐค ์ˆ˜ ์žˆ๋‹ค.

    • ๋ณ€๊ฒฝ ์ ์„ ์ฐพ๋Š” Reconciliation์˜ Diffing ์•Œ๊ณ ๋ฆฌ์ฆ˜ (render or reconciliation phase)

    • ๋ณ€๊ฒฝ ์ ์„ ์‹ค์ œ UI์— ์ ์šฉํ•˜๋Š” ReactDOMComponent.updateComponent (commit phase)

Reconciliation: The diffing algorithm#

Reconciliation์€ ์–ด๋–ค ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ์ „/ํ›„ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ๋น„๊ต(Diff)ํ•˜์—ฌ, ๊ฐฑ์‹ ์ดํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ์„ ์ฐพ์•„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์˜ DOM ์กฐ์ž‘์„์ตœ์†Œํ™”์‹œํ‚จ๋‹ค.

๋‹ค์‹œ ์ •๋ฆฌ

  • render() ์—์„œ ์ƒˆ๋กœ์šด ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ๋ฅผ ์ƒ์„ฑ

  • ์ด์ „ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ์™€ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ ์ ์„ ์ฐพ์•„ ์—…๋ฐ์ดํŠธ

๊ทธ๋Ÿฐ๋ฐ Diff ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ O(n^3)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๋ฆฌ์•กํŠธ๋Š” ๋‹ค์Œ์˜ ๋ฐฉ๋ฒ•์œผ๋กœ O(n)์— ๊ทผ์‚ฌํ•œ ํœด๋ฆฌ์Šคํ‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

  • ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋‘ ์—˜๋ฆฌ๋จผํŠธ๋Š” ๋‹ค๋ฅธ ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค.

  • ๊ฐ™์€ ๋ ˆ๋ฒจ์˜ ์—˜๋ฆฌ๋จผํŠธ์— key ํ”„๋กœํผํ‹ฐ๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.

โ˜ ํœด๋ฆฌ์Šคํ‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜ : ์ง๊ด€์— ์˜์กดํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜. ์ฆ‰ ํœด๋ฆฌ์Šคํ‹ฑ์€ ๋ณดํ†ต ํ•ฉ๋ฆฌ์ ์ธ์‹คํ–‰ ์‹œ๊ฐ„์„ ๊ฐ€์ง€์ง€๋งŒ ๊ทธ๊ฒƒ์ด ํ•ญ์ƒ ๊ทธ๋ ‡๋‹ค๋Š” ์–ด๋– ํ•œ ์ถ”๋ก  ๊ณผ์ •์ด๋‚˜ ์ฆ๋ช…์ด ์—†๋‹ค.

๊ฐ™์€ ์œ„์น˜์—์„œ ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ

  1. ๊ธฐ์กด ํŠธ๋ฆฌ๋ฅผ ์ œ๊ฑฐ ํ›„ ์ƒˆ๋กœ์šด ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ ๋‹ค.

  2. ๊ธฐ์กด ํŠธ๋ฆฌ ์ œ๊ฑฐ ์‹œ ํŠธ๋ฆฌ ๋‚ด๋ถ€(ํ•˜์œ„)์˜ ์—˜๋ฆฌ๋จผํŠธ/์ปดํฌ๋„ŒํŠธ๋“ค์€ ๋ชจ๋‘ ์ œ๊ฑฐํ•œ๋‹ค. (์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ ์ œ๊ฑฐ๋˜๋ฉด์„œ componentWillUnmount() ๊ฐ€ ์‹คํ–‰๋จ.) ์ด์ „ ํŠธ๋ฆฌ์˜ ๋ชจ๋“  state๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค.

  3. ์ƒˆ๋กœ์šด ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค ๋•Œ ๋‚ด๋ถ€ ์—˜๋ฆฌ๋จผํŠธ/์ปดํฌ๋„ŒํŠธ๋“ค๋„ ๋ชจ๋‘ ์ƒˆ๋กœ ๋งŒ๋“ ๋‹ค. (์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ componentDidMount() ๊ฐ€ ์‹คํ–‰๋จ.)

๊ฐ™์€ ์œ„์น˜์—์„œ ์—˜๋ฆฌ๋จผํŠธ์˜ ํƒ€์ž…์ด ๊ฐ™์€ ๊ฒฝ์šฐ

  1. ์—˜๋ฆฌ๋จผํŠธ์˜ attributes ๋ฅผ ๋น„๊ตํ•œ๋‹ค.

  2. ๋ณ€๊ฒฝ๋œ attributes ๋งŒ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

  3. ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๋“ค์— diff ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์žฌ๊ท€์ ์œผ๋กœ ์ ์šฉํ•œ๋‹ค.

๊ฐ™์€ ์œ„์น˜์—์„œ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ‘œํ˜„ํ•˜๊ณ  ๊ทธ ํƒ€์ž…์ด ๊ฐ™์€ ๊ฒฝ์šฐ

  1. ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค ์ž์ฒด๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. (state๊ฐ€ ์œ ์ง€๋œ๋‹ค.)

  2. ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค์˜ ์—…๋ฐ์ดํŠธ ์ „ ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์„œ๋“œ ๋“ค์ด ํ˜ธ์ถœ๋˜๋ฉฐ props๊ฐ€ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.

  3. render() ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ์˜ ์ด์ „ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ์™€ ๋‹ค์Œ ์—˜๋ฆฌ๋จผํŠธ ํŠธ๋ฆฌ์—๋Œ€ํ•ด diff ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์žฌ๊ท€์ ์œผ๋กœ ์ ์šฉํ•œ๋‹ค.

์ž์‹ ์—˜๋ฆฌ๋จผํŠธ ์žฌ๊ท€

  • ๋ฆฌ์•กํŠธ๋Š” ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์ ์ธ ๋น„๊ต๋ฅผ ํ•  ๋•Œ ๋‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•˜๊ณ  ์ฐจ์ด์ ์ด ์žˆ์œผ๋ฉด ๋ณ€๊ฒฝ์„ ์ƒ์„ฑํ•œ๋‹ค.

  • ์ •๋ ฌ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์— ์ทจ์•ฝํ•˜๋‹ค.

keys

  • ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๋“ค์ด key๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด key๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ํŠธ๋ฆฌ์™€ ์ดํ›„ ํŠธ๋ฆฌ์˜ ์ž์‹ ๋“ค์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

Avoid Reconciliation#

  • ์ปดํฌ๋„ŒํŠธ์˜ ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

    • ShouldComponentUpdate ํ•จ์ˆ˜๊ฐ€ return false ํ•˜๋„๋ก ํ•œ๋‹ค.

    • ์ปดํฌ๋„ŒํŠธ๊ฐ€ PureComponent ๋ฅผ ์ƒ์†๋ฐ›๋„๋ก ํ•œ๋‹ค.

    • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ React.memo() ๋กœ ๊ฐ์‹ธ์„œ export ํ•œ๋‹ค.

โ˜ ํ•ต์‹ฌ์€ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ state , props ๊ฐ€ ๋ณ€๊ฒฝ ๋˜์—ˆ์„ ๋•Œ๋งŒ ๋ Œ๋”๋งํ•˜๋„๋กํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ๋ฆฌ์•กํŠธ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ง•ํ•˜๋Š”๊ฒƒ์ด๋‹ค.

๊ฐ€์žฅ ์ข‹์€ ์ผ€์ด์Šค๋Š” ๊ฐ™์€ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ์˜ํ•ด ๊ฐ™์€ props ๋กœ ์ž์ฃผ ๋ Œ๋”๋ง ๋ ๋•Œ์ด๋‹ค. ์ด์ „ ๋ฉ”๋ชจ์ด์ง• ๊ฒฐ๊ณผ์™€ props ๊ฐ€ ๊ฐ™๋‹ค๋ฉด ๋‚ด๋ถ€๋ฅผ ๋น„๊ตํ•˜์ง€ ์•Š๊ณ  ๋ฉ”๋ชจ์ด์ง•๋œ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐ˜๋Œ€๋กœ props ๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„์ด๋ผ๋ฉด, ์ด์ „ props ์™€ ๋‹ค์Œ props ๋น„๊ต๋ฅผ ํ•˜๊ณ , ์ปดํฌ๋„ŒํŠธ ๋ Œ๋”๋ง์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”ํ•œ props ๋น„๊ต๋ฅผ ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ๋˜ํ•œ ๋ฉ”๋ชจ์ด์ง•์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚จ์šฉํ•ด์„  ์•ˆ๋œ๋‹ค.

์ฒ˜์Œ๋ถ€ํ„ฐ ์„ฑ๋Šฅ์— ์ตœ์ ํ™”๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋น„ํšจ์œจ์ ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ ์ ˆํžˆ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ์ค‘์š”ํ•˜๋‹ค. ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ ์ ˆํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์ด์Šˆ๋ฅผ๋น ๋ฅด๊ฒŒ ํŒŒ์•…ํ•˜๊ณ  ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์ „๋žต์ด๋‹ค.

UI ๋Ÿฐํƒ€์ž„์œผ๋กœ์„œ์˜ React

์žฌ์กฐ์ • (Reconciliation) - React

์„ฑ๋Šฅ ์ตœ์ ํ™” - React

React ๋ Œ๋”๋ง๊ณผ ์„ฑ๋Šฅ ์•Œ์•„๋ณด๊ธฐ : TOAST Meetup

React.memo() ํ˜„๋ช…ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ

๋ฆฌ์•กํŠธ ํ›…(Hook)#

ํ›…(Hook)์ด๋ž€?#

  • ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ React state๋ฅผ ์—ฐ๋™(hook into)ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜.

  • ์ฆ‰ ์ƒํƒœ๋ฅผ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์— ๋™๊ธฐํ™” ํ•ด์ค€๋‹ค. (์ด ๋ง์€ ์ƒํƒœ๊ฐ€ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ๋‚ดํฌํ•จ.)

๋™๊ธฐ#

  • ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ์ƒํƒœ์™€ ๊ด€๋ จ๋œ ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

    • render props, HOC์™€ ๊ฐ™์€ ํŒจํ„ด์€ ๋ž˜ํผ๋ฅผ ๊นŠ๊ฒŒ ๋งŒ๋“ ๋‹ค.
  • ๋ผ์ดํ”„์‚ฌ์ดํด ๋ฉ”์„œ๋“œ ๋“ค์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณต์žกํ•˜๊ณ  ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค.

  • ํด๋ž˜์Šค๋ณด๋‹ค ํ•จ์ˆ˜๊ฐ€ ์ง๊ด€์ ์ด๋‹ค. this ๋ฐ”์ธ๋”ฉ


ํ›…์˜ ๊ทœ์น™#

โ˜ ๋ฆฌ์•กํŠธ๋Š” ํ›…์ด ํ˜ธ์ถœ๋˜๋Š” ์ˆœ์„œ์— ์˜์กดํ•œ๋‹ค. (์ƒํƒœ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ํ˜ธ์ถœ ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.)

  • ์ตœ์ƒ์œ„(at the Top Level)์—์„œ๋งŒ ํ›…์„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. (๋ฐ˜๋ณต๋ฌธ, ์กฐ๊ฑด๋ฌธ, ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•˜์ง€ ๋ง๋ผ)

    // ๐Ÿ”ด ์กฐ๊ฑด๋ฌธ์— Hook์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์ฒซ ๋ฒˆ์งธ ๊ทœ์น™์„ ๊นผ์Šต๋‹ˆ๋‹คif (name !== '') {    useEffect(function persistForm() {        localStorage.setItem('formData', name);    });}
  • ์˜ค์ง React ํ•จ์ˆ˜ ๋‚ด์—์„œ Hook์„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค. (์ผ๋ฐ˜ JS ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœํ•˜์ง€ ๋ง๋ผ)

โ˜ ๋ฆฌ์•กํŠธ์˜ ํ›…์€ ๋ Œ๋”๋ง ๋˜๋Š” ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ์˜ ํ•œ ์ˆ˜์ค€ ์œ„์˜ ์™ธ๋ถ€ ๊ณต๊ฐ„(์‹คํ–‰ ์ปจํ…์ŠคํŠธ)์— ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(๋ฐฐ์—ด)ํ˜•ํƒœ๋กœ ์ €์žฅ๋˜๋Š” ๋ฐ์ดํ„ฐ( state , setter )์ด๋‹ค. ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์™€ ๊ณต์œ ๋˜์ง€ ์•Š๊ณ , ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ ์—‘์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋‹ค.

useState#

useState์—์„œ ๋ฐ˜ํ™˜๋œ setter ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, React์—๊ฒŒ ๋‚ด๋ถ€์ ์œผ๋กœ ์•ก์…˜์„ dispatch ํ•˜๊ฒŒ ๋˜๊ณ , ์ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ new state๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์—…๋ฐ์ดํŠธ ํ•ด์•ผ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ฆฐ๋‹ค.

React hooks: not magic, just arrays

useEffect#

  • ๋ Œ๋”๋ง ์ดํ›„(DOM ์—…๋ฐ์ดํŠธ ํ›„)์— ์ˆ˜ํ–‰ํ•  "side effect"๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

Fiber#

  • virtualDOM์˜ ์ฆ๋ถ„ ๋ Œ๋”๋ง์„ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•จ.

  • requestIdleCallback ์„ ํ™œ์šฉ.

  • ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ธฐ ์œ„ํ•œ ๋‚ด๋ถ€ ๊ฐ์ฒด

  • ๋‚ด์žฅ ์Šคํƒ์— ์˜์กดํ•œ ๋™๊ธฐ์‹ ์žฌ๊ท€ ๋ชจ๋ธ์—์„œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์™€ ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋Š” ๋น„๋™๊ธฐ์‹๋ชจ๋ธ๋กœ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์žฌ๊ตฌํ˜„ํ•จ.

    • ํ˜ธ์ถœ ์Šคํƒ์„ ๋งˆ์Œ๋Œ€๋กœ ์ค‘๋‹จํ•˜๊ณ  ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์ˆ˜๋™์œผ๋กœ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด

React Fiber Architecture - A Deep Dive

ยท ์•ฝ 8๋ถ„

์›นํŒฉ#

  • ์›นํŒฉ์€ static module bundler์ด๋‹ค.

  • ์›นํŒฉ์€ ์—”ํŠธ๋ฆฌ ํฌ์ธํŠธ๋ถ€ํ„ฐ ํ”„๋กœ์„ธ์Šคํ•˜์—ฌ, ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“ˆ์— ๋Œ€ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ dependency graph๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ ํ•˜๋‚˜์˜ ๋ฒˆ๋“ค ํŒŒ์ผ์„ ๊ตฌ์„ฑํ•œ๋‹ค .

    • Entry : dependency graph๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ ์‹œ์ž‘ํ•  ์ง„์ž…์ 

    • Output : ๋ฒˆ๋“ค๋œ ๊ฒฐ๊ณผ ํŒŒ์ผ

    • Loader : ๊ธฐ๋ณธ์ ์œผ๋กœ js, json ํŒŒ์ผ๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ, loader๋Š” ์›นํŒฉ์ด ๋‹ค๋ฅธ์œ ํ˜•์˜ ํŒŒ์ผ๋„ ๋ชจ๋“ˆ๋กœ์„œ ๊ฐ€์ ธ์˜ค๊ณ  dependency graph๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค. ex) jpg ์ด๋ฏธ์ง€, ํฐํŠธ, ...

    • Plugin : ๋ฒˆ๋“ค๋ง ์ตœ์ ํ™”, ์ž์› ๊ด€๋ฆฌ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜์˜ ์ฃผ์ž… ๋“ฑ ๋‹ค์–‘ํ•œ ๋ชฉ์ ์˜ ํ™˜๊ฒฝ ์„ค์ •์„ ์œ„ํ•ด ์‚ฌ์šฉ.

    • Mode : production | development ๋“ฑ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ์›นํŒฉ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

HTTP#

HTTP ๋ฒ„์ „๋ณ„ ์ฐจ์ด์ #

HTTP์˜ ์ง„ํ™”

HTTP/0.9#

  • ์ดˆ๊ธฐ ๋ฒ„์ „

  • GET ์ด ์œ ์ผํ•œ ๋ฉ”์„œ๋“œ

  • HTTP ํ—ค๋”๊ฐ€ ์—†์—ˆ๊ณ  HTML ํŒŒ์ผ๋งŒ ์ „์†ก๋  ์ˆ˜ ์žˆ์—ˆ์Œ.

  • ์ƒํƒœ๋‚˜ ์˜ค๋ฅ˜ ์ฝ”๋“œ๋„ ์—†์—ˆ๋‹ค.

HTTP/1.0#

  • ๋ฒ„์ „ ์ •๋ณด๊ฐ€ ์š”์ฒญ์œผ๋กœ ์ „์†ก๋˜๊ธฐ ์‹œ์ž‘ ex) GET /mypage.html HTTP/1.0

  • ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ ์‘๋‹ต์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ๋ถ™์–ด ์ „์†ก๋จ.

  • HTTP ํ—ค๋” ๊ฐœ๋…์ด ๋„์ž…๋จ.

    • HTML ํŒŒ์ผ ์™ธ์— ๋‹ค๋ฅธ ๋ฌธ์„œ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ.

HTTP/1.1#

  • HTTP์˜ ์ฒซ ๋ฒˆ์งธ ํ‘œ์ค€ ๋ฒ„์ „

  • ์ปค๋„ฅ์…˜์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ.

    • ์›๋ณธ ๋ฌธ์„œ ๋‚ด์— ์ž„๋ฒ ๋“œ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์œ„ํ•ด์„œ, ๊ธฐ์กด์— ์—ฐ๊ฒฐ๋œ ์ปค๋„ฅ์…˜์„ ๋‹ค์‹œ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ์Œ.
  • ํŒŒ์ดํ”„๋ผ์ด๋‹์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์ด ์™„์ „ํžˆ ์ „์†ก๋˜๊ธฐ ์ „์— ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์ „์†ก์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ–ˆ๋‹ค.

2020-11-08-201108-image-0

HTTP/2#

  • ์ด์ง„ ํ”„๋กœํ† ์ฝœ (1.1์€ ํ…์ŠคํŠธ ํ”„๋กœํ† ์ฝœ)

  • Multiplexing

2020-11-08-201108-image-1

2020-11-08-201108-image-2

โ˜ multiplexing vs pipelining

  • pipelining์€ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค โ†’ Head Of Line blocking ๋ฌธ์ œ

  • multiplexing์€ ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค.

2020-11-08-201108-image-3

HTTP 1.1 vs HTTP.2 vs HTTP/2 with Push - Manning

HTTP ์ƒํƒœ ์ฝ”๋“œ#

1xx : ์ •๋ณด ์‘๋‹ต#

2xx : ์„ฑ๊ณต ์‘๋‹ต#

  • 200 : OK. ์š”์ฒญ ์„ฑ๊ณต

  • 201 : Created. ์ƒ์„ฑ ์š”์ฒญ ์„ฑ๊ณต

  • 202 : Accepted. ์š”์ฒญ ์ˆ˜๋ฝ

  • 204 : ์„ฑ๊ณตํ–ˆ์œผ๋‚˜ ๋ฐ˜ํ™˜ํ•  ๊ฒƒ์ด ์—†์Œ

3xx : ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ๋ฉ”์‹œ์ง€#

  • 300 : Multiple choices. ์—ฌ๋Ÿฌ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์š”์ฒญ ๊ฒฐ๊ณผ ๋ชฉ๋ก

  • 301 , 302 , 303 : Redirect. ๋ฆฌ์†Œ์Šค ์œ„์น˜๊ฐ€ ๋ณ€๊ฒฝ๋œ ์ƒํƒœ

  • 304 : Not modified. ๋ฆฌ์†Œ์Šค๊ฐ€ ์ˆ˜์ •๋˜์ง€ ์•Š์•˜์Œ

4xx : ํด๋ผ์ด์–ธํŠธ ์—๋Ÿฌ ์‘๋‹ต#

  • 400 : Bad Request. ์š”์ฒญ ์˜ค๋ฅ˜

  • 401 : Unauthorized. ๊ถŒํ•œ ์—†์Œ

  • 403 : Forbidden. ์š”์ฒญ ๊ฑฐ๋ถ€

  • 404 : Not Fount. ๋ฆฌ์†Œ์Šค๊ฐ€ ์—†๋Š” ์ƒํƒœ

5xx : ์„œ๋ฒ„ ์—๋Ÿฌ ์‘๋‹ต#

  • 500 : ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌ ๋ชปํ•จ

  • 501 : Not Implemented. ์„œ๋ฒ„๊ฐ€ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์š”์ฒญ

  • 503 : Service Unavailable. ๊ณผ๋ถ€ํ•˜ ๋“ฑ์œผ๋กœ ๋‹น์žฅ ์„œ๋น„์Šค๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ

๋ธŒ๋ผ์šฐ์ € ๋ Œ๋”๋ง ๊ณผ์ •#

2020-11-08-201108-image-4

2020-11-08-201108-image-5

  • DOM ๋ฐ CSSOM ํŠธ๋ฆฌ๋Š” ๊ฒฐํ•ฉ๋˜์–ด ๋ Œ๋”๋ง ํŠธ๋ฆฌ๋ฅผ ํ˜•์„ฑํ•ฉ๋‹ˆ๋‹ค.

  • ๋ Œ๋”๋ง ํŠธ๋ฆฌ์—๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋…ธ๋“œ๋งŒ( ๋ฉ”ํƒ€ ํƒœ๊ทธ, ์Šคํฌ๋ฆฝํŠธํƒœ๊ทธ, display: none ๋“ฑ์ด ์ œ์™ธ๋จ. )ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

    โ˜ visibility: hidden , display: none ์€ ๋‹ค๋ฅด๋‹ค.

  • ๋ ˆ์ด์•„์›ƒ์€ ๊ฐ ๊ฐ์ฒด์˜ ์ •ํ™•ํ•œ ์œ„์น˜ ๋ฐ ํฌ๊ธฐ๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค. (๊ฒฝ์šฐ์— ๋”ฐ๋ผ "๋ฆฌํ”Œ๋กœ์šฐ" ๋ผ๊ณ ๋„ ํ•œ๋‹ค.)

  • ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋Š” ์ตœ์ข… ๋ Œ๋”๋ง ํŠธ๋ฆฌ์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ํŽ˜์ธํŠธ์ด๋ฉฐ, ํ”ฝ์…€์„ ํ™”๋ฉด์— ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. (๊ฒฝ์šฐ์— ๋”ฐ๋ผ "๋ฆฌํŽ˜์ธํŠธ"๋ผ๊ณ ๋„ ํ•œ๋‹ค.)


๋ธŒ๋ผ์šฐ์ € ๋ Œ๋”๋ง ์ตœ์ ํ™”#

์˜ค๋Š˜๋‚  ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๊ธฐ๋Š” ์ดˆ๋‹น 60ํšŒ(60fps)์˜ ๋นˆ๋„๋กœ ํ™”๋ฉด์„ ์ƒˆ๋กœ ๊ณ ์นœ๋‹ค. ๋”ฐ๋ผ์„œ๊ฐ ํ”„๋ ˆ์ž„์—๋Š” 16ms ๊ฐ€๋Ÿ‰์˜ ์‹œ๊ฐ„๋งŒ ํ• ๋‹น๋œ๋‹ค. (1์ดˆ / 60 = 16.66ms) ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‹คํ–‰ ์ค€๋น„๋ฅผ ํ•˜๋Š” ์‹œ๊ฐ„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 10ms ๋‚ด์— ๋ชจ๋“  ์ž‘์—…์„ ์™„๋ฃŒํ•ด์•ผ ํ•œ๋‹ค.

ํ”ฝ์…€ ํŒŒ์ดํ”„๋ผ์ธ#

2020-11-08-201108-image-6

2020-11-08-201108-image-7

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์‹œ๊ฐ์  ๋ณ€ํ™”๋ฅผ ์ผ์œผํ‚ค๋Š” ์ž‘์—…. CSS Animation, Transitions, Web Animation API ์—ญ์‹œ ํฌํ•จ.

  • ์Šคํƒ€์ผ ๊ณ„์‚ฐ : ์–ด๋–ค ์Šคํƒ€์ผ ๊ทœ์น™(CSS)์„ ์–ด๋–ค ์š”์†Œ์— ์ ์šฉํ• ์ง€ ๊ณ„์‚ฐํ•˜๋Š” ํ”„๋กœ์„ธ์Šค

  • ๋ ˆ์ด์•„์›ƒ : ํ™”๋ฉด์—์„œ ์–ผ๋งˆ์˜ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๊ณ  ์–ด๋””์— ๋ฐฐ์น˜๋˜๋Š”์ง€ ๊ณ„์‚ฐํ•˜๊ธฐ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ํŽ˜์ธํŠธ : ํ”ฝ์…€์„ ์ฑ„์šฐ๋Š” ํ”„๋กœ์„ธ์Šค. ํ…์ŠคํŠธ, ์ƒ‰, ์ด๋ฏธ์ง€, ๊ฒฝ๊ณ„ ๋ฐ ๊ทธ๋ฆผ์ž ๋“ฑ ๋ชจ๋“  ์‹œ๊ฐ์  ๋ถ€๋ถ„์„ ๊ทธ๋ฆฌ๋Š” ์ž‘์—…. ๋ ˆ์ด์–ด๋ผ๊ณ  ํ•˜๋Š” ๋‹ค์ˆ˜์˜ ํ‘œ๋ฉด์—์„œ ์ˆ˜ํ–‰

  • ํ•ฉ์„ฑ : ํŽ˜์ด์ง€์˜ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์ด ์—ฌ๋Ÿฌ ๋ ˆ์ด์–ด๋กœ ๊ทธ๋ ค์กŒ๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€๊ฐ€ ์ •ํ™•ํžˆ๋ Œ๋”๋ง ๋˜๋ ค๋ฉด ์ •ํ™•ํ•œ ์ˆœ์„œ๋กœ ํ™”๋ฉด์— ๊ทธ๋ ค์•ผ ํ•œ๋‹ค.

โ˜ ์ฝ”๋“œ๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ์˜ ์–ด๋–ค ๋ถ€๋ถ„์„ ํŠธ๋ฆฌ๊ฑฐ ํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”

1. JS / CSS > ์Šคํƒ€์ผ > ๋ ˆ์ด์•„์›ƒ > ํŽ˜์ธํŠธ > ํ•ฉ์„ฑ#

2020-11-08-201108-image-8

๋ ˆ์ด์•„์›ƒ ๋„ˆ๋น„, ๋†’์ด, ์™ผ์ชฝ ๋˜๋Š” ์ƒ๋‹จ ์œ„์น˜ ๋“ฑ ์š”์†Œ์˜ ๊ธฐํ•˜ํ•™์  ํ˜•ํƒœ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” "layout" ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‹ค๋ฅธ ๋ชจ๋“  ์š”์†Œ๋ฅผ ํ™•์ธํ•˜๊ณ  ํŽ˜์ด์ง€์— ๋Œ€ํ•ด "๋ฆฌํ”Œ๋กœ์šฐ"๋ฅผ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. ์˜ํ–ฅ์„ ๋ฐ›์€ ์˜์—ญ์ด ์žˆ์œผ๋ฉด ๋‹ค์‹œ ํŽ˜์ธํŠธํ•˜๊ณ , ๋‹ค์‹œํ•ฉ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

2. JS / CSS > ์Šคํƒ€์ผ > ํŽ˜์ธํŠธ > ํ•ฉ์„ฑ#

2020-11-08-201108-image-9

ํŽ˜์ด์ง€์˜ ๋ ˆ์ด์•„์›ƒ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š” ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง€, ํ…์ŠคํŠธ ์ƒ‰์ƒ, ๊ทธ๋ฆผ์ž ๋“ฑ์˜ "paint only" ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ ˆ์ด์•„์›ƒ์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  ํŽ˜์ธํŠธ ์ž‘์—…, ํ•ฉ์„ฑ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

3. JS / CSS > ์Šคํƒ€์ผ > ํ•ฉ์„ฑ#

2020-11-08-201108-image-10

๋ ˆ์ด์•„์›ƒ๊ณผ ํŽ˜์ธํŠธ๊ฐ€ ํ•„์š” ์—†๋Š” ์†์„ฑ์„ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ฉ์„ฑ ๋‹จ๊ณ„๋กœ ๊ฑด๋„ˆ ๋›ด๋‹ค. ๊ฐ€์žฅ ์ด์ƒ์ ์ด๊ณ  ๋น„์šฉ์ด ๊ฐ€์žฅ ์ ๊ฒŒ ๋“œ๋Š” ๋ฒ„์ „์ด๋‹ค. ( ํ˜„์žฌ ๋ถ€ํ•ฉ๋˜๋Š” ์†์„ฑ์€ transform , opacity 2๊ฐ€์ง€ ๋ฟ์ด๋‹ค. )

โ˜ CSS ์†์„ฑ์ด ์–ด๋–ค ๋ฒ„์ „์„ ํŠธ๋ฆฌ๊ฑฐํ•  ์ง€ ์•Œ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ CSS ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ฐธ์กฐ. ๋˜๋Š” ์ด ๋งํฌ ์ฐธ์กฐ

์ฐธ๊ณ ์ž๋ฃŒ#

Rendering Performance | Web Fundamentals | Google Developers


์ด๋ฏธ์ง€ ๋ ˆ์ด์ง€๋กœ๋“œ#

Lazy-loading images

The Complete Guide to Lazy Loading Images | CSS-Tricks


ยท ์•ฝ 11๋ถ„

์„ฑ๋Šฅ ์ธก์ •#

๋ธŒ๋ผ์šฐ์ € ๊ธฐ์ค€#

DOMContentLoadedย ์ด๋ฒคํŠธ#

  • HTML๊ณผ CSS ํŒŒ์‹ฑ์ด ๋๋‚˜๋Š” ์‹œ์ 

  • ๋ Œ๋” ํŠธ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•  ์ค€๋น„๊ฐ€ ๋œ(DOM ๋ฐ CSSOM ๊ตฌ์„ฑ์ด ๋๋‚œ) ์ƒํ™ฉ

loadย ์ด๋ฒคํŠธ#

  • HTML ์ƒ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๊ฐ€ ๋กœ๋“œ๋œ ์‹œ์ 

๊ทธ๋ฆฌ๊ณ  ์ด ๋‘ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์‹œ์ ์€ ๋‚ด๋น„๊ฒŒ์ด์…˜ ํƒ€์ด๋ฐ API๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž ๊ธฐ์ค€#

2020-11-08-201109-image-0

FP(First Paint)#

  • ํฐ ํ™”๋ฉด์—์„œ ํ™”๋ฉด์— ๋ฌด์–ธ๊ฐ€๊ฐ€ ์ฒ˜์Œ์œผ๋กœ ๊ทธ๋ ค์ง€๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์ˆœ๊ฐ„์ด๋‹ค.

FCP(First Contentful Paint)#

  • ํ…์ŠคํŠธ๋‚˜ ์ด๋ฏธ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์ˆœ๊ฐ„์ด๋‹ค.

FMP(First Meaningful Paint)#

  • ์‚ฌ์šฉ์ž์—๊ฒŒ ์˜๋ฏธ ์žˆ๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ๊ทธ๋ ค์ง€๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์ฒซ ์ˆœ๊ฐ„์ด๋‹ค. ์ฝ˜ํ…์ธ ๋ฅผ ๋…ธ์ถœํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ CSS, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋กœ๋“œ๊ฐ€ ์‹œ์ž‘๋˜๊ณ  ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์–ด ์ฃผ์š” ์ฝ˜ํ…์ธ ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

TTI(Time to Interactive)#

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ดˆ๊ธฐ ์‹คํ–‰์ด ์™„๋ฃŒ๋˜์–ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ–‰๋™์„ ์ทจํ•  ์ˆ˜ ์žˆ๋Š” ์ˆœ๊ฐ„์ด๋‹ค.

์„ฑ๋Šฅ ์ตœ์ ํ™”

๋กœ๋”ฉ ์ตœ์ ํ™”#

๋ธ”๋ก ๋ฆฌ์†Œ์Šค(๋˜๋Š” ๋ Œ๋”๋ง ์ฐจ๋‹จ ๋ฆฌ์†Œ์Šค) ์ตœ์ ํ™”#

๋ธŒ๋ผ์šฐ์ € ๋กœ๋”ฉ ๊ณผ์ •์—์„œ ํŒŒ์‹ฑ ์ค‘ ๋ธ”๋ก ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ธ”๋ก ๋ฆฌ์†Œ์Šค์—๋Š” CSS ์™€ JavaScript๊ฐ€ ํฌํ•จ๋œ๋‹ค.

CSS ์ตœ์ ํ™”#

  • DOM ํŠธ๋ฆฌ๋Š” ํŒŒ์‹ฑํ•˜๋ฉด์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

  • CSSOM ํŠธ๋ฆฌ๋Š” CSS๋ฅผ ๋ชจ๋‘ ํ•ด์„ํ•ด์•ผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ฆ‰ CSSOM ํŠธ๋ฆฌ๊ฐ€ ๊ตฌ์„ฑ๋˜์ง€ ์•Š์œผ๋ฉด ๋ Œ๋” ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค์ง€ ๋ชปํ•˜๊ณ , ๋ Œ๋”๋ง์ด ์ฐจ๋‹จ๋˜์–ด์žˆ๋‹ค.

  • ๋”ฐ๋ผ์„œ CSS๋Š” ํ•ญ์ƒ HTML ๋ฌธ์„œ ์ตœ์ƒ๋‹จ์— ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

  • ๋˜ํ•œ ํŠน์ • ์กฐ๊ฑด(์„ธ๋กœ ๋ชจ๋“œ, ์ธ์‡„ ๋ชจ๋“œ ๋“ฑ)์—์„œ๋งŒ ํ•„์š”ํ•œ CSS๋Š”, ํ•ด๋‹น ๊ฒฝ์šฐ์—๋งŒ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ ํ™”ํ•œ๋‹ค.

    ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ (์ตœ์ ํ™” ์ „)

    <link href="style.css" rel="stylesheet" /><link href="print.css" rel="stylesheet" /><link href="portrait.css" rel="stylesheet" />

    ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ (์ตœ์ ํ™” ํ›„)

    <link href="style.css" rel="stylesheet" /><link href="print.css" rel="stylesheet" media="print" /><link href="portrait.css" rel="stylesheet" media="orientation:portrait" />
  • ์™ธ๋ถ€ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” @import ๋ฌธ์€ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๋‹ค์šด๋กœ๋“œ ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋กœ๋“œ ์‹œ๊ฐ„์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

JavaScript ์ตœ์ ํ™”#

  • JavaScript๋Š” DOMํŠธ๋ฆฌ์™€ CSSOM ํŠธ๋ฆฌ๋ฅผ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— HTML ํŒŒ์‹ฑ์„์ฐจ๋‹จํ•˜๋Š” ๋ธ”๋ก ๋ฆฌ์†Œ์Šค์ด๋‹ค.

  • <script> ํƒœ๊ทธ๋ฅผ ๋งŒ๋‚˜๋ฉด ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ ๊ทธ ์ด์ „๊นŒ์ง€ ์ƒ์„ฑ๋œ DOM์—๋งŒ ์ ‘๊ทผํ• ์ˆ˜ ์žˆ๋‹ค.

  • ๊ทธ๋ฆฌ๊ณ  ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ DOM ํŠธ๋ฆฌ ์ƒ์„ฑ์ด ์ค‘๋‹จ๋œ๋‹ค.

  • ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ JavaScript๋ฅผ ๋ Œ๋”๋ง ์ฐจ๋‹จ ๋ฆฌ์†Œ์Šค๋ผ๊ณ  ํ•œ๋‹ค.

๋ฆฌ์†Œ์Šค ์š”์ฒญ ์ˆ˜ ์ค„์ด๊ธฐ#

์ด๋ฏธ์ง€ ์Šคํ”„๋ผ์ดํŠธ#

2020-11-08-201109-image-1

  • ์›น ํŽ˜์ด์ง€์—์„œ ์•„์ด์ฝ˜ ๋งˆ๋‹ค ๋‹ค๋ฅธ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ฆฌ์†Œ์Šค ์š”์ฒญ์ด ์•„์ด์ฝ˜ ๋งˆ๋‹ค๋ฐœ์ƒ

  • ์—ฌ๋Ÿฌ ์•„์ด์ฝ˜์„ ๋ฌถ์–ด ํ•˜๋‚˜์˜ ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ค๊ณ , CSS์˜ background-position ์†์„ฑ์„์‚ฌ์šฉํ•ด ๋ถ€๋ถ„ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฆฌ์†Œ์Šค ์š”์ฒญ ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

CSS, JavaScript ๋ฒˆ๋“ค๋ง#

  • ๋ชจ๋“ˆ ๊ธฐ๋ฐ˜ ๊ฐœ๋ฐœ ์ด์ „์—๋Š” ์—ฌ๋Ÿฌ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์„ ๋ถ„๋ฆฌํ•ด์„œ ๊ฐ€์ ธ์™”์—ˆ๋‹ค.

  • Webpack, Rollup ๋“ฑ์˜ ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ชจ๋“ˆ ํŒŒ์ผ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์„œ 1๊ฐœํŒŒ์ผ๋กœ ๋งŒ๋“ค์–ด ๋ฆฌ์†Œ์Šค ์š”์ฒญ ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๋‚ด๋ถ€ ์Šคํƒ€์ผ ์‹œํŠธ ?#

โ˜ ๋‚ด๋ถ€ ์Šคํƒ€์ผ ์‹œํŠธ๋Š” ๋ฆฌ์†Œ์Šค ์š”์ฒญ ํšŸ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด์ง€๋งŒ, ๋ฆฌ์†Œ์Šค ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์„œ HTML์— CSS๊ฐ€ ๋งค๋ฒˆ ํฌํ•จ๋œ๋‹ค.

์ž‘์€ ์ด๋ฏธ์ง€๋ฅผ HTML, CSS๋กœ ๋Œ€์ฒด#

  • ์•„์ด์ฝ˜ ์ด๋ฏธ์ง€ ๊ฐœ์ˆ˜๊ฐ€ ์ ์€ ๊ฒฝ์šฐ, ์ด๋ฏธ์ง€๋ฅผ Base64๋กœ ๋ณ€ํ™˜ํ•œ URI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTML, CSS์— ํฌํ•จํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    <img    src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAAbvf3sAAAAAXNSR0IArs4c6QAAAHBJREFUKBVjYBimICwsLAaEsXmPGV0QqnAeUNxfW1v7/tWrVy8hq0HRgKQ4CahoIxDPQ9cE14CseNWqVUtAJoMUo2tiBFkXGRmp9/fv3zNAZhJIMUgMBmAGMTMzmyxfvhzhPJAmmCJ0Gp8cutqhwAcASWgwk+79LiQAAAAASUVORK5CYII="/>

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•„์š”ํ•œ ํ•จ์ˆ˜๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ#

import _ from 'lodash';
_.array(...);_.object(...);

โ‡’

import array from 'lodash/array';import object from 'lodash/fp/object';
array(...);object(...);

HTML ๋งˆํฌ์—… ์ตœ์ ํ™”#

  • ์ค‘์ฒฉ์„ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌ์„ฑํ•œ๋‹ค.

Avoid an excessive DOM size

์••์ถ•(Minify)ํ•˜์—ฌ ์‚ฌ์šฉ#

  • ์›นํŒฉ ํ”Œ๋Ÿฌ๊ทธ์ธ๊ณผ ๊ฐ™์€ ๋„๊ตฌ์˜ ๋„์›€์œผ๋กœ ๋ถˆํ•„์š”ํ•œ ์ฃผ์„์ด๋‚˜ ๊ณต๋ฐฑ์„ ๋ชจ๋‘ ์‚ญ์ œํ•˜๊ณ , ๋‚œ๋…ํ™” ํ•˜๋Š” ๋“ฑ ์ฝ”๋“œ์˜ ์šฉ๋Ÿ‰์„ ์••์ถ•ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ Œ๋”๋ง ์ตœ์ ํ™”#

requestAnimationFrame#

  • ์‹œ๊ฐ์  ๋ณ€ํ™”๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ •ํ™•ํ•œ ์‹œ๊ฐ„(ํ”„๋ ˆ์ž„ ์‹œ์ž‘ ์‹œ)์— ์ˆ˜ํ–‰๋˜๊ธธ ์›ํ•œ๋‹ค.

  • ์ด๋ฅผ ๋ณด์žฅํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ requestAnimationFrame ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

  • setTimeout ๋˜๋Š” setInterval ์€ ์ฝœ๋ฐฑ์ด ์ •ํ™•ํ•œ ์‹œ๊ฐ„์— ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•˜์ง€์•Š๋Š”๋‹ค.

2020-11-08-201109-image-2

โ˜ setTimeout ๊ณผ setInterval ์˜ ์ฝœ๋ฐฑ์€ (macro)Task queue ๋ฅผ ์‚ฌ์šฉ. requestAnimationFrame ์€ AnimationFrame ์‚ฌ์šฉ.

์Šคํƒ€์ผ ๊ณ„์‚ฐ์˜ ๋ฒ”์œ„์™€ ๋ณต์žก์„ฑ ์ค„์ด๊ธฐ#

2020-11-08-201109-image-3

  • DOM ๋ณ€๊ฒฝ, ์š”์†Œ ์ถ”๊ฐ€ ๋ฐ ์ œ๊ฑฐ, ์†์„ฑ ๋ณ€๊ฒฝ, ํด๋ž˜์Šค ๋˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์€ ๋ชจ๋‘ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์†Œ ์Šคํƒ€์ผ์„ ์žฌ๊ณ„์‚ฐํ•˜๊ณ  ๋งŽ์€ ๊ฒฝ์šฐ์— ๋ ˆ์ด์•„์›ƒ ๋‹จ๊ณ„(๋ฆฌํ”Œ๋กœ์šฐ)๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

  • ์Šคํƒ€์ผ ๊ณ„์‚ฐ ๋‹จ๊ณ„์˜ ์ฒซ ๋ถ€๋ถ„์€ ๋งค์นญ ์„ ํƒ๊ธฐ ์ง‘ํ•ฉ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค. (์š”์†Œ, ํด๋ž˜์Šค , ID, pseudo ์„ ํƒ์ž ๋“ฑ๋“ฑ)

  • ์Šคํƒ€์ผ ๊ณ„์‚ฐ์˜ ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” ๋งค์นญ๋œ ์„ ํƒ๊ธฐ์—์„œ ์Šคํƒ€์ผ ๊ทœ์น™์„ ๊ฐ€์ ธ์™€์„œ ์š”์†Œ์˜๋งˆ์ง€๋ง‰ ์Šคํƒ€์ผ์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ณผ์ •์ด ํฌํ•จ๋œ๋‹ค.

  • ๋”ฐ๋ผ์„œ ์„ ํƒ๊ธฐ์˜ ๋ณต์žก์„ฑ์„ ์ค„์ด๊ณ  (BEM ๋“ฑ์˜ ๋ฐฉ๋ฒ•๋ก  ์ ์šฉ) ์Šคํƒ€์ผ์„ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๋Š”์š”์†Œ์˜ ์ˆ˜๋ฅผ ์ค„์—ฌ์•ผ ํ•œ๋‹ค.

ํฌ๊ณ  ๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ ๋ฐ ์Šค๋ž˜์‹ฑ ํ”ผํ•˜๊ธฐ#

  • ๋ ˆ์ด์•„์›ƒ์˜ ๋ฒ”์œ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ „์ฒด ๋ฌธ์„œ๋กœ ์ง€์ •๋œ๋‹ค.

    • ๋„ˆ๋น„, ๋†’์ด, ์™ผ์ชฝ ๋˜๋Š” ์ƒ๋‹จ ๋“ฑ "๊ธฐํ•˜ํ•™์  ์†์„ฑ"์˜ ๋ณ€๊ฒฝ์€ ๋ชจ๋‘ ๋ ˆ์ด์•„์›ƒ์ดํ•„์š”ํ•˜๋‹ค.

    • flexbox ๋ฅผ ์‚ฌ์šฉํ•œ ๋ ˆ์ด์•„์›ƒ์ด float ๋ฅผ ์‚ฌ์šฉํ•œ ๋ ˆ์ด์•„์›ƒ ๋ณด๋‹ค ๋น„์šฉ์ด ์ ๋‹ค.

  • DOM ์š”์†Œ์˜ ์ˆ˜๋Š” ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ๋ฏ€๋กœ ๊ฐ€๊ธ‰์  ๋ ˆ์ด์•„์›ƒ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ํ”ผํ•ด์•ผ ํ•œ๋‹ค.

  • ๊ฐ•์ œ ๋™๊ธฐ์‹ ๋ ˆ์ด์•„์›ƒ ๋ฐ ๋ ˆ์ด์•„์›ƒ ์Šค๋ž˜์‹ฑ์„ ํ”ผํ•ด์•ผ ํ•œ๋‹ค.

    โ˜ ์›๋ž˜ ๋ ˆ์ด์•„์›ƒ์€ ๋น„๋™๊ธฐ์ด๋‚˜, ํŠน์ • ์ƒํ™ฉ์—์„œ ๋™๊ธฐ์ ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜์žˆ๋‹ค. ์ด๊ฒƒ์„ ๊ฐ•์ œ ๋™๊ธฐ์‹ ๋ ˆ์ด์•„์›ƒ ์ด๋ผ ํ•œ๋‹ค.

    function logBoxHeight() {    box.classList.add('super-big');
        // Gets the height of the box in pixels    // and logs it out.    console.log(box.offsetHeight);}
    • ์œ„์˜ ํ•จ์ˆ˜๋Š” ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•œ ํ›„์—, ๋†’์ด๋ฅผ ์š”์ฒญํ•œ๋‹ค.

    • ๋†’์ด๋ฅผ ๊ตฌํ•˜๋Š” ๊ฒƒ ์—ญ์‹œ ๋ ˆ์ด์•„์›ƒ์„ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

    • ์Šคํƒ€์ผ ๊ณ„์‚ฐ๊ณผ ๋ ˆ์ด์•„์›ƒ์„ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋ฉด ์ž ์žฌ์  ๋ณ‘๋ชฉ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š๋‹ค.

    function resizeAllParagraphsToMatchBlockWidth() {    // Puts the browser into a read-write-read-write cycle.    for (var i = 0; i < paragraphs.length; i++) {        paragraphs[i].style.width = box.offsetWidth + 'px';    }}
    • ์œ„์˜ ํ•จ์ˆ˜๋Š” ๊ฐ ๋ฃจํ”„์˜ ๋ฐ˜๋ณต์ด ์Šคํƒ€์ผ ๊ฐ’ box.offsetWidth ๋ฅผ ์ฝ์€ ๋‹ค์Œ, ์ฆ‰์‹œ paragraphs[i].style.width ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค.

    • ์ด์ „ ๋ฐ˜๋ณต์—์„œ ๋ ˆ์ด์•„์›ƒ์ด ๋ณ€๊ฒฝ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— box.offsetWidth ์„ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์—ญ์‹œ ๊ฐ•์ œ ๋™๊ธฐ์‹ ๋ ˆ์ด์•„์›ƒ์„ ์œ ๋ฐœํ•œ๋‹ค. ์ด๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

    // Read.var width = box.offsetWidth;
    function resizeAllParagraphsToMatchBlockWidth() {    for (var i = 0; i < paragraphs.length; i++) {        // Now write.        paragraphs[i].style.width = width + 'px';    }}

ํŽ˜์ธํŠธ ๋ณต์žก์„ฑ ๋‹จ์ˆœํ™” ๋ฐ ํŽ˜์ธํŠธ ์˜์—ญ ์ค„์ด๊ธฐ#

  • transform ๋˜๋Š” opacity ๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ์†์„ฑ ๋ณ€๊ฒฝ์€ ํ•ญ์ƒ ํŽ˜์ธํŠธ๋ฅผ ํŠธ๋ฆฌ๊ฑฐ ํ•œ๋‹ค.

  • ๊ฐ€๋Šฅํ•œ ํ•˜์œ„ ๋…ธ๋“œ์˜ DOM์„ ์กฐ์ž‘ํ•˜๊ณ  ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝ

    • DOM์ด ์ž‘๊ณ  ๊นŠ์ด๊ฐ€ ์–•์„์ˆ˜๋ก ๊ณ„์‚ฐ์ด ๋น ๋ฅด๋‹ค.

    • ๋ถˆํ•„์š”ํ•œ ๋ž˜ํผ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.

  • ์˜ํ–ฅ ๋ฐ›๋Š” ์—˜๋ฆฌ๋จผํŠธ ์ œํ•œ