"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > 나는 모듈 번들러를 작성했습니다. 메모 등

나는 모듈 번들러를 작성했습니다. 메모 등

2024-08-05에 게시됨
검색:755

I wrote a module bundler. notes, etc

간단한 JavaScript 번들러를 만들었고 예상보다 훨씬 쉬웠습니다. 이 게시물에서 제가 배운 모든 것을 공유하겠습니다.

대규모 애플리케이션을 작성할 때 JavaScript 소스 코드를 별도의 js 파일로 나누는 것이 좋습니다. 그러나 여러 스크립트 태그를 사용하여 이러한 파일을 HTML 문서에 추가하면

와 같은 새로운 문제가 발생합니다.
  • 글로벌 네임스페이스 오염.

  • 경쟁 조건.

모듈 번들러는 다양한 파일의 소스 코드를 하나의 큰 파일로 결합하여 단점을 피하면서 추상화의 이점을 누릴 수 있도록 도와줍니다.

모듈 번들러는 일반적으로 이 작업을 두 단계로 수행합니다.

  1. 항목 파일부터 시작하여 모든 JavaScript 소스 파일을 찾습니다. 이를 종속성 해결이라고 하며 생성된 맵을 종속성 그래프라고 합니다.
  2. 종속성 그래프를 사용하여 브라우저에서 실행할 수 있는 대규모 JavaScript 소스 코드 문자열인 번들을 생성합니다. 이는 파일에 기록할 수 있으며 스크립트 태그를 사용하여 HTML 문서에 추가할 수 있습니다.

종속성 해결

앞서 언급했듯이, 여기서는

  • 항목 파일을 가져옵니다.
  • 내용을 읽고 구문 분석합니다.
  • 모듈 배열에 추가
  • 모든 종속성(가져오는 다른 파일)을 찾습니다.
  • 종속성 내용 읽기 및 구문 분석
  • 배열에 종속성 추가
  • 마지막 모듈에 도달할 때까지 종속성 등의 종속성을 찾습니다.

이를 수행하는 방법은 다음과 같습니다(JavaScript 코드 미리 작성)

텍스트 편집기에서 Bundler.js 파일을 만들고 다음 코드를 추가하세요.

const bundler = (entry)=>{
          const graph = createDependencyGraph(entry)

          const bundle = createBundle(graph)
          return bundle
}

번들러 기능은 번들러의 주요 항목입니다. 파일(항목 파일)에 대한 경로를 취하고 문자열(번들)을 반환합니다. 그 안에서 createDependencyGraph 함수를 사용하여 종속성 그래프를 생성합니다.

const createDependencyGraph = (path)=>{
          const entryModule = createModule(path)

          /* other code */
}

createDependencyGraph 함수는 항목 파일의 경로를 사용합니다. createModule 함수를 사용하여 이 파일의 모듈 표현을 생성합니다.

let ID = 0
const createModule = (filename)=>{
          const content = fs.readFileSync(filename)
          const ast = babylon.parse(content, {sourceType: “module”})

          const {code} = babel.transformFromAst(ast, null, {
              presets: ['env']
            })

           const dependencies = [ ]
           const id = ID  
           traverse(ast, {
                   ImportDeclaration: ({node})=>{
                       dependencies.push(node.source.value)
                   }
            }
            return {
                           id,
                           filename,
                           code,
                           dependencies
                       }
}

createAsset 함수는 파일 경로를 가져와 해당 내용을 문자열로 읽어옵니다. 그런 다음 이 문자열은 추상 구문 트리로 구문 분석됩니다. 추상 구문 트리는 소스 코드 내용을 트리로 표현한 것입니다. 이는 HTML 문서의 DOM 트리에 비유될 수 있습니다. 이렇게 하면 검색 등의 일부 기능을 코드에서 더 쉽게 실행할 수 있습니다.
바빌론 파서를 사용하여 모듈에서 ast를 생성합니다.

다음으로 바벨 코어 트랜스파일러의 도움으로 코드 콘텐츠를 브라우저 간 호환성을 위해 es2015 이전 구문으로 변환합니다.
그 후, 소스 파일(종속성)의 각 가져오기 선언을 찾기 위해 babel의 특수 함수를 사용하여 ast를 탐색합니다.

그런 다음 이러한 종속성(상대 파일 경로의 문자열 텍스트)을 종속성 배열에 푸시합니다.

또한 이 모듈을 고유하게 식별하기 위한 ID를 생성하고
마지막으로 이 모듈을 나타내는 객체를 반환합니다. 이 모듈에는 ID, 문자열 형식의 파일 내용, 종속성 배열 및 절대 파일 경로가 포함되어 있습니다.

const createDependencyGraph = (path)=>{
          const entryModule = createModule(path)

          const graph = [ entryModule ]
          for ( const module of graph) {
                  module.mapping = { }
module.dependencies.forEach((dep)=>{
         let absolutePath = path.join(dirname, dep);
         let child = graph.find(mod=> mod.filename == dep)
         if(!child){
               child = createModule(dep)
               graph.push(child)
         }
         module.mapping[dep] = child.id
})
          }
          return graph
}

createDependencyGraph 함수로 돌아가서 이제 그래프 생성 프로세스를 시작할 수 있습니다. 그래프는 애플리케이션에 사용된 각 소스 파일을 나타내는 각 객체가 포함된 객체 배열입니다.
입력 모듈을 사용하여 그래프를 초기화한 다음 반복합니다. 항목이 하나만 포함되어 있지만 항목 모듈(및 추가할 다른 모듈)의 종속성 배열에 액세스하여 배열 끝에 항목을 추가합니다.

종속성 배열에는 모듈의 모든 종속성의 상대 파일 경로가 포함됩니다. 배열은 반복되며 각 상대 파일 경로에 대해 절대 경로가 먼저 확인되어 새 모듈을 만드는 데 사용됩니다. 이 하위 모듈은 그래프 끝으로 푸시되고 모든 종속성이 모듈로 변환될 때까지 프로세스가 다시 시작됩니다.
또한 각 모듈은 각 종속성 상대 경로를 하위 모듈의 ID에 간단히 매핑하는 매핑 개체를 제공합니다.
모듈의 중복과 무한 순환 종속성을 방지하기 위해 각 종속성에서 모듈이 이미 존재하는지 확인합니다.
마지막으로 이제 애플리케이션의 모든 모듈이 포함된 그래프를 반환합니다.

번들링

종속성 그래프가 완료되면 번들 생성에는 두 단계가 포함됩니다.

  1. 각 모듈을 함수로 래핑합니다. 이는 각 모듈이 자체 범위를 갖는 아이디어를 생성합니다
  2. 런타임에 모듈을 래핑합니다.

각 모듈 래핑

모듈 객체를 문자열로 변환해야 Bundle.js 파일에 쓸 수 있습니다. moduleString을 빈 문자열로 초기화하여 이를 수행합니다. 다음으로 각 모듈을 키 값 쌍으로 모듈 문자열에 추가하는 그래프를 반복합니다. 모듈의 ID는 키이고 두 항목이 포함된 배열입니다. ) 두 번째는 종속성 매핑을 포함하는 객체입니다.

const wrapModules = (graph)=>{
         let modules = ‘’
           graph.forEach(mod => {
    modules  = `${http://mod.id}: [
      function (require, module, exports) {
        ${mod.code}
      },
      ${JSON.stringify(mod.mapping)},
    ],`;
  });
return modules
}

또한 각 모듈을 래핑하는 함수는 필수, 내보내기 및 모듈 개체를 인수로 사용합니다. 이는 브라우저에는 존재하지 않지만 코드에는 나타나기 때문에 생성하여 이 모듈에 전달하기 때문입니다.

런타임 만들기

이것은 번들이 로드되는 즉시 실행되는 코드이며, 모듈에 require, module 및 module.exports 개체를 제공합니다.

const bundle = (graph)=>{
        let modules = wrapModules(graph)
        const result = `
    (function(modules) {
      function require(id) {
        const [fn, mapping] = modules[id];

        function localRequire(name) {
          return require(mapping[name]);
        }

        const module = { exports : {} };

        fn(localRequire, module, module.exports);

        return module.exports;
      }

      require(0);
    })({${modules}})`;
  return result;
}

모듈 객체를 인수로 사용하는 즉시 호출되는 함수 표현식을 사용합니다. 그 안에는 ID를 사용하여 모듈 객체에서 모듈을 가져오는 require 함수를 정의합니다.
파일 경로 문자열을 ID에 매핑하기 위해 특정 모듈과 관련된 localRequire 함수를 구성합니다. 그리고 내보내기 속성이 비어 있는 모듈 객체
이는 모듈 코드를 실행하여 localrequire, module 및 내보내기 객체를 인수로 전달한 다음 노드 js 모듈처럼 module.exports를 반환합니다.
마지막으로 항목 모듈(인덱스 0)에서 require를 호출합니다.

번들을 테스트하려면 Bundler.js 파일의 작업 디렉터리에 index.js 파일과 두 개의 디렉터리(src 및 public 디렉터리)를 만듭니다.

public 디렉토리에서 index.html 파일을 생성하고 body 태그에 다음 코드를 추가하세요:


    
        Module bundler
        
    
    
       

상수 이름 = “David”
기본 이름 내보내기

also create a hello.js file and add the following code

'./name.js'에서 이름 가져오기
const hello = document.getElementById(“루트”)
hello.innerHTML = “안녕하세요” 이름

Lastly in the index.js file of the root directory import our bundler, bundle the files and write it to a bundle.js file in the public directory

const createBundle = require(“./bundler.js”)
const run = (출력, 입력)=>{
번들 = creatBundle(entry)
fs.writeFileSync(bundle, 'utf-8')
}
실행("./public/bundle.js", "./src/hello.js")


Open our index.html file in the browser to see the magic.

In this post we have illustrated how a simple module bundler works. This is a minimal bundler meant for understanding how these technologies work behind the hood.

please like if you found this insightful and comment any questions you may have.
릴리스 선언문 이 글은 https://dev.to/frontendokeke/i-wrote-a-module-bundler-notes-etc-4ofa?1 에서 복제되었습니다.1 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3