Webpack 原理与实践之如何使用 Webpack 实现模块化打包?

开发 前端
webpack还具备代码拆分的能力,能够将应用中所有的模块按需分块打包,不用担心全部代码打包到一起,产生单个文件过大,导致加载慢的问题。这种模块按需分块打包非常适合大型web项目。

本文转载自微信公众号「前端万有引力」,作者一川。转载本文请联系前端万有引力公众号。

写在前面

我们知道当前生产中主流的模块化打包工具有Webpack、Parcel和Rollup。作为模块化打包工具,它们基本的特点有:

  • 能够将散落的模块打包在一起
  • 能够编译转换代码中的新特性,使得可以兼容各种生产环境

对于主流的webpack而言,webpack作为一个模块打包工具,自身就可以实现模块化代码打包的问题,通过webpack可以将零散的JS代码打包到一个JS文件中。对于有环境兼容性问题的代码,webpack可以在代码打包过程中通过loader机制对其实现编译转换,然后再进行打包。对于不同类型的前端模块,webpack支持在js中以模块化的方式载入任意类型的资源文件,例如:可以通过webpack实现在JS中加载CSS文件,被加载的CSS文件会以style标签的方式工具。

webpack还具备代码拆分的能力,能够将应用中所有的模块按需分块打包,不用担心全部代码打包到一起,产生单个文件过大,导致加载慢的问题。这种模块按需分块打包非常适合大型web项目。

Webpack上路

Webpack作为主流的前端模块打包器,提供了一整套前端项目模块化方案,而不仅仅局限于JS的模块化,可以实现对前端项目开发过程中涉及到的资源进行模块化。

我们知道ES Modules中制定的html中使用script导入js模块,需要设定type="module",用来区分加载的是普通JS脚本还是一个模块。对于支持ES Modules的浏览器可以直接使用,但是对于不支持的浏览器就会报错,因此需要使用webpack模块打包工具避免报错。

  1. <script src="./index.js" type="module"></script> 
  1. // heading.js 
  2. export default function(){ 
  3.   const element = document.createElement("div"); 
  4.   element.textContent = "hello yichuan"
  5.   element.addEventListener("click",()=>{ 
  6.     console.log("hello onechuan"); 
  7.     return element 
  8.   }) 
  9.  
  10. // index.js 
  11. import createHeader  from "./heading.js"
  12. document.body.append(createHeader()) 

对于,我们需要先安装webpack的核心模块和cli程序,用于在命令行中调用webpack。npx是npm5.2以后新增的一个命令,可以更方便地执行远程模块或者项目node_modules中的cli程序。

  1. $ npm init --yes 
  2. $ npm i webpack webpack-cli -D 
  3. $ npx webpack --version 
  4. $ npx webpack 

通过执行npx webpack实现自动化打包,webpack会默认从src/index.js文件开始打包,打包完毕后会在根目录下生产dist目录,所有打包文件会在dist目录。

  1. |--dist 
  2.   |--main.js 
  1. (()=>{"use strict";document.body.append(function(){const e=document.createElement("div");e.textContent="hello yichuan",e.addEventListener("click",(()=>(console.log("hello onechuan"),e)))}())})(); 

webpack4.0以后的版本支持零配置的方式直接启动打包,整个过程会按照约定将src/index.js文件作为打包入口,最终打包的结果会存放到dis/main.js中。但是,很多时候webpack的默认规则并能满足我们实际需求,对此我们需要对webpack进行自定义配置。

webpack支持在项目中创建webpack.config.js文件进行自定义打包配置,由于webpack是运行在node.js环境,对应应该遵守CommonJS规则进行导入导出。

  1. |--backpack 
  2.   |--src 
  3.     |--heading.js 
  4.     |--main.js 
  5.   |--index.html 
  6.   |--package.json 
  7.   |--webpack.config.js-------webpack配置文件 

webpack自定义的配置文件:

  1. // webpack.config.js 
  2. const path = require("path"); 
  3.  
  4. module.exports = { 
  5.   entry:"./src/index.js",//打包入口 
  6.   output:{//打包出口 
  7.     filename:"bundle.js",//命名打包后的文件 
  8.     path:path.join(__dirname,"output"
  9.   }, 
  10.   // 打包模式 
  11.   mode:"none" 

执行打包命令后会在项目根目录下自动生成打包后的文件目录,我们看到下面是执行打包命令后生成的文件,生成的是一个立即执行函数。

  1. /******/ (function(modules) { // webpackBootstrap  函数 
  2. /******/  // The module cache 
  3. /******/  var installedModules = {}; 
  4. /******/ 
  5. /******/  // The require function 
  6. /******/  function __webpack_require__(moduleId) { 
  7. /******/ 
  8. /******/   // Check if module is in cache 
  9. /******/   if(installedModules[moduleId]) { 
  10. /******/    return installedModules[moduleId].exports; 
  11. /******/   } 
  12. /******/   // Create a new module (and put it into the cache) 
  13. /******/   var module = installedModules[moduleId] = { 
  14. /******/    i: moduleId, 
  15. /******/    l: false
  16. /******/    exports: {} 
  17. /******/   }; 
  18. /******/ 
  19. /******/   // Execute the module function 
  20. /******/   modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 
  21. /******/ 
  22. /******/   // Flag the module as loaded 
  23. /******/   module.l = true
  24. /******/ 
  25. /******/   // Return the exports of the module 
  26. /******/   return module.exports; 
  27. /******/  } 
  28. /******/ 
  29. /******/ 
  30. /******/  // expose the modules object (__webpack_modules__) 
  31. /******/  __webpack_require__.m = modules; 
  32. /******/ 
  33. /******/  // expose the module cache 
  34. /******/  __webpack_require__.c = installedModules; 
  35. /******/ 
  36. /******/  // define getter function for harmony exports 
  37. /******/  __webpack_require__.d = function(exports, name, getter) { 
  38. /******/   if(!__webpack_require__.o(exports, name)) { 
  39. /******/    Object.defineProperty(exports, name, { enumerable: true, get: getter }); 
  40. /******/   } 
  41. /******/  }; 
  42. /******/ 
  43. /******/  // define __esModule on exports 
  44. /******/  __webpack_require__.r = function(exports) { 
  45. /******/   if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 
  46. /******/    Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 
  47. /******/   } 
  48. /******/   Object.defineProperty(exports, '__esModule', { value: true }); 
  49. /******/  }; 
  50. /******/ 
  51. /******/  // create a fake namespace object 
  52. /******/  // mode & 1: value is a module id, require it 
  53. /******/  // mode & 2: merge all properties of value into the ns 
  54. /******/  // mode & 4: return value when already ns object 
  55. /******/  // mode & 8|1: behave like require 
  56. /******/  __webpack_require__.t = function(value, mode) { 
  57. /******/   if(mode & 1) value = __webpack_require__(value); 
  58. /******/   if(mode & 8) return value; 
  59. /******/   if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 
  60. /******/   var ns = Object.create(null); 
  61. /******/   __webpack_require__.r(ns); 
  62. /******/   Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 
  63. /******/   if(mode & 2 && typeof value != 'string'for(var key in value) __webpack_require__.d(ns, keyfunction(key) { return value[key]; }.bind(nullkey)); 
  64. /******/   return ns; 
  65. /******/  }; 
  66. /******/ 
  67. /******/  // getDefaultExport function for compatibility with non-harmony modules 
  68. /******/  __webpack_require__.n = function(module) { 
  69. /******/   var getter = module && module.__esModule ? 
  70. /******/    function getDefault() { return module['default']; } : 
  71. /******/    function getModuleExports() { return module; }; 
  72. /******/   __webpack_require__.d(getter, 'a', getter); 
  73. /******/   return getter; 
  74. /******/  }; 
  75. /******/ 
  76. /******/  // Object.prototype.hasOwnProperty.call 
  77. /******/  __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 
  78. /******/ 
  79. /******/  // __webpack_public_path__ 
  80. /******/  __webpack_require__.p = ""
  81. /******/ 
  82. /******/ 
  83. /******/  // Load entry module and return exports 
  84. /******/  return __webpack_require__(__webpack_require__.s = "./src/index.js"); 
  85. /******/ }) 
  86. /************************************************************************/ 
  87. /******/ ({ 
  88.  
  89. /***/ "./src/heading.js"
  90. /*!************************!*\ 
  91.   !*** ./src/heading.js ***! 
  92.   \************************/ 
  93. /*! exports provided: default */ 
  94. /***/ (function(module, __webpack_exports__, __webpack_require__) { 
  95.  
  96. "use strict"
  97. eval("__webpack_require__.r(__webpack_exports__);\n// heading.js\n/* harmony default export */ __webpack_exports__[\"default\"] = (function(){\n  const element = document.createElement(\"div\");\n  element.textContent = \"hello yichuan\";\n  element.addEventListener(\"click\",()=>{\n    console.log(\"hello onechuan\");\n    return element\n  })\n});\n\n//# sourceURL=webpack:///./src/heading.js?"); 
  98.  
  99. /***/ }), 
  100.  
  101. /***/ "./src/index.js"
  102. /*!**********************!*\ 
  103.   !*** ./src/index.js ***! 
  104.   \**********************/ 
  105. /*! no exports provided */ 
  106. /***/ (function(module, __webpack_exports__, __webpack_require__) { 
  107.  
  108. "use strict"
  109. eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _heading_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./heading.js */ \"./src/heading.js\");\n// index.js\n\ndocument.body.append(Object(_heading_js__WEBPACK_IMPORTED_MODULE_0__[\"default\"])())\n\n//# sourceURL=webpack:///./src/index.js?"); 
  110.  
  111. /***/ }) 
  112.  
  113. /******/ }); 

在上面打包之后的文件中,src目录中的每个模块对应打包后文件中的一个函数,从而实现模块的私有作用域,在此文件中还挂载了一些其他的数据和工具函数。

写在后面

 

这篇文章主要写了webpack上路使用,对于webpack的基本使用并不是很复杂,特别是在webpack4.0后,很多配置都已经被简化。在这种配置并不复杂的前提下,开发人员对它的掌握程度,主要体现在是否能够理解它的工作机制和原理。

 

责任编辑:武晓燕 来源: 前端万有引力
相关推荐

2021-12-24 08:01:44

Webpack优化打包

2021-12-20 00:03:38

Webpack运行机制

2021-12-25 22:29:04

WebpackRollup 前端

2021-12-15 23:42:56

Webpack原理实践

2021-12-22 22:44:49

Webpack热替换模块

2021-12-19 07:21:48

Webpack 前端插件机制

2015-10-10 10:01:28

前端模块化webpack

2021-12-17 00:02:28

Webpack资源加载

2010-02-03 09:01:01

Java动态模块化

2017-03-24 10:56:21

Webpack技巧建议

2017-05-02 16:29:11

Webpack技巧建议

2021-12-21 14:00:25

WebpackDevServer的开发

2024-05-27 00:00:01

2017-05-18 11:43:41

Android模块化软件

2021-06-28 05:59:17

Webpack 前端打包与工程化

2020-08-05 08:21:41

Webpack

2010-01-21 09:27:30

模块化的优点NetBeans

2022-01-20 10:56:53

Webpack5持久化缓存

2022-05-03 20:48:17

Webpackcommonjsesmodule

2021-05-31 05:36:43

WebpackJavaScript 前端
点赞
收藏

51CTO技术栈公众号