Webpack

简介(V4版本)

官网

在这里插入图片描述

webpack是基于模块化的打包(构建)工具,它把一切视为模块

它通过一个开发时态的入口模块为起点,分析出所有的依赖关系,然后经过一系列的过程(压缩、合并),最终生成运行时态的文件。

webpack的特点:

  • 为前端工程化而生:webpack致力于解决前端工程化,特别是浏览器端工程化中遇到的问题,让开发者集中注意力编写业务代码,而把工程化过程中的问题全部交给webpack来处理
  • 简单易用:支持零配置,可以不用写任何一行额外的代码就使用webpack
  • 强大的生态:webpack是非常灵活、可以扩展的,webpack本身的功能并不多,但它提供了一些可以扩展其功能的机制,使得一些第三方库可以融于到webpack中
  • 基于nodejs:由于webpack在构建的过程中需要读取文件,因此它是运行在node环境中的
  • 基于模块化:webpack在构建过程中要分析依赖关系,方式是通过模块化导入语句进行分析的,它支持各种模块化标准,包括但不限于CommonJS、ES6 Module

webpack的安装

webpack通过npm安装,它提供了两个包:

  • webpack:核心包,包含了webpack构建过程中要用到的所有api
  • webpack-cli:提供一个简单的cli命令,它调用了webpack核心包的api,来完成构建过程

安装方式:

  • 全局安装:可以全局使用webpack命令,但是无法为不同项目对应不同的webpack版本
  • 本地安装:推荐,每个项目都使用自己的webpack版本进行构建

打包结果分析

首先我们准备以下几个文件夹:

在这里插入图片描述

// a.js
require("./b.js")
console.log("module a")
// b.js
require("./c.js")
console.log("module b")
// c.js
console.log("module c")
// index.js
require("./a.js")
console.log("Hello Webpack")

然后执行脚本命令:

在这里插入图片描述

npm run dev

打包之后代码如下(去掉一部分注释后):

(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, { enumerable: true, get: getter });
    }
  };
  // define __esModule on exports
  __webpack_require__.r = function (exports) {
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    }
    Object.defineProperty(exports, '__esModule', { value: true });
  };
  // create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function (value, mode) {
    if (mode & 1) value = __webpack_require__(value);
    if (mode & 8) return value;
    if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
    var ns = Object.create(null);
    __webpack_require__.r(ns);
    Object.defineProperty(ns, 'default', { enumerable: true, value: value });
    if (mode & 2 && typeof value != 'string') for (var key in value) __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
    return ns;
  };
  // 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 = "./src/index.js");
})
  ({
    "./src/a.js":
      (function (module, exports, __webpack_require__) {
        eval("__webpack_require__(/*! ./b */ \"./src/b.js\")\r\nconsole.log(\"module a\")\n\n//# sourceURL=webpack:///./src/a.js?");
      }),
    "./src/b.js":
      (function (module, exports, __webpack_require__) {
        eval("__webpack_require__(/*! ./c */ \"./src/c.js\")\r\nconsole.log(\"module b\")\n\n//# sourceURL=webpack:///./src/b.js?");
      }),
    "./src/c.js":
      (function (module, exports) {
        eval("console.log(\"module c\")\n\n//# sourceURL=webpack:///./src/c.js?");
      }),
    "./src/index.js":
      (function (module, exports, __webpack_require__) {
        eval("__webpack_require__(/*! ./a */ \"./src/a.js\")\r\nconsole.log(\"hello webpack\");\n\n//# sourceURL=webpack:///./src/index.js?");
      })
  });

当我们把函数体折叠时,很容易看出来这是一个立即执行函数为了不污染全局变量

在这里插入图片描述

该函数接受一个modules的参数,以一唯一路径作为键值,函数作为值(为了各模块内容互不影响),函数体为eval函数,每个模块对应的内容则作为eval函数的参数,使用**_webpack_require_** 函数中的参数全部会替换为modules中对应的键值

我们知道webpack打包依赖入口文件,当不指定时,默认为 index.js ,所以在立即执行函数内部,肯定会有运行入口文件的代码

我们看到第68行

return __webpack_require__(__webpack_require__.s = "./src/index.js");

接着我们来分析 _webpack_require_ 这个函数

	// moduleId 即立即执行函数的参数的key值 说白了就是唯一路径
	function __webpack_require__(moduleId) {
    // 判断缓存模块中有没有该路径
    if (installedModules[moduleId]) {
      // 有则返回该模块的导出结果
      return installedModules[moduleId].exports;
    }
    // 没有则创建一个模块对象,并将其添加到缓存中
    var module = installedModules[moduleId] = {
      i: moduleId, // i 为模块路径
      l: false, // l 表示模块是否加载完成
      exports: {} // exports 为模块导出对象,默认为一个空对象
    };
    // 从模块对象中取出该路径对应的函数,执行 this指向moudle.exports
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    //将该模块标记为加载完成
    module.l = true;
    // 返回模块的导出结果
    return module.exports;
  }
  1. 因为模块有缓存,所以当多次加载相同模块时,该模块代码只会运行一次
  2. 模块中使用thisexports,module.exports 是一致的

22行到63行 主要为了做兼容,以及暴露一些属性和定义一些辅助函数,影响不大

为什么模块中的内容要放在eval函数里呢?

主要是为了方便调试

对modules参数进行改造:

{
  "./src/a.js":
  (function (module, exports, __webpack_require__) {
    __webpack_require__("/src/b.js")
    console.log("module a")
    const a = null;
    a.abc();
  }),
    "./src/b.js":
    (function (module, exports, __webpack_require__) {
      __webpack_require__("/src/c.js")
      console.log("module b")
    }),
    "./src/c.js":
    (function (module, exports) {
        console.log("module c")
     }),
      "./src/index.js":
      (function (module, exports, __webpack_require__) {
        __webpack_require__("/src/a.js")
        console.log("Hello Webpack")
      })
}

a模块运行必定报错 报错信息在main.js:98

在这里插入图片描述

点击跳转如下,发现我明明是a模块的报错,却显示了所有模块的信息

在这里插入图片描述
接下来,我们在使用eval试试, 发现直接显示了a.js 这个模块文件,当时这个跟eval关系不大 是由这个决定的 这个注释是用来给浏览器看的
在这里插入图片描述
在这里插入图片描述
当我们点击跳转时,发现报错代码直接跳到了a.js模块文件,瞬间清晰很多。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值