webpack最初的目标是实现前端项目模块化,目的在于更高效的管理和维护项目中的每一个资源
最早的时候,我们通过文件划分的形式实现模块化,也就是将每个功能及其相关状态数据各自单独放在不同的js文件中
约定每个文件就是一个独立的模块,然后把js文件引入到页面,一个script标签对应一个模块,然后调用模块化的成员,这种的弊端非常的明显,模块都在全局中工作,大量的模块成员污染了环境,模块和模块之间没有依赖关系,维护起来困难,没有私有空间
随着命名空间的出现,规定每个模块只能暴露一个全局对象,然后模块的内容都挂载在这个对象中,但是这种方式也没有解决第一种方式的依赖等问题
再后来,我们使用立即执行函数为模块提供私有空间,通过参数的形式作为依赖声明,但是仍然存在一定的问题,通过script标签引入页面,这些模块的加载不受控制,时间久了维护起来也很困难
理想的解决方案就是在页面引入一个js入口文件,其余用到的模块可以通过代码控制,按需加载起来
现代前端开发变得越来越复杂,我们在开发过程中可能会遇到的问题:
webpack是一个用于现代的javascript应用程序的静态模块的打包工具
静态模块指的是开发阶段,可以被webpack直接引用的资源,可以直接被打包进bundle.js的资源
编译代码能力,提高效率,解决浏览器兼容的问题
模块整合能力,提高性能,可维护性,解决浏览器频繁请求文件的问题
万物皆可模块,项目维护性增强,支持不同种类的前端模块类型,统一的模块化方案,所有资源文件都可以通过代码控制
webpack的运行流程是一个串行的过程,他的工作流程就是将各个插件串联起来
在运行过程中会广播时间,插件只需要监听它所关心的事件,就能加入到这条webpack机制中,去改变webpack的运作,使整个系统扩展性良好
从启动到结束会依次执行以下三大步骤:
Shell 语句中读取与合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数 
loader用于对模块的源代码进行转换,在import或加载模块是预处理文件
webpack做的事情,仅仅是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成指定的文件中
在webpack中,任何文件都是模块,不仅仅是js文件,默认情况下,在遇到import或者require加载模块的时候,webpack只支持js和json文件打包
像css、sass、png等这些类型的文件的时候,webpack则无能为力,这时候就需要配置对应的loader进行文件内容的解析、
loader的方式有三种:loader支持链式调用,链中的每个loader会处理之前处理果的资源,最终变为js代码,顺序为相反的顺序执行
除此之外,loader的特性还有如下:
package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块Plugin是一种计算机应用程序,他和主应用程序互相交互,提供特定的功能
是一种遵循一定规范的应用程序接口编写出来的程序,只能运行在程序规定的系统下,因为其需要调用原纯净系统提供的函数库和数据
webpack中的plugin也是如此,plugin赋予其各种灵活的功能,例如打包优化,资源管理,环境变量注入等,它们运行在webpack的不同阶段,贯穿了webpack整个编译周期
本质是一个具有apply方法的javascript对象
关于整个编译生命周期钩子,有如下:
HtmlWebpackPlugin:在打包结束后,⾃动生成⼀个 html ⽂文件,并把打包生成的js 模块引⼊到该 html 中
CSS 到一个单独的文件中webpack内置的插件,不需要安装vue的打包过程中,如果我们将一些文件放到public的目录下,那么这个目录会被复制到dist文件夹中复制的规则在patterns属性中设置:
from:设置从哪一个源中开始复制
to:复制到的位置,可以省略,会默认复制到打包的目录下
globOptions:设置一些额外的选项,其中可以编写需要忽略的文件
两者在运行时机上的区别:
在编写 loader 前,我们首先需要了解 loader 的本质
其本质为函数,函数中的 this 作为上下文会被 webpack 填充,因此我们不能将 loader设为一个箭头函数
函数接受一个参数,为 webpack 传递给 loader 的文件源内容
函数中 this 是由 webpack 提供的对象,能够获取当前 loader 所需要的各种信息
函数中有异步操作或同步操作,异步操作通过 this.callback 返回,返回值要求为 string 或者 Buffer
一般在编写loader的过程中,保持功能单一,避免做多种功能
如less文件转换成 css文件也不是一步到位,而是 less-loader、css-loader、style-loader几个 loader的链式调用才能完成转换
如果自己要实现plugin,也需要遵循一定的规范:
apply 方法的对象,这样才能访问compiler实例compiler 和 compilation 对象都是同一个引用,因此不建议修改Webpack 进入下一个流程,不然会卡住在 emit 事件发生时,代表源文件的转换和组装已经完成,可以读取到最终将输出的资源、代码块、模块及其依赖,并且可以修改输出资源的内容
HMR全称 Hot Module Replacement,可以理解为模块热替换,指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个应用
我们在应用运行过程中修改了某个模块,通过自动刷新就会导致整个应用的整体刷新,那页面中的状态信息都会丢失
如果使用的HMR,就可以实现只将修改的模块试试替换至应用中,不必完全刷新整个应用
配置热更新非常简单
- const webpack = require('webpack')
- module.exports = {
- // ...
- devServer: {
- // 开启 HMR 特性
- hot: true
- // hotOnly: true
- }
- }
通过上述这种配置,如果我们修改并保存css文件,确实能够以不刷新的形式更新到页面中
我们修改并保存js文件之后,页面依旧自动刷新了,这里并没有触发热更新
所以,HMR并不像webpack的其他特性一样可以开箱即用,还需要一些额外的配置
- if(module.hot){
- module.hot.accept('./util.js',()=>{
- console.log("util.js更新了")
- })
- }
关于webpack热模块更新的总结如下:
webpack-dev-server创建两个服务器:提供静态资源的服务(express)和Socket服务webpack proxy,是webpack提供的代理服务
基本的行为就是接收客户端发送的请求后转发给其他服务器,目的就是为了便于开发者在开发模式下解决跨域问题(浏览器安全策略限制)
想要实现代理首先需要一个中间服务器,webpack中提供服务器的工具为webpack-dev-server
目的是为了提高开发者日常的开发效率,只适用在开发阶段
devServetr里面的proxy是关于代理的配置,该属性为对象的形式,对象中的每一个属性就是一个代理的规则匹配
属性的名称是需要被代理的请求路径前缀,一般是为了辨别都会设置前缀为api,值为对应的代理匹配规则
proxy工作原理实质上是利用http-proxy-middleware这个http代理中间件,实现请求转发给其他服务器
在开发阶段,webpack-dev-server会启动一个本地开发服务器,所以我们的应用在开发阶段是独立运行在location的一个端口上,而后端服务又是运行在另一个地址上
所以在开发阶段中,由于浏览器同样策略的原因,当本地访问后端就会出现跨域请求的问题
通过设置webpack proxy实现代理请求后,相当于浏览器与服务端中添加一个代理者
当本地发送请求的时候,代理服务器响应该请求,并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终再由代理服务器将数据响应给本地
再代理服务器传递数据给本地浏览器的过程中,两者同源,并不存在跨域行为,这时候浏览器就能正常的接收数据
注意:服务器与服务器之间请求数据并不会存在跨域行为,跨域行为是浏览器安全策略限制
随着前端的项目逐渐扩大,必然会带来一个问题就是性能
尤其在大型复杂的项目中,前端业务可能因为一个小小的依赖,导致整个页面卡顿甚至崩溃
一般在项目完成后,会通过webpack进行打包,利用webpack对前端项目性能优化是一个十分重要的环节
关于webpack对前端性能的优化,可以通过文件体积大小入手,其次还可通过分包的形式、减少http请求次数等方式,实现对前端性能的优化
随着我们的项目涉及到的页面越来越多,功能和业务代码也会随着越多,相应的webpack的构建时间也会越来越久
构建时间与我们日常开发效率密切相关,当我们本地启动devserver或者build的时候,如果时间过长,会大大的降低我们的工作效率
优化webpack构建的方式有很多,主要可以从优化搜索时间、缩小文件搜索范围、减少不必要的编译等方面入手
模块化是一种处理复杂系统分解为更好的可管理模块的方式
可以用来分割,组织和打包应用。每个模块完成一个特定的子功能,所有的模块按某种方法组装起来,成为一个整体
通过这些模块打包工具,能够提高我们的开发效率,减少成本
Rollup 是一款 ES Modules 打包器,从作用上来看,Rollup 与 Webpack 非常类似。不过相比于 Webpack,Rollup要小巧的多
Parcel ,是一款完全零配置的前端打包器,它提供了 “傻瓜式” 的使用体验,只需了解简单的命令,就能构建前端应用程序
Parcel 跟 Webpack 一样都支持以任意类型文件作为打包入口,但建议使用HTML文件作为入口,该HTML文件像平时一样正常编写代码、引用资源
Snowpack,是一种闪电般快速的前端构建工具,专为现代Web设计,较复杂的打包工具(如Webpack或Parcel)的替代方案,利用JavaScript的本机模块系统,避免不必要的工作并保持流畅的开发体验
vite ,是一种新型前端构建工具,能够显著提升前端开发体验
它主要由两部分组成:
其作用类似webpack+ webpack-dev-server,其特点如下:
vite会直接启动开发服务器,不需要进行打包操作,也就意味着不需要分析模块的依赖、不需要编译,因此启动速度非常快
相比上述的模块化工具,webpack大而全,很多常用的功能做到开箱即用。有两大最核心的特点:一切皆模块和按需加载
与其他构建工具相比,有如下优势: