>  기사  >  웹 프론트엔드  >  webpack 모듈과 webpack3의 새로운 기능에 대한 자세한 설명

webpack 모듈과 webpack3의 새로운 기능에 대한 자세한 설명

小云云
小云云원래의
2018-02-09 13:30:291492검색

이 기사는 간단한 예에서 시작하여 패키징 파일의 다음 세 가지 질문을 분석합니다. 웹팩 패키징 파일은 어떤 모습인가요? 주요 모듈형 솔루션과의 호환성을 달성하는 방법은 무엇입니까? webpack3의 새로운 기능은 무엇입니까? Webpack은 종속성 및 모듈을 처리하는 데 탁월한 강력한 모듈 패키징 도구입니다. 이 기사는 Bundle.js 파일 분석부터 시작하여 다양한 모듈 솔루션의 로딩 메커니즘을 탐색하고, Webpack을 처음으로 이해하고, webpack3의 기능을 자세히 설명합니다. .

간단한 예

webpack 구성

 // webpack.config.js
module.exports = {
 entry: './src/index.js',
 output: {
 filename: 'bundle.js',
 path: path.resolve(__dirname, 'dist')
 },
};

간단한 js 파일

 // src/index.js
 console.log('hello world');

webpack 패키징 후의 코드

생각해보면 코드 한 줄밖에 없는데 저한테 이렇게 많은 것을 패키징하는 걸까요? ? ? (검은색 물음표)

// dist/bundle.js
 /******/ (function(modules) { // webpackBootstrap
/******/  // The module cache
/******/  var installedModules = {};
/******/
/******/  // The require function
/******/  function __webpack_require__(moduleId) {
/******/
/******/   // Check if module is in cache
/******/   if(installedModules[moduleId]) {
/******/    return installedModules[moduleId].exports;
/******/   }
/******/   // Create a new module (and put it into the cache)
/******/   var module = installedModules[moduleId] = {
/******/    i: moduleId,
/******/    l: false,
/******/    exports: {}
/******/   };
/******/
/******/   // Execute the module function
/******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/   // Flag the module as loaded
/******/   module.l = true;
/******/
/******/   // Return the exports of the module
/******/   return module.exports;
/******/  }
/******/
/******/
/******/  // expose the modules object (__webpack_modules__)
/******/  __webpack_require__.m = modules;
/******/
/******/  // expose the module cache
/******/  __webpack_require__.c = installedModules;
/******/
/******/  // define getter function for harmony exports
/******/  __webpack_require__.d = function(exports, name, getter) {
/******/   if(!__webpack_require__.o(exports, name)) {
/******/    Object.defineProperty(exports, name, {
/******/     configurable: false,
/******/     enumerable: true,
/******/     get: getter
/******/    });
/******/   }
/******/  };
/******/
/******/  // getDefaultExport function for compatibility with non-harmony modules
/******/  __webpack_require__.n = function(module) {
/******/   var getter = module && module.__esModule ?
/******/    function getDefault() { return module['default']; } :
/******/    function getModuleExports() { return module; };
/******/   __webpack_require__.d(getter, 'a', getter);
/******/   return getter;
/******/  };
/******/
/******/  // Object.prototype.hasOwnProperty.call
/******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/  // __webpack_public_path__
/******/  __webpack_require__.p = "";
/******/
/******/  // Load entry module and return exports
/******/  return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
console.log('hello world');
/***/ })
/******/ ]);

먼저 코드의 이 부분을 분석하고 단순화해 보겠습니다. 사실 전체가 자체 실행 함수이고, 그런 다음 모듈 배열을 전달합니다.

 (function(modules) { 
  //...
 })([function(module, exports) {
  //..
 }])

좋아요, 전달된 모듈은 무엇인가요? 배열은 (사실 댓글은 다 뻔한데 대충 번역한거임)

 /******/ (function(modules) { // webpackBootstrap
/******/  // The module cache 缓存已经load过的模块
/******/  var installedModules = {};
/******/
/******/  // The require function 引用的函数
/******/  function __webpack_require__(moduleId) {
/******/
/******/   // Check if module is in cache 假如在缓存里就直接返回
/******/   if(installedModules[moduleId]) {
/******/    return installedModules[moduleId].exports;
/******/   }
/******/   // Create a new module (and put it into the cache) 构造一个模块并放入缓存
/******/   var module = installedModules[moduleId] = {
/******/    i: moduleId, //模块id
/******/    l: false, // 是否已经加载完毕
/******/    exports: {} // 对外暴露的内容
/******/   };
/******/
/******/   // Execute the module function 传入模块参数,并执行模块
/******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/   // Flag the module as loaded 标记模块已经加载完毕
/******/   module.l = true;
/******/
/******/   // Return the exports of the module 返回模块暴露的内容
/******/   return module.exports;
/******/  }
/******/
/******/
/******/  // expose the modules object (__webpack_modules__) 暴露模块数组
/******/  __webpack_require__.m = modules;
/******/
/******/  // expose the module cache 暴露缓存数组
/******/  __webpack_require__.c = installedModules;
/******/
/******/  // define getter function for harmony exports 为ES6 exports定义getter
/******/  __webpack_require__.d = function(exports, name, getter) {
/******/   if(!__webpack_require__.o(exports, name)) { // 假如exports本身不含有name这个属性
/******/    Object.defineProperty(exports, name, {
/******/     configurable: false,
/******/     enumerable: true,
/******/     get: getter
/******/    });
/******/   }
/******/  };
/******/
/******/  // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default']
/******/  __webpack_require__.n = function(module) {
/******/   var getter = module && module.__esModule ?
/******/    function getDefault() { return module['default']; } :
/******/    function getModuleExports() { return module; };
/******/   __webpack_require__.d(getter, 'a', getter);
/******/   return getter;
/******/  };
/******/
/******/  // Object.prototype.hasOwnProperty.call
/******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/  // __webpack_public_path__ webpack配置下的公共路径
/******/  __webpack_require__.p = "";
/******/
/******/  // Load entry module and return exports 最后执行entry模块并且返回它的暴露内容
/******/  return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
console.log('hello world');
/***/ })
/******/ ]);

전체적인 과정은 어떻게 되나요?

  • 모듈 배열에 전달

  • __webpack_require__(__webpack_require__.s = 0)을 호출하세요.

모듈 개체를 구성하고 캐시를 입력합니다.

모듈을 호출하고 해당 매개변수를 전달합니다.

모듈 객체를 로드된 것으로 표시

모듈에 의해 노출된 콘텐츠를 반환합니다(module.exports는 위 함수에 전달되며 참조는 수정될 수 있습니다)

  • Pass module, module.exports, __webpack_require__ 모듈 함수

  • 실행 과정에서 위 세 가지의 참조를 수정하여 변수 노출 및 참조를 완료합니다

webpack 모듈 메커니즘은 무엇입니까? webpack 모듈을 살펴보려면 공식 웹사이트

doc.webpack-china.org/concepts/mo…

webpack 모듈의 종속성을 다양한 방식으로 표현할 수 있으며 몇 가지 예는 다음과 같습니다. import 문

    CommonJS require() 문
  • AMD 정의 및 require 문
  • css/sass/less 파일의 @import 문.
  • HTML 파일()의 스타일(url(...)) 또는 이미지 링크(이미지 url)
  • 강력한 webpack 모듈은 다양한 모듈 솔루션과 호환되며 독립적입니다. )
  • 우리는 작성할 수 있습니다 알아보기 위한 또 다른 예시

  • CommonJS

수정 src/index.js

var cj = require('./cj.js');
console.log('hello world');
cj();

src/cj.js를 추가하고 이전 예시는 그대로 유지

// src/cj.js
function a() {
 console.log("CommonJS");
}
module.exports = a;

webpack을 다시 실행

/******/ (function(modules) { // webpackBootstrap
 //... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
let cj = __webpack_require__(1);
console.log('hello world');
cj();
/***/ }),
/* 1 */
/***/ (function(module, exports) {
function a() {
 console.log("CommonJS");
}
module.exports = a;
/***/ })
/******/ ]);

추가로 가져온 것이 있는 것을 확인할 수 있습니다 index.js 모듈 함수에는 파일을 참조하기 위한 추가 매개변수 __webpack_require__가 있습니다(__webpack_require__는 이전 섹션에서 소개되었습니다). 전반적으로 종속 모듈은 module.exports를 수정합니다. 모듈을 사용하여 내보내기를 가져옵니다

ES2015 import

Add src/es.js

// src/es.js
export default function b() {
 console.log('ES Modules');
}

Modify src/index.js

// src/index.js
import es from './es.js';
console.log('hello world');
es();
webpack.config.js不变,执行webpack
/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('hello world');
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* default */])();
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (immutable) */ __webpack_exports__["a"] = b;
function b() {
 console.log('ES Modules');
}
/***/ })
/******/ ]);

모두 엄격 모드가 되고 웹팩이 자동으로 적용되는 것을 볼 수 있습니다. 실제로 CommonJS와 유사합니다. import한 다음 이를 수정한 다음 기본 모듈에서 require합니다.

Object.defineProperty(__webpack_exports__, "__esModule", { value: true });

이것은 무엇에 사용됩니까? 사실 현재 내보내기를 es 모듈로 표시하는 것입니다. 이전 __webpack_require__.n을 아직도 기억하고 계시나요? 꺼내서 살펴보겠습니다

/******/  // getDefaultExport function for compatibility with non-harmony modules 解决ES module和Common js module的冲突,ES则返回module['default']
/******/  __webpack_require__.n = function(module) {
/******/   var getter = module && module.__esModule ?
/******/    function getDefault() { return module['default']; } :
/******/    function getModuleExports() { return module; };
/******/   __webpack_require__.d(getter, 'a', getter);
/******/   return getter;
/******/  };

비 ES 모듈과의 충돌을 피하기 위해? 갈등은 어디에 있습니까?

사실 이 부분은 ES Modules를 변환하는 Babel의 소스코드를 보시면 아시겠지만, 해당 모듈과의 호환성을 위해 ES Modules가 바로exports.default에 걸려있게 되고, 그다음에 __esModule 속성이 추가됩니다. . 도입할 때 변환 모듈인지 판단합니다. 그렇다면 모듈을 도입합니다['default'], 그렇지 않으면 모듈을 도입합니다

효과를 확인하기 위해 ES 모듈을 몇 개 더 도입하겠습니다

// src/es.js
export function es() {
 console.log('ES Modules');
}
export function esTwo() {
 console.log('ES Modules Two');
}
export function esThree() {
 console.log('ES Modules Three');
}
export function esFour() {
 console.log('ES Modules Four');
}

esTwo 및 esFour를 더 소개하지만 esFour를 사용하지 마세요

// src/index.js
import { es, esTwo, esFour} from './es.js';
console.log('hello world');
es();
esTwo();

결과

/******/ (function(modules) { // webpackBootstrap
// ...
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__es_js__ = __webpack_require__(1);
console.log('hello world');
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["a" /* es */])();
Object(__WEBPACK_IMPORTED_MODULE_0__es_js__["b" /* esTwo */])();
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (immutable) */ __webpack_exports__["a"] = es;
/* harmony export (immutable) */ __webpack_exports__["b"] = esTwo;
/* unused harmony export esThree */
/* unused harmony export esFour */
function es() {
 console.log('ES Modules');
}
function esTwo() {
 console.log('ES Modules Two');
}
function esThree() {
 console.log('ES Modules Three');
}
function esFour() {
 console.log('ES Modules Four');
}
/***/ })
/******/ ]);

사실 이전과 동일합니다. 이 예제의 요점은 무엇인가요? 우리가 소개한 것은 아니지만, esFour는 우리가 참조했지만 사용하지 않은 모듈이고 webpack은 그것들을 모두 수행합니다. 실제로 webpack 플러그인 uglify를 사용하면 마크를 통해 두 개의 사용되지 않은 표시가 제거됩니다. esThree 및 esFour 코드가 제거됩니다(사실 트리 쉐이킹입니다)

AMD

webpack을 다시 살펴보겠습니다. AMD 지원 방법

src/amd.js 추가

/* unused harmony export esThree */
/* unused harmony export esFour */

index.js 수정

// src/amd.js
define([
],function(){
 return {
  amd:function(){
   console.log('AMD');
  }
 };
});

Get

// src/index.js
define([
 './amd.js'
],function(amdModule){
 amdModule.amd();
});

먼저 amd.js를 보고 코드를 정리하세요

/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
 __webpack_require__(1)
], __WEBPACK_AMD_DEFINE_RESULT__ = function(amdModule){
 amdModule.amd();
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
    __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_ARRAY__ = [
], __WEBPACK_AMD_DEFINE_RESULT__ = function(){
 return {
  amd:function(){
   console.log('AMD');
  }
 };
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
    __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ })
/******/ ]);

간단히 말하면, 배열을 정의하고 수집한 다음 매개변수 획득 종속성에 따라 반환 함수를 넣습니다

apply는 배열을 하나씩 매개변수로 분해합니다

index.js 모듈 부분을 보세요

function(module, exports, __webpack_require__) {
 var __WEBPACK_AMD_DEFINE_ARRAY__,
  __WEBPACK_AMD_DEFINE_RESULT__;
 !(
  __WEBPACK_AMD_DEFINE_ARRAY__ = [],
  __WEBPACK_AMD_DEFINE_RESULT__ = function() {
   return {
    amd: function() {
     console.log('AMD');
    }
   };
  }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
  __WEBPACK_AMD_DEFINE_RESULT__ !== undefined &&
  (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)
 );
})

사실, amd.js에 의해 노출되는 {amd:[Function: amd]}

css/image?

css를 소개하고 있으며, 이미지도 webpack의 모듈이 될 수 있습니다. 충격적이네요. 이는 일반적인 hack commonjs나 함수 호출을 통해 간단히 호출할 수 없으며, 이는 JS에 있어서는 웹팩 로더의 도움으로 구현되어야 합니다.

像css就是转换成一段js代码,通过处理,调用时就是可以用js将这段css插入到style中,image也类似,这部分就不详细阐述了,有兴趣的读者可以深入去研究

webpack3新特性

我们可以再顺便看下webpack3新特性的表现

具体可以看这里medium.com/webpack/web…

Scope Hoisting

我们可以发现模块数组是一个一个独立的函数然后闭包引用webpack主函数的相应内容,每个模块都是独立的,然后带来的结果是在浏览器中执行速度变慢,然后webpack3学习了Closure Compiler和RollupJS这两个工具,连接所有闭包到一个闭包里,放入一个函数,让执行速度更快,并且整体代码体积也会有所缩小

我们可以实际看一下效果(要注意的是这个特性只支持ES Modules,是不支持CommonJs和AMD的)

使用上面的例子,配置webpack.config.js,增加new webpack.optimize.ModuleConcatenationPlugin()

const path = require('path');
const webpack = require('webpack');
module.exports = {
 entry: './src/index.js',
 output: {
 filename: 'bundle.js',
 path: path.resolve(__dirname, 'dist')
 },
 module: {
 },
 plugins: [
 new webpack.optimize.ModuleConcatenationPlugin(),
 ]
};

打包

/******/ (function(modules) { // webpackBootstrap
// ... 省略代码
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
// CONCATENATED MODULE: ./src/es.js
function es() {
 console.log('ES Modules');
}
function esTwo() {
 console.log('ES Modules Two');
}
function esThree() {
 console.log('ES Modules Three');
}
function esFour() {
 console.log('ES Modules Four');
}
// CONCATENATED MODULE: ./src/index.js
// src/index.js
console.log('hello world');
es();
/***/ })
/******/ ]);

我们可以惊喜的发现没有什么require了,它们拼接成了一个函数,good!

위 내용은 webpack 모듈과 webpack3의 새로운 기능에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.