前端工程化经历过很多优秀的工具,例如 Grunt、Gulp、webpack、rollup 等等,每种工具都有自己适用的场景,而现今应用最为广泛的当属 weback 打包了。因此 webpack 也自然而然成了面试官打探你是否懂前端工程化的重要指标。
由于 webpack 技术栈比较复杂,因此决定分以下几篇文章全面深入的讲解:
基础应用篇
高级应用篇
性能优化篇
原理篇( webpack 框架执行流程、手写 plugin、手写 loader )
webpack 是什么
webpack 是模块打包工具
webpack 可以不进行任何配置(不进行任何配置时,webpack 会使用默认配置)打包如下代码:
// moduleA.js
function ModuleA(){
this.a = "a";
this.b = "b";
}
export default ModuleA
// index.js
import ModuleA from "./moduleA.js";
const module = new ModuleA();
复制代码
我们知道浏览器是不认识的 import 语法的,直接在浏览器中运行这样的代码会报错。那么我们就可以借助 webpack 来打包这样的代码,赋予 JavaScript 模块化的能力。
最初版本的 webpack 只能打包 JavaScript 代码,随着发展 css 文件,图片文件,字体文件都可以被 webpack 打包。
本文将主要讲解 webpack 是如何打包这些资源的,属于比较基础的文章主要是为了后面讲解性能优化和原理做铺垫,如果已经对 webpack 比较熟悉的同学可以跳过本文。
webpack 基础功能
初始化安装 webpack
mkdir webpackDemo // 创建文件夹
cd webpackDemo // 进入文件夹
npm init -y // 初始化package.json
npm install webpack webpack-cli -D // 开发环境安装 webpack 以及 webpack-cli
复制代码
通过这样安装之后,我们可以在项目中使用 webpack 命令了。
打包第一个文件
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development', // {1}
entry: { // {2}
main:'./src/index.js'
},
output: { // {3}
publicPath:"", // 所有dist文件添加统一的前缀地址,例如发布到cdn的域名就在这里统一添加
filename: 'bundle.js',
path: path.resolve(__dirname,'dist')
}
}
复制代码
代码分析:
development | production
[注意] 这个基础的配置文件哪怕你不写,我们执行 webpack 命令也可以运行,那是因为 webpack 提供了一个默认配置文件。
创建文件进行简单打包:
src/moduleA.js
const moduleA = function () {
return "moduleA"
}
export default moduleA;
--------------------------------
src/index.js
import moduleA from "./moduleA";
console.log(moduleA());
复制代码
修改npm run build
命令
"scripts": {
"build": "webpack --config webpack.config.js"
}
复制代码
执行 npm run build 命令
打包后的 bundle.js 源码分析
源码经过简化,只把核心部分展示出来,方便理解
var installedModules = {};
function __webpack_require__(moduleId) {
// 缓存文件
if(installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
// 初始化 moudle,并且也在缓存中存入一份
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
// 执行 "./src/index.js" 对应的函数体
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// 标记"./src/index.js"该模块以及加载
module.l = true;
// 返回已经加载成功的模块
return module.exports;
}
// 匿名函数开始执行的位置,并且默认路径就是入口文件
return __webpack_require__(__webpack_require__.s = "./src/index.js");
})
// 传入匿名执行函数体的module对象,包含"./src/index.js","./src/moduleA.js"
// 以及它们对应要执行的函数体
({
"./src/index.js": (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _moduleA__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./moduleA */ \"./src/moduleA.js\");\n\n\nconsole.log(Object(_moduleA__WEBPACK_IMPORTED_MODULE_0__[\"default\"])());\n\n\n//# sourceURL=webpack:///./src/index