CRA 없이 React 세팅하기 (Webpack, Babel, SWC)

InseoYangInseoYang
10 min read

회사에서 마이크로 프론트엔드 아키텍처를 적용해야 할 필요가 있어서 그에 대한 공부를 하며 연습하던 중, 다른건 그나마 만들어서 임포트가 되는데 어떻게 해도 리액트 컴포넌트 라이브러리는 만들지 못하는 내 자신에 대한 현타가 왔다. 컴포넌트만 모아둔 라이브러리에 무겁다고 소문난(?) cra로 환경을 만들기에는 왠지 오바인것 같아서 이거저거 해봤지만 나는 기본기도 없는(ㅠㅠ) 갓태어난 응애 개발자인지라 뭐 블로그 몇개 보고 척척 해내기엔 무리가 있었다. 항해 최종발표회날(바야흐로 3개월쯤전..) 어떤 프론트엔드 개발자분이 cra를 사용한 이유에 대해 물어보셨었는데, 그땐 “아 지금은 당연히 모르지 나 3개월 공부했는데 ㅋㅋ” 라고 생각만 하고 제대로 공부를 하지 않은게 지금 이렇게 스노우볼로 멘탈을 때리게 될줄은 몰랐다. 모던자바스크립트를 두 번을 읽어도 웹팩 바벨 챕터 쯤 되면 정신이 혼미해서져서 음음 그치그치 하고 대충 넘어가버린 과거의 내 자신의 죄를 지금이라도 씻어보고자 작성하는 (다소 부족할 수 있는) 글. (틀린내용이 있을 수 있으나 제 뇌의 한계이므로.. 댓글로 정정해주시면 감사하겠습니다..)

그래도 다시 한 번 CRA

cra로 리액트 프로젝트를 세팅하는 방법부터 먼저 다시 살펴보자. 꺼진불도 다시보자

yarn create react-app 패키지이름 --template typescript

(일단 나는 yarn과 typescript에 익숙해서 이렇게 만들지만, 나중에 yarn, npm, pnpm 등에 대해서도 한번 공부해보고 싶긴 함. 말만하지말고 진짜공부해야되는데..)

기나긴(?) cra가 끝나고 나서 package.json을 살펴보면 다음과 같은 dependency들이 설치된걸 확인할 수 있다.

  • package.json

      {
        "name": "babo",
        "version": "0.1.0",
        "private": true,
        "dependencies": {
          "@testing-library/jest-dom": "^5.14.1",
          "@testing-library/react": "^13.0.0",
          "@testing-library/user-event": "^13.2.1",
          "@types/jest": "^27.0.1",
          "@types/node": "^16.7.13",
          "@types/react": "^18.0.0",
          "@types/react-dom": "^18.0.0",
          "react": "^18.2.0",
          "react-dom": "^18.2.0",
          "react-scripts": "5.0.1",
          "typescript": "^4.4.2",
          "web-vitals": "^2.1.0"
        },
        "scripts": {
          "start": "react-scripts start",
          "build": "react-scripts build",
          "test": "react-scripts test",
          "eject": "react-scripts eject"
        },
        "eslintConfig": {
          "extends": [
            "react-app",
            "react-app/jest"
          ]
        },
        "browserslist": {
          "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
          ],
          "development": [
            "last 1 chrome version",
            "last 1 firefox version",
            "last 1 safari version"
          ]
        }
      }
    

물론 혼자 대가리깨져가며 컴포넌트 라이브러리를 만들 때, 오지게 봤던 목록이지만 봐도봐도 뭐가필요한진 잘 모르겠어서 쓰기 시작한 블로그 글이다. 뭐 눈치상 react, react-dom은 필요한것같긴 한데, 눈치상 개발하는것이 또 어떤 후폭풍을 안겨줄지 무서운 관계로.. 그리고 또 이런 쉬운방법이 있다는건 알지만? 처음부터 만들어가며 뭐가 어떤기능을 하는건지 살펴보자

아니 근데 웹팩과 바벨은 눈씻고 찾아봐도 없는데 ?

놀랍게도 숨겨져있음.

yarn ejejct

를 사용하면 숨겨져있던 친구들이 나온다. 이 액션은 다시 되돌릴 수 없는데 ㄱㅊ? 라고 물어보는데 사실 연습용 프로젝트라 무서울거 없지만 괜히 한번 주춤함. 처음써보는 명령어였다. 둨큰. 사실 좀 쫄았어요.

  • yarn eject 실행 후의 package.json

      {
        "name": "babo",
        "version": "0.1.0",
        "private": true,
        "dependencies": {
          "@babel/core": "^7.16.0",
          "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
          "@svgr/webpack": "^5.5.0",
          "@testing-library/jest-dom": "^5.14.1",
          "@testing-library/react": "^13.0.0",
          "@testing-library/user-event": "^13.2.1",
          "@types/jest": "^27.0.1",
          "@types/node": "^16.7.13",
          "@types/react": "^18.0.0",
          "@types/react-dom": "^18.0.0",
          "babel-jest": "^27.4.2",
          "babel-loader": "^8.2.3",
          "babel-plugin-named-asset-import": "^0.3.8",
          "babel-preset-react-app": "^10.0.1",
          "bfj": "^7.0.2",
          "browserslist": "^4.18.1",
          "camelcase": "^6.2.1",
          "case-sensitive-paths-webpack-plugin": "^2.4.0",
          "css-loader": "^6.5.1",
          "css-minimizer-webpack-plugin": "^3.2.0",
          "dotenv": "^10.0.0",
          "dotenv-expand": "^5.1.0",
          "eslint": "^8.3.0",
          "eslint-config-react-app": "^7.0.1",
          "eslint-webpack-plugin": "^3.1.1",
          "file-loader": "^6.2.0",
          "fs-extra": "^10.0.0",
          "html-webpack-plugin": "^5.5.0",
          "identity-obj-proxy": "^3.0.0",
          "jest": "^27.4.3",
          "jest-resolve": "^27.4.2",
          "jest-watch-typeahead": "^1.0.0",
          "mini-css-extract-plugin": "^2.4.5",
          "postcss": "^8.4.4",
          "postcss-flexbugs-fixes": "^5.0.2",
          "postcss-loader": "^6.2.1",
          "postcss-normalize": "^10.0.1",
          "postcss-preset-env": "^7.0.1",
          "prompts": "^2.4.2",
          "react": "^18.2.0",
          "react-app-polyfill": "^3.0.0",
          "react-dev-utils": "^12.0.1",
          "react-dom": "^18.2.0",
          "react-refresh": "^0.11.0",
          "resolve": "^1.20.0",
          "resolve-url-loader": "^4.0.0",
          "sass-loader": "^12.3.0",
          "semver": "^7.3.5",
          "source-map-loader": "^3.0.0",
          "style-loader": "^3.3.1",
          "tailwindcss": "^3.0.2",
          "terser-webpack-plugin": "^5.2.5",
          "typescript": "^4.4.2",
          "web-vitals": "^2.1.0",
          "webpack": "^5.64.4",
          "webpack-dev-server": "^4.6.0",
          "webpack-manifest-plugin": "^4.0.2",
          "workbox-webpack-plugin": "^6.4.1"
        },
        "scripts": {
          "start": "node scripts/start.js",
          "build": "node scripts/build.js",
          "test": "node scripts/test.js"
        },
        "eslintConfig": {
          "extends": [
            "react-app",
            "react-app/jest"
          ]
        },
        "browserslist": {
          "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
          ],
          "development": [
            "last 1 chrome version",
            "last 1 firefox version",
            "last 1 safari version"
          ]
        },
        "jest": {
          "roots": [
            "<rootDir>/src"
          ],
          "collectCoverageFrom": [
            "src/**/*.{js,jsx,ts,tsx}",
            "!src/**/*.d.ts"
          ],
          "setupFiles": [
            "react-app-polyfill/jsdom"
          ],
          "setupFilesAfterEnv": [
            "<rootDir>/src/setupTests.ts"
          ],
          "testMatch": [
            "<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
            "<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
          ],
          "testEnvironment": "jsdom",
          "transform": {
            "^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
            "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
            "^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
          },
          "transformIgnorePatterns": [
            "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
            "^.+\\.module\\.(css|sass|scss)$"
          ],
          "modulePaths": [],
          "moduleNameMapper": {
            "^react-native$": "react-native-web",
            "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
          },
          "moduleFileExtensions": [
            "web.js",
            "js",
            "web.ts",
            "ts",
            "web.tsx",
            "tsx",
            "json",
            "web.jsx",
            "jsx",
            "node"
          ],
          "watchPlugins": [
            "jest-watch-typeahead/filename",
            "jest-watch-typeahead/testname"
          ],
          "resetMocks": true
        },
        "babel": {
          "presets": [
            "react-app"
          ]
        }
      }
    

자. 어마어마하다. 이쯤되면 후회하는 점. 왜 타입스크립트 템플릿으로 생성했을까. 지금 자바스크립트 기준으로만 저거 봐도 정신 나갈것같은데. 근데사실 타스때문에 그렇다기보단 그냥 많은듯

+ script , config 라는 폴더가 생긴다. 이친구들도 나중에 뜯어보면 꽤재밌을듯

저 안에 있는 것들을 하나하나 살펴보고싶지만 일단 이번 블로그의 주제는 cra없이 리액트 개발환경 만들기 이므로 나만의백로그(?)에 넣어두고 하던걸 하자.

⇒ 아무튼 저래서 결론은 cra로 했을 때 eject하기 전까진 webpack, babel이 안보이지만 사실은 숨겨져있는거다. 즉, webpack.config.js나 .babelrc로 필요한 설정을 추가적으로 해 줄 수 있다는 말임.(eject된 package.json 맨아래에도 이미 바벨 설정이 있음 !!)

⇒ 저래서 cra 무겁다 무겁다 했구나 싶다. 몇 개는 에러메세지로 이미 숱하게 봐서 익숙한 친구들도 있다. 대체 어쩌라는건지 몰라서 새로 설치해준 적도 있는데 사실 숨겨져있던거라니.. 나의 무지함에 한번 더 박수(?)..

babel, webpack 사용하기

드디어 어렵게 결론-1.

라이브러리

설치

필요한 라이브러리 : react, react-dom, babel, webpack, eslint, prettier … 어쩌구

(+ typescript 사용할 경우 : typescript, @types/node, @types/react, @types/react-dom … 어쩌구)

  1. react : react, react-dom
yarn add react react-dom

당연함. 우리는 리액트 쓸거니까. ㅋㅋ. 가 끝이아니다. 난 저 react-dom이라는 친구가 첫인상으로는 라우터 사용할때 쓰는건가 했는데 생각해보니 그건 react-router-dom임.헷갈릴걸 헷갈려라(변명: 넥스트 쓴지 좀 돼서요^^) 저친구는 우리가 기술면접 준비할때 그렇게 달달 외웠던 리액트의 “가상돔”을 사용하기 위한 친구다. 추가적으로 html 파일에 리액트 element들을 렌더링해주는역할을 한다.

  1. typescript : typescript, @types/react, @types/react-dom
yarn add -D typescript @types/react @types/react-dom

써글롬의 타입스크립트. 확실히 자바스크립트를 사용하는것보다 이제는 조금더 편하지만, 이친구를 사용해주기 위해서는 호환을 위해 라이브러리를 추가적으로 더 설치해줘야 한다.

⇒ 타입스크립트는 개발 환경에서만 사용되므로(브라우저는 타입스크립트를 읽을 수 없어 js로 어차피 변환해주어야하기 때문임) devDependency에 설치해주는 것이 효율적이라고 생각된다.

이거까진 알겠는데.. 바벨,웹팩은 왜 씀?

⇒ 브라우저에서 최신 js 문법(ES6+)을 지원하지 않는 경우가 있을 수 있으므로, ES5로 변환해주는 애들임. 근까 지금 짠 코드는 무조건(은아닐지몰라도) 최신일텐데 구린 브라우저(ㅋㅋ)에서 돌리면 절대안돌아가니까, 구린애들도 알아먹을 수 있도록 뭐 기회의 평등같은걸 주는 애들이라 보면 됨.

  1. babel : babel-loader, @babel/core, @babel/preset-env, @babel/preset-react, @babel/preset-typescript
yarn add -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript

이 아래부터 ***-loader들이 계속 등장할 예정인데, 결국 그 접두사 친구들을 로드해서 읽어줄 수 있는 애들을 말한다고 추측됨..!

사용해야 하는 preset들도 설치해주자

  1. webpack : webpack, webpack-cli, webpack-dev-server, webpack-merge, html-webpack-plugin, ts-loader
yarn add -D webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin ts-loader

webpack-cli 는 이름부터 알 수 있듯이 간단한 명령어로 웹팩을 일하게해주는 애다.

webpack-dev-server : 이친구 왜 필요할까? 라는 생각이 들었는데, 개발 환경에서 내가 로컬호스트로 계속 확인하면서 볼 수 있으려면 이친구가 돌아줘야함

설정파일

tsconfig.json

  • 사용할 수 있는 설정들(전부는 아님)

      {
       "compilerOptions": {
        // 'es3', 'es5', 'es2015', 'es2016', 'es2017','es2018', 'esnext' 가능
        "target": "es5",
        //무슨 import 문법 쓸건지 'commonjs', 'amd', 'es2015', 'esnext'
        "module": "commonjs", 
          // js 파일들 ts에서 import해서 쓸 수 있는지 
        "allowJs": true, 
          // 일반 js 파일에서도 에러체크 여부 
        "checkJs": true, 
          // tsx 파일을 jsx로 어떻게 컴파일할 것인지 'preserve', 'react-native', 'react', 'react-jsx'
        "jsx": "preserve", 
          //컴파일시 .d.ts 파일도 자동으로 함께생성 (현재쓰는 모든 타입이 정의된 파일)
        "declaration": true, 
          // .d.ts 파일을 저장할 위치
          "declarationDir": "./types",
          //모든 ts파일을 js파일 하나로 컴파일해줌 (module이 none, amd, system일 때만 가능)
        "outFile": "./", 
          //js파일 아웃풋 경로바꾸기
        "outDir": "./", 
          //루트경로 바꾸기 (js 파일 아웃풋 경로에 영향줌)
        "rootDir": "./", 
          //컴파일시 주석제거 
        "removeComments": true, 
    
          //strict 관련, noimplicit 어쩌구 관련 모드 전부 켜기
        "strict": true, 
          //any타입 금지 여부
        "noImplicitAny": true, 
          //null, undefined 타입에 이상한 짓 할시 에러내기 
        "strictNullChecks": true, 
          //함수파라미터 타입체크 강하게 
        "strictFunctionTypes": true, 
          //class constructor 작성시 타입체크 강하게
        "strictPropertyInitialization": true, 
          //this 키워드가 any 타입일 경우 에러내기
        "noImplicitThis": true, 
          //자바스크립트 "use strict" 모드 켜기
        "alwaysStrict": true, 
    
          //쓰지않는 지역변수 있으면 에러내기
        "noUnusedLocals": true, 
          //쓰지않는 파라미터 있으면 에러내기
        "noUnusedParameters": true, 
          //함수에서 return 빼먹으면 에러내기 
        "noImplicitReturns": true, 
          //switch문 이상하면 에러내기 
        "noFallthroughCasesInSwitch": true, 
          // 결과물 생략하기
          "noEmit": true 
       },
          // js로 변환할 파일
          "include": ["./src/**/*.tsx"],
          // 변환하지 않을 파일
          "exclude": [
              "node_modules",
              // 테스트코드
              "src/**/*.test.tsx",
              // 스토리북 관련 코드
              "src/**/*.stories.tsx"
          ]
      }
    
  • cra를 하면 생성되는 ts설정파일

      {
        "compilerOptions": {
          "target": "es5",
          "lib": [
            "dom",
            "dom.iterable",
            "esnext"
          ],
          "allowJs": true,
          "skipLibCheck": true,
          "esModuleInterop": true,
          "allowSyntheticDefaultImports": true,
          "strict": true,
          "forceConsistentCasingInFileNames": true,
          "noFallthroughCasesInSwitch": true,
          "module": "esnext",
          "moduleResolution": "node",
          "resolveJsonModule": true,
          "isolatedModules": true,
          "noEmit": true,
          "jsx": "react-jsx"
        },
        "include": [
          "src"
        ]
      }
    

참고해서 정말 필요한것만 !! 넣어보자면 이라고하기엔 기존 tsconfig를 빼다 박았다. 아직 커스터마이징까진 어렵네요. 안전빵으로 감.

{
  "compilerOptions": {
        // es5로 변환할거임
    "target": "es5",
        // 빌트인 js api 등 문법적인 것들에 대한 type definition 가져와야함
    "lib": [
            // window, document 등을 사용할 수 있게 해줌
      "dom",
      "dom.iterable",
      "esnext"
    ],
        // js 파일도 import 해서 사용할 수 있도록 한다.
    "allowJs": true,
        // 모든 .d.ts파일을 체크하지 말고 소스코드에서 사용되는 것만 체크해줭
    "skipLibCheck": true,
        // false로 세팅시 commonjs/amd/umd를 es6와 비슷하게 해석함 근데우린어차피 es6쓸거니깐
    "esModuleInterop": true,
        // default 임포트를 매번 * as 어쩌구 해주지 않아도 됨
    "allowSyntheticDefaultImports": true,
        // 서터릭터 하게 기릿
    "strict": true,
        // 파일이름에 일관된 대소문자 사용 가능하게
    "forceConsistentCasingInFileNames": true,
        // switch문 이상하면 오류내줘
    "noFallthroughCasesInSwitch": true,
        // 최신 import 문법 쓸거임
    "module": "esnext",
        // import,require 중에서 골라줌
    "moduleResolution": "node", // node10과 같음 왜냐면 10이전에서는 import 안먹힘 무적권 require
    // json 파일로 된 모듈 임포트 가능한~
        "resolveJsonModule": true,
        // const enums 나 namespaces 같은 애들은 완벽하게 변환안될수있다고 경고해줘~
    "isolatedModules": true,
        // 결과 파일을 저장하지 않게해줘~
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

webpack.config.js

  • 예시

      const HtmlWebpackPlugin = require("html-webpack-plugin");
      const { CleanWebpackPlugin } = require("clean-webpack-plugin");
      const path = require("path");
      const webpack = require("webpack");
      // const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
      module.exports = {
        mode: "development", // 미설정시 기본값 "production"
        entry: "./src/index.tsx",
        resolve: {
          extensions: [".js", ".jsx", ".ts", ".tsx"],
        },
        module: {
          rules: [
            {
              test: /\.tsx?$/,
              use: ["babel-loader", "ts-loader"],
            },
          ],
        },
        output: {
          path: path.join(__dirname, "/dist"),
          filename: "bundle.js",
        },
        plugins: [
          new HtmlWebpackPlugin({ template: "./public/index.html" }),
          new CleanWebpackPlugin(),
              new webpack.ProvidePlugin({ React: "react" })
              // new MiniCssExtractPlugin()
        ],
        devServer: {
          port: 3000,
          historyApiFallback: true,
          hot: true,
          open: true,
        },
      };
    

babel.config.js(= .babelrc)

module.exports = {
  presets: [
    "@babel/preset-react",
    "@babel/preset-env",
    "@babel/preset-typescript",
  ],
};

설정해주면 끝인가? 답은 “아니”ㅋㅋ

package.json 파일을 업데이트 해줘야함.

  • webpack config에서 devserver 설정을 해줬을 시
"scripts": {
    "start": "webpack serve", // 웹팩 개발 서버 시작 명령어
    "build": "webpack", // 빌드 명령어
  },
  • 안해줬을 시(개발서버 안열림, dist 파일 생성됨)
"scripts": { 
  "start": "webpack --mode development", 
  "build": "webpack --mode production" 
}
  • 안해줬을 시(개발서버 열림)
"scripts": { 
  "start": "webpack-dev-server --mode development --open --hot", 
  "build": "webpack --mode production" 
}

cra를 사용했다면 yarn start 실행 시, react-scripts start(node scripts/start.js)가 실행됐었는데 우린 cra 안썼으니까 웹팩한테 ㅃㄹㅃㄹ 돌려주셈! 하고 일시켜야함.

근데 잠만. 밑의 스크립트에서 나는 development하나만 작성했는데 재는 production 모드를 어디서 불러와서 빌드한다는거?

  • 지선생님 예시

      const path = require('path');
      const HtmlWebpackPlugin = require('html-webpack-plugin');
    
      module.exports = (env, argv) => {
        // argv.mode에 따라 설정을 동적으로 변경
        const isDevelopment = argv.mode === 'development';
    
        return {
          entry: './src/index.js',
          output: {
            filename: isDevelopment ? 'bundle.dev.js' : 'bundle.prod.js',
            path: path.resolve(__dirname, 'dist'),
          },
          plugins: [
            new HtmlWebpackPlugin({
              template: './src/index.html',
            }),
          ],
          devServer: {
            open: true,
          },
        };
      };
    

→ 또는 webpack.dev.js, webpack.common.js, webpack.prod.js로 config파일을 분리해봐라..

근데그럼 scripts도 변경해야함(개발환경구축용) : --config <웹팩설정파일이름>으로 지정해줘야함

"scripts": {
-    "start": "webpack --mode development"
+    "start": "webpack serve --open --config webpack.dev.js",
// 혹은 "webpack-dev-server --config webpack.dev.js --open --hot"
-    "build": "webpack --mode production"
+    "build": "webpack --config webpack.prod.js"
    },

--open : 개발서버 열면서 브라우저 자동으로 열어줌

--hot : 변경 사항 자동 업뎃해줌(번들링)

SWC 사용하기

next 13부터 babel을 사용하지 않고 swc를 사용하며 속도가 굉장 향상되었다.

따라서 나도.. 바벨안쓰고 얘를 사용해보고 싶어짐 !

라이브러리

  1. webpack : webpack, webpack-cli, webpack-dev-server, html-webpack-plugin, ts-loader

  2. swc : @swc/cli, @swc/core, swc-loader

설정

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.tsx',
  resolve: {
    extensions: [".js", ".jsx", ".ts", ".tsx"],
  },
  output: {
    path: path.join(__dirname, '/dist'),
    filename: 'index_bundle.js'
  },
  devServer: {
    static: {
      directory: path.join(__dirname, 'public'),
    },
    compress: true,
    port: 3001
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/ ,
        exclude: /(node_modules)/,
              // 결국 이 부분이 바뀌고(원래는 "babel-loader") .swcrc 파일이 추가됐다고 보면 됨.
                use: ["swc-loader", "ts-loader"],
                // 근데 .swcrc 파일 추가하기싫으면 이랗게하면댐
        // use: {
        //     loader: "swc-loader",
                //     options: {여기에 .swcrc 이랑 똑같이 해주면 됨ㅋㅋ}
        // }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      filename: "./index.html",
      template: path.join(__dirname, 'public/index.html')
    })
  ],
  devServer: {
    port: 3000,
    historyApiFallback: true,
    hot: true,
    open: true,
  },
}

.swcrc

  • 사용가능한 설정

      {
       "$schema": "https://json.schemastore.org/swcrc",
       "jsc": {
           "parser": {
           "syntax": "ecmascript",
           "jsx": false,
           "dynamicImport": false,
           "privateMethod": false,
           "functionBind": false,
           "exportDefaultFrom": false,
           "exportNamespaceFrom": false,
           "decorators": false,
           "decoratorsBeforeExport": false,
           "topLevelAwait": false,
           "importMeta": false
       },
       "transform": null,
       "target": "es5",
       "loose": false,
       "externalHelpers": false,
       // swc v1.2.50 이상이고 target이 es2016+ 일때만 가능한 설정
       "keepClassNames": false
       },
      // 코드 경량화를 위함 설정
       "minify": false
      }
    
{
  "jsc":{
    "parser": {
      "syntax": "ecmascript",
      "jsx": true
    },
    "transform": {
      "react":{
        "runtime": "automatic"
      }
    }
  }
}

package.json 업데이트

"scripts": {
    "start": "webpack-dev-server --mode development --open --hot",
    "build": "webpack --mode production"
  },

나머지 public폴더나 index.jsx, App.jsx는 cra의 그것과 동일하게 설정해주면 됨ㅋㅋ 귀찮은 사람들을 위하여..

  • public/index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <meta
            name="description"
            content="Web site created without create-react-app"
          />
          <title>React App</title>
        </head>
        <body>
          <noscript>You need to enable JavaScript to run this app.</noscript>
          <div id="root"></div>
        </body>
      </html>
    
  • src/index.tsx

      import React from 'react';
      import ReactDOM from 'react-dom/client';
      import App from './App';
    
      const root = ReactDOM.createRoot(
        document.getElementById('root') as HTMLElement
      );
      root.render(
        <React.StrictMode>
          <App />
        </React.StrictMode>
      );
    
  • src/App.tsx

      import React from 'react';
    
      function App() {
        return (
          <div>
            <header>
                Learn React
            </header>
          </div>
        );
      }
    
      export default App;
    

풀리지않은 의문점

자 이제 cra없이 리액트 환경을 만드는 것 까지는 알겠다.. 바벨..웹팩.. 이놈들이 뭘해주는 친구들인지 대략적으로는 알고있었지만 좀 더 자세히 알게된 느낌..?

그러나 리액트 컴포넌트 라이브러리를 만드는건 여전히 모르겠다.. 현재 대가리 깨져가며 이거저거 시도중이긴 한데, 뭘 제대로 모르니까 뭘어떻게 더 설정해줘야하는지도 모르겠고 불필요한 설정도 해둔 것 처럼 보임. 빌드한파일을 emit 해줘야할것같긴 한데, 더 자세히 공부 절대절대 필요해보임.

어째뜬 따라서 더 공부해서 정리할 예정..

추가) 넥스트에서 eject해도 저거와 비슷한 package.json일지 궁금해짐. 근데 cna에는 eject가 딱히없다. 이것도 차차뜯어봐야지


참고자료

https://www.typescriptlang.org/tsconfig https://webpack.kr/configuration/ https://babeljs.io/docs/config-files#project-wide-configuration https://swc.rs/docs/configuration/swcrc https://leetrue-log.vercel.app/leetrue-nextjs-swc https://velog.io/@kcj_dev96/CRA없이-리액트-프로젝트-셋팅#tsconfigjson https://helloinyong.tistory.com/347 https://medium.com/age-of-awareness/setup-react-with-webpack-and-babel-5114a14a47e9

0
Subscribe to my newsletter

Read articles from InseoYang directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

InseoYang
InseoYang