웹사이트 검색

React 앱에 대해 서버 측 렌더링을 활성화하는 방법


경고: 이 튜토리얼은 ReactDOM.hydrate()ReactDOMServer.rendertoString()에 대한 간략한 소개를 목적으로 합니다. 프로덕션 용도로 사용할 수 없습니다.

또는 Next.js는 React로 구축된 정적 및 서버 렌더링 애플리케이션을 만드는 현대적인 접근 방식을 제공합니다.

소개

서버측 렌더링(SSR)은 서버에서 클라이언트측 단일 페이지 애플리케이션(SPA)을 렌더링한 다음 완전히 렌더링된 페이지를 클라이언트로 보내는 데 널리 사용되는 기술입니다. . 이를 통해 동적 구성 요소를 정적 HTML 마크업으로 제공할 수 있습니다.

이 접근 방식은 인덱싱이 JavaScript를 제대로 처리하지 못하는 경우 검색 엔진 최적화(SEO)에 유용할 수 있습니다. 느린 네트워크로 인해 큰 JavaScript 번들을 다운로드하는 데 방해가 되는 상황에서도 유용할 수 있습니다.

이 자습서에서는 Create React App을 사용하여 React 앱을 초기화한 다음 서버 측 렌더링을 활성화하도록 프로젝트를 수정합니다.

이 튜토리얼이 끝나면 클라이언트 측 React 애플리케이션과 서버 측 Express 애플리케이션이 포함된 작업 프로젝트를 갖게 됩니다.

전제 조건

이 자습서를 완료하려면 다음이 필요합니다.

  • Node.js를 로컬에 설치했습니다. Node.js를 설치하고 로컬 개발 환경을 만드는 방법에 따라 수행할 수 있습니다.

이 튜토리얼은 Node v16.13.1, npm v8.1.2, react v17.0.2, @babel/core v7.16.0, webpack v4.44.2, express v4.17.1, nodemon v2.0.15 및 npm-run-all v4. 1.5.

1단계 — React 앱 생성 및 앱 구성 요소 수정

먼저 npx를 사용하여 최신 버전의 Create React App을 사용하여 새 React 앱을 시작합니다.

react-ssr-example 앱을 호출해 보겠습니다.

  1. npx create-react-app react-ssr-example

그런 다음 새 디렉터리로 cd합니다.

cd react-ssr-example

마지막으로 설치를 확인하기 위해 새 클라이언트 측 앱을 시작합니다.

  1. npm start

브라우저 창에 표시되는 예제 React 앱을 관찰할 것입니다.

이제 src 디렉토리에서 새 구성 요소를 생성해 보겠습니다.

  1. nano src/Home.js

다음으로 Home.js 파일에 다음 코드를 추가합니다.

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

export default Home;

이렇게 하면 이름을 가리키는 \Hello\ 메시지가 있는 <h1> 제목이 생성됩니다.

다음으로 구성 요소에서 를 렌더링하겠습니다. src 디렉터리에서 App.js 파일을 엽니다.

  1. nano src/App.js

그런 다음 기존 코드 줄을 다음과 같은 새 코드 줄로 바꿉니다.

import Home from './Home';

function App() {
  return <Home name="Sammy"/>;
}

export default App;

이것은 name 구성 요소에 전달하므로 표시할 메시지는 다음과 같습니다.

Output
"Hello Sammy!"

앱의 index.js 파일에서 render 대신 ReactDOM의 hydrate 메서드를 사용하여 DOM 렌더러에 서버 측 렌더링 후 앱.

src 디렉토리에서 index.js 파일을 열어봅시다:

  1. nano src/index.js

그런 다음 index.js 파일의 내용을 다음 코드로 바꿉니다.

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

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

이것으로 클라이언트 측 설정이 완료되면 서버 측 설정으로 넘어갈 수 있습니다.

2단계 - Express 서버 생성 및 앱 구성 요소 렌더링

이제 앱이 준비되었으므로 렌더링된 버전을 보낼 서버를 설정하겠습니다. 서버에는 Express를 사용합니다.

참고: Create React App의 react-scriptswebpack-dev-server의 요구 사항으로 express 버전을 설치합니다. 종속성 트리 충돌을 방지하기 위해 이 자습서에는 이 설치 단계가 더 이상 포함되지 않습니다.

다음으로 프로젝트의 루트 디렉터리에 새 server 디렉터리를 만듭니다.

  1. mkdir server

그런 다음 server 디렉토리 내에서 Express 서버 코드를 포함할 새 index.js 파일을 만듭니다.

  1. nano server/index.js

필요한 가져오기를 추가하고 몇 가지 상수를 정의합니다.

import path from 'path';
import fs from 'fs';

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import express from 'express';

import App from '../src/App';

const PORT = process.env.PORT || 3006;
const app = express();

다음으로 일부 오류 처리와 함께 서버 코드를 추가합니다.

// ...

app.get('/', (req, res) => {
  const app = ReactDOMServer.renderToString(<App />);
  const indexFile = path.resolve('./build/index.html');

  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">${app}</div>`)
    );
  });
});

app.use(express.static('./build'));

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

서버에서 직접 클라이언트 앱의 구성 요소를 가져올 수 있습니다.

여기서 세 가지 중요한 일이 발생합니다.

  • Express는 build 디렉토리의 콘텐츠를 정적 파일로 제공하는 데 사용됩니다.
  • ReactDOMServerrenderToString은 앱을 정적 HTML 문자열로 렌더링하는 데 사용됩니다.
  • 빌드된 클라이언트 앱의 정적 index.html 파일을 읽습니다. 앱의 정적 콘텐츠는 idroot<div>에 삽입됩니다. 이것은 요청에 대한 응답으로 전송됩니다.

3단계 - webpack, Babel 및 npm 스크립트 구성

서버 코드가 작동하려면 Babel을 사용하여 번들링하고 트랜스파일해야 합니다. 이를 달성하기 위해.

참고: 이 튜토리얼의 이전 버전은 babel-core, babel-preset-envbabel-preset-react-app를 설치했습니다. 이 패키지는 보관되었으며 대신 모노 리포지토리 버전이 사용되었습니다.

Create React App의 react-scriptswebpack, webpack-cli, webpack-node-externals 패키지 설치를 처리합니다. , @babel/core, babel-loader, @babel/preset-env, @babel/preset-react . 종속성 트리 충돌을 방지하기 위해 이 자습서에는 이 설치 단계가 더 이상 포함되지 않습니다.

다음으로 프로젝트의 루트 디렉터리에 새 Babel 구성 파일을 만듭니다.

  1. nano .babelrc.json

그런 다음 envreact-app 사전 설정을 추가합니다.

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

참고: 이 튜토리얼의 이전 버전에서는 .babelrc 파일을 사용했습니다(.json 파일 확장자 없음). 이것은 Babel 6의 구성 파일이었지만 더 이상 Babel 7의 경우가 아닙니다.

이제 Babel Loader를 사용하여 코드를 변환하는 서버에 대한 웹팩 구성을 생성합니다. 프로젝트의 루트 디렉터리에 webpack.server.js 파일을 생성하여 시작합니다.

  1. nano webpack.server.js

그런 다음 webpack.server.js 파일에 다음 구성을 추가합니다.

const path = require('path');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: './server/index.js',
  target: 'node',
  externals: [nodeExternals()],
  output: {
    path: path.resolve('server-build'),
    filename: 'index.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader'
      }
    ]
  }
};

이 구성으로 트랜스파일된 서버 번들은 index.js라는 파일의 server-build 폴더에 출력됩니다.

webpack-node-externalstarget: nodeexternals: [nodeExternals()] 사용에 유의하십시오. 번들의node_modules; 서버는 이러한 파일에 직접 액세스할 수 있습니다.

이것으로 종속성 설치와 webpack 및 Babel 구성이 완료됩니다.

이제 package.json을 다시 방문하여 도우미 npm 스크립트를 추가합니다.

  1. nano package.json

빌드할 package.json 파일에 dev:build-server, dev:startdev 스크립트를 추가합니다. SSR 애플리케이션을 제공합니다.

"scripts": {
  "dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
  "dev:start": "nodemon ./server-build/index.js",
  "dev": "npm-run-all --parallel build dev:*",
  // ...
},

dev:build-server 스크립트는 환경을 \development\로 설정하고 이전에 생성한 구성 파일로 webpack을 호출합니다. dev:start 스크립트는 nodemon을 호출하여 빌드된 출력을 제공합니다.

dev 스크립트는 npm-run-all을 호출하여 build 스크립트와 다음으로 시작하는 모든 스크립트를 병렬로 실행합니다. dev:* - dev:build-serverdev:start 포함.

참고: 기존 \start\, \build\, \test\\eject\를 수정할 필요가 없습니다. package.json 파일의 스크립트.

nodemon은 변경 사항이 있을 때 서버를 다시 시작하는 데 사용됩니다. npm-run-all은 여러 명령을 병렬로 실행하는 데 사용됩니다.

이제 터미널 창에 다음 명령을 입력하여 해당 패키지를 설치해 보겠습니다.

  1. npm install nodemon@2.0.15 --save-dev
  2. npm install npm-run-all@4.1.5 --save-dev

이를 통해 다음을 실행하여 클라이언트 측 앱을 빌드하고, 서버 코드를 번들 및 트랜스파일하고, :3006에서 서버를 시작할 수 있습니다.

  1. npm run dev

서버 webpack 구성은 이제 변경 사항을 감시하고 변경 사항에 따라 서버가 다시 시작됩니다. 그러나 클라이언트 앱의 경우 변경 사항이 있을 때마다 수동으로 다시 빌드해야 합니다.

참고: 여기에 대한 공개 문제가 있습니다.

이제 웹 브라우저에서 http://localhost:3006/을 열고 서버측 렌더링된 앱을 관찰합니다.

이전에는 소스 코드를 보면 다음과 같이 밝혀졌습니다.

Output
<div id="root"></div>

그러나 이제 변경 사항을 적용하면 소스 코드에 다음이 표시됩니다.

Output
<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>

서버 측 렌더링이 구성 요소를 HTML로 성공적으로 변환했습니다.

결론

이 자습서에서는 React 애플리케이션을 초기화하고 서버 측 렌더링을 활성화했습니다.

이 게시물을 통해 우리는 가능한 것에 대해 표면을 긁었습니다. 라우팅, 데이터 가져오기 또는 Redux도 서버 측 렌더링 앱의 일부가 되어야 하면 상황이 좀 더 복잡해지는 경향이 있습니다.

SSR 사용의 주요 이점 중 하나는 JavaScript 코드를 실행하지 않는 크롤러의 경우에도 콘텐츠를 크롤링할 수 있는 앱이 있다는 것입니다. 이것은 검색 엔진 최적화(SEO)와 소셜 미디어 채널에 메타데이터를 제공하는 데 도움이 될 수 있습니다.

SSR은 또한 완전히 로드된 앱이 첫 번째 요청 시 서버에서 전송되기 때문에 종종 성능에 도움이 될 수 있습니다. 사소하지 않은 앱의 경우 SSR은 약간 복잡해질 수 있는 설정이 필요하고 서버에 더 큰 부하를 생성하기 때문에 마일리지가 다를 수 있습니다. React 앱에 서버 측 렌더링을 사용할지 여부는 특정 요구 사항과 사용 사례에 가장 적합한 장단점이 무엇인지에 따라 다릅니다.

React에 대해 자세히 알아보려면 연습 및 프로그래밍 프로젝트에 대한 React 주제 페이지를 살펴보세요.