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 앱을 호출해 보겠습니다.
- npx create-react-app react-ssr-example
그런 다음 새 디렉터리로 cd
합니다.
cd react-ssr-example
마지막으로 설치를 확인하기 위해 새 클라이언트 측 앱을 시작합니다.
- npm start
브라우저 창에 표시되는 예제 React 앱을 관찰할 것입니다.
이제 src
디렉토리에서 새
구성 요소를 생성해 보겠습니다.
- nano src/Home.js
다음으로 Home.js
파일에 다음 코드를 추가합니다.
function Home(props) {
return <h1>Hello {props.name}!</h1>;
};
export default Home;
이렇게 하면 이름을 가리키는 \Hello\
메시지가 있는 <h1>
제목이 생성됩니다.
다음으로
구성 요소에서
를 렌더링하겠습니다. src
디렉터리에서 App.js
파일을 엽니다.
- 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
파일을 열어봅시다:
- 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-scripts
는 webpack-dev-server
의 요구 사항으로 express
버전을 설치합니다. 종속성 트리 충돌을 방지하기 위해 이 자습서에는 이 설치 단계가 더 이상 포함되지 않습니다.
다음으로 프로젝트의 루트 디렉터리에 새 server
디렉터리를 만듭니다.
- mkdir server
그런 다음 server
디렉토리 내에서 Express 서버 코드를 포함할 새 index.js
파일을 만듭니다.
- 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
디렉토리의 콘텐츠를 정적 파일로 제공하는 데 사용됩니다. ReactDOMServer
의renderToString
은 앱을 정적 HTML 문자열로 렌더링하는 데 사용됩니다.- 빌드된 클라이언트 앱의 정적
index.html
파일을 읽습니다. 앱의 정적 콘텐츠는id
가root
인<div>
에 삽입됩니다. 이것은 요청에 대한 응답으로 전송됩니다.
3단계 - webpack, Babel 및 npm 스크립트 구성
서버 코드가 작동하려면 Babel을 사용하여 번들링하고 트랜스파일해야 합니다. 이를 달성하기 위해.
참고: 이 튜토리얼의 이전 버전은 babel-core
, babel-preset-env
및 babel-preset-react-app
를 설치했습니다. 이 패키지는 보관되었으며 대신 모노 리포지토리 버전이 사용되었습니다.
Create React App의 react-scripts
는 webpack
, webpack-cli
, webpack-node-externals
패키지 설치를 처리합니다. , @babel/core
, babel-loader
, @babel/preset-env
, @babel/preset-react
. 종속성 트리 충돌을 방지하기 위해 이 자습서에는 이 설치 단계가 더 이상 포함되지 않습니다.
다음으로 프로젝트의 루트 디렉터리에 새 Babel 구성 파일을 만듭니다.
- nano .babelrc.json
그런 다음 env
및 react-app
사전 설정을 추가합니다.
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
참고: 이 튜토리얼의 이전 버전에서는 .babelrc
파일을 사용했습니다(.json
파일 확장자 없음). 이것은 Babel 6의 구성 파일이었지만 더 이상 Babel 7의 경우가 아닙니다.
이제 Babel Loader를 사용하여 코드를 변환하는 서버에 대한 웹팩 구성을 생성합니다. 프로젝트의 루트 디렉터리에 webpack.server.js
파일을 생성하여 시작합니다.
- 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-externals
의 target: node
및 externals: [nodeExternals()]
사용에 유의하십시오. 번들의node_modules; 서버는 이러한 파일에 직접 액세스할 수 있습니다.
이것으로 종속성 설치와 webpack 및 Babel 구성이 완료됩니다.
이제 package.json
을 다시 방문하여 도우미 npm
스크립트를 추가합니다.
- nano package.json
빌드할 package.json
파일에 dev:build-server
, dev:start
및 dev
스크립트를 추가합니다. 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-server
및 dev:start
포함.
참고: 기존 \start\
, \build\
, \test\
및 \eject\를 수정할 필요가 없습니다.
package.json
파일의 스크립트.
nodemon
은 변경 사항이 있을 때 서버를 다시 시작하는 데 사용됩니다. npm-run-all
은 여러 명령을 병렬로 실행하는 데 사용됩니다.
이제 터미널 창에 다음 명령을 입력하여 해당 패키지를 설치해 보겠습니다.
- npm install nodemon@2.0.15 --save-dev
- npm install npm-run-all@4.1.5 --save-dev
이를 통해 다음을 실행하여 클라이언트 측 앱을 빌드하고, 서버 코드를 번들 및 트랜스파일하고, :3006
에서 서버를 시작할 수 있습니다.
- 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 주제 페이지를 살펴보세요.