webpack是一个用于现代JavaScript应用程序的静态模块打包工具。在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子,最后输出由多个模块组合成的文件,webpack专注构建模块化项目。
Webpack可以看做是模块的打包机器:它做的事情是,分析项目结构,找到js模块以及其它的一些浏览器不能直接运行的拓展语言,例如:Scss,TS等,并将其打包为合适的格式以供浏览器使用。
Webpack提供了模块化开发的基础设施,使得开发者可以更加高效地组织和维护代码,同时提供了各种优化和自定义的功能,使得开发者可以构建出更加健壮和兼容的应用程序。
# Webpack的功能和用途
- 模块化开发:Webpack可以很好地处理和打包JavaScript模块,以及其他的浏览器不能直接运行的拓展语言(如TypeScript、Scss等),使得开发者能够更加高效地组织和维护代码。可以将应用程序拆分成多个模块,每个模块只关注自己的功能,降低了代码的耦合度,提高了代码的可维护性。
- 自动刷新:监听本地源代码的变化,自动构建,刷新浏览器。
- 代码校验:在代码被提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过。
- 自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
- 简化开发过程/处理资源引用:对于非JavaScript文件,如CSS或图片,Webpack可以配置加载器将这些文件转化为模块,使得开发者能够在JavaScript代码中引入和使用这些文件,极大地简化了开发过程。能替代部分grunt/gulp的工作,比如打包、压缩混淆、图片转base64等。
- 强大的插件系统:Webpack拥有丰富的插件系统,可以帮助开发者完成各种任务,可以用来实现各种自定义的功能,比如代码压缩、代码分析、热更新等。
- 代码分割和动态导入:Webpack支持将代码分割成多个块(chunk),实现按需加载,提高了网页的加载速度。同时,Webpack还支持动态加载代码块,实现更灵活的加载策略,从而提高应用程序的加载速度。
- 模块热替换:Webpack支持模块热替换(HMR),可以在开发过程中实现实时预览和调试。
- 优化输出/文件优化:Webpack可以对输出文件进行优化,如压缩代码、提取公共代码等,以减少输出文件的大小,提高网页加载速度。
- 兼容性/代码转换:通过转换和编译最新的JavaScript语法和ECMAScript新特性,Webpack可以帮助提高代码的兼容性。Webpack支持将各种类型的文件(如ES6、TypeScript、Sass、Less等)转换成浏览器可以识别的JavaScript、CSS等文件。
# 使用Webpack能解决的问题
- 在日常的开发中经常在一个index.html页面中引入多个css、js文件,如不小心改变JavaScript文件加载顺序,项目会崩溃,每个script标签都需要向服务器请求一次静态资源,过多的请求会拖慢网页的渲染速度,会导致页面加载慢。使用Webpack可以将他们合并为一个文件,优化前端性能。
- 多个script标签中,全局变量的作用域污染问题。在wepack中,多个模块的作用域是隔离的,彼此不会出现命名冲突。
- 在开发阶段,可能不断的操作dom而使用jQuery,每次都去手敲代码去编译太麻烦。这时可以在根目录下新建配置一个webpack.config.js来提高效率。
- 使用第三方插件时需要npm初始化。
- 对于非JavaScript文件(如CSS或图片),需要配置加载器将这些文件转化为模块才能被JavaScript代码引入和使用。而手动处理是非常繁琐的,这就为Webpack这些工具的出现提供了需求。
- 利用TypeScript这种在JavaScript基础上拓展的开发语言实现目前版本的JavaScript不能直接使用的特性时,需要额外处理才能被浏览器识别。而Webpack可以自动将这些文件转换和打包为合适的格式供浏览器使用。
- 使用Scss、Less等CSS预处理器开发的文件需要额外的处理才能被浏览器识别。而Webpack可以自动将这些文件转换和打包为合适的格式供浏览器使用。
- 对于复杂的网页应用,通常有着复杂的JavaScript代码和一大堆依赖包。而Webpack可以很好地处理和打包这些文件和依赖包,使得开发者能够更加高效地组织和维护代码。
- 当今JavaScript、css的语法规范不断更新,但是浏览器的兼容性却不能同步的更新,开发者可以通过 webpack 预处理器进行编译,自由的使用 JS、CSS 等语言的新语法。通过转换和编译最新的JavaScript语法和ECMAScript新特性,Webpack可以帮助提高代码的兼容性。
- 通过导入导出语句可以清晰地看到模块间的依赖关系,模块可以借助工具进行打包,页面可以加载合并后的资源,减少了网络开销。
# 工作原理
Webpack的工作原理是将各种资源文件看作模块,建立依赖树,将模块编译成浏览器能够识别的格式,然后根据依赖树将模块组合成一个bundle文件,最后将bundle文件发布到网站上。通过使用Webpack进行模块化打包,可以减少HTTP请求,从而提高网页的载入速度。
Webpack会分析所有资源文件,建立所有资源文件之间的依赖关系,构建依赖树,然后根据依赖树渲染出每一个模块。每一个模块都会被编译成机器能够理解的格式,比如JavaScript代码会被编译成浏览器能够识别的JavaScript代码,CSS代码会被编译成浏览器能够识别的CSS代码,图片会被压缩成更小的格式。之后,Webpack会将所有编译完成的模块按照它们之间的依赖关系组合成一个单独的文件,这个文件就是我们所说的“bundle”,最后将bundle文件发布到网站上,完成打包处理。
# 流程概括
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
webpack 的实际入口是 Compiler 中的 run 方法,run 一旦执行后,就开始了编译和构建流程 ,其中有几个比较关键的 webpack 事件节点。
- compile 开始编译
- 目的:这是整个编译过程的开始,意味着开始将源代码转换为可执行代码或目标代码。
- 操作:读取源代码文件,并开始进行初步的解析和处理。
- make 从入口点分析模块及其依赖的模块,创建这些模块对象
- 目的:确定项目的依赖关系,并创建模块对象以供后续处理。
- 操作:工具(如Webpack)会分析源代码中的import或require语句,分析项目的依赖关系,并确定哪些模块需要被编译。为每个模块创建一个对象,这个对象包含了该模块的所有相关信息。
- build-module 构建模块
- 目的:对每个模块的源代码进行处理和转换。
- 操作:这一步包括将模块的源代码进行转换、优化、合并等操作。例如,Babel会在此阶段将ES6+的语法转换为ES5语法。
- after-compile 完成构建
- 目的:在所有模块都构建完成后执行一些全局的操作。
- 操作:例如,可能会进行全局的代码优化、清理临时文件等。
- seal 封装构建结果
- 目的:将构建的结果进行封装,以便于部署和分发。
- 操作:可能会将所有的模块和资源打包到一个或多个文件中,并进行压缩、优化等操作。
- emit 把各个chunk输出到结果文件
- 目的:将各个模块或chunk输出到结果文件。
- 操作:工具会根据其内部的依赖关系,将每个chunk(例如,由多个模块组成的代码块)输出到指定的结果文件。
- after-emit 完成输出
- 目的:在所有chunks都输出到结果文件后执行一些后续操作。
- 操作:例如,可能会复制生成的资源到输出目录、执行一些清理任务等。
webpack编译会创建两个核心对象: compiler:包含了webpack环境的所有的配置信息,包括options,loader和plugin,和webpack整个生命周期相关的钩子 compilation:作为plugin内置事件回调函数的参数,包含了当前的模块资源、编译生成资源、变化的文件以及被跟踪依赖的状态信息。当检测到一个文件变化,一次新的Compilation将被创建