[Webpack/Vite 파헤치기] 2. Create React App 내부의 의존성과 환경 설정 꺼내기
서론
앞선 게시물에 이어, CRA 기반의 React App과 Vite 기반의 React App 비교를 위해 먼저 CRA 기반의 React App의 구조 및 내포하고 있는 설정들의 파악이 필요하다고 판단했습니다.
따라서 React App을 eject하여, 내포하고 있던 다양한 dependencies와 config들을 분석하는 시간을 먼저 갖고자 했습니다.
따라서 이번 포스트에서는 React App을 eject 했을 때 드러나는 의존성 및 설정들의 역할과, 최종적으로 그 구조를 도식화하여 살펴볼 예정입니다.
CRA eject시 드러나는 의존성들
- CRA로 생성한 React App을
react-scripts eject명령어를 통해 숨겨진 설정들과 의존성들을꺼내면(eject)다음과 같은 의존성들이 추가됨. - 크게 요약하면
Babel관련 종속성,Webpack관련 종속성(Webpack Loader),CSS/SASS관련 종속성,ESLint관련 종속성, 테스트 관련 종속성, 기타 유틸 로 이뤄져 있음
Babel 관련
Babel이란?
ES6 이상의 코드를 이전 환경에 호환되도록 변환하거나,타입스크립트,React jsx등 다른 문법의 코드를 변환해주는 툴체인
관련 종속성
- @babel/core : Babel 컴파일러의 코어
- babel-plugin-named-asset-import :
Babel pluginfornamed asset importsin Create React App- JS/CSS를 제외한
정적 자원들을Named Import형태로 가져올 수 있도록하는 플러그인Named Import: default export가 아닌,named Export된 요소들을 불러오기 위한 import (ex.import { funcA } from 'A.js';)
- JS/CSS를 제외한
- babel-preset-react-app : CRA에서 사용된 Babel 프리셋으로, 해당 프리셋 패키지안에 있는 create.js에 설정된
환경(개발, 프로덕션) 별 프리셋및플러그인 설정을 내보냄
Webpack 관련
Webpack이란?
webpack: Javascript 기반의모듈 번들러로, React App의 여러 모듈들을 의존관계끼리 엮어 하나 이상의 번들 정적 에셋으로 번들링하는 툴
관련 종속성
- webpack-dev-server: 웹팩과 함께 사용하는,
라이브 리로딩을 제공하는개발 서버로, 내부적으로 webpack-dev-middleware를 사용해 웹팩 에셋에 빠르게 인-메모리 접근 - webpack-manifest-plugin:
에셋 매니페스트를 생성하기 위한 웹팩플러그인으로, 생성된매니페스트는 아래와 같이소스 파일 이름-대응되는 빌드 output 파일간의 매핑들을 포함함 (이를 통해 추후새롭게 번들링된 파일의 파일명을 빠르게 파악해 사용 가능){ "dist/batman.js": "dist/batman.1234567890.js", "dist/joker.js": "dist/joker.0987654321.js" } - workbox-webpack-plugin:
PWA(프로그레시브 웹 앱)을 위한 라이브러리 모음인 Workbox의 웹팩용 플러그인으로,서비스 워커 생성(GenerateSW)및사전 캐싱(precache)할 에셋 목록(매니페스트)을 생성해 서비스 워커 파일에 주입(InjectManifest)하는 기능을 제공 # - terser-webpack-plugin: 변수 이름 축소, 공백 및 주석 제거, 미사용 코드 제거 등을 통해 코드를 압축(최소화)하는
Terser의 웹팩 플러그인... minimizer: [ // This is only used in production mode new TerserPlugin({ terserOptions: { parse: { // We want terser to parse ecma 8 code. However, we don't want it // to apply any minification steps that turns valid ecma 5 code // into invalid ecma 5 code. This is why the 'compress' and 'output' // sections only apply transformations that are ecma 5 safe // https://github.com/facebook/create-react-app/pull/4234 ecma: 8, }, compress: { ecma: 5, warnings: false, // Terser가 uglify-es의 포크이기 때문에, Uglify에서 발생했던 // '특정 라이브러리 사용시 비교 연산자 처리 버그'가 있기 때문에 // 비교 연산자를 압축하는 것을 비활성화 함 // https://github.com/mishoo/UglifyJS2/issues/2011 comparisons: false, // 작은 함수들을 인라인 함수로 변환해 함수 오버헤드를 줄이는 옵션으로 // 값이 2일경우 적절한 인라인 레벨을 Terser가 선택하도록 함 // 정확히는, inline functions with arguments, 즉 // 아래 두 가지 버그 이슈때문에 2로 명시 // https://github.com/facebook/create-react-app/issues/5250 // https://github.com/terser-js/terser/issues/120 inline: 2, }, mangle: { // 변수 및 함수 이름 난독화 관련 옵션으로, // safari10 이란 Safari 10 브라우저의 버그를 회피하기 위한 설정 safari10: true, }, // 개발 툴에서 프로파일링 할 수 있도록, 클래스 이름과 함수 명을 난독화할지 설정하는 변수 keep_classnames: isEnvProductionProfile, keep_fnames: isEnvProductionProfile, output: { // 압축된 코드의 출력 형태와 관한 옵션 // 최종적으로 압축된 코드는 ES5 버전 호환성을 지님 ecma: 5, // 모든 주석을 제거하도록 함 comments: false, // 문자열 및 정규 표현식에 존재하는 유니코드 문자를 ASCII 이스케이프 시퀀스(\uXXXX와 같은 형태. ex) `H` => `\u0048`)로 변경 // 이모티콘 또는 특정 정규 표현식이 default로는 제대로 압축되지 않기 때문 // https://github.com/facebook/create-react-app/issues/2488 ascii_only: true, }, }, }), // This is only used in production mode new CssMinimizerPlugin(), ], },- eject된
webpack.config.js설정에 따르면, 프로덕션 환경에서 이러한코드 압축이 수행되며ES8(ECMAScript 2017)문법까지 이해하고 파싱하되코드 압축(compress)및출력(output)은ES5호환성을 유지하도록 코드를minimize하려 함 - 이외에도 비교 연산자를 압축하지 않는다거나, 클래스 이름 및 함수 명을 난독화 할지 등을 설정하고 있음
- eject된
- css-minimizer-webpack-plugin: cssnano를 사용해
CSS 파일들을 최적화 및 최소화하는 웹팩 플러그인으로,캐싱및병렬 처리를 지원하는 것이 특징임cssnano란,PostCSS생태계 기반의 CSS 압축 툴로주석/공백/줄 바꿈 제거,헥스코드 축약,단위 제거등의 압축을 수행- 테스트 해볼 수 있는 사이트: Minify CSS Online. CSS Minification tool powered by CSSNANO. | Minify CSS Online
- @pmmmwh/react-refresh-webpack-plugin:
React Component에 대해핫 리로딩이라고도 부르는빠른 새로고침을 가능하게 해주는 웹팩 플러그인- 위 패키지는
react-dom,react-refresh등의 패키지에 의존하므로 선행 설치가 필요함
- 위 패키지는
- case-sensitive-paths-webpack-plugin 모든
필수 모듈의 전체 경로를디스크 상 실제 경로와 정확히 일치하도록 강제하는 웹팩 플러그인- 이를 통해
대소문자에 둔감(case-insensitive)한 환경(ex. OS X(macOS))의 개발자가대소문자 구분 규칙을 지키지 않아 다른 개발자나 빌드 환경에서 충돌이 발생하는 문제를 방지
- 이를 통해
- eslint-webpack-plugin: 웹팩 빌드 과정에서 코드의 문제를 발견하고 고치기 위해
ESlint를 사용하는 플러그인webpack.config.js에서는react-dev-utils/eslintFormatter포매터와eslint-config-react-app/base설정을 사용해 린팅
로더 #
로더란?
- 웹팩이 처리할 수 없는
Javascript 파일 이외의 파일들을 변환할 수 있도록 도와주는 라이브러리로, 파일을import하거나 로드할 때사전처리를 수행할 수 있음로더는체이닝될 수 있으며, 체인의 각 로더는 각각 (앞선 로더에 의해)처리된 리소스를 전달 받아 변환을 적용함- 최종적으로,
Webpack은 이러한체인의 마지막 로더로 부터Javascript 파일을 넘겨 받기를 기대함
- 로더는
webpack.config.js의module.rules배열에서 지정할 수 있으며, 선언된 역순으로 로더가 적용됨- 예를 들어
module: { rules: ["style-loader", "css-loader", "sass-loader"]}라고 선언이 되어있다면,sass-loader->css-loader->style-loader순으로 작업이 이뤄짐
- 예를 들어
관련 종속성
-
babel-loader : 웹팩을 위한
Babel Module 로더.js,.jsx,.ts,.tsx와 같은 파일들에 대해 폴리필, TS 및 React JSX 트랜스파일링 등의 작업을 수행하도록 연결
-
@svgr/webpack:
SVGR을 위한 웹팩 로더// SVGR 예시 코드 import Logo from 'assets/logo.svg'; // SVG 파일을 React Component 처럼 import const App = () => { return ( <div> <Logo width="100" className="mx-auto" /> </div> ); };SVGR이란,SVG를React Component로 변환해주는 툴로,React Component에서SVG 파일들을 컴포넌트 쓰듯 import 해 사용할 수 있게 해주는 툴
-
css-loader: 사용된
CSS를문자열로 변환해주는 로더로,@import와url()을import/require()와 동일하게해석및resolve해줌// 예시 1. url() -> require() url(image.png) => require('./image.png') // 예시 2. @import -> require() @import 'style.css' => require('./style.css') // 예시 3. @import url() -> require() @import url(style.css) => require('./style.css') // 변환 전 CSS h1 { color: #FFFFFF; } body { background-color: #272727; } // 문자열로 변환된 CSS ... [n.id, "h1 {\n color: #FFFFFF;\n}\nbody {\n background-color: #272727;\n}"]- 또한, CSS Module을 지원해 CSS 클래스 이름이 전역적으로 충돌하는 것을 방지하게 해줌
-
style-loader:
css-loader와 함께 쓰길 권장하는 로더로,CSS를DOM에 주입하는 로더 (정확히는, CSS를 DOM에 주입하는Javascript 코드로 변환하는 역할)- 옵션의
injectType을 통해 어떻게style이DOM에 주입될 지 지정할 수 있음- 하나 또는 여러 개의
<style>태그로 주입할 지(singletonStyleTag/styleTag),<link>태그를 통해 css 파일을 참조하도록 할 지(linkTag) 등의 옵션이 있음
- 하나 또는 여러 개의
CRA 프로젝트 설정 에서는
개발 환경일 경우style-loader를,프로덕션 빌드에서는MiniCssExtractPlugin를 사용 - 옵션의
-
sass-loader:
SASS/SCSS파일을 불러와,CSS로컴파일하는 로더css-loader,style-loader와 체이닝해 DOM에 즉각적으로 스타일들을 반영하거나,mini-css-extract-plugin과 체이닝해 개별 CSS 파일로 추출할 수 있음- 이때, 체인에서
sass-loader가 이들보다 앞에(즉, 로더 배열의 후순에) 위치해야 함
- 이때, 체인에서
-
postcss-loader: 프로젝트에서 사용된
CSS파일을 불러와,PostCSS의 여러 처리(CSS 린팅,최신 CSS 문법의 폴리필등)들을 수행하도록 하는 로더- CRA 프로젝트 설정에서는
tailwindcss,postcss-preset-env,postcss-normalize플러그인을 사용
- CRA 프로젝트 설정에서는
-
file-loader: Javascript 코드 중 파일을
import/require()하는 구문에 대해, 해당 파일을지정된 디렉토리(output directory)로 이동시킨 뒤public URL을 생성하는 로더public URL: 애플리케이션 내 모든asset들이 위치할 기본 경로인 Public Path와 해당 자원의 위치를 결합한 URL
// 변환 전 import png from './image.png'; // 변환 후 const png = "dirname/0dcbbaa701328ae351f.png"; // 'dirname/[contenthash].[ext]' 포맷 -
resolve-url-loader: 분산된
SCSS파일과, 각SCSS파일과 관련된 에셋들(이미지, 폰트 등)을 같은 곳에 위치시키도록 해주는 로더여러 곳에 SCSS 파일을 분산해두었으며, 그와관련된 에셋들을 같은 곳에 위치시켜 사용하고, 에셋에 대한 접근을완전한 상대경로(현재 파일을 기준으로한 상대 경로,url(./filename.ext)또는url(filename.ext))로 접근하는 경우 적합웹팩은url()구문에서완전한 상대경로가 사용됐을 경우 해당에셋이루트 SCSS 파일과같은 디렉토리에 존재한다고 가정하기 때문에분산 저장된 SCSS 및 에셋들을 제대로 처리하지 못함resolve-url-loader는 이러한URL들을 재작성하여 제대로 동작하도록 도와줌- 참고1)
resolve-url-loader보다 앞서 처리되는 로더가 있는 경우, 해당 로더들은소스 맵을 제공해야 함- 그래야
resolve-url-loader가 앞선 로더들이 전처리한CSS 코드속의상대 경로를 올바르게 파악할 수 있기 때문
- 그래야
-
source-map-loader: 소스 코드 파일들로부터
소스맵을추출하는 로더소스맵:원본 소스코드와트랜스파일된 소스 코드간의 매핑 정보가 선언된 파일- 압축, 난독화 등의
처리를 거친 코드와원본 코드간의 관계를 알려주어,트랜스파일링된 코드의디버깅을 도움
- 압축, 난독화 등의
- 애플리케이션 내(
node_modules폴더를 포함한)모든 Javascript 엔트리로 부터이미 존재하는 소스맵을 추출하며, 이는인라인 소스맵뿐만 아니라URL로 링크된 소스맵도 포함- 이러한 처리는
자체 소스맵을 갖고있는 라이브러리의소스맵이웹팩 번들의 소스맵으로추출및처리되지 않을 경우,브라우저가소스맵 데이터를잘못 해석하는 일을방지해줌
- 이러한 처리는
CSS / SASS 관련
- browserslist:
Babel,Autoprefixer등 여러 프론트엔드 툴에서 동일한타깃 브라우저 및 Node.js 런타임 버전을 공유하기 위한Configuration- 이를 통해 불필요한
Polyfil,벤더 프리픽스등을 줄일 수 있으며, 프론트엔드 툴 간 일관성이 보장됨 - CRA 프로젝트 설정에서는 프로덕션 빌드의 경우 0.2% 이상의 점유율을 지녔으며(
>0.2%) 24개월 내 업데이트가 없는 브라우저를 제외하고(not dead) 오페라 미니를 제외한(not op_mini all), 개발 환경에서는 가장 최신 버전의크롬/파이어폭스/사파리를 지원 하도록 설정됨
- 이를 통해 불필요한
- mini-css-extract-plugin : CSS를 포함하고 있는 JS 파일 별로
CSS를 추출해 JS 파일 당CSS 파일을 생성하는웹팩 플러그인으로,css-loader와 함께 사용하기를 권장함- 다만,
웹팩 엔트리 포인트또는 initial chunk에서 import 하고 있는 CSS의 경우, (이 플러그인이) 페이지에서 해당 CSS들을 로드하도록 하지 않음엔트리 포인트:webpack.config.js에서entry로 설정된 파일initial chunk: 엔트리 포인트의메인 청크를 의미하며,엔트리 포인트에 명시된 모든 모듈 및 의존성을 포함하고 있는 청크
- 즉, 엔트리 포인트에 대응되는
CSS 파일의 경우, 자동으로<link>태그를 생성하거나 /<link>태그를 포함한index.html을 만들기 위해html-webpack-plugin를 사용해야 함- html-webpack-plugin: 웹팩 번들 서빙을 위한 HTML 파일
생성을 간소화시켜주는웹팩 플러그인
If you have any
CSS assetsin webpack’s output (for example, CSS extracted with the mini-css-extract-plugin) then these will be included with<link>tags in the HTML head.
( 만약 Webpack 출력이 CSS 에셋을 포함할 경우, HTML<head>에<link>태그로 포함될 것입니다.)
출처: jantimon/html-webpack-plugin: Simplifies creation of HTML files to serve your webpack bundles - html-webpack-plugin: 웹팩 번들 서빙을 위한 HTML 파일
- 다만,
- tailwindcss:
유틸리티-우선(utility-first)CSS 프레임워크로, 프레임워크에서지정한 클래스 명을 사용하면CSS 유틸리티가 적용됨인라인 스타일과 비슷하지만, 미리정의된 디자인(predefined design)을 사용할 수 있고호버/포커스 등 상태및미디어 쿼리를 사용할 수 있음
- postcss:
Javascript 플러그인을 사용해CSS 린팅,변수및믹스인지원,최신 CSS 문법의 트랜스파일등의 기능을 제공하는 변환기- 내부적으로
CSS->Parser->[Plugin 1, Plugin 2, ... ]->Stringifier->New CSS로 이어지는 구조를 갖고 있음- CSS를
Tokenizer와Parser를 통해 분해 및 AST화 한 뒤, Plugin 들을 적용시키고 나온AST를순수 CSS 문자열로 변환함
- CSS를
- 널리 사용되고 있는 autoprefixer가 대표적인
PostCSS플러그인임
- 내부적으로
- postcss-flexbugs-fixes :
flowbox 이슈및크로스-브라우저 이슈를수정하기 위한PostCSS 플러그인 - postcss-normalize:
browserlist설정에 맞춰 normalize.css 라이브러리 또는 sanitize.css 라이브러리를 사용할 수 있도록 해주는 툴normalize.css:HTML 요소에 대해 크로스-브라우저 간일관된 스타일을 제공하는 CSS 라이브러리- nomarlize.css의 내용을 살펴보면,
중첩 리스트(dl, ol, ul)의 margin 없애기(line 36),Firefox에서의 box-sizing 추가및border 색상을 상속하도록 정정(line 46) 하는 등의 내용을 포함함
- nomarlize.css의 내용을 살펴보면,
sanitize.css:normalize.css의 모든 요소들이 포함되어 있으며, 나아가유용한 기본 설정(useful defaults)을 포함하는 CSS 라이브러리- sanitize.css의 내용을 살펴보면,
커서는 불명확한 인터페이스에 힌트를 주기 위해서만 변하도록 하거나(line 37),background-repeat이 기본적으로 반복되지 않도록 하는(line 13) 등의 내용을 포함함
- sanitize.css의 내용을 살펴보면,
- [postcss-preset-env]:
최신 CSS 문법을 브라우저가 이해할 수 있도록변환하고,타겟 브라우저 및 런타임에 맞춰필요한 폴리필을결정하는PostCSS 플러그인- MDN과 Can I Use로부터 버전 별 지원 기능 정보들을 가져와
browserlist를 기반으로 기능의 변환이 필요한지 판단하며, 내부적으로autoprefixer를 포함해 브라우저 지원 목록에 따라 필요할때만 접두사를 적용하도록 함 - CRA 프로젝트 설정에서는
autoprefixer: { flexbox: 'no-2009' }, stage: 3라고 옵션을 지정하여최신및IE 버전의 flexbox 문법에만접두사를 추가하도록 하며, 또한stage 3에 해당하는 CSS 기능들을 변환하도록 설정- 참고1) Interactive Playground - PostCSS Preset Env - CSS Tools를 통해
browserlist옵션 별 변환된 CSS를 확인할 수 있음 - 참고2)
flexbox의 경우, 과거display:box->display: flexbox->display: flex와 같은 변경을 거친 옵션임 “Old” Flexbox and “New” Flexbox | CSS-Tricks - 참고3) CSS 기능의 stage 수준을 확인하고 싶다면 CSS Database - CSS Tools을 확인할 것
- 참고1) Interactive Playground - PostCSS Preset Env - CSS Tools를 통해
- MDN과 Can I Use로부터 버전 별 지원 기능 정보들을 가져와
ESLint 관련
- eslint: Javascript 코드에서
발견된 패턴을식별및보고하는 툴- 여기서 말하는 “패턴"으로는
문법 오류, 버그를 일으킬 수 있는사용되지 않는 변수/접근 불가능한 코드등의 요소, 정해진 코딩컨벤션을 위반하는 코드등이 있음 - Espree를 사용해 Javascript 코드를 파싱하며, 패턴을 확인하기 위해
AST를 사용함 - 사람들이 종종 대체제로 오인하는
Prettier와는 다른 작업을 수행하는 툴임:Linter(ESLint)와Code Formatter(Prettier)Linter는 코드에서 발견되는잠재적 오류,안티 패턴등을식별하고경고하는 도구이고,Code Formatter는들여쓰기(indent),줄바꿈(line break)등의 요소들을 일관되도록 하여코드 가독성을 높이는 도구임
- 여기서 말하는 “패턴"으로는
- eslint-config-react-app:
CRA에서 사용되는ESLint 설정을 포함하고 있는 패키지
테스트 관련
- jest: 자바스크립트 테스팅 프레임워크로, 테스트를 찾아 실행하는
테스트 러너뿐만 아니라Test Matcher(expect()와 같은Assertion)그리고Test Mock(jest.spyOn,jest.mock등) 프레임워크를 제공- CRA 프로젝트 설정에서는
<rootDir>/src내 모든js/jsx/ts/tsx파일 중__test__폴더 내 모든 테스트 파일 또는*.spec.{확장자}/*.test.{확장자}파일 에 대해 테스트를 수행하도록 설정되어 있음
- CRA 프로젝트 설정에서는
- babel-jest :
코드 전처리(transform)를 위해Babel을 사용하도록 하는 Jest의 플러그인Javascript/JSX파일 테스트 전, 전처리 수행- CRA 프로젝트 설정에서는
babel-preset-react-app프리셋을 사용하고, 해당 프리셋에서runtime을classic(react 17 미만) 또는automatic(_jsx(react/jsx-runtime)을 사용하는 환경)으로 설정한트랜스포머를 생성해 사용하는데에 쓰임
- jest-resolve:
jest내부에서 배포하는 패키지로, 모듈 경로를 Resolve 하는데 사용되는AsyncResolver,SyncResolver와 같은Resolver를 배포AsyncResolver-SyncResolver는 이름 그대로 모듈이름을 동기적으로(resolveStubModuleName : string) 또는 비동기적으로(resolveStubModuleNameAsync : Promise) Resolve 할 것인지 차이
- jest-watch-typeahead:
파일 이름또는테스트 이름으로 테스트들을 필터링해 실행할 수 있는 플러그인
기타 유틸
- bfj:
Big-Friendly JSON의 약자로, 대형 JSON 데이터 셋용 비동기 스트리밍 함수를 제공- 만약 큰 JSON 문자열을 파싱하거나, 대규모 데이터 셋을 문자열로 변환할 경우 이벤트 루프를 독점하고,
OOM(메모리 부족) 예외를 발생시킬 수 있음 - 이때,
BFJ는비동기 함수, 그리고사전-할당된 고정-길이 배열을 사용해 이런 문제를 완화하려고 함 - CRA 프로젝트 설정에서는 빌드 시 발생하는
stat(warning, error 등)들을 기록한bundle-stats.json파일을 작성하기 위해 사용
- 만약 큰 JSON 문자열을 파싱하거나, 대규모 데이터 셋을 문자열로 변환할 경우 이벤트 루프를 독점하고,
- camelcase:
대시(-)/점(.)/밑줄(_)/공백( )으로 구분된 문자열을camelCase또는PascalCase로 변환해주는 함수를 제공camelCase와PascalCase모두, 단어들을 합칠때 공백없이 각 단어의 첫 글자를 대문자로 표기한다는 공통점이 있지만camelCase는 첫 번째 단어의 첫 글자를 소문자로,PascalCase는 첫 번째 단어를 포함한 모든 단어의 첫 글자를 대문자로 표기한다는 차이가 있음- CRA 프로젝트 설정에서는
커스텀 Jest 트랜스포머(fileTransform.js)에서SVG 파일을React 컴포넌트처럼 가져올 때, SVG 파일 이름을 PascalCase로 처리하기 위해 사용
- dotenv:
.env파일로부터 환경 변수들을 불러와,node.js의process.env객체에 주입하는 패키지.env파일에는키=값으로 이루어진 변수들을 두고 사용- 2년 전부터
dotenv에"암호화 된" .env 파일을 지원하고,크로스-플랫폼 일관성을 지원하는 dotenvx를 사용하길 권고하고 있음
- dotenv-expand:
dotenv에변수 확장(variable expansion)기능을 추가한 패키지변수 확장: 한 변수에서 다른 변수를${이름}구문을 통해 참조할 수 있는 기능HOST_URL=http://localhost:3000 API_URL=${HOST_URL}/api- CRA 프로젝트 설정에서는
env.js에서 환경 변수들을 설정할 때,.env파일들을 우선순위가 높은대로 배열에 담은 뒤 순회하며dotenv를 통해 환경변수들을 불러온 뒤, 그 사이에 존재하는변수 확장을 처리하기 위해dotenv-expand로 한 번 더 처리하는 형태로 사용
- fs-extra:
node.js의fs모듈에 포함되어 있지 않은 파일 시스템 메서드를 추가하고,fs메서드들에 대한Promise지원을 추가한 패키지fs모듈의 모든 기능을 포함한채 확장하기 때문에fs-extra만 가져와 사용하면 됨- 또한, 모든
fs 메서드들이Promise를 지원하도록 했기 때문에, 별도의callback을 넘기지 않을 경우Promise를 반환함 ESM(ES Module)도 지원하나(fs-extra/esm),fs메서드들이 포함되어 있지 않으므로 별도로 import 해주어야 함- CRA 프로젝트 설정에서는 애플리케이션을 build할 때 사용됨
// 1. Yarn 패키지 매니저가 사용되는지 확인하는데 사용 const useYarn = fs.existsSync(paths.yarnLockFile); // 2. 빌드 디렉토리 내 파일들을 지우는데 사용 fs.emptyDirSync(paths.appBuild); // 3. `Public` 폴더 내 정적 에셋들을 빌드 디렉토리로 복사하는데에 사용 fs.copySync(paths.appPublic, paths.appBuild, { dereference: true, filter: file => file !== paths.appHtml, });
- identity-obj-proxy:
ES6 Proxy를 이용한항등(Identity) 객체를 제공하는 패키지로,CSS 모듈과 같이Webpack이 처리해주는import동작을모킹하는데 유용함Proxy: 다른 객체에 대한프록시를 생성하여, 해당 객체의 기본적인 작업을가로채고, 재정의할 수 있도록 하는ES6 문법Proxy(obj, handler):Proxy생성자는프록시할 다른 객체(obj)와다른 객체의 어떤 작업을 가로채고 해당 작업을 어떻게 재정의할 지 정의된 객체(hanlder)두 가지 매개변수를 받음- 정의할 수 있는
handler 함수로는apply(),construct(),get(),set()등이 있으며, 아래idObj에서는 객체 프로퍼티에 접근하는 메서드인get()을 재정의한handler function을 정의하고 있음
- 정의할 수 있는
identity-obj-proxy에서는 아래와 같이, 접근하려는 key 이름을 그대로 반환하는Proxy 객체를 제공함idObj = new Proxy({}, { // 객체 내부 메서드(Object internal methods)인 get 호출을 가로채고 대신 응답하는 handler function get: function getter(target, key) { if (key === '__esModule') { return false; } return key; } });
항등(Identity) 객체: 모든 원소를 자기 자신과 같은 값을 대응시키는 함수인항등 함수(ex) f(x) = x)처럼, 모든key에 대해obj[key] = 'key' (또는 obj.key = 'key')인 객체
// 예시 코드 // jest.config.js // ... module.exports = { moduleNameMapper: { '\\.jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/fileMock.js', // CSS 또는 LESS(Leaner Style Sheets) 정적 에셋 모듈 경로에 대해 identity-obj-proxy의 프록시 객체를 대신 사용하도록 설정 // 즉, 프로젝트 내 사용되는 모든 CSS Module에 대해 className을 `identity-obj-proxy`에서 제공하는 프록시 객체에서 lookup 하도록 설정 '\\.(css|less)$': 'identity-obj-proxy', }, }; // SomeComponent.js import React, { Component } from 'react'; // jest와 같은 프레임워크를 통해 컴포넌트를 테스트 할 땐 이미지, CSS와 같은 정적 에셋들이 특별히 유용하진 않음 // 따라서, 이들을 실제처럼 `css-loader`와 같은 툴을 통해 해싱된 클래스 명을 주입하기 보다, 모킹된 프록시를 만들어 className이 일치하는지만 확인하도록 하는 것이 더 안전하고 편리 // 따라서 `identity-obj-proxy`와 같은 모듈이 제공하는 `항등 객체`에서 className을 lookup해 확인하도록 설정 import styles from './App.css'; // CSS Module import export default class App extends Component { render() { return ( <div className={styles.root}> <h1 className={styles.hello}>Hello, world!</h1> </div> ); } } - prompts: CLI 프롬프트를 쉽게 만들어주는 패키지
jest-cli,react-dev-utils에서 의존하는 패키지
- react-app-polyfill:
Create-React-App프로젝트에서 일반적으로 사용된Javascript 기능과최소 요구 사항에 대한Polyfill을 포함하는 패키지- 프로젝트에서 지원하고자 하는
최소 버전의 진입점을import하면Create React App프로젝트를 이용하기 위한최소 언어 기능을 포함하도록 할 수 있음
// 아래와 같은 import문을 프로젝트 진입점('src/index.js')의 첫 번째 줄로 기입해야 함 // 최소 IE 9버전 이상(IE9, IE10, IE11, ...)을 지원하려는 경우 import 'react-app-polyfill/ie9'; // 최소 IE 11버전 이상을 지원하려는 경우 import 'react-app-polyfill/ie11';- 또한,
stable한 기능이지만 타겟 브라우저에서 이를 지원하지 않는 경우 이를 제공하는 Polyfill('react-app-polyfill/stable')을 사용할 수 있음 (Create-React-App을 사용하고 있는 경우, 사용자가 정의한browserlist를 자동적으로 불러와, 타겟 브라우저에서 필요한 폴리필만 가져옴)
- 프로젝트에서 지원하고자 하는
- react-dev-utils:
Create-React-App에서 사용되는 몇가지 유틸리티들을 포함하는 패키지react-dev-utils는단일 엔트리 포인트를 갖고 있지 않으며, 각각의 모듈을직접 import해야 하는 형태로 작성되어 있음react-dev-utils를 구성하는 주요 모듈 중,CRA 프로젝트에서 사용된 모듈은 다음과 같음InterpolateHtmlPlugin: html-webpack-plugin을 사용해index.html에사용자 정의 변수를삽입할 수 있도록 돕는 웹팩 플러그인InlineChunkHtmlPlugin: 마찬가지로 html-webpack-plugin을 사용해index.html에인라인 스크립트 청크를 삽입하는 웹팩 플러그인- 즉,
<script src="...">대신<script>태그 내부에 직접 코드를 삽입
- 즉,
ModuleScopePlugin: 애플리케이션의소스 디렉토리에서상대 경로로 가져온(relative import) 파일들을 디렉토리 외부에서 접근하지 못하도록 보장하는 웹팩 플러그인getCSSModuleLocalIdent:index.module.css라는 이름의 CSS 파일에 대해파일 이름또는폴더 이름을 사용한CSS 모듈 클래스 이름을 생성해주는style-loader 모듈ModuleNotFoundPlugin:Webpack에서 발생하는,모듈을 찾을 수 없다는 에러를 알기 쉽게 꾸며주는 웹팩 플러그인ForkTsCheckerWebpackPlugin: 타입스크립트 타입 검사를 별도의 프로세스에서 실행하는 웹팩 플러그인eslintFormatter:Create React App콘솔 출력과의 통합을 위한 커스텀 ESLint 포매터checkRequiredFiles: 필수 파일 목록을 받아 포함되지 않은 파일들을 chalk를 사용해 터미널에 출력하는 함수formatWebpackMessages: webpack의 stats 객체가 갖고있는경고 및 에러 메시지를추출하고 꾸며주는 유틸리티 함수printHostingInstructions:패키지 경로,public URL등을 받아, 프로젝트 빌드 후호스팅 지침을 출력해주는 유틸리티 함수FileSizeReporter:빌드 전JS 및 CSS 에셋파일 크기를 기록해두고,빌드 후 이들의 크기 비교를 수행하고 출력하는 유틸리티 함수 모음printBuildError: 잘 알려진 빌드 에러들을 꾸며주는 유틸리티 함수evalSourceMapMiddleware:/__get-internal-source로 시작하는 요청에서 웹팩 내부 URL(webpack-internal:///<module-id>)의module id를 추출해<source-text><sourceMappingURL><sourceURL>(모듈 원본 소스코드 + 소스맵 URL(base64 인코딩된 소스맵 정보) + 소스 URL )를 반환하는웹팩 내부 미들웨어생성 함수noopServiceWorkerMiddleware:${servedPath}/service-worker.js라는, 이전의Service Worker설정을 초기화하는 파일을 제공하는Express미들웨어ignoredFiles: 소스 디렉토리 외부의node_modules를 파일 감시에서 무시하기 위해, 정규표현식을 활용해 파일 경로 패턴을 생성하는 함수// webpackDevServer.config.js watch: { // Reportedly, this avoids CPU overload on some systems. // https://github.com/facebook/create-react-app/issues/293 // src/node_modules is not ignored to support absolute imports // https://github.com/facebook/create-react-app/issues/1065 ignored: ignoredFiles(paths.appSrc), },redirectServedPathMiddleware:req.url이servedPath로 시작하지 않을 경우${servedPath}/${req.path}로 리다이렉션 시키는Express미들웨어clearConsole: 콘솔 내용을 지우는 유틸리티 함수WebpackDevServerUtils:WebpackDevServer를 위한 웹팩 컴파일러 인스턴스를 생성하거나, 대체 포트를 제공하거나,package.json의proxy세팅을 기반으로WebpackDevServer프록시 설정 객체를 생성하는 등의 작업을 수행하는 유틸리티 함수 모음openBrowser: 주어진 URL과 함께 브라우저를 여는 유틸리티 함수
- react-refresh:
Fast Refresh라고 부르는, “실행중인 React 애플리케이션에서 컴포넌트를 상태값의 손실 없이 편집할 수 있도록 해주는 기능"을 번들러에 통합시키기 위한 패키지- How should we set up apps for HMR now that Fast Refresh replaces react-hot-loader? · Issue #16604 · facebook/react 에 따르면, 과거에 사용되던
react-hot-loader라는 패키지를 대체하는 패키지임 - CRA 프로젝트 설정에서는 개발환경이며(
isEnvDevelopment), React Refresh를 사용해야 하는 경우(shouldUseReactRefresh)ReactRefreshWebpackPlugin플러그인을 사용하며,babel-loader에react-refresh/babel플러그인을 연결함
- How should we set up apps for HMR now that Fast Refresh replaces react-hot-loader? · Issue #16604 · facebook/react 에 따르면, 과거에 사용되던
- resolve:
node.js의require.resolve()알고리즘을 구현하여, 비동기/동기적으로require.resolve()를 호출할 수 있도록 해주는 패키지require.resolve():require()를 통해 모듈을 탐색할 때, 주어진 경로를 해석하는 함수- 대략적인 pseudo algorithm은 문서참고
- semver: npm을 위한
시멘틱 버전 관리(Semantic Versioning)도구.- Semantic Versioning 2.0.0 | Semantic Versioning에 따르면, 의존성이 많은 시스템에서 의존성 지정이 너무 엄격해 발생할 수 있는
버전 락(Version Lock), 또는 의존성이 너무 느슨하게 지정되어 발생할 수 있는버전 난잡성(Version Promiscuity)를 방지하기 위해서시멘틱 버전 관리사양을 제안함 시멘틱 버저닝에서는,X.Y.Z와 같은 체계의 형태로 버전 번호를 관리하는데, 이때 각 부분은 다음을 의미X: 메이저 업데이트. 하위 호환성이 없는 API의변경 사항Y: 마이너 업데이트. 하위 호환성이 있는(Backward Compatible)API의추가/변경 사항Z: 패치. API에 영향을 주지않는버그 수정(Bug Fixes)
- 이러한
시멘틱 버저닝 관리 체계에 있어, 유용한 여러유틸리티 함수를 제공하는 것이semverconst semver = require('semver') semver.valid('1.2.3') // '1.2.3' semver.valid('a.b.c') // null semver.clean(' =v1.2.3 ') // '1.2.3' semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // 첫 번째 인자가 두 번째 인자로 주어진 버전 조건을 만족하는가? true semver.gt('1.2.3', '9.8.7') // 첫 번째 인자가 두 번째 인자보다 높은 버전인가? false semver.lt('1.2.3', '9.8.7') // 첫 번째 인자가 두 번째 인자보다 낮은 버전인가? true
- Semantic Versioning 2.0.0 | Semantic Versioning에 따르면, 의존성이 많은 시스템에서 의존성 지정이 너무 엄격해 발생할 수 있는
Ejecting 이후 콘솔에 출력된 메세지
// 의존성용 config 파일들 및 스크립트 파일 생성
Adding \config\env.js to the project
Adding \config\getHttpsConfig.js to the project
Adding \config\modules.js to the project
Adding \config\paths.js to the project
Adding \config\webpack.config.js to the project
Adding \config\webpackDevServer.config.js to the project
Adding \config\jest\babelTransform.js to the project
Adding \config\jest\cssTransform.js to the project
Adding \config\jest\fileTransform.js to the project
Adding \scripts\build.js to the project
Adding \scripts\start.js to the project
Adding \scripts\test.js to the project
Adding \config\webpack\persistentCache\createEnvironmentHash.js to the project
// 감춰져있던 의존성들 추가
Updating the dependencies
Removing react-scripts from dependencies
Adding @babel/core to dependencies
Adding @pmmmwh/react-refresh-webpack-plugin to dependencies
Adding @svgr/webpack to dependencies
Adding babel-jest to dependencies
Adding babel-loader to dependencies
Adding babel-plugin-named-asset-import to dependencies
Adding babel-preset-react-app to dependencies
Adding bfj to dependencies
Adding browserslist to dependencies
Adding camelcase to dependencies
Adding case-sensitive-paths-webpack-plugin to dependencies
Adding css-loader to dependencies
Adding css-minimizer-webpack-plugin to dependencies
Adding dotenv to dependencies
Adding dotenv-expand to dependencies
Adding eslint to dependencies
Adding eslint-config-react-app to dependencies
Adding eslint-webpack-plugin to dependencies
Adding file-loader to dependencies
Adding fs-extra to dependencies
Adding html-webpack-plugin to dependencies
Adding identity-obj-proxy to dependencies
Adding jest to dependencies
Adding jest-resolve to dependencies
Adding jest-watch-typeahead to dependencies
Adding mini-css-extract-plugin to dependencies
Adding postcss to dependencies
Adding postcss-flexbugs-fixes to dependencies
Adding postcss-loader to dependencies
Adding postcss-normalize to dependencies
Adding postcss-preset-env to dependencies
Adding prompts to dependencies
Adding react-app-polyfill to dependencies
Adding react-dev-utils to dependencies
Adding react-refresh to dependencies
Adding resolve to dependencies
Adding resolve-url-loader to dependencies
Adding sass-loader to dependencies
Adding semver to dependencies
Adding source-map-loader to dependencies
Adding style-loader to dependencies
Adding tailwindcss to dependencies
Adding terser-webpack-plugin to dependencies
Adding webpack to dependencies
Adding webpack-dev-server to dependencies
Adding webpack-manifest-plugin to dependencies
Adding workbox-webpack-plugin to dependencies
Updating the scripts
Configuring package.json
Adding Jest configuration
Adding Babel preset
참고
- 각 의존성들의 Github Repository 및 공식 문서