최근에 React 프로젝트르 세팅하다가 React-Hot-Loader 문서를 보니, React Fast Refresh라는 새로운 도구가 나온 것을 발견했다. React-Hot-Loader를 만든 페이스북 개발자 Dan Abramov는, 기존 핫 로더에 한계가 있다고 평가하면서, 앞으로는 React Fast Refresh로 대체될 것이라 생각한다고 의견을 밝혔다. 기존의 핫 로더는, 대규모 앱에서 코드변경, export/import 문제, Typescript관련 문제 등 앱이 매우 느리게 동작하는 것이 문제였다. 그 대안으로 나온게 Fast Refresh이며, 2019년 React Native 0.61에 처음 도입 되었다.
그렇다면 React Fast Refresh가 하는 일은 무엇인가?
- 앱 전체를 다시 다운로드 하지 않고, React 구성 요소만 다시 렌더링 한다.
- 구문 오류 또는 런타임 오류가 발생했을 경우에, 자동으로 앱을 다시 실행시킨다.
- 구문 오류가 있는 모듈은 실행시키지 않는다. Fast Refresh가 동작하는 도중에 구문 오류가 발생할 경우, 오류가 발생한 파일을 수정하면 앱을 자동으로 다시 로드한다.
- Hooks를 지원한다.
그렇다면 React Fast Refresh를 적용하려면 어떻게 하면 되는 것일까?
- Create React App: `FAST_REFRESH=true` 옵션을 사용한다. development에서는 true값을 디폴트로 사용하고 있다.
- Parcel 2: React Refresh#3654에 추가되었다.
- Webpack: 아직 실험적인 버전이지만 Webpack-Plugin이 존재한다.
나는 현재 최신 스펙인 Webpack5 + Typescript를 기반으로 설정을 진행해 보았다. 설치는 아래 명령어를 사용한다.
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
타입 스크립트를 사용한다면 `type-fest`를 설치한다 (스펠링 주의!)
npm install -D type-fest
Webpack.config.js는 다음과 같이 구성한다.
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
plugins: [
isDevelopment && require.resolve('react-refresh/babel'),
].filter(Boolean),
},
},
],
},
],
},
plugins: [
isDevelopment && new webpack.HotModuleReplacementPlugin(),
isDevelopment && new ReactRefreshWebpackPlugin(),
].filter(Boolean),
};
하지만 자세히 보면 위 코드는, typescript의 ts-loader가 아닌 babel-loader을 사용하고 있다. 따라서 위 코드를 사용하려면 번거롭게 Babel-Typesscript를 구성해야 한다. Hot Module Replacement를 이용하기 위헤, Babel까지 추가 설치하는건 약간 부담이 되었다. 다른 방법은 없을까 찾아보는 도중, Issue에 타입스크립트 적용에 대한 토론이 남아있었다. Add react-refresh-typescript #248을 보고 webpack.config.js를 다음과 같이 구성한다.
npm install -D react-refresh-typescript
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const webpack = require('webpack');
const ReactRefreshTypeScript = require('react-refresh-typescript').default;
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('ts-loader'),
options: {
getCustomTransformers: () => ({
before: isDevelopment ? [ReactRefreshTypeScript()] : [],
}),
},
},
],
},
],
},
plugins: [
isDevelopment && new webpack.HotModuleReplacementPlugin(),
isDevelopment && new ReactRefreshWebpackPlugin(),
].filter(Boolean),
};
'JavaScript' 카테고리의 다른 글
Spread Syntax와 Rest Parameter (0) | 2019.11.03 |
---|---|
패턴 매칭(Pattern Matching) in JavaScript (0) | 2019.09.30 |
Beginning Javascript Iterator and Generator (2) | 2019.01.12 |
Why React Hooks (0) | 2019.01.05 |
Javascript Optional Chaining (1) | 2018.11.10 |