前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅入理解 webpack 模块

浅入理解 webpack 模块

作者头像
尹光耀
发布2021-10-19 10:13:54
4130
发布2021-10-19 10:13:54
举报
文章被收录于专栏:前端小馆前端小馆

前言

很久没有写文章了,今天心血来潮,就写一下之前总结的关于 webpack 模块的问题。刚好在几个月前遇到过另一个问题,当时也简单看了一下 webpack 和 NodeJS 模块的源码实现:

如果你有观察过 webpack 转换后的代码,一定会发现,不管是 import 还是 require 都会被转换成 __webpack_require__ 这种形式。

webpack 自己实现了一套模块化的规范,使用 __webpack_require__ 来导入模块,将其挂载到 module.exports 上面,有点儿类似 CommonJS 的模块化规范。

一个来自 QQ 群的提问

某天晚上,我的 QQ 群有个童鞋问了这么一个问题:

我也比较好奇为什么 require 引入的图片还需要在后面加个 default 呢?为什么 import 引入的却不需要?是否和 file-loader 处理图片文件有关?

带着这个疑问,于是我写了一个简单的 DEMO 来验证了一下,代码如下:

在执行了 webpack 命令后,可以看到编译后的精简代码是这样的:

webpack 模块源码分析

首先,我们可以看出来这个编译后的 js 文件就是一个立即执行函数,他接收了当前文件引入的外部模块作为一个参数,所有的外部模块被放到了一个对象当中,以当前 src 目录下的绝对路径作为 key 值,value 这是一个方法,这个方法注入了 __webpack_require____webpack_exports__ 作为参数,简单来说就是类似于:

代码语言:javascript
复制
(function(modules) {
})({
 "./src/logo.png": function(module, __webpack_exports__, __webpack_require__) {
    eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = (__webpack_require__.p + \"a218f2cb12bf56dd2a68003790d1e986.png\");\n\n//# sourceURL=webpack:///./src/logo.png?");
  }
})

我们可以明显看到,这个图片在导出的时候,实际上是在 __webpack_exports__["default"] 里面的,那么在使用 require 引入的时候又是什么样的呢? 我们来看一下 index.tsx 被编译后的代码:

代码语言:javascript
复制
/***/ "./src/pages/home/index.jsx":
/*!**********************************!*\
  !*** ./src/pages/home/index.jsx ***!
  \**********************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, \"default\", function() { return Index; }); var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./node_modules/_react@16.13.1@react/index.js\"); var react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\"./src/pages/home/constants.js\");\n\n\n\nvar logo = __webpack_require__( \"./src/logo.png\");\n\nfunction Index(props) {\n  return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"img\", {\n    src: logo\n  });\n}\n\n//# sourceURL=webpack:///./src/pages/home/index.jsx?");

很明显可以看到,这里在引入 logo 这个图片的时候,是直接使用 __webpack_require__ 来导入的,我们前面看到过 __webpack_require__ 的实现。

代码语言:javascript
复制
/******/     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: {},
/******/             hot: hotCreateModule(moduleId),
/******/             parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),
/******/             children: []
/******/         };
/******/
/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
/******/
/******/         // Flag the module as loaded
/******/         module.l = true;
/******/
/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }

这里只是返回了 module.exports,并没有 default,所以如果是直接用 require 来引入图片的话,那就肯定不会生效。

如果我们使用 import 来导入的话会怎么样呢?

代码语言:javascript
复制
/***/ "./src/pages/home/index.jsx":
/*!**********************************!*\
  !*** ./src/pages/home/index.jsx ***!
  \**********************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);__webpack_require__.d(__webpack_exports__, \"default\", function() { return Index; }); var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(\"./node_modules/_react@16.13.1@react/index.js\"); var react__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__); var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(\"./src/pages/home/constants.js\"); var _logo_png__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__( \"./src/logo.png\");\n\n\n\n\nvar constants = __webpack_require__( \"./src/pages/home/constants.js\");\n\nfunction Index(props) {\n  return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"img\", {\n    src: _logo_png__WEBPACK_IMPORTED_MODULE_2__[\"default\"]\n  });\n}\n\n//# sourceURL=webpack:///./src/pages/home/index.jsx?");

我们可以看到,虽然导入的时候也没有带上一个 default,但是 React 在创建 img 标签的时候,给它带上了一个 default,关键点在于这句 return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(\"img\", {\n src: _logo_png__WEBPACK_IMPORTED_MODULE_2__[\"default\"]\n }),所以直接用 import 也是可以导入的。

ES Module 和 CommonJS

实际上,如果你在 NodeJS 里面使用过一些 npm 上面第三方的模块,会发现导入的时候都是要求我们使用 require('xxx').default 的,比如大名鼎鼎的 node-xlsx

代码语言:javascript
复制
import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']];
var buffer = xlsx.build([{name: "mySheetName", data: data}]); // Returns a buffer

相信看了前面的分析后,你也能猜到这是为什么了吧?node-xlsx 是直接使用 export default 导出的,而为了抹平这种差异,导致我们不得不使用 require.default 来导入它。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一个来自 QQ 群的提问
  • webpack 模块源码分析
  • ES Module 和 CommonJS
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档