ModuleConcatenationPlugin

과거에 번들링을 할 때 webpack의 절충점 중 하나는 번들의 각 모듈이 개별 함수 클로저에 의해 래핑된다는 점이었습니다. 이러한 래퍼 함수는 브라우저에서 자바스크립트의 실행을 느리게 만들었습니다. 이와 달리, Closure Comiler와 RollupJS와 같은 도구는 모든 모듈을 하나의 클로저로 호이스팅 하거나 연결하여 코드가 브라우저에서 더 빠른 실행 시간을 갖게 했습니다.

이 플러그인은 위의 내용과 같은 연결 동작이 webpack에서 가능하게 해줍니다. 기본적으로 이 플러그인은 production mode에서는 이미 가능하고 나머지에서는 아직 가능하지 않습니다. 만약 생산 mode 최적화를 무효로 해야 하는 경우, optimization.concatenateModules 옵션false로 설정하세요. 다른 모드에서 연결 동작을 가능하게 하고 싶을 경우, ModuleConcatenationPlugin을 수동으로 설정하거나 optimization.concatenateModules 옵션을 사용하세요.

new webpack.optimize.ModuleConcatenationPlugin();

이 연결 동작은 “범위 호이스팅” 이라고 불립니다.

범위 호이스팅은 특별히 ECMAScript Module 문법에서 사용 가능하도록 만들어진 형태입니다. 이로 인해 webpack은 현재 사용 중인 모듈의 종류와 다른 여러 조건에 따라 평범한 번들링으로 퇴화할 수도 있습니다.

Optimization Bailouts

글에서 설명하듯이 webpack은 부분적인 범위 호이스팅을 시도합니다. 이는 모듈을 하나의 범위로 합치지만 모든 경우에 합치지는 못합니다. 만약 webapck이 모듈을 합칠 수 없다면 두 가지 대안은 Prevent와 Root 입니다. Prevent는 모듈이 반드시 그 자신의 범위 안에 있어야 한다는 것을 의미합니다. Root는 새로운 모듈 그룹이 생성될 것이라는 의미입니다. 다음의 조건이 결과를 결정합니다.

ConditionOutcome
Non ES6 ModulePrevent
Non Import로 가져옴Root
다른 청크에서 가져옴Root
다수의 다른 모듈 그룹에서 가져옴Root
import()로 가져옴Root
ProvidePlugin의 영향을 받거나 module 사용Prevent
HMR 허용Root
eval() 사용Prevent
다수의 청크Prevent
"cjs-module"로부터 * 내보내기Prevent

Module Grouping Algorithm

아래의 자바스크립트 의사코드는 이 알고리즘을 설명합니다.

modules.forEach((module) => {
  const group = new ModuleGroup({
    root: module,
  });
  module.dependencies.forEach((dependency) => {
    tryToAdd(group, dependency);
  });
  if (group.modules.length > 1) {
    orderedModules = topologicalSort(group.modules);
    concatenatedModule = new ConcatenatedModule(orderedModules);
    chunk.add(concatenatedModule);
    orderedModules.forEach((groupModule) => {
      chunk.remove(groupModule);
    });
  }
});

function tryToAdd(group, module) {
  if (group.has(module)) {
    return true;
  }
  if (!hasPreconditions(module)) {
    return false;
  }
  const nextGroup = group;
  const result = module.dependents.reduce((check, dependent) => {
    return check && tryToAdd(nextGroup, dependent);
  }, true);
  if (!result) {
    return false;
  }
  module.dependencies.forEach((dependency) => {
    tryToAdd(group, dependency);
  });
  group.merge(nextGroup);
  return true;
}

Debugging Optimization Bailouts

webpack CLI를 사용할 경우 --display-optimization-bailout 플래그는 bailout 원인을 보여줍니다. webpack config를 사용할 경우 stats 객체에 다음을 추가하세요.

module.exports = {
  //...
  stats: {
    // Examine all modules
    maxModules: Infinity,
    // Display bailout reasons
    optimizationBailout: true,
  },
};

3 Contributors

skipjackTheLarkInnbyzyk

Translators