์ฌ๋๋ค์ Razzle์ด .env
๋ณ์๋ฅผ ์ด๋ป๊ฒ ๋ค๋ฃจ๋์ง(์ฆ, webpack์ ์ํด _build_ ์๊ฐ์ ๋ฌธ์์ดํ) create-react-app์ฒ๋ผ ์ด๋ ค์์ ๊ฒช์ต๋๋ค.
Razzle์๋ ๋ฐํ์ ๋ณ์๋ฅผ ์กด์คํ๋ ๋ฐฉ๋ฒ์ด ์์ด์ผ ์ฌ์ฉ์๊ฐ Now/Heroku/Azure ๋ฑ์ ์ฑ์ ๋ ์ฝ๊ฒ ๋ฐฐํฌํ ์ ์์ต๋๋ค.
PORT
, HOST
๋ฐ RAZZLE_RUNTIME_XXXXXXX
์ ๋์ฌ๊ฐ ๋ถ์ ๊ธฐํ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ฐํ์ ์ค์ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
์ปดํ์ผ ์๊ฐ์ ์ฌ์ฉ ๊ฐ๋ฅ(์ฆ, ์นํฉ์ ์ํด ๋ฌธ์์ดํ๋จ)
RAZZLE_XXXXXX
PORT
HOST
๋ฐํ์์ ์ฌ์ฉ ๊ฐ๋ฅ
PORT
HOST
RAZZLE_RUNTIME_XXXXXXX
์ปดํ์ผ ์๊ฐ์ ์ฌ์ฉ ๊ฐ๋ฅ(์ฆ, ์นํฉ์ ์ํด ๋ฌธ์์ดํ๋จ)
RAZZLE_XXXXXX
๋ ๋ค๋ฅธ ๋์์ razzle-heroku ํ๋ฌ๊ทธ์ธ ๊ณผ ๊ฐ์ด RAZZLE_XXXX
์ ๋์ฌ๊ฐ ๋ถ์ ๋ณ์๋ฅผ _only_ ๋ฌธ์์ดํํ๋ ๊ฒ์
๋๋ค. ์ด๊ฒ์ ๋ํ ์ด์ ๋ฒ์ ๊ณผ๋ ํธํ๋ฉ๋๋ค. ํํธ์ผ๋ก ์ด๋ ๊ฒ ํ๋ฉด Heroku๊ฐ ๊ตฌ์ฑ ํ๊ฒฝ ๋ณ์(์: MONGO_URI
)์ ์ด๋ฆ์ ์ง์ ํ๋ ์์
์ ๋ ์ฝ๊ฒ ์ํํ ์ ์์ต๋๋ค. ๋ฐ๋ฉด์,์ด ์ค์๋ก ์๋ง์ผ๋ก ์ฝ๊ฒ _too_ ๊ฒ (์ฆ์ด๋ค ๊ณต์ ๋ํ ์ฝ๋ ๋ด ๋ฐํ์ ๋ณ์๋ฅผ ์ฐธ์กฐ undefined
์์ฉ ํ๋ก๊ทธ๋จ์ ํญ๋ฐ ... ํด๋ผ์ด์ธํธ).
๋๋ ๊ฐ์ธ์ ์ผ๋ก ํด๋ผ์ด์ธํธ์์ process.env๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋ํด ๋๋ฌด ๊ฑฑ์ ํ์ง ์์ ๊ฒ์ ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฏธ ์๋ฒ์์ '์ฐฝ'์ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์๊ณ ์์ด์ผ ํฉ๋๋ค. ๋๋ process.env๊ฐ ๋ฐ๋ ํ๋์ ํ ๊ฒ์ด๋ผ๋ ๊ฒ์ด ์ดํด๊ฐ ๋ฉ๋๋ค. (env๋ฅผ ๊ฐ์ง ๋ ธ๋ ํ๋ก์ธ์ค๊ฐ ์์ผ๋ฉฐ ๋ธ๋ผ์ฐ์ ๋ ๋ด๊ฐ ์๊ณ ์๋ env ๋ณ์๋ฅผ ๋ ธ์ถํ์ง ์์ต๋๋ค.) ์ ๋ process.env๋ฅผ ์๋ฒ ๋น๋ฐ์ด ๋๋ ์ ์๋ ์ฅ์๋ผ๊ณ ์๊ฐํ๋ฏ๋ก ์ฐจ๋ผ๋ฆฌ ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋ผ์ด์ธํธ ์ธก์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋์๊ฒ ๋ฌ๋ ค ์๋ค๋ฉด process.env.RAZZLE_INLINED_XXXXXX ๋ณ์๋ ๋น๋ ์ค์ ์ปดํ์ผ๋๊ณ (ํด๋ผ์ด์ธํธ์์ ์ธ๋ผ์ธ DefinePlugin'd ๋ฌธ์์ด๋ก ์ฌ์ฉ ๊ฐ๋ฅ) ๋ค๋ฅธ ๋ชจ๋ ๋ณ์๋ ์๋ฒ ์ธก์์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค.
NODE_ENV๋ ์ธ๋ผ์ธ๋ ์ ์์ต๋๋ค. ๋๋ถ๋ถ ๋น๋์ ๋ํ ์ค๋ช ์ผ๋ก ์ฌ์ฉ๋๋ฉฐ ์ฝ๋๊ฐ ์คํ๋๋ ํ๊ฒฝ๊ณผ ๊ฐ์ ๋ณ์๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ๋ ๊ฒ ํด์ผ ํ๋ ๋ช ๊ฐ์ง ์ฑ๋ฅ์์ ์ด์ ๋ ์์ต๋๋ค.
๋๋ PORT์ HOST๊ฐ ๋ฐํ์์ ๊ฐ๋ณ์ ์ด๋ผ๋ ์์ด๋์ด๋ฅผ ์ข์ํฉ๋๋ค. ๋ค๋ฅธ ํ๊ฒฝ์์ ๋์ผํ ๋น๋ ์ํฐํฉํธ๋ฅผ ์คํํ ์ ์์ต๋๋ค.
๋๋ ํฌ์์ ํ์ธํ ์ ์์ต๋๋ค. ํ์ฌ ๋์์ ๋ด๊ฐ ์์ํ ๊ฒ๊ณผ ๋ฌ๋๊ณ ํนํ aws์์ up
๋ฐฐํฌํ ๋ ๊ฑธ๋ ค ๋์ด์ก์ต๋๋ค. ์ด์ razzle.config.js
์ฌ์ฉ์ ์ง์ ํ์ฌ ๋ชจ๋ razzle ํน์ ๋ณ์์ RAZZLE_XXX
์ ๋์ฌ๊ฐ ๋ถ๊ณ ์ปดํ์ผ ์๊ฐ์ ๋ฌธ์์ดํ๋๋๋ก ํ์ต๋๋ค. ๋๋จธ์ง๋ process.env.XXX
์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ํ process.env
ํตํด ๋ฐํ์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ @gregmartyn์ ์๊ฒฌ์ ๋์ํฉ๋๋ค.
๊ธฐ์กด React ํ๋ก์ ํธ์์ Razzle์ ์ค์ ํ๋ ๋์ ์ด ๋ฌธ์ ์ ์ง๋ฉดํ์ต๋๋ค. ํฌํธ๋ ๋ฐํ์์ ์ฌ์ ์ํ ์ ์์ผ๋ฉฐ ๋ค๋ฅธ process.env ๋ณ์๋ ์๋ฒ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋น๋ ์ ํ์ฌ ๋์:
process.env.PORT
process.env.NODE_ENV;
process.env.ASSETS_MANIFEST;
process.env.HOSTING_SET_VARIABLE;
ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋์ ๋ฉ๋๋ค.
3000;
'development';
'/Users/[...]/build/assets.json';
undefined;
์ด๋ ๊ฒ ํ๋ฉด ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ ์ ํํ ๋์ผํ ํ๋ก์ธ์ค ํ๊ฒฝ์ ์ฌ์ฉํ ์ ์์ง๋ง ๋ฐํ์์ ์ฌ์ ์ํ๊ฑฐ๋ ๋ค๋ฅธ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด์ ๋ฒ์ ๊ณผ ์์ ํ ํธํ๋๋๋ก ํ๋ ค๋ฉด ๋น๋ ์๊ฐ์ ๋ค์์ผ๋ก ๋ณํํด์ผ ํฉ๋๋ค(์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ ๋์ผํ๊ฒ ์ ์ง๋ ์ ์์).
process.env.PORT || 3000;
process.env.NODE_ENV || 'development';
process.env.ASSETS_MANIFEST || '/Users/[...]/build/assets.json';
process.env.HOSTING_SET_VARIABLE;
์ด๋ฐ ์์ผ๋ก ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋์์ process.env.PORT๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ๊ฐ์ 3000์ ๋๋ค.
razzle ์ด PORT=80
๋ก _built_ ์ธ ๊ฒฝ์ฐ ํด๋ผ์ด์ธํธ๋ process.env.PORT
๋ฅผ 80
๋ก ๋ณํํ๊ณ ์๋ฒ๋ process.env.PORT || 80
ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ์ฌ์ ๋์ผํ ๋์์ด ๋ฐ์ํฉ๋๋ค.
ํ๋ คํ ํจ๊ป _run_ ๊ฒฝ์ฐ PORT=81
(๋ด์ฅํ ๋์ 80
), ํด๋ผ์ด์ธํธ ํ๊ฒฝ ๋ณ์๋ ๋จ์์์ ๊ฒ์
๋๋ค 80
์๋ฒ ๋ณ์๊ฐ ๋ฐ์ํฉ๋๋ค ๋์ 81
.
์ด ๋์์ ๋ฌผ๋ก ์๊ธฐ์น ์์ ๋์์ผ๋ก ์ด์ด์ง ์ ์์ง๋ง ์์ ํ ์ญํธํ์ฑ์ ์ ์งํ๋ฉด์ ๊ฐ์ฅ ์ ์ฐํ process.env ์ฌ์ฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ํฌํธ๋ ๋ฐํ์์ ์๋ฒ์์ ๊ณ์ ๋ฎ์ด์ธ ์ ์์ผ๋ฉฐ ํธ์คํ ํ๋ซํผ์์ ์ค์ ํ ๋ค๋ฅธ ํ๊ฒฝ ๋ณ์๋ ์๋ฒ์์ ์๋ ๊ทธ๋๋ก ์๋ํฉ๋๋ค.
์ฌ๊ธฐ์์ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ Razzle์ด ํ์ฌ ์ฌ๋ฌ ๊ฐ์ ์๋ก ๋ค๋ฅธ ๊ธฐ๋ฅ์ ํ๋์ ๊ฐ์ฒด๋ก ๋ฌถ๊ณ ๊ธฐ์กด ๊ธฐ๋ฅ์ ๊ทผ๋ณธ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ค๊ณ ํ๋ค๋ ๊ฒ์ ๋๋ค.
๋ค์์ ์ํํ๋ ค๊ณ ํฉ๋๋ค.
๋ฌธ์ :
๋ด ์ ํธ ์ฌํญ์ ์ด ๊ธฐ๋ฅ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก ๋ถํ ํ๊ณ process.env๋ฅผ ์ ํ ๋ณ๊ฒฝํ์ง ์๋ ๊ฒ์
๋๋ค.
DefinePlugin์ razzle.config.js์ ๊ฐ์ ํ์ผ์ ํธ์ถํ์ฌ ๋น๋ ์์๋ฅผ ์ป์ ์ ์์ต๋๋ค.
Redux๊ฐ configureStore(window.__PRELOADED_STATE__)๋ฅผ ์ฌ์ฉํ์ฌ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๊ฒ๊ณผ ์ ์ฌํ ํจํด์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ด์ ๋ฒ์ ๊ณผ์ ํธํ์ฑ์ ์ํด ์ ๊ทธ๋ ์ด๋ ๋ ธํธ๋ ๊ตฌ์ ๋ฐฉ์์ ์ ์ํ๋ ์ํ razzle.config.js๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
ํ๋์ ๋ถ๋ก: ๋๋ "process.env๋ฅผ ์ ํ ๋ณ๊ฒฝํ์ง ๋ง๋ผ"๊ณ ๋งํ์ต๋๋ค. ๊ทธ๋ฌ๋ ์์ ๋ด ์๊ฒฌ์์ ์ฑ๋ฅ์์ ์ด์ ๋ก process.env.NODE_ENV์ ์์ธ๊ฐ ์๋ค๋ ๊ฒ์ ์ ์ ์์๊ณ "NODE_ENV" ์์ฒด๋ ์ผ๋ฐ์ ์ผ๋ก "NODE_ENV = ์์ฐ์ ์ด๊ฒ์ด ์ต์ ํ๋ ๋น๋์์ ์๋ฏธํฉ๋๋ค"์ ์๋ฏธ๋ฅผ ์ทจํ์ต๋๋ค.
@gregmartyn ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด NODE_ENV๋ฅผ ์ค์ ํ๊ณ ํ์ฌ ์๋ํ๋ babel ์ฌ์ ์ค์ ์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ํ๊ฒฝ์ ์๋ง์ผ๋ก ๋ง๋ ๋์ ์ด๊ธฐ ์ถ๋ก ์ ํ๋ก์ ํธ๊ฐ ์ด๋ฏธ ์์๋ ํ์ SSR์ด ์ถ๊ฐ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ธฐ ๋๋ฌธ์ CRA์์ ํจ์ฌ ์ฝ๊ฒ ์ด๋ํ ์ ์๋๋ก ํ๋ ๊ฒ์ด์์ต๋๋ค. ์ฐ๋ฆฌ๋ ๋ํ ๋ค๋ฅธ ํ๋ก์ ํธ์์ CRA๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋ ๋๊ตฌ๋ฅผ (์ฝ๊ฐ) ๋จ์ํํฉ๋๋ค.
์; NODE_ENV๊ฐ ์ ์ฉํ ์์ธ๋ผ๋ ๋ฐ ๋์ํ์ต๋๋ค. ๊ทธ๊ฒ์ ๊ทธ ์์ฒด์ ๊ฒ์ด๊ณ ๋น๋์ ๋ฐ์ ํ๊ฒ ์ฐ๊ฒฐ๋์ด ์์ผ๋ฏ๋ก ๋๋ผ์ด ์ผ์ด ์๋๋๋ค. ์ฌ์ฉ์ ์ง์ SSR ์๋ฃจ์ ์์ CRA๋ฅผ ๋ฐ๋ก ๊ฑด๋๋ฐ์์ผ๋ฏ๋ก CRA๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ด๊ฒ๋ ๋ฌธ์ ์ธ ๊ฒ ๊ฐ์ต๋๋ค: https://github.com/facebook/create-react-app/issues/2353
CRA ์ฑ์ ๋ฐํ์ ์ฝ๋๊ฐ ์๋ฒ์์ ์ ํ ์คํ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ด CRA๋ณด๋ค Razzle์๊ฒ ๋ ํฐ ๋ฌธ์ ๋ผ๊ณ ์๊ฐํฉ๋๋ค. CRA๋ process.env๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ ๋ชจ๋ ์์ ์ ์ํํ ์ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ ์ธก ์ฝ๋์ ๊ดํ ํ CRA๋ ๊ทธ๋ ์ง ์์ผ๋ฉด ๋น์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ฐ๋ฉด์ Razzle์ SSR์ ๋ํด express๋ฅผ ์์ํ๊ณ ํด๋น ์ฝ๋๋ process.env๊ฐ ๋ ธ๋ ๋ฐํ์ ํ๊ฒฝ ๋ณ์์ ์ ์ฒด ์ธํธ์ ์ก์ธ์คํ ์ ์๋ ์ผ๋ฐ์ ์ธ ์๋ฏธ ์ฒด๊ณ๋ฅผ ๊ฐ์ง ๊ฒ์ผ๋ก ํฉ๋ฆฌ์ ์ผ๋ก ์์ํฉ๋๋ค. Process.env๋ ์๋ฒ์์ ์ค์ ์๋ฏธ๊ฐ ์์ผ๋ฏ๋ก CRA๊ฐ ๋ค๋ฅธ ์ฌ์ฉ ์ฌ๋ก์ ๋ํด ์ด๋ฅผ ์ฑํํ ๊ฒ์ ์ ๊ฐ์ ๋๋ค. "cra.inlines"์ ๊ฐ์ "process.env" ๋์ ๋ค๋ฅธ ์ด๋ฆ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋์ , ๋ํ ์ฝ๋๋ ํด๋ผ์ด์ธํธ ์ธก๋ง ๊ณ ๋ คํ ๋ ๋ด๋ฆฐ ๊ฒฐ์ ์ ์ํฅ์ ๋ฐ์ต๋๋ค.
RAZZLE_XXX ํ๊ฒฝ ๋ณ์๊ฐ ๋ชจ๋ ํด๋ผ์ด์ธํธ์์ ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ๋ ๋ชจ๋ ๊ณณ์์ ๋นจ๊ฐ์์ผ๋ก ํ์๋์ด์ผ ํฉ๋๋ค.
๋ฏผ๊ฐํ ํ๊ฒฝ ๋ณ์๋ฅผ ํด๋ผ์ด์ธํธ์ ์ ์กํ์ง ์๊ณ ์ด๋ป๊ฒ ์ฌ์ฉํฉ๋๊น?
๋ํ ์ฝ๋์์ ์ฐธ์กฐํ์ง ์์ผ๋ฉด ํด๋ผ์ด์ธํธ๋ก ์ ์ก๋์ง ์์ต๋๋ค.
@jaredpalmer ์๋ง๋์ด ๋ฌธ์ ๋ afterjs์๋ง ํด๋น๋ฉ๋๊น? ๋๋ ์๋ฒ ์ฝ๋์์๋ง ๊ทธ๊ฒ๋ค์ ์ฐธ์กฐํ๊ณ ์์ต๋๋ค.
RAZZLE
์ ๋์ฌ ์์ด ํ๊ฒฝ ๋ณ์๋ฅผ ์ ์ํ๋ ๊ธฐ๋ฅ์ ๋ํ ํฌํ๋ฅผ ์ถ๊ฐํ๊ณ ์ถ์ต๋๋ค. ์ต์ํ process.env
๋ ์๋ฒ ์ธก์์ ์ง์์ ธ์๋ ์ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฉด dotenv
์ ๊ฐ์ ๊ฒ์ ์ฌ์ฉํ์ฌ ์๋ฒ ์ธก ํ๊ฒฝ ๋ณ์๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์์ฉ ํ๋ก๊ทธ๋จ ํ๊ฒฝ์ ๋ํ ๊ฐ์ ์ ๋๋ฌด ๋ฐฉํดํ๋ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค.
๋๋ ํ์ฌ razzle์ด ํด๋ผ์ด์ธํธ์ ์๋ฒ์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ด๋ป๊ฒ ์ฃผ์ ํ๋์ง์ ๋ํด ํ์คํ ์์ง ๋ชปํ์ง๋ง, ํ์คํ ๋น์ ์ ํด๋ผ์ด์ธํธ์์ ์๋ฒ์ ํน์ ํ ๊ฒ๋ค์ ์ํ์ง ์์ ๊ฒ์ ๋๋ค. ๋ถํํ๋ ์ด๊ฒ์ ์ง๊ธ ๋์๊ฒ ์ผ์ข ์ ๊ฑฐ๋ ์ฐจ๋จ๊ธฐ์ ๋๋ค.
https://github.com/jaredpalmer/razzle/issues/477#issuecomment -363538712์์ ๋ํ ๋ฐ์ ์ฑ์ ๋ํด ์ ์๋ ์๋ฃจ์ ์ ๋ค์ ๊ฒ์ํ๊ณ ์์ต๋๋ค.
์ฃผ์ ๊ฐ๋ ์ ๋ฐํ์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ ์ ํ๊ฒ ์ค์ ํ๊ธฐ ์ํด ์๋ฒ ์คํ ์ง์ ์ ๋ฐํ์์ ์ฃผ์ ๋๋ ์ปดํ์ผ ํ์์ ํ๋ ์ด์คํ๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์ด ์๋ฃจ์ ์ ๋์ปค ์ปจํ ์ด๋์์ ์๋ฒ๋ฅผ ์คํํ๊ธฐ ์ํ ๊ฒ์ด์ง๋ง ์ด RFC์ ๋ง๊ฒ ์กฐ์ ๋ ์ ์์ต๋๋ค.
์ด ์๋ฃจ์ ์์ RAZZLE_XXXX ํ๊ฒฝ ๋ณ์๊ฐ ์ผ์นํ๊ณ HOST, PORT ๋ฐ REDIS_URL๊ณผ ํจ๊ป ์ฃผ์ ๋ฉ๋๋ค.
์ ๋ ๊ฐ์ธ์ ์ผ๋ก ์ด ๋ฌธ์ ๋ก ์ด๋ ค์์ ๊ฒช์๊ณ ์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ์ฐพ๋ ๋ฐ ๋ช ์๊ฐ์ ๋ณด๋์ต๋๋ค.
์ด๊ฒ์ webpack ์ปดํ์ผ์ ๋ด์ฌ๋์ด ์์ผ๋ฉฐ razzle it ์์ฒด์ ๊ด๋ จ์ด ์์ต๋๋ค.
create-react-app์ด ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ณ ๋ ํ๋ก์ ํธ์ ๊ฑธ์ณ ์ผ๋ถ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฐ ๋ฃจ๋น ์ฝ๋๋ฅผ ์ด์ํ ํ ๋ค์ ์๋ฃจ์ ์ ์ฌ์ฉํ์ฌ heroku์ ๋์ปค ์ปจํ ์ด๋์ razzle typescript ๋ฐ์ ์ฑ์ ์ฑ๊ณต์ ์ผ๋ก ๋ฐฐํฌํ์ต๋๋ค.
์ด ์คํฌ๋ฆฝํธ๋ ๋ฐํ์ ํ๊ฒฝ์ ์ฒ๋ฆฌํ๋ ๋ชจ๋๋ก ์ฌ์ฉ๋ฉ๋๋ค.
export interface EnvironmentStore {
NODE_ENV?: string;
[key: string]: string | undefined;
}
// Capture environment as module variable to allow testing.
let compileTimeEnv: EnvironmentStore;
try {
compileTimeEnv = process.env as EnvironmentStore;
} catch (error) {
compileTimeEnv = {};
// tslint:disable-next-line no-console
console.log(
'`process.env` is not defined. ' +
'Compile-time environment will be empty.'
);
}
// This template tag should be rendered/replaced with the environment in production.
// Padded to 4KB so that the data can be inserted without offsetting character
// indexes of the bundle (avoids breaking source maps).
/* tslint:disable:max-line-length */
const runtimeEnv = '{{RAZZLE_VARS_AS_BASE64_JSON__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________}}';
/* tslint:enable:max-line-length */
// A function returning the runtime environment, so that
// JSON parsing & errors occur at runtime instead of load time.
export const loadRuntimeEnv = (): EnvironmentStore => {
let env;
if (typeof env === 'undefined') {
if (compileTimeEnv.NODE_ENV === 'production') {
try {
env = JSON.parse((Buffer.from(runtimeEnv.trim(), 'base64').toString()));
} catch (error) {
env = {};
const overflowsMessage = runtimeEnv.slice(32, 33) !== null;
// tslint:disable-next-line no-console
console.error(
'Runtime env vars cannot be parsed. Content is `%s`',
runtimeEnv.slice(0, 31) + (overflowsMessage ? 'โฆ' : '')
);
}
} else {
env = compileTimeEnv;
}
}
return env;
};
export default loadRuntimeEnv;
์ฉ๋ฒ:
import { loadRuntimeEnv, EnvironmentStore } from './env';
const env: EnvironmentStore = loadRuntimeEnv();
const serverHost: string =env.RAZZLE_SERVER_HOST || 'localhost';
์ด ์คํฌ๋ฆฝํธ๋ server.js ๋์ ์ง์ ์ ์ผ๋ก ์ฌ์ฉ๋๋ฉฐ ์ค์ ๋ฐํ์ ํ๊ฒฝ ๋ณ์๋ก {{RAZZLE_VARS_AS_BASE64_JSON___... }} ์๋ฆฌ ํ์์๋ฅผ ์ฝ์ ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
require('newrelic');
const logger = require('heroku-logger');
const path = require('path');
const fs = require('fs');
const PLACEHOLDER = /\{\{RAZZLE_VARS_AS_BASE64_JSON_*?\}\}/;
const MATCHER = /^RAZZLE_/i;
const InjectableEnv = {
inject: function(file, ...args) {
const buffer = fs.readFileSync(file, { encoding: 'utf-8' });
let injectee = buffer.toString();
const matches = injectee.match(PLACEHOLDER);
if (!matches) {
return;
}
const placeholderSize = matches[0].length;
let env = InjectableEnv.create(args);
const envSize = env.length;
const newPadding = placeholderSize - envSize;
if (newPadding < 0) {
console.log('You need to increase your placeholder size');
process.exit();
}
const padding = Array(newPadding).join(' ');
env = InjectableEnv.pad(padding, env);
const injected = injectee.replace(PLACEHOLDER, env);
fs.writeFileSync(file, injected, { encoding: 'utf-8' });
},
create: function() {
const vars = Object.keys(process.env)
.filter(key => MATCHER.test(key))
.reduce((env, key) => {
env[key] = process.env[key];
return env;
}, {});
vars.NODE_ENV = process.env.NODE_ENV;
if (typeof process.env.HOST !== 'undefined' && typeof vars.RAZZLE_SERVER_HOST === 'undefined') {
vars.RAZZLE_SERVER_HOST = process.env.HOST;
}
if (typeof process.env.PORT !== 'undefined' && typeof vars.RAZZLE_SERVER_PORT === 'undefined') {
vars.RAZZLE_SERVER_PORT = process.env.PORT;
}
if (typeof process.env.REDIS_URL !== 'undefined' && typeof vars.RAZZLE_REDIS_URL === 'undefined') {
vars.RAZZLE_REDIS_URL = process.env.REDIS_URL;
}
return Buffer.from(JSON.stringify(vars)).toString('base64');
},
pad: function(pad, str, padLeft) {
if (typeof str === 'undefined')
return pad;
if (padLeft) {
return (pad + str).slice(-pad.length);
} else {
return (str + pad).substring(0, pad.length);
}
}
}
const root = process.cwd();
const serverBundle = path.resolve(path.join(root, '/build/server.js'));
if (fs.existsSync(serverBundle)) {
logger.info('Injecting runtime env');
InjectableEnv.inject(serverBundle);
logger.info('Launching server instance');
require(serverBundle);
}
# You should always specify a full version here to ensure all of your developers
# are running the same version of Node.
FROM node:8.9.4
ENV NODE_ENV=production \
REACT_BUNDLE_PATH=/static/js/vendor.js \
PATH=/app/node_modules/.bin:$PATH \
NPM_CONFIG_LOGLEVEL=warn
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
# use changes to package.json to force Docker not to use the cache
# when we change our application's nodejs dependencies:
COPY package.json yarn.lock /tmp/
RUN cd /tmp \
&& yarn install --production=false --pure-lockfile \
&& mkdir -p /app \
&& cp -a /tmp/node_modules /app \
&& yarn cache clean \
&& rm -rf *.*
# From here we load our application's code in, therefore the previous docker
# "layer" thats been cached will be used if possible
WORKDIR /app
ADD . /app
RUN yarn build
EXPOSE 3000
CMD ["node", "docker-start.js"]
์ค๋ฒํ๋ก ๋ฉ์์ง ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋์ง ์์ ์ ์ํด ๋ถํ๋๋ฆฌ๋ฉฐ, ๋์์ด ๋์ จ์ผ๋ฉด ํฉ๋๋ค.
create-react-app์ฉ Heroku Buildpack
create-react-app์ฉ Heroku Buildpack์ ๋ด๋ถ ๋ ์ด์ด
์ด๊ฒ์ webpack ์ปดํ์ผ์ ๋ด์ฌ๋์ด ์์ผ๋ฉฐ razzle it ์์ฒด์ ๊ด๋ จ์ด ์์ต๋๋ค.
Razzle์ DefinePlugin์ ์ค์ ํ๋ ๊ฒ์ ๋๋ค. ์ด๊ฒ์ Razzle์์ ํด๊ฒฐํ ์ ์์ต๋๋ค.
๋๋ ๋น์ ์ด ๋งํ๋ ๊ฒ์ ๋ฐ๋ฅธ๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ด๊ฐ ์๋ชป ์ดํดํ๋์ง ์๋ ค์ฃผ์ธ์. ๋น๋ ์ ์๋ฒ ๋น๋์์ ์ธ์คํด์ค ์์ ์ ๋ฌธ์์ด์ ๊ต์ฒดํ๋ ์๋ฆฌ ํ์์๋ฅผ process.env์ ๋ฃ์ต๋๋ค. ์๋ฒ ๋น๋ฐ์ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๊ฒ์ ๋๋ค. (ํด๋ผ์ด์ธํธ ๋น๋์์๋ ์คํ๋์ง ์๋ ์ด์ ๋ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.) ๋ฌธ์ : HMR์์๋ ์๋ํ์ง ์์ต๋๋ค. ํดํน์ ๋๋ค. ์์์ 4k ๊ฒฝ๊ณ๋ฅผ ๋์ ํฉ๋๋ค. ํ์ฌ ํ์์์๋ ํด๋ผ์ด์ธํธ์ ๊ณต์ ํด์ผ ํ๋ ํ๊ฒฝ ๋ณ์๋ฅผ ๋ค๋ฃจ์ง ์์ผ๋ฉฐ ๋น๋ ์๊ฐ ์์๋ก ๋จ์ ์์ต๋๋ค. ์ปจํ ์ด๋์ ๋ํ ์ถ๊ฐ ์์ ๋จ๊ณ์ ๋๋ค.
๋ด๊ฐ https://github.com/jaredpalmer/razzle/issues/528#issuecomment -377058844์์ ๋งํ ๋ง์ ๋ถ๋ถ์ ๋ค์ ์ค๋ช ํ๋ ค๋ฉด
ํด๊ฒฐ ๋ฐฉ๋ฒ์ Razzle๊ณผ CRA๊ฐ ํ์ํ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๊ธฐ๋ฅ์ process.env์ ๋ด์ผ๋ ค ํ๋ค๋ ์ฌ์ค์ ์ธ์ํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. Docker์ ํจ๊ป ์๋ํ๋๋ก ํ๊ธฐ ์ํด ์ ์ (๋น๋ ์๊ฐ) ๋ฐ ๋์ (์ฌ๊ธฐ์๋ ์ปจํ ์ด๋ ์์ ์๊ฐ), ๋น๋ฐ ๋ฐ ๋น๋น๋ฐ์ 4๊ฐ์ง ๊ฐ๋ฅํ ์ํ ์ค ํ๋๋ฅผ ๊ฐ๋ ํ๋๊ฐ ์๋ ํ๋์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํฉ๋๋ค. ์ฐ๋ฆฌ๋ 4๊ฐ์ง ์ํ(process.env.STATIC_PRIVATE_X, process.env.DYNAMIC_PUBLIC_Y, ...) ๋ชจ๋์ ๋ํ ์ ๋์ฌ๋ฅผ ์๊ฐํด๋ผ ์ ์์ง๋ง ๋ ๊นจ๋ํ ์๋ฃจ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ํจ์ฌ ๋ ๋ซ๋ค๊ณ ์๊ฐํฉ๋๋ค.
process.env๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ ๋น๋ฐ ์ ์ฅ์๋ก ์๋ํ๋ ๋ฐฉ์์ผ๋ก ์๋ํ๋ค๋ฉด ์ํฉ์ ํจ์ฌ ๋ ์ฝ๊ฒ ์ดํดํ ์ ์์ต๋๋ค. ํ ๊ฐ์ง ์์ธ๊ฐ ์์ต๋๋ค. NODE_ENV๋ ๋น๋ ํ์ ์ธ๋ผ์ธ์ด์ง๋ง ๋น๋์ ์์ฑ์ด๊ธฐ ๋๋ฌธ์ ๊ด์ฐฎ์ต๋๋ค. ๋ฐํ์์ NODE_ENV๋ฅผ ์ค์ ํ๋ ๊ฒ์ ์๋ฏธ๊ฐ ์์ต๋๋ค.
์ด์ ํด๋ผ์ด์ธํธ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ๋ง ๋จ์์ต๋๋ค. ์ด๊ฒ์ด process.env๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ฅผ ์ ํ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. ์ ์ ํญ๋ชฉ์ ์๋ฅผ ๋ค์ด razzle.build.X๋ฅผ ์ฌ์ฉํ๊ณ redux์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋์ ํญ๋ชฉ์ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
Node์์ process.env๊ฐ ๋๋ฆฐ ๋ ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์์ง๋ง process.env๋ฅผ ํ ๋ฒ ์ฝ๋ ์บ์ ๊ณ์ธต์ผ๋ก ํด๊ฒฐํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
@gregmartyn ๋๋ ์ด๊ฒ์ด ํดํน์ด๋ผ๋ ๋ฐ ๋์ํฉ๋๋ค ... ๊ทธ๋ฆฌ๊ณ ๊ทธ๊ฒ์ ์์์ 4K ๊ฒฝ๊ณ๋ฅผ ๋์ ํฉ๋๋ค. ์ด ์์ด๋์ด๋ ํ์ฌ CRA๋ก ์ํ๋ ์์ (๊ฒ์๋ ์ฐธ์กฐ ์ฐธ์กฐ)์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ ์๋ฒ ์ธก ๋ฐํ์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ํ ๊ฒ์ ๋๋ค.
์ด ๋ฌธ์ ์ ๊ทผ๋ณธ ์์ธ์ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ผ๋ก ์๊ฐ ๋๋ PR ์
๋ํ PORT
& HOST
๋ ์ด์์ ์ผ๋ก๋ ์๋ฒ ์ปดํ์ผ ์๊ฐ์ ํผ์ ๋จ๊ฒจ์ง๋ ๊ฒ์ ๋์ํฉ๋๋ค.
@tgrisser ์ข์์ ! ๊ทธ๊ฒ์ ํฐ ๊ฐ์ ์
๋๋ค.
PORT
๋ฐ HOST
์ธ์๋ ์ปดํ์ผํด์๋ ์๋๋ ๋ณ์ ๋ชฉ๋ก์ PUBLIC_PATH
๋ฅผ ์ถ๊ฐํฉ๋๋ค.
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ, ์ ๋ ์ด๋ฒ ์ฃผ์ ์ง์ฅ์์ ์ด ๋ชจ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์์ต๋๋ค. ๊ณ์ ์ง์ผ๋ด ์ฃผ์ธ์. #611์ด ๋ณํฉ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
config.js๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๊ฐ ์ ๋ณด์ ์ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅด๋ฉด ๋ฒ๋ค์์ ๋ฏผ๊ฐํ ํ๊ฒฝ ๋ณ์๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ๊ณผ ๊ด๋ จํ์ฌ ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค. ๋๋จํ๋ค :D
v2 ๋ ธํธ ๋ณด๊ธฐ
@jaredpalmer ๋ด๊ฐ ๋์น ๊ฒ์ด ์์ ์ ์์ง๋ง readme ๋ฌธ์๊ฐ ์๋ฏธํ๋ ๋ฐ์๋ ๋ถ๊ตฌํ๊ณ ์ด๊ฒ์ ์ฌ์ ํ โโPORT์ ๊ฐ์ ๋ฌธ์ ์ ๋ํ ๋ฌธ์ ์
๋๋ค. process.env.MY_THING
๋ ์ ์๋ํ์ง๋ง process.env.PORT
๋ ์ฌ์ ํ ๋น๋ ์ ๋์ฒด๋๋ฉฐ ๋ฐํ์ ์ ์ฝ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ Heroku ์์ ๋ ์ค์ ๋ก ์๋ํ์ง ์์ต๋๋ค.
์ด ์ค๋ ๋์์ ๋ ผ์๋ PORT, HOST ๋ฑ์ ํน๋ณํ ์ฒ๋ฆฌ๋ ๋ณด์ง ๋ชปํ์ต๋๋ค.
PORT๋ฅผ ์ค์ ๋ณ์๋ก ๋ง๋๋ ๊ฒ๋ #581์ ์ํด ์ฐจ๋จ๋ฉ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ํจ์นํ๊ณ ์๋์ํค๊ธฐ ์ํด PORT๋ฅผ ์ ๊ฑฐํ๋ DefinePlugin ๋ฐฐ์ด์ ์์ฑํ๋ razzle.config.js๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค. (ํ์ง๋ง ์๋ํฉ๋๋ค!)
๋ฐํ์์ .env ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ค๋ ์ฌ๋์ด ์๋ค๋ฉด ์ด ์์ ํจํค์ง๋ฅผ ์ฌ์ฉํ์ธ์.
https://www.npmjs.com/package/razzle-plugin-runtimeenv
๋๊ตฐ๊ฐ Azure์ Razzle ์ฑ์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ์กฐ์ธํด ์ฃผ์๊ฒ ์ต๋๊น? ์ ๋ง ํ๋ค์ด์.
๋ฐํ์์ .env ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ค๋ ์ฌ๋์ด ์๋ค๋ฉด ์ด ์์ ํจํค์ง๋ฅผ ์ฌ์ฉํ์ธ์.
https://www.npmjs.com/package/razzle-plugin-runtimeenv
์ด๋ป๊ฒ ์๋ํฉ๋๊น? ์๋ฅผ ๋ณด์ฌ ์ฃผ์๊ฒ ์ต๋๊น?
ํ๊ฒฝ ๋ณ์๋ ์ค์ ๋ก ๋ฐํ์์ ์ฃผ์ ๋์ด์ผ ํ๋ค๊ณ ์๊ฐํฉ๋๋ค. razzle ์ฑ์ ์ปจํ ์ด๋ํํ๋ฉด ์คํ๋๋ ํ๊ฒฝ๊ณผ ๋ ๋ฆฝ์ ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค๊ณ ์๋ฒ๋ฅผ ์์ํ ๋ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฝ๊ณ ํด๋ผ์ด์ธํธ ์ฑ์ ์ ๊ณตํ๊ณ ์ถ์ต๋๋ค.
๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ๋น๋ ์๊ฐ์๋ง ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ค์ ๋ก ํ๊ฒฝ ๋ณ์๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
๋ด๊ฐ ์ฌ๊ธฐ์์ ์ธ๊ธํ๋ฏ์ด :
https://github.com/HamidTanhaei/razzle-plugin-runtime/issues/1#issuecomment -525731273
razzle-plugin-runtime
๋ฐํ์์์ .env ๋ฐ .env.development ํ์ผ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐํ์์ ์ฑ์์ ํ๊ฒฝ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํฉ๋๋ค.
์๋ฅผ ๋ค์ด axios
๊ตฌ์ฑ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
axios.defaults.baseURL =
${process.env.RAZZLE_APP_API_BASE_PATH}${process.env.RAZZLE_APP_API_VERSION} ;
๋ค์๊ณผ ๊ฐ์ด ์์ฐ์ ์ํ ์์ฐ ENV ๋ณ์๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
https://github.com/jaredpalmer/razzle#adding -temporary-environment-variables-in-your-shell
๋๊ตฐ๊ฐ Azure์ Razzle ์ฑ์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ์กฐ์ธํด ์ฃผ์๊ฒ ์ต๋๊น? ์ ๋ง ํ๋ค์ด์.
https://github.com/jaredpalmer/razzle/issues/906#issuecomment -467046269์์ @fabianisher ๊ฐ ๊ณต์ ํ ์๋ฃจ์ ์ ์ฌ์ฉํ์ฌ Azure ํฌํธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@jaredpalmer ๋ด๊ฐ ๋์น ๊ฒ์ด ์์ ์ ์์ง๋ง readme ๋ฌธ์๊ฐ ์๋ฏธํ๋ ๋ฐ์๋ ๋ถ๊ตฌํ๊ณ ์ด๊ฒ์ ์ฌ์ ํ โโPORT์ ๊ฐ์ ๋ฌธ์ ์ ๋ํ ๋ฌธ์ ์ ๋๋ค.
process.env.MY_THING
๋ ์ ์๋ํ์ง๋งprocess.env.PORT
๋ ์ฌ์ ํ ๋น๋ ์ ๋์ฒด๋๋ฉฐ ๋ฐํ์ ์ ์ฝ์ง ์์ต๋๋ค. ๋ฐ๋ผ์ Heroku ์์ ๋ ์ค์ ๋ก ์๋ํ์ง ์์ต๋๋ค.์ด ์ค๋ ๋์์ ๋ ผ์๋ PORT, HOST ๋ฑ์ ํน๋ณํ ์ฒ๋ฆฌ๋ ๋ณด์ง ๋ชปํ์ต๋๋ค.