Webpack은 프런트엔드의 "공성 사자"로서 너무 많은 일을 할 수 있습니다. Webpack은 모든 리소스(JS, TS, JSX, 이미지, 글꼴, CSS 등 포함)를 패키징하고 종속성에 배치할 수 있습니다. . 필요에 따라 리소스를 사용하기 위해 종속성을 참조할 수 있습니다. Webpack은 프런트 엔드에서 여러 파일 리소스를 변환하고 복잡한 모듈 종속성을 분석하는 훌륭한 작업을 수행했습니다. 또한 로더를 사용자 정의하고 자체 리소스를 자유롭게 로드할 수 있습니다. 그렇다면 Webpack은 어떻게 패키징을 구현합니까? 오늘 와서 살펴보세요.
1. require란 무엇입니까?
require에 관해서 가장 먼저 떠오르는 것은 import입니다. import는 es6의 구문 표준입니다.
–
require는 런타임 호출이므로 이론적으로 require는 코드의 어느 곳에서나 사용될 수 있습니다.
호출하므로 파일 시작 부분에 배치해야 합니다. ;
Webpack을 사용하여 컴파일할 때 import를 require로 변환하는 데 사용됩니다. CommonJS에는 모듈을 로드하는 데 사용되는 전역 메서드가 있습니다. . AMD 및 CMD도 참조를 위해 require 메소드를 사용합니다.
예:
var add = require('./a.js');간단히 말해서
add(1,2)
require는 실제로 함수이고 참조된 ./a.js
는 함수의 매개변수일 뿐입니다.
2. 수출이란 무엇입니까?
여기서는 내보내기를 객체로 생각할 수 있습니다. MDN 내보내기의 구체적인 사용법을 볼 수 있습니다.
먼저 패키징 후 코드 구조를 살펴보겠습니다. require 및 내보내기가 패키징 후에 나타납니다.
모든 브라우저에서 require 내보내기를 실행할 수 있는 것은 아닙니다. 코드의 정상적인 작동을 보장하려면 require 및 내보내기를 직접 구현해야 합니다. 패키지된 코드는 자체 실행 함수이며, 매개변수에는 종속성 정보가 포함되어 있으며 실행된 함수 본문은 eval을 통해 코드를 실행합니다.
전체적인 디자인 도면은 다음과 같습니다.
1단계: 구성 파일 작성
구성 파일은 후속 생성 파일을 준비하기 위해 패키지된 항목과 패키지된 종료 출력을 구성합니다.
const path = require("경로"); 모듈.수출 = { 항목: "./src/index.js", 출력: { path: path.resolve(__dirname, "./dist"),//패키징 후 파일 주소 출력에는 절대 경로가 필요하므로 경로가 필요합니다. 파일 이름:"main.js" }, mode: "development"
2단계: 모듈 분석의 전반적인 아이디어
: 요약하자면, fs 파일을 사용하여 항목 파일을 읽고 종속 파일이 여전히 있는 경우 AST를 통해 가져오기 종속 파일의 경로를 얻는 것입니다. 종속성이 있는 경우 종속성 분석이 명확해질 때까지 계속 반복하여 맵에 유지됩니다.
세부 분석 : AST가 이 기능으로 탄생했기 때문에 왜 AST를 사용하는지 궁금해할 수도 있습니다. ImportDeclaration을 사용하면 가져오기 구문을 빠르게 필터링할 수 있습니다. 물론, 파일은 일반 매칭도 가능합니다. 문자열을 읽은 후 작성하면 됩니다. 멋진 정규식은 파일 종속성 경로를 얻는 데 유용하지만 충분히 우아하지는 않습니다.
index.js file
import { str } from "./a.js"; console.log(`${str} Webpack`)
a.js 파일
import { b} from "./b.js" 내보내기 const str = "hello"
b.js 파일
내보내기 const b="bbb"
모듈 분석 작성: AST의 @babel/parser를 사용하여 파일에서 읽은 문자열을 AST 트리로 변환하고 @babel/traverse를 사용하여 변환합니다. 구문 ImportDeclaration을 분석하고 사용하여 가져오기를 필터링하고 파일 종속성을 찾습니다.
const content = fs.readFileSync(entryFile, "utf-8"); const ast = parser.parse(content, { sourceType: "모듈" }); const dirname = path.dirname(entryFile); const 종속 항목 = {}; 횡단(동, { ImportDeclaration({ 노드 }) { //가져오기 필터링 const newPathName = "./" + path.join(dirname, node.source.value); 종속 항목[node.source.value] = newPathName; } }) const { 코드 } = 변환FromAst(ast, null, { 사전 설정: ["@babel/preset-env"] }) 반품 { 항목파일, 부양가족, 암호 }
결과는 다음과 같습니다.
종속성 분석을 위해 재귀 또는 루프를 사용하여 파일을 하나씩 가져옵니다. 여기서는 모든 종속성을 분석하기 위해 for 루프를 사용합니다. 루프가 모든 종속성을 분석할 수 있는 이유는 dependency.modules .push가 있을 때입니다. 새로운 종속성, module.length가 변경됩니다.
for (let i = 0; i < this.modules.length; i++) { const 항목 = this.modules[i]; const { 종속 항목 } = 항목; if (종속) { for (부양가족에 j를 두세요) { this.modules.push(this.parse(dependents[j])); } } }
3단계: WebpackBootstrap 함수 작성 + 출력 파일 생성
WebpackBootstrap 함수 작성 : 여기서 가장 먼저 해야 할 일은 WebpackBootstrap 함수를 컴파일한 후 브라우저에서 가져오는 것입니다. require를 인식하지 못하면 먼저 선언해야 합니다. 결국 require는 메소드이므로 변수 오염을 방지하기 위해 범위 격리에도 주의해야 합니다. 또한 코드가 실행될 때 내보내기가 이미 존재하는지 확인하기 위해 코드에서 내보내기를 선언해야 합니다.
출력 파일 생성 : 생성된 파일의 주소를 구성 파일에 이미 작성한 다음 fs.writeFileSync를 사용하여 출력 폴더에 씁니다.
파일(코드) { const filePath = path.join(this.output.path, this.output.filename) const newCode = JSON.stringify(코드); // 번들 파일 콘텐츠 생성 const Bundle = `(function(modules){ 함수 요구(모듈){ 함수 pathRequire(relativePath){ return require(modules[module].dependents[relativePath]) } const 내보내기={}; (함수(요구, 내보내기, 코드){ 평가(코드) })(pathRequire,exports,modules[모듈].code); 수출품 반환 } require('${this.entry}') })(${newCode})`; // 웹팩부스트랩 // 파일을 생성합니다. dist 디렉토리 fs.writeFileSync(filePath,bundle,'utf-8') 에 넣으세요. }
4단계: 실행 순서 분석
브라우저 콘솔에서 패키지된 결과를 실행할 수 있습니다. 정상적으로 작동하면 hello Webpack이 인쇄됩니다.
위의 분석을 통해 Webpack의 일반적인 프로세스에 대한 기본적인 이해가 필요합니다. AST를 사용하여 코드를 구문 분석하는 것은 단지 설명을 위한 방법일 뿐이며 Webpack의 실제 구현에는 자체 AST 구문 분석 방법이 있습니다. Webpack 생태계는 매우 완벽합니다. 관심 있는 어린이는 다음 세 가지 질문을 고려할 수 있습니다.