[react] ssr 프로젝트 만들기 (1) - hello world 찍기
[react] ssr 프로젝트 만들기 (2) - css, 번들에 추가하기
에서는 client 번들링 파일 이름이 동일하여 cdn에 올릴 때 이슈가 발생할 수 있다.
이 이슈를 해결해보자
소스 코드
https://github.com/insidedw/react-webpack5-ssr/commit/bbf8ea9efe8a73d6e470335ad2a34af23312100e
inject css on ssr using mini-css-extract-plugin and webpack-manifest-… · insidedw/react-webpack5-ssr@bbf8ea9
…plugin
github.com
시작하기 전 스타일링이 ssr에 포함되도록 준비해보자
webpack-manifest-plugin 설치
MiniCssExtractPlugin 을 이용해서 css를 별도의 파일로 추출해보자
npm i -D mini-css-extract-plugin
webpack.client.js 설정
MiniCssExtractPlugin 설정과 output에 filename, clean 항목 추가해서 js, css 파일을 번들링해보자
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode: 'development',
entry: './src/client.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[hash].js',
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
})
],
}
이 상태로 빌드하면, 페이지가 정상적으로 로드 되지 않는다.
이유는 public/index.html에서 client.bundle.js를 항상 주입하기 때문이다.
우리가 번들링 된 파일 이름을 동적으로 변경되도록 설정했기 때문에 매치가 안되는 상황이다.
그렇다면 매번 변경되는 번들링 파일을 어떻게 동적으로 ssr에 주입 할 수 있을까?
webpack-manifest-plugin 를 활용하면 된다.
webpack.client.js 설정
번들링시 생성되는 코드에 대한 정보를 json파일로 저장하여 관리하는 webpack-manifest-plugin을 추가
npm i -D webpack-manifest-plugin
const path = require('path')
const { WebpackManifestPlugin } = require('webpack-manifest-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
mode: 'development',
entry: './src/client.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].[hash].js',
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
}),
new WebpackManifestPlugin({
fileName: 'manifest.json',
publicPath: '/',
}),
],
}
빌드해보면 dist에 manifest.json 파일이 생성된다.
manifest.json
{
"main.css": "/main.d46c0ceaea7442158cfe.css",
"main.js": "/main.d46c0ceaea7442158cfe.js"
}
server.js 코드 추가
manifest.json 파일을 읽어와서 해당 값을 가공 후 html에 주입시키는 작업을 해야한다.
public/index.html파일은 더이상 필요가 없다.
import path from 'path'
import fs from 'fs'
import React from 'react'
import express from 'express'
import { renderToString } from 'react-dom/server'
import App from './components/App'
const app = express()
app.use(express.static('dist'))
const html = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React SSR</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
`
const manifest = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../dist/manifest.json'), 'utf8'))
const scripts = Object.keys(manifest)
.filter((key) => key.endsWith('.js'))
.map((key) => `<script defer src="${manifest[key]}"></script>`)
.join('\n')
const styles = Object.keys(manifest)
.filter((key) => key.endsWith('.css'))
.map((key) => `<link rel="stylesheet" type="text/css" href="${manifest[key]}">`)
.join('\n')
app.get('*', (req, res) => {
const appString = renderToString(<App />)
return res.send(
html
.replace('<div id="root"></div>', `<div id="root">${appString}</div>`)
.replace('</head>', `${styles}</head>`)
.replace('</body>', `${scripts}</body>`),
)
})
app.listen(3000, () => {
console.log('Server is listening on port 3000')
})
테스트 해보면, css 주입도 ssr에 잘 된걸 확인 할 수 있다.
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/007.gif)
style-loader는 더이상 필요하지 않으므로 삭제하자
npm uninstall style-loader
'IT > react' 카테고리의 다른 글
[react] ssr 프로젝트 만들기 (5) - stream으로 html 그리기 (0) | 2024.07.08 |
---|---|
[react] ssr 프로젝트 만들기 (4) - react router 추가 (0) | 2024.07.02 |
[react] ssr 프로젝트 만들기 (2) - css, 번들에 추가하기 (0) | 2024.07.02 |
[react] ssr 프로젝트 만들기 (1) - hello world 찍기 (0) | 2024.07.01 |
[react] CRA 대신 webpack으로 react 프로젝트 구성하기 (0) | 2024.04.03 |