Next.js: ๊ฐœ๋ฐœ ์„œ๋ฒ„์— ์Šคํƒ€์ผ์ด ์ง€์ •๋˜์ง€ ์•Š์€ ์ฝ˜ํ…์ธ  (FOUC)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2020๋…„ 05์›” 18์ผ  ยท  20์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: vercel/next.js

๋ฒ„๊ทธ ์‹ ๊ณ 

๋ฒ„๊ทธ ์„ค๋ช…

๋ฒ„๊ทธ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

Next.js๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ <div id="__next"> ์š”์†Œ๊ฐ€ ์ฒ˜์Œ ํ‘œ์‹œ ๋  ๋•Œ CSS๊ฐ€ <head> ๋กœ ์™„์ „ํžˆ ์ˆ˜ํ™”๋˜์ง€ ์•Š์€ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๋กœ ์ธํ•ด ๊ฐœ๋ฐœ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์Šคํƒ€์ผ์ด ์ง€์ •๋˜์ง€ ์•Š์€ ์ฝ˜ํ…์ธ  (๋˜๋Š” FOUC)๊ฐ€ ๊นœ๋ฐ•์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ํ”„๋กœ๋•์…˜์—์„œ ๊ดœ์ฐฎ์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค (์ด์ƒํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค).

์žฌํ˜„ํ•˜๋ ค๋ฉด

๋™์ž‘์„ ์žฌํ˜„ํ•˜๋Š” ๋‹จ๊ณ„, ์ฝ”๋“œ ์กฐ๊ฐ ๋˜๋Š” ์ €์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค.

  1. ๋‹ค์Œ ์„ ์‹คํ–‰ ํ•ฉ๋‹ˆ๋‹ค .
$ git clone https://github.com/tutorbookapp/covid-tutoring
  1. ๋‹ค์Œ์„ ์‹คํ–‰ํ•˜์—ฌ ์ข…์†์„ฑ (์ž์„ธํ•œ ๋‚ด์šฉ์€ README.md )์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.
$ npm i && lerna bootstrap --hoist
  1. ๋‹ค์Œ์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฐœ๋ฐœ ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
$ npm run dev
  1. ํŽ˜์ด์ง€๋ฅผ ์ฒ˜์Œ๋กœ๋“œ ํ•  ๋•Œ FOUC๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™

์˜ˆ์ƒํ–ˆ๋˜ ์ผ์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ์„ค๋ช….

<div id="__next"> ์š”์†Œ ๋งŒ (์— ํฌํ•จ๋˜๋Š” ์Šคํƒ€์ผ ์‹œํŠธ๊ฐ€ ๋ฐฐ ์ƒ๊ธฐ ํ‘œ์‹œ๋˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ ๋ฐ˜์‘ ์ฆ‰,)์— ์‚ฝ์ž…๋˜๋Š” ํ•„์š”ํ•œ ์Šคํฌ๋กค์—†์ด ์Šคํƒ€์ผ ํ›„์— ํ‘œ์‹œ๋˜์–ด์•ผ <head> . ๋‚˜๋จธ์ง€ ์Šคํƒ€์ผ ์‹œํŠธ๋Š” <div id="__next"> ์š”์†Œ๋ฅผ ํ‘œ์‹œํ•˜์—ฌ๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์Šคํฌ๋ฆฐ ์ƒท

ํ•ด๋‹น๋˜๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๋ฐ ๋„์›€์ด๋˜๋Š” ์Šคํฌ๋ฆฐ ์ƒท์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ ์„œ๋ฒ„์—์„œ ๋ณผ ์ˆ˜์žˆ๋Š” FOUC๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

fouc

ํ”„๋กœ๋•์…˜ ์›น ์‚ฌ์ดํŠธ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค .

no-fouc

์‹œ์Šคํ…œ ์ •๋ณด

  • ์šด์˜์ฒด์ œ : Ubuntu 18.04.2
  • ๋ธŒ๋ผ์šฐ์ € : Firefox 76.0.1
  • Next.js ๋ฒ„์ „ : 9.4.0
  • Node.js ๋ฒ„์ „ : 12.16.1
bug needs investigation

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ƒ์‚ฐ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ์—ฌ์ „ํžˆ StyledComponents + Material UI๋กœ FOUC๋ฅผ ๊ฒฝํ—˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  20 ๋Œ“๊ธ€

CSS ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ๋•Œ๋„์ด ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์ง€๋งŒ styled-jsx๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

_app.js์˜ ์ „์—ญ CSS๊ฐ€ ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์žˆ๋Š” ๋™์•ˆ ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊บผ์ง„ ์ƒํƒœ๋กœ๋กœ๋“œ๋˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์€ ์œ ์‚ฌํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๋ฝ ๋œ ์Šคํƒ€์ผ์ด์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ SSR์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

@robgraeber ๋‚˜๋Š” ๋‹น์‹ ์ดํ•˜๋Š” ์ •ํ™•ํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. CSS๋Š” ๋ณ„๋„์˜ css ํŒŒ์ผ ๋Œ€์‹  _app.js๋กœ ์ปดํŒŒ์ผ๋ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•˜๋Š” ์ตœ์†Œ ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค : https://github.com/dnaranjo89/next-css-ssr

๋˜ํ•œ ๋•Œ๋กœ๋Š” ๊ด€๋ฆฌ์ž์—์„œ ์ผ๋ถ€ ์ „์—ญ CSS๋ฅผ ํŽธ์ง‘ํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜๋ฉด ์ „์ฒด ํŽ˜์ด์ง€์˜ CSS๊ฐ€ ์–ด๋–ป๊ฒŒ ๋“  ์†์ƒ๋ฉ๋‹ˆ๋‹ค. ๊ฒฝํ—˜ ํ•œ ์‚ฌ๋žŒ ์žˆ๋‚˜์š”?

@derskeal ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€์ด sass ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ๋ ˆ์ด์•„์›ƒ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ sass๋ฅผ ํ†ตํ•ด ์Šคํƒ€์ผ ์‹œํŠธ๋ฅผ ๊ฐ€์ ธ ์˜ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://github.com/giuseppeg/styled-jsx-plugin-sass

@Timer ๋‚˜๋Š”์ด repo https://github.com/yanv1991/demo-react-dom ์—์„œ์ด ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ ํ•  ์ˆ˜

์ด ํ”„๋กœ์ ํŠธ๋Š” ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค :

error - Error [FirebaseError]: projectId must be a string in FirebaseApp.options
    at new FirestoreError (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/firestore/dist/index.node.cjs.js:1223:28)
    at Function.Firestore.databaseIdFromApp (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/firestore/dist/index.node.cjs.js:21018:19)
    at new Firestore (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/firestore/dist/index.node.cjs.js:20850:42)
    at /Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/firestore/dist/index.node.cjs.js:22871:66
    at Component.instanceFactory (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/firestore/dist/index.node.cjs.js:22410:16)
    at Provider.getOrInitializeService (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/component/dist/index.cjs.js:219:39)
    at Provider.getImmediate (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/component/dist/index.cjs.js:120:33)
    at FirebaseAppImpl._getService (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/app/dist/index.node.cjs.js:228:49)
    at FirebaseAppImpl.firebaseAppImpl.<computed> [as firestore] (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/app/dist/index.node.cjs.js:440:39)
    at Object.serviceNamespace [as firestore] (/Users/joe/Desktop/scratch2/covid-tutoring/node_modules/@firebase/app/dist/index.node.cjs.js:420:45)
    at eval (webpack-internal:///./src/firebase/db.tsx:19:124)
    at Module../src/firebase/db.tsx (/Users/joe/Desktop/scratch2/covid-tutoring/.next/server/static/development/pages/_app.js:128:1)
    at __webpack_require__ (/Users/joe/Desktop/scratch2/covid-tutoring/.next/server/static/development/pages/_app.js:23:31)
    at eval (webpack-internal:///./src/firebase/user.tsx:12:61)
    at Module../src/firebase/user.tsx (/Users/joe/Desktop/scratch2/covid-tutoring/.next/server/static/development/pages/_app.js:152:1)
    at __webpack_require__ (/Users/joe/Desktop/scratch2/covid-tutoring/.next/server/static/development/pages/_app.js:23:31) {
  code: 'invalid-argument',
  toString: [Function]
}

์ด๊ฒƒ์€ next@^9.4.5-canary.15 ์—์„œ ์ˆ˜์ •๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค! ์—…๊ทธ๋ ˆ์ด๋“œํ•˜์—ฌ ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

@Timer ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐ŸŽ‰ ํ…Œ์ŠคํŠธ๋ฅผํ–ˆ๊ณ  ์ˆ˜์ • ์‚ฌํ•ญ์ด ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ์„œ๋ฒ„ (์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์‚ฌ์ดํŠธ์—์„œ ์ ์ง„์ ์œผ๋กœ ํŽ˜์ด์ง€ ๋ณ€ํ™˜)์˜ ๊ฐœ๋ฐœ ๋ชจ๋“œ์™€ ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ์—์„œ์ด ๋ฌธ์ œ๋ฅผ ๊ฒฝํ—˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ^9.4.5-canary.15 ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค!

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

ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋Š” <style data-next-hide-fouc="true">body{display:none}</style> .

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

ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋Š” <style data-next-hide-fouc="true">body{display:none}</style> .

์—ฌ๊ธฐ์—์„œ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฐŒ๋ฅด๊ธฐ ๋˜๋Š” ๊ด€๋ จ์—์„œ ๋ฐœ์ƒํ•  ๋•Œ ๋‹ค๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ๋ˆ„๊ตฌ๋“ ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์—ฌ๊ธฐ์—์„œ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฐŒ๋ฅด๊ธฐ ๋˜๋Š” ๊ด€๋ จ์—์„œ ๋ฐœ์ƒํ•  ๋•Œ ๋‹ค๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ๋ˆ„๊ตฌ๋“ ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜์—๊ฒŒ์ด ๋ฌธ์ œ๋Š” ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ๊ฐ€ ์•„๋‹Œ ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ๋งŒ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‚˜๋Š” prod ๋ฌธ์ œ๊ฐ€ ๋‹ค๋ฅธ ์›์ธ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

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

ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—๋Š” <style data-next-hide-fouc="true">body{display:none}</style> .

ํ”„๋กœ๋•์…˜์—์„œ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? Canary ๋ฆด๋ฆฌ์Šค๋Š” ๊ฐœ๋ฐœ ๋นŒ๋“œ๋ฅผ ์ˆ˜์ •ํ–ˆ์ง€๋งŒ ํ”„๋กœ๋•์…˜์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์ค‘๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๋‹ค์Œ ์นด๋‚˜๋ฆฌ์•„ ์ตœ์‹  ๋ฒ„์ „์ธ๊ฐ€์š”?

์˜ˆ @jimmynames , canary๋Š” WIP ์ตœ์‹  ๋ฒ„์ „์ž…๋‹ˆ๋‹ค (์ด ์šฉ์–ด๋Š” ์นด๋‚˜๋ฆฌ์•„ ์ƒˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋…์„ฑ ์—ฐ๊ธฐ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ด‘๋ถ€์—์„œ ์œ ๋ž˜ํ–ˆ์Šต๋‹ˆ๋‹ค ... Next.js์˜ ์นด๋‚˜๋ฆฌ์•„ ๋ฒ„์ „์€ ์Šค์ผ€์น˜๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

์ด ์ˆ˜์ • ์‚ฌํ•ญ์€ Next.js 9.5.0 ๋ฐ 9.5.1 ์ด์ƒ์˜ ์•ˆ์ •์ ์ธ ๋ฆด๋ฆฌ์Šค์— ์žˆ์Šต๋‹ˆ๋‹ค (๊ฐœ๋ฐœ ์„œ๋ฒ„์—๋งŒ ์ ์šฉ๋จ)!

์ƒ์‚ฐ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ์—ฌ์ „ํžˆ StyledComponents + Material UI๋กœ FOUC๋ฅผ ๊ฒฝํ—˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ฌด๋„ ์ด๊ฒƒ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๊นŒ?

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰