Server side rendering: JSX 을 서버에서 렌더링 하기?

DG
7 min readDec 1, 2019

--

src/client/components/Home.js

import React from 'react'
const Home = () => {return <div>I'm the Home component</div>}export default Home

다음과 같은 아주 가벼운 Home 가 있습니다. 이를 express 서버측에서 화면에 렌더링 해주고 싶다면 어떻게 해야할까요?

방법은 아주 간단합니다. 다음과 같이 renderToString 함수를 써주면 됩니다!

src/index.js

const express = require('express')const React = require('react')const renderToString = require('react-dom/server').renderToStringconst Home = require('./client/components/Home').defaultconst app = express()app.get('/', (req, res) => {const content = renderToString(<Home />)res.send(content)})app.listen(5000, () => console.log('render server listening on port 5000'))

renderToString?

renderToString 함수란 ReactDOM 모듈에서 사용할 수 있는 함수입니다. 기본적으로 render 함수와 아주 비슷한 녀석인데요, render 함수 같은 경우에는 JSX 코드로 짜여진 녀석들을 여러개의 컴포넌트객체로 만들어주고, DOM 노드로 계속해서 올려주는 역할을 해줍니다.

반면에 renderToString 함수는 JSX 로 짜여진 component들을 순수 HTML 코드로 변환시켜준 후에 딱 한번만 렌더링시켜주는 녀석입니다.

그러면 src/index.js 파일을 실행을 시켜보면, 우리가 JSX 로 만들어준 Home 컴포넌트를 localhost:5000/ 에 들어가서 확인할 수 있어야 하겠죠? 서버를 한 번 실행시켜보도록 하겠습니다.

⇒  node src/index.js
/Users/sindong-gyu/Documents/server-side-rendering-react-redux/server/src/index.js:8
const content = renderToString(<Home />)
^

오류가 발생하였습니다. 어떻게 된 일 일까요? src/index.js 는 현재 common js syntax를 사용하고 있습니다. 반면에 renderToString에게 인자로 주어진 <Home /> 컴포넌트를 보면 JSX 문법을 사용하고 있습니다. 당연히 common syntax 를 사용하고 있는 node 가 해당 문법을 해석할 수 없기 때문에 해당 부분에서 에러가 나고 있습니다. 이를 고쳐주기 위해서는 node 가 React 에서 사용하는 문법들을 이해할 수 있게끔 환경을 맞춰주어야 합니다.

클라이언트 사이드에서는 그럼 어떻게 es6 문법이나, jsx 문법을 사용할 수 있는 것 일까요?

클라이언트 쪽에서는 위와 같이 여러 jsx 문법으로 쓰여진 컴포넌트들을 화면에 불러와줄 수 있습니다. 그게 가능한 이유는 jsx 문법으로 쓰여진 컴포넌트들을 index.js 파일에서 한번에 불러오고, 이를 웹팩의 설정값들을 이용해서 babel 로 하나의 통합된 common js 문법의 코드로 바꿔주게 됩니다. 이를 통해서 생성된 파일을 우리는 bundle.js 라고 부릅니다.

그러면 서버 사이드에서 webpack을 이용하여서 jsx 문법으로 작성된 코드를 읽어보도록 해볼까요?

webpack.server.js

const path = require('path')module.exports = {// Inform webpack that we're building a bundle for nodejs,// rather than for the brower. Default value is browser.target: 'node',// Tell webpack the root file of our server applicationentry: './src/index.js',// Tell webpack where to put the out file that is generatedoutput: {filename: 'bundle.js',path: path.resolve(__dirname, 'build')},// Tell webpack to run babel on every file it runs throughmodule: {rules: [{// Run babel only on javascript filestest: /\.js?$/,// If webpack finds js file, run babel-loader as a loaderloader: 'babel-loader',// Tell webpack not to run babel over filesexclude: /node_modules/,// Options will be applied to the babeloptions: {presets: ['react','stage-0',['env', { targets: { browsers: ['last 2 versions'] } }]]}}]}}

package.json

"scripts": {"dev:build:server": "webpack --config webpack.server.js"},

terminal command

yarn dev:build:server

result

$ webpack --config webpack.server.js
Hash: c4c07676ef60903ccd9f
Version: webpack 3.5.6
Time: 1990ms
Asset Size Chunks Chunk Names
bundle.js 755 kB 0 [emitted] [big] main
[51] ./src/index.js 451 bytes {0} [built]
[73] ./node_modules/express/lib 160 bytes {0} [built]
[91] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 122 hidden modules
WARNING in ./node_modules/express/lib/view.js
79:29-41 Critical dependency: the request of a dependency is an expression
✨ Done in 4.13s.

이제 우리의 프로젝트를 살펴보면 새롭게 build/bundle.js 파일이 생겼음을 볼 수 있습니다.

그러면 이제 bundle.js 파일을 실행시켜보고 브라우저를 통해서 직접 확인해볼까요?

페이지를 로드 시키면 처음에 localhost 로 요청을 보내고, 해당 localhost로부터 받아온 파일에는 어떤 javascript 도 없이 순수한 html 코드만이 존재하고 있습니다.

Server side rendering 의 첫걸음을 방금 막 마치셨습니다. 축하드려요.

Git Repository

--

--

DG
DG

Written by DG

한국의 iOS 개발자이다. 강아지와 운동을 좋아함. github: https://github.com/donggyushin

No responses yet