카테고리 없음

React 18 Typescript(+NodeJS)에서 SSR 사용하기

Wood Pecker 2022. 6. 24. 00:01

1. 개요

      SSR(Server-Side Rendering)은 여러 장점이 있다.  React 18버전에서 사용하여 본다.  React 18 버전은  2022년 3월에 release 되었는데 많은 변화와 새로운 개념들이 도입되었다. 그렇지만 일단 가장 간단하게 실행되는 SSR프로젝트를 만들어 보고 새로운 기능들은 차츰 적용하면서 테스트 하여 보자.   

  [참고]  https://www.digitalocean.com/community/tutorials/react-server-side-rendering 

 

1.  환경설치

     기본적으로 nodejs등 환경 설치는 사전 준비된 것으로 가정한다.   최신 환경으로  업그레이드한다
     >   npm i -g npm@latest

     >   npm rm -g create-react-app     

      >  npm install -g react@latest react-dom@latest

      >   npm install -g @types/react @types/react-dom

2.  프로젝트 생성하기  

    Create React App을 사용하여 React 프로젝트(프로젝트명:ssr )를 만들어 보자.     

      >   npx create-react-app ssr --template typescript

      >   cd  ssr 

 

   설치된 버전을 확인하여 본다.

   >   npm view react version
   >  npm view react-script version 

 

      >   npm start 

          React 템플리트 코드가  실행될 것이다.  port 3000으로 실행되고 있는 Client Side Rendering 이다. 

3. src/App.tsx 파일을 다음과 같이 수정한다. 
   webpack 설정을 쉽게하기 위해 src/log.svg 파일을 delete 삭제한다. 

import React from 'react';
import './App.css';

function Home(props:any){
  return <h1>Hello {props.name}!</h1>;
}

function welcome(){
  console.log("Welcome... ");
  document.getElementById("test")!.innerHTML
         =document.getElementById("test")!.innerHTML+" Button Click!! ";
}


function App() {
  return (
    <div className="App">
        <Home name="Yahoo!!"/>
        <div id="test">Test </div>
        <button onClick={welcome}>Click Me!</button>
    </div>
  );
}

export default App;

 

 

4. src/index.tsx 파일을 다음과 같이 수정한다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
//const root = ReactDOM.createRoot(
//  document.getElementById('root') as HTMLElement
//);
//root.render(
//  <React.StrictMode>
//    <App />
//  </React.StrictMode>
//);

ReactDOM.hydrateRoot(
  document.getElementById('root')!,
  <React.StrictMode>
      <App />
  </React.StrictMode>
);

5. server 프로그램을 작성한다.   프로젝트 root 폴더 아래에 server폴더를 만들고 
    그 안에  server.tsx 파일을 신규 생성하고  다음과 같이 입력한다.  
    <App>  컴포넌트를  ReactDOMServer.renderToString 함수를 이용하여  
   직접 임포트하여 렌더링하여 브라우저에 보내준다.  서버 프로그램은 포트 3006에서 실행하도록 설정하였다.

ReactDOMServer.renderToString

ReactDOMServer.renderToString

import path from 'path';
import fs from 'fs';
import ReactDOMServer from 'react-dom/server';
import express from 'express';
import App from '../src/App';

const PORT = process.env.PORT || 3006;
const app = express();
console.log('서버 프로그램 실행 .....');
app.get('/', (req, res) => {
    const html = ReactDOMServer.renderToString(<App />);
    const indexFile = path.resolve('./build/index.html');
    console.log(indexFile,'서버 working...');
    fs.readFile(indexFile, 'utf8', (err, data) => {
      if (err) {
        console.error('Something went wrong:', err);
        return res.status(500).send('Oops, better luck next time!');
      }
      return res.send(
        data.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
      );
    });
  });
  app.use(express.static( path.resolve('./build')));
  app.listen(PORT, () => {
    console.log(`Server is listening on port ${PORT}`);
  });


6. 서버 프로그램을 동작시켜 주기 위해서 아래와 같이 몇가지 설정을 변경한다.

    webpack과 babel을 사용하여 서버 프로그램을 실행하여 줄 것이다.
    프로젝트 루트폴더에 .babelrc.json 파일을 생성하고 아래와 같이 입력한다.

{    "presets": [
      "@babel/preset-env",
       ["@babel/preset-react", {"runtime": "automatic"}],
       "@babel/preset-typescript"
    ]
}

프로젝트 루트 폴더에 webpack.server.tsx 파일을 생성하고 아래와 같이 입력한다. 

import nodeExternals from 'webpack-node-externals';
import path from 'path';

module.exports = {
      entry: './server/server.tsx',
      target: 'node',
      mode: 'production',
      externals: [nodeExternals()],
      output: {
             path: path.resolve(__dirname, `server-build`),
             filename: 'index.js'
       },
      resolve: {
            extensions: [".tsx","js"]
       },
      module: {
          rules: [
             {   test: /\.tsx$/,   use: ['babel-loader']  },
             {   test: /\.css$/use: 'css-loader' },
           ]
      }
  };
 
만일 module이 없다고 에러가 발생하면 다음과 같이 모듈을 설치한다.
 
     > npm install --save-dev @types/webpack @types/webpack-node-externals
     > npm install --save-dev webpack-node-externals
    

package.json 파일에 다음과 같이 아래  3줄을 추가한다.

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "dev:build-server": "NODE_ENV=development webpack --config webpack.server.tsx --mode=development",
    "dev:start": "nodemon ./server-build/index.js",
    "dev": "npm-run-all --parallel build dev:*"
  },
 
 아래 모듈이 없다면 다음의 명령어를 실행한다.

   >  npm install npm-run-all 

   >  webpack -v   

   >  npm install --save-dev webpack
    > npm install --save-dev webpack-cli
 
   >  nodemon -v
   >  npm install -g nodemon
 
   > npm run build
   
   >  webpack --config webpack.server.tsx --mode=development
          또는 
   >  webpack --config webpack.server.tsx --mode=production

  [참조명령]
   //>  npm install -g webpack webpack-cli webpack-dev-server --save-dev
   //> npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
    //>  npm cache clean --force
    //>  npm install webpack@latest webpack-cli@latest
    //> npm add babel-loader @babel/core @babel/preset-react 

 

이제 최종적으로 다음과 같이 명령어로 실행한다. 

   >  nodemon ./server-build/index.js

웹브라우저에서 다음의 주소를 입력하여 보자.  버튼 이벤트도 정상 실행되는지 확인해 본다. 

 

 

 

 

 

 

반응형