webpack通过plugin机制让其使用更加灵活,以适应各种应用场景,当然也大大增加了webpack的复杂性,在webpack运行的生命周期中会广播出许多事件,plugin可以hook这些事件,在合适的时机通过webpack提供的API改变其在处理过程中的输出结果。
描述webpack是一个现代JavaScript应用程序的静态模块打包器module bundler,当webpack处理应用程序时,它会递归地构建一个依赖关系图dependency graph,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。
使用webpack作为前端构建工具通常可以做到以下几个方面的事情:
代码转换: TypeScript编译成JavaScript、SCSS编译成CSS等。
文件优化: 压缩JavaScript、CSS、HTML代码,压缩合并图片等。
代码分割: 提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
模块合并: 在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
自动刷新: 监听本地源代码的变化,自动重新构建、刷新浏览器页面,通常叫做热重载Hot Reload;
代码校验: 在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
自动发布: 更新完代码后,自动构建出线上发布代码并传输给发布系统。
在webpack应用中有两个核心:
模块转换器,用于把模块原内容按照需求转换成新内容,可以加载非js模块;
扩展插件,在webpack构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
本文编写的就是编写一个简单的webpack插件,设想一个简单的场景,假如我们实现了一个多页的Vue应用,每个打包的页面都会共享一个相同的头部和底部,也就是顶部navigation bar和底部的footer。因为类似于Vue这种框架都是在运行时才会加载出来头部与底部,而这部分代码实际上完全可以作为一个独立的公用子项目去开发,没必要在多页应用的每个页面都引用一次组件再让框架去解析组件。另外在多页应用页面之间跳转时,如果编写一个头部组件在每个页面组件内部去引用的话,很容易因为需要加载解析JS的时间比较长从而出现导航栏闪烁的问题。
如果要解决上边提到的问题的话,可以采用的一个方案就是使用静态页面片,我们可以将头部和底部的页面片在webpack打包的时候将其注入到要打包完成的html页面中,这样的话不但可以节省一些框架解析组件的JS消耗,而且还可以有更好的SEO表现。虽然只是一个头部与底部并未承载多少信息,但是如果是在s-s-r场景下大量的重复CPU任务,提升一点对于整体来说还是有一个比较大的提高的,就像图形学中画线的算法一样,架不住运算次数太多。此外这样可以比较好的解决组件头部闪烁的问题,因为其是随着HTML一并返回的,所以能立即渲染在页面上不需要JS的加载解析,同样对于骨架屏而言也是可以采用webpack注入页面片的这种方案加载,文中涉及到的所有代码都在https://github.com/WindrunnerMax/webpack-simple-environment。
初探webpack,那么便从搭建简单的webpack环境开始,首先是初始化并安装依赖。
$ yarn init -y $ yarn add -D webpack webpack-cli cross-env首先可以尝试一下webpack打包程序,webpack可以零配置进行打包,目录结构如下:
webpack-simple ├── package.json ├── src │ ├── index.js │ └── sum.js └── yarn.lock // src/sum.js export const add = (a, b) => a + b; // src/index.js import { add } from "./sum"; console.log(add(1, 1));之后写入一个打包的命令。
// package.json { // ... "scripts": { "build": "webpack" }, // ... }执行npm run build,默认会调用node_modules/.bin下的webpack命令,内部会调用webpack-cli解析用户参数进行打包,默认会以src/index.js作为入口文件。
$ npm run build执行完成后,会出现警告,这里还提示我们默认mode为production,此时可以看到出现了dist文件夹,此目录为最终打包出的结果,并且内部存在一个main.js,其中webpack会进行一些语法分析与优化,可以看到打包完成的结构是。
// src/main.js (()=>{"use strict";console.log(2)})(); 配置webpack当然我们打包时一般不会采用零配置,此时我们就首先新建一个文件webpack.config.js。既然webpack说默认mode是production,那就先进行一下配置解决这个问题,因为只是一个简单的webpack环境我们就不区分webpack.dev.js和webpack.prod.js进行配置了,简单的使用process.env.NODE_ENV在webpack.config.js中区分一下即可。在这里我们主要关心dist打包过后的文件,在这里就不进行dev环境的处理以及webpack-dev-server的搭建了,cross-env是用以配置环境变量的插件。
// package.json { // ... "scripts": { "build": "cross-env NODE_ENV=production webpack --config webpack.config.js" }, // ... } const path = require("path"); module.exports = { mode: process.env.NODE_ENV, entry: "./src/index.js", output: { filename: "index.js", path:path.resolve(__dirname, "dist") } }不过按照上边的需求来说,我们不光是需要处理js文件的,还需要处理html文件,这里就需要使用html-webpack-plugin插件。
$ yarn add -D html-webpack-plugin