본문 바로가기

React

React CRA 환경에서 eject하지 않고 Webpack 커스텀하기

 

Asia-Pacific(APAC) 지역에서 담당하는 프로젝트의 Repository를 fork하여 Korea에 서비스를 할 수 있게 환경을 구축하는 프로젝트를 맡게 되었다. 

클라이언트 프로젝트 환경은 Typescript 기반의 리액트로 만들어져 있고, CRA로 생성된것으로 확인하였다.

 

우리팀은 대부분은 MacOS 기반에서 개발을 하지만, 간혹 Windows를 사용하시는 분들 위해 Mac/Linux/Windows 용의 스크립트를 만들고, 각 서버 환경별 Docker Container 배포를 위한 Dockerfile 만들어서 Korea 인프라팀에게 공유하였다.

 

그러나 프로젝트가 물흐르듯이 진행되다가 문제가 발생하였다.

디자인 팀의 퍼블리싱하시는 분이 마크업을 진행하실 때 CSS로 S3 bucket을 Full url로 선언하셨다.

그리고 배포시 각 서버의 S3 bucket url을 환경변수에 맡게 동적으로 변경시키기 위해서는 CSS가 아닌 최신 SCSS/SASS/LESS와 같은 스타일 시트를 사용해야했다.

 

결국 Webpack Custom을 하게 될 상황이 발생했다. (eject 없이 Webpack Custom 할 수 있는 방법에 대해서 고민 🤔)

참고로 CRA로 만들어진 프로젝트는 Webpack 설정을 추상화시켜서 복잡한 dependency와 설정들을 노출시키지 않는 장점이 있다.

 

개인적인 경험으로 웹팩 설정할 때 마다 느낀 것은 여러번 설정해보고 경험해보면 당연 좋은데, 초기 프로젝트 이후 설정을 변경할 일이 많지 않았다. 게다가 코드구현으로 해결하기 보다 Docs를 읽어보고 옵션 값 넣어보고 이거 Webpack 빌드 잘되나 안되나? 하면서....

노가다 경험이 꽤 있어서 개인적으로 eject는 왠만해서 피하고 싶어 같은 팀분에게 PR을 날릴 겸 Help 요청을 했다. 😂

 

내가 팀원분에게 PR 요청
팀원분에게 리뷰 답변 옴

 

다른 프로젝트 하느라 PR요청만 해둔 상태인데, 역시 고민이 있을 때 마다 항상 적극적으로 참여해주고 리서치를 해준 동료분에게 항상 감사를 한다. 동료가 곧 복지다! 👍

 

동료분이 남겨주신 댓글 링크에 eject 없이 추상화된 일부 설정을 추출하여 꼭 필요한 커스텀만 적용할 수 있는 사례에 대해서 공유해주셨다.

  • react-app-rewired: "Override create-react-app WebPack configs without ejecting". The core maintainer has left, and the README displays a warning about possible breakage. We've used it on other projects without issue, but it's probably time to look for an alternative.
  • CRACO: "An easy and comprehensible configuration layer for create-react-app". The long documentation and the need to install additional plugins made it look a bit too complex for my need.
  • rewire: a Node.js monkey-patching library. It is more general-purpose than react-app-rewired and CRACO, but it allows minimal changes. That's the solution I ended up choosing.

https://marmelab.com/blog/2021/07/22/cra-webpack-no-eject.html

 

Overriding the Create-React-App Webpack Configuration Without Ejecting

Create-React-App is a great tool to bootstrap React apps, but it can be quite painful when you need fine-grained control over the Webpack configuration.

marmelab.com

 

CRACO 같은 경우 설정이 꽤나 복잡하고 불필요한 리소스가 많았고 설정을 계속 실패해서

rewire를 시도했는데 build 단계에서 production mode 로 글로벌 변수가 SCSS로 빌드된 CSS 결과물이 잘 만들어졌다.

하지만, development mode에서는 SCSS 빌드가 실패하였고 돌고돌아.. react-app-rewired 적용에 성공 하였다.

 

다음은 실제 적용한 Best practice 일부의 코드를 공유한다.

 

package.json

"devDependencies": {
        "react-app-rewired": "^2.2.1",
        "react-scripts": "^4.0.3",
        "sass": "^1.50.1",
        "string-replace-loader": "^3.1.0"
    }

 

config-overrides.js

기본적으로 config-overrides.js 파일은 개발 또는 프로덕션 모드에서 리액트를 빌드 하기 위해 Customising된 Webpack Config에서 사용할 단일 함수를 내보낸다.
이것을 선언하면 웹팩 빌드 단계에서 Override 되어 Merge된 웹팩을 통해 최종 빌드 결과물에 반영될 것이다.
config-overrides.js는 파일을 직접 선언해도 되고, config-overrides 디렉토리에 index.js를 선언하여 export 해도 가능하다.
또한, react-app-rewired 스크립트로 --config-overrides 옵션을 줘서 config-overrides.js 위치를 변경할 수 있다고 한다.
/**
 * https://github.com/timarney/react-app-rewired#2-create-a-config-overridesjs-file-in-the-root-directory
 * This is a file to override for running react-app-wired.
 * @type {{webpack: (function(*, *): *)}}
 */
module.exports = {
    webpack: function (config, env) {
        config.module.rules.push({
            test: /\.(less|scss|sass)$/,
            use: [
                {
                    loader: 'string-replace-loader',
                    options: {
                        search: '$S3_URL',
                        replace:
                            process.env.REACT_APP_S3_BUCKET_ENDPOINT || 'https://static-prod.kor.apac.asurion53.com'
                    }
                }
            ]
        });
        return config;
    }
};

 

test.scss

$s3-url: '$S3_URL';

.btn1 {
    border: none;
    background: url(#{$s3-url}/images/bg_220418.jpg) no-repeat top left;
    padding: 2px 8px;
    width: 700px;
    height: 100vh;
}

 

예시코드는 위와 같고 웹팩을 빌드하면 test.scss에 선언된 $S3_URL이 config-overrides.js에 선언된 설정을 통해 글로벌 변수로 치환되면서 빌드 결과물인 CSS에 잘 적용되었다.