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);
//번들링 된 코드를 출력 파일에 작성.