初识Webpack
写作不易,未经作者允许禁止以任何形式转载!
如果觉得文章不错,欢迎关注、点赞和分享!
Webpack 初体验
用 Webpack 解决什么问题
- 模块化
- 高级特性、开发效率、安全性
- ES6+、Typescript、sacc、less
- 监听文件变化并反映到浏览器上,提高开发效率
- 开发完成后的打包,压缩、合并、tree-shaking 等以及其他相关的优化
Webpack 是什么
-
Webpck 是一个静态的模块化打包工具,为现代的 JS 应用程序
-
我们来对上面的解释进行拆解:
- 打包 bundler:webpack 可以将帮助我们进行打包,所以它是一个打包工具。
- 静态的 static:这样表述的原因是我们最终可以将代码打包成最终的静态资源(部署到静态服务器)
- 模块化 module:webpack 默认支持各种模块化开发,ES Module、CommonJS、AMD 等
- 现代的 modern:现代前端开发面临各种各样的问题,才催生了 webpack 的出现和发展
Webpack 和 Vite
Webpack 会被 Vite 取代吗?
- vite 推出后确实引起了很多的反响,也有很多人看好 vite 的发展
- 但是目前 vite 取代 webpack 还有很长的路要走
- 目前 vue 项目支持使用 vite,也支持使用 webpack
- vite 最终打包的过程,依然需要借助于 rollup 完成
- vite 核心思想并不是首创
- 事实上,vite 的思想和之前的 snowpack 是重合的,而且相对目前来说 snowpack 会更加成熟
- 当然,后续发展来看 vite 可能会超越 snowpack
- webpack 的更新迭代
- webpack 在发展工程中,也会不断改进自己,借鉴其他工具的一些优势和思想
- 在这么多年的发展中,无论是自身的优势还是生态都是非常强大的。
关于 Vite 的思考
-
学习任何的东西,重要的是学习核心思想
- 学习了 JS 学 TS 不是从 0 开始
- 学习了 Vue,学 React 也不是从 0 开始
-
任何工具的出现,都是更好地服务于我们开发
-
无论是 vite 的出现,还是以后新的工具出现,不要有任何排斥的思想;
-
我们要深刻地明白,工具都是为了更好地给我们提供服务
-
不可能出现了某个工具,让我们的开发效率变得更低,而这个工具却可以变得非常流行,这是不存在的
-
Webpack 默认打包
-
我们可以通过 webpack 进行打包,之后运行打包之后的代码
-
在目录下直接执行 webpack 命令
webpack
-
直接在终端执行 webpack 可能本机安装版本和项目版本不同,所以在 package.json 中定义命令例如:“build”:“webpack”,这样就会根据 package.json 中的 webpack 版本进行打包(前提是已 install)。
-
-
生成一个 dist 文件夹,里面存放一个 main.js 文件,就是打包之后的文件
- 这个文件中的代码被压缩和丑化了
- 暂时不关心他是如何做到的,后续我讲 webpack 实现模块化原理时会再次讲到。
- 另外发现代码中依然存在 ES6 的语法,比如箭头函数、const 等,这是因为默认情况下 webpack 并不清楚我们打包后的文件是否需要转成 ES5 之前的语法,后续我们需要通过 babel 来进行转换和设置;
-
发现可以正常进行打包的,但是有一个问题,webpack 是如何确地入口的?
- 事实上,我们运行 webpack 时,webpack 会查找到当前目录下的 src/index.js 作为入口
- 所以,如果当前项目中没有 src/index.js,那么会报错
-
当然也可以通过配置来指定入口和出口,例如(通常写配置文件)
npx webpack --entry ./src/main.js --output-path ./build
Webpack 配置文件
-
通常情况下,webpack 需要打包的项目是非常复杂的,并且我们需要一系列的配置来满足要求,默认配置必然是不可以的。
-
我们可以在根目录下创建一个 webpack.config.js 文件,来作为 webpack 的配置文件,例如
const path = require('path'); |
-
继续执行 webpack 命令,依然可以正常打包
-
也可以不使用 webpack.config.js 作为文件名,使用命令定义路径和文件名即可,例如
-
webpack --config ./wk.congfig.js
Webpack 依赖图
webpack 到底是如何对我们的项目进行打包的呢?
-
事实上 webpack 在处理应用程序的时候,它会根据命令或者配置文件找到入门文件;
-
从入口开始,会生成一个依赖关系图,这个依赖关系图会包含应用程序中所需的所有模块(比如 js 文件、css 文件、字体等)
-
然后遍历图结构,打包一个个模块(根据文件的不同使用不同的 loader 解析)
Mode 配置
-
Mode 配置选项,可以告知 webpack 使用响应模式的内置优化:
-
默认值是 production(什么都不设置的情况下);
-
可选值有:‘none’ | ‘development’ | ‘production’;
-
这几个选项有什么样的区别呢?
选项 | 描述 |
---|---|
developtment |
会将DefinePlugin 中process.env.NODE_ENV 的值设置为``developtment`,为模块和 chunk 启用有效的名 |
production |
会将``DefinePlugin中 process.env.NODE_ENV的值设置为 production。为模块和 chunk 启用确定性的混淆名称, FlagDependencyUsagePlugin, FlagInlcudeedChunkPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin和 TerserPlugin` |
none |
不使用任何默认优化选项 |
Mode 配置代表配置了更多
- 绿色选项 = 所有红色选项
Webpack 核心流程
这个过程核心完成了 内容转换 + 资源合并 两种功能,实现上包含三个阶段:
-
初始化阶段:
- 初始化参数:从配置文件、 配置对象、Shell 参数中读取,与默认配置结合得出最终的参数
- 创建编译器对象:用上一步得到的参数创建 Compiler 对象
- 初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等
- 开始编译:执行 compiler 对象的 run 方法
- 确定入口:根据配置中的 entry 找出所有的入口文件,调用 compilition.addEntry 将入口文件转换为 dependence 对象
-
构建阶段:
- 编译模块(make):根据 entry 对应的 dependence 创建 module 对象,调用 loader 将模块转译为标准 JS 内容,调用 JS 解释器将内容转换为 AST 对象,从中找出该模块依赖的模块,再 递归 本步骤直到所有入口依赖的文件都经过了本步骤的处理
- 完成模块编译:上一步递归处理所有能触达到的模块后,得到了每个模块被翻译后的内容以及它们之间的 依赖关系图
-
生成阶段:
- 输出资源(seal):根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
- 写入文件系统(emitAssets):在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
单次构建过程自上而下按顺序执行,下面会展开聊聊细节,在此之前,对上述提及的各类技术名词不太熟悉的同学,可以先看看简介:
-
Entry
:编译入口,webpack 编译的起点 -
Compiler
:编译管理器,webpack 启动后会创建 compiler 对象,该对象一直存活知道结束退出 -
Compilation
:单次编辑过程的管理器,比如watch = true
时,运行过程中只有一个compiler
但每次文件变更触发重新编译时,都会创建一个新的compilation
对象 -
Dependence
:依赖对象,webpack 基于该类型记录模块间依赖关系 -
Module
:webpack 内部所有资源都会以“module”对象形式存在,所有关于资源的操作、转译、合并都是以 “module” 为基本单位进行的 -
Chunk
:编译完成准备输出时,webpack 会将module
按特定的规则组织成一个一个的chunk
,这些chunk
某种程度上跟最终输出一一对应 -
Loader
:资源内容转换器,其实就是实现从内容 A 转换 B 的转换器 -
Plugin
:webpack 构建过程中,会在特定的时机广播对应的事件,插件监听这些事件,在特定时间点介入编译过程
webpack 编译过程都是围绕着这些关键对象展开的,更详细完整的信息,可以参考 Webpack 知识图谱 。
Webpack 和 Gulp
-
gulp 的核心理念是 task runner
- 可以定义自己的一系列任务,等待任务被执行;
- 基于文件 Stream 的构建流; p 我们可以使用 gulp 的插件体系来完成某些任务;
-
webpack 的核心理念是 module bundler pwebpack 是一个模块化的打包工具;
- 可以使用各种各样的 loader 来加载不同的模块;
- 可以使用各种各样的插件在 webpack 打包的生命周期完成其他的任务;
-
gulp 相对于 webpack 的优缺点:
- gulp 相对于 webpack 思想更加的简单、易用,更适合编写一些自动化的任务;
- 但是目前对于大型项目(Vue、React、Angular)并不会使用 gulp 来构建,比如默认 gulp 是不支持模块化的。
优质文章推荐:
- [万字总结] 一文吃透 Webpack 核心原理
- [源码解读] Webpack 插件架构深度讲解
- 十分钟精进 Webpack:module.issuer 属性详解
- 有点难的 webpack 知识点:Dependency Graph 深度解析
- 分享几个 Webpack 实用分析工具
- 分享一份 Webpack 知识图谱
掘金:前端 LeBron
知乎:前端 LeBron
持续分享技术博文,关注微信公众号 👇🏻