本文转载自微信公众号「前端万有引力」,作者一川。转载本文请联系前端万有引力公众号。
我们知道当前生产中主流的模块化打包工具有Webpack、Parcel和Rollup。作为模块化打包工具,它们基本的特点有:
能够将散落的模块打包在一起
能够编译转换代码中的新特性,使得可以兼容各种生产环境
对于主流的webpack而言,webpack作为一个模块打包工具,自身就可以实现模块化代码打包的问题,通过webpack可以将零散的JS代码打包到一个JS文件中。对于有环境兼容性问题的代码,webpack可以在代码打包过程中通过loader机制对其实现编译转换,然后再进行打包。对于不同类型的前端模块,webpack支持在js中以模块化的方式载入任意类型的资源文件,例如:可以通过webpack实现在JS中加载CSS文件,被加载的CSS文件会以style标签的方式工具。
webpack还具备代码拆分的能力,能够将应用中所有的模块按需分块打包,不用担心全部代码打包到一起,产生单个文件过大,导致加载慢的问题。这种模块按需分块打包非常适合大型web项目。
Webpack作为主流的前端模块打包器,提供了一整套前端项目模块化方案,而不仅仅局限于JS的模块化,可以实现对前端项目开发过程中涉及到的资源进行模块化。
我们知道ES Modules中制定的html中使用script导入js模块,需要设定type="module",用来区分加载的是普通JS脚本还是一个模块。对于支持ES Modules的浏览器可以直接使用,但是对于不支持的浏览器就会报错,因此需要使用webpack模块打包工具避免报错。
复制
<script src="./index.js" type="module"></script>
1.
复制
// heading.js export default function(){ const element = document.createElement("div"); element.textContent = "hello yichuan"; element.addEventListener("click",()=>{ console.log("hello onechuan"); return element }) } // index.js import createHeader from "./heading.js"; document.body.append(createHeader())
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
对于,我们需要先安装webpack的核心模块和cli程序,用于在命令行中调用webpack。npx是npm5.2以后新增的一个命令,可以更方便地执行远程模块或者项目node_modules中的cli程序。
复制
$ npm init --yes $ npm i webpack webpack-cli -D $ npx webpack --version $ npx webpack
1.
2.
3.
4.
通过执行npx webpack实现自动化打包,webpack会默认从src/index.js文件开始打包,打包完毕后会在根目录下生产dist目录,所有打包文件会在dist目录。
复制
|--dist |--main.js
1.
2.
复制
(()=>{"use strict";document.body.append(function(){const e=document.createElement("div");e.textContent="hello yichuan",e.addEventListener("click",(()=>(console.log("hello onechuan"),e)))}())})();
1.
webpack4.0以后的版本支持零配置的方式直接启动打包,整个过程会按照约定将src/index.js文件作为打包入口,最终打包的结果会存放到dis/main.js中。但是,很多时候webpack的默认规则并能满足我们实际需求,对此我们需要对webpack进行自定义配置。
webpack支持在项目中创建webpack.config.js文件进行自定义打包配置,由于webpack是运行在node.js环境,对应应该遵守CommonJS规则进行导入导出。
复制
|--backpack |--src |--heading.js |--main.js |--index.html |--package.json |--webpack.config.js-------webpack配置文件
1.
2.
3.
4.
5.
6.
7.
webpack自定义的配置文件:
复制
// webpack.config.js const path = require("path"); module.exports = { entry:"./src/index.js",//打包入口 output:{//打包出口 filename:"bundle.js",//命名打包后的文件 path:path.join(__dirname,"output") }, // 打包模式 mode:"none" }
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
执行打包命令后会在项目根目录下自动生成打包后的文件目录,我们看到下面是执行打包命令后生成的文件,生成的是一个立即执行函数。
复制
/******/ (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/heading.js": /*!************************!*\ !*** ./src/heading.js ***! \************************/ /*! exports provided: default */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; 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?"); /***/ }), /***/ "./src/index.js": /*!**********************!*\ !*** ./src/index.js ***! \**********************/ /*! no exports provided */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; 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?"); /***/ }) /******/ });
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
在上面打包之后的文件中,src目录中的每个模块对应打包后文件中的一个函数,从而实现模块的私有作用域,在此文件中还挂载了一些其他的数据和工具函数。
这篇文章主要写了webpack上路使用,对于webpack的基本使用并不是很复杂,特别是在webpack4.0后,很多配置都已经被简化。在这种配置并不复杂的前提下,开发人员对它的掌握程度,主要体现在是否能够理解它的工作机制和原理。