본문 바로가기
javascript

webpack

by rami_ 2024. 2. 24.

기본질문

  • 웹팩이란?
    • javascript 어플리케이션을 위한 모듈 번들러
      • 모듈 번들러 : 애플리케이션을 구성하는 여러 모듈 및 자원(HTML, CSS, javascript, image, font 등)들을 하나로 번들링하여 관리함. 이를 통해 개발자는 여러 파일을 하나의 파일로 결합하여 네트워크 로드를 줄이고, 코드를 조직화하고, 의존성을 관리할 수 있음
      빌드, 번들링, 변환 이 세 단어는 모두 같은 의미이다.
  • 웹팩이 하는 일.
    • 여러개의 javascript 파일 및 이미지, css 파일, 폰트 등을 하나로 묶어주는 도구.
    • 모듈 번들링
      • 의존성 그래프를 기반으로 프로젝트의 모든 모듈을 분석하고 이를 하나 또는 여러개의 번들로 묶어줌.
      • 모듈시스템을 지원하며 각 모듈 간의 의존성을 파악하여 효율적으로 번들링.
    • 로더
      • 다양한 파일 형식(js, css, image)을 모듈로 취급할 수 있도록 하는 로더 시스템 제공.
      • 각 파일을 로딩하고 필요한 전/후 처리 작업을 수행할 수 있음. Babel을 사용하여 ES6+코드를 ES5로 변환하는 등의 작업을 할 수 있음.
    • 번들 최적화
      • 코드 압축, 트리쉐이킹, 코드 스플리팅을 지원함.
      • 이를 통해 초기 로딩속도를 향상시키고 불필요한 코드를 제거하여 번들 크기를 최소화 할 수 있음.
    • 플러그인
      • 사용자는 플러그인을 활용하여 번들링과정을 커스터마이징하거나 추가 기능을 구현할 수 있음.
      • HTMLWebpackPlugin, MiniCssExtractPlugin
    • 개발서버 제공
      • 개발과정에서 실시간으로 변경사항을 반영할 수 있는 개발서버를 제공함.
      • 파일 변경 감지 및 자동 재빌드, 브라우저 자동 새로고침 등의 기능을 제공하여 개발자의 작업을 편리하게 함.
  • react에서 webpack이 없으면 css와 image파일 처리는 할 수 없나?
    • 아님.
    • css 파일
      • 웹팩 O : import문을 사용함.
      • 웹팩 X : <link> 태그를 통해 HTML 파일에 직접 포함시켜야 함.
    • 이미지 파일
      • 웹팩 O : import문을 사용함.
      • 웹팩 X : <img> 태그를 사용하거나 css의 background-image 속성을 통해 이미지를 배경으로 사용할 수 있음.
  • 웹팩 설정 옵션
    • entry
      • 웹팩이 번들링을 시작할 entry point 파일을 지정.
    • output
      • 번들링된 파일의 출력 설정. 번들링된 파일의 경로와 이름을 지정할 수 있음.
    • mode
      • 개발 또는 프로덕션 모드를 선택함. mode 값에 따라 웹팩은 최적화 옵션을 자동으로 설정함.
    • module
      • 모듈 처리에 대한 규칙을 정의함. 주로 로더를 지정하여 다양한 파일 형식을 처리하도록 설정함.
    • resolve
      • 모듈 해결방법을 설정함. 모듈 경로나 확장자를 해석하거나 별칭을 지정할 수 있음.
    • plugins
      • 웹팩의 기능을 확장하기 위한 플러그인을 설정함.
      • 번들 최적화, 환경변수 주입, HTML 생성 등
    • optimization
      • 번들 최적화 옵션을 설정.
      • 코드 압축, 트리쉐이킹, 코드 분할 등의 최적화를 수행함.
    • devServer
      • 개발서버 설정.
      • 파일 변경 감지, 자동새로고침 등을 제공함.
    • devtool
      • 디버깅을 위한 소스맵 설정을 지정함.
      • 소스맵은 번들링된 코드와 원본 코드 간의 대응 관계를 제공함.
    • externals
      • 번들링에서 제외할 외부 의존성을 설정
      • CDN을 통해 제공되는 라이브러리를 번들링에서 제외할 수 있음.
    • target
      • 빌드할 환경을 설정.
      • 웹 브라우저, Node.js 등 다양한 환경에 맞게 빌드할 수 있음.
    • performance
      • 번들크기와 관련된 성능 경고를 설정함.
      • 번들 크기가 크거나 로딩 시간이 길어지는 경우 경고를 출력함.
  • 웹팩 vs rollup vs vite
    •  웹팩
      • 주로 대규모 복잡한 웹 어플리케이션을 위해 설계됨.
      • 다양한 파일 형식의 로더를 지원하여 프로젝트의 다양한 리소스를 번들링 할 수 있음.
      • 코드 분할, 자바스크립트 압축(Uglification), 트리쉐이킹 등의 다양한 최적화 기능을 제공함.
      • 설정이 복잡하고 초기 설정에 시간이 걸릴 수 있지만, 대규모 프로젝트에 적합함.
    • Rollup
      • 주로 라이브러리 또는 패키지를 위헤 설계됨.
      • ES6 모듈 표준에 중점을 두고 있으며, 코드를 효율적으로 번들링하여 라이브러리로 배포하는데 적합함.
      • 코드를 더욱 효율적으로 최적화할 수 있는 경향이 있음.
      • 웹팩보다 설정이 단순하며 특히 라이브러리나 패키지 개발에 매우 적함함.
    • Vite
      • 개발서버에 HMR(Hot Module Replacement)을 사용하여 실시간으로 빠른 개발환경을 제공함.
      • 빌드 시간을 최소화하기 위해 빠른 빌드 시스템을 제공함.
      • 프로젝트 초기설정이 단순하고 빠르게 시작할 수 있으며, 특히 작은 및 중간 규모의 프로젝트에 적합함.

코드로 구현하기

const fs = require("fs"); //Node.js의 파일 시스템 모듈. 파일 읽기/쓰기 등
const path = require("path"); //Node.js의 경로 관련 모듈.
const { parse } = require("@babel/parser"); //Babel의 파서 모듈을 로드함. 자바스크립트 코드를 파싱하여 AST(Abstract Syntax Tree)로 변환함.
const traverse = require("@babel/traverse").default; //Babel의 traverse 모듈을 로딩함. default는 ES6모듈에서 기본 내보내기를 가져옴.
const babel = require("@babel/core");

function createGraph(entry) {
  //주어진 진입점 파일을 기준으로 의존성 그래프를 생성.
  //파일을 읽고 AST생성한 후, AST를 순회하여 'ImportDeclaration' 노드를 찾아 그에 해당하는 의존성 추가.
  const content = fs.readFileSync(entry, "utf-8");
  const ast = parse(content, { sourceType: "module" });
  const dependencies = [];

  traverse(ast, {
    ImportDeclaration: ({ node }) => {
      dependencies.push(node.source.value);
    },
  });

  return { entry, dependencies };
}

function bundle(graph) {
  //생성된 의존성 그래프를 바탕으로 모든 모듈을 단일 파일로 번들링 함.
  let moudles = "";

  graph.forEach((module) => {
    moudles += `'${module.entry}': function(require, module, exports) {
        ${module.content}
    },`;
  });

  const result = `(function(moudules) {
    function require(moduleId) {
        const module = { exports: {} };
        modules[moduleId](require, module, module.exports);
        return module.exports;
    }
    require('${graph[0].entry}');
  })({${module}})`;

  return result;
}

function build(entry) {
  //진입점 파일을 기준으로 의존성 그래프를 새엇ㅇ하고 모든 모듈의 코드를 번들에 포함시킴.
  const graph = [createGraph(entry)];

  for (const module of graph) {
    module.content = fs.readFileSync(module.entry, "utf-8");
    module.dependencies.forEach((dep) => {
      const depPath = path.resolve(path.dirname(entry), dep);
      const depGraph = createGraph(depPath);

      module.content = module.content.replace(dep, depPath);

      graph.push(depGraph);
    });
  }

  return bundle(graph);
}

const entryFile = path.resolve(__dirname, "src", "index.js");
//진입점 파일의 절대경로를 설정.
const output = path.resolve(__dirname, "dist", "bundle.js");
//출력 파일의 절대 경로.
const bundledCode = build(entryFile);
//진입점 파일을 기반으로 번들링된 코드를 생성.
fs.writeFileSync(output, bundledCode);
//번들링 된 코드를 출력 파일에 작성.

'javascript' 카테고리의 다른 글

자바스크립트의 은닉화 그리고 모듈  (3) 2024.03.12
rollup  (0) 2024.03.10
break && continue  (0) 2022.03.05
new 연산자  (0) 2022.02.27
Prototype method vs Object method  (0) 2022.02.27