聊聊Webpack

对webpack的理解

webpack是一个用于现代JavaScript应用程序的静态模块打包工具。当Webpack处理应用程序时,会在内部递归构建一个依赖流程图,然后根据模块的依赖关系进行静态分析项目结构,找到js模块以及其他的一些浏览器不能直接运行的扩展语言,如Scss,TS等,通过loader转换文件通过plugin注入钩子,最后输出一个或多个模块组合成的文件(bundles)以提供给浏览器使用。(在Webpack中一切文件皆为模块)

webpack的作用

  • 模块打包。将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序,并保证项目结构的清晰和可读性

  • 减少io请求。通常在请求时,会返回一个html到浏览器,但是如果没有通过Webpack将所有静态资源都合并好,就会通过script、link等标签引用的静态资源,浏览器就会再次发出请求去获取这些资源,请求的次数增多

  • 编译兼容。通过Webpack的loader机制,将浏览器不认识的语法编译成浏览器认识的语法,使在开发的时候可以使用新特性和新语法做开发,提高开发效率

  • 能力扩展。通过Webpack的plugin机制,可以进一步实现注入按需加载,代码压缩等一系列功能,帮助进一步提高自动化程度、工程效率以及打包输出的质量

webpack的功能

  • 代码转换:Typescript编译成JavaScript,SCSS编译成CSS等

  • 文件优化:压缩文件大小,如代码html、CSS、JavaScript以及一些图标文件和图片文件的压缩

  • 代码分割:提取出多个页面的公共代码,提取首屏不需要执行的部分代码,让其异步加载,提高页面性能

  • 模块合并:把一些需要构建功能的模块化分类文件合并为一个文件

  • 自动刷新:监听项目本地源代码的修改,自动构建刷新浏览器页面

  • 代码校验:会在代码提交到仓库前需要检测代码是否符合规范,以及单元测试是否通过

  • 自动发布:在项目更新完代码之后,会自动构建出线上发布代码并传输给发布系统

webpack五个核心概念

1.Entry(入口)

标识Webpack应该使用哪个模块作为构建其内部依赖图的开始。

Entry会有单入口和多入口两种情况:单入口适用于SPA(单页应用)的场景,值是一个字符串; 多入口适用于MPA(多页应用)的场景,值是一个对象

js 复制代码
// 单页应用
module.exports = { entry: "./src/index.js", };

// 多页应用
module.exports = { entry: { app: "./src/app.js", adminApp: "./src/adminApp.js", }, };

2.Output(出口)

告诉Webpack将编译后的文件存放在哪里以及输出文件的名称,默认放置在./dist文件夹中

js 复制代码
// 单入口
const path = require('path'); 
module.exports = { 
    output: { 
        filename: "bundle.js", 
        path: path.resolve(__dirname, 'dist'), 
    },
};

// 多入口
const path = require('path');
module.exports = { 
    output: { 
       // 使用占位符,确保文件唯一性
        filename: "[name].js", 
        path: path.resolve(__dirname, 'dist'),
    },
};

3.Loader

loader用于对模块的源代码进行转换。本质上是一个函数,在函数中对接收到的内容进行转化,返回转化后的结果。

实际上Webpack内部默认只能够处理JS代码,在打包的过程中,会默认将所有遇到的文件都当作JavaScript代码进行解析,因此当项目存在非JS类型文件时,就需要先对其进行必要的转换,才能继续执行打包任务。

js 复制代码
const path = require("path"); 
module.exports = { 
    module: { 
        rules: [{ 
            // test属性:指定匹配规则,识别出哪些文件会被转换
                test: /\.txt$/, 
            // use属性:指定使用的loader名称
                use: "raw-loader" 
            }], 
    }, 
};

常见的loader

名称 描述
babel-loader 转换ES6为ES5
ts-loader 将TypeScript转换成JavaScript
css-loader 加载CSS,支持模块化、压缩、文件导入等特性
sass-loader 将SCSS/SASS转换成CSS
style-loader 使用<style>将css-loader内部样式注入到HTML页面
json-loader 加载 JSON 文件(默认包含)
image-loader 加载并且压缩图片文件
svg-inline-loader 将压缩后的 SVG 内容注入代码中
raw-loader 加载文件原始内容(utf-8)
file-loader 把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
url-loader file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)

更多 loader 可参考官网

4.Plugin

plugin插件可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

js 复制代码
// 通过 npm 安装 html-webpack-plugin,并使用require()引入
const HtmlWebpackPlugin = require("html-webpack-plugin"); 
const webpack = require("webpack"); // 用于访问内置插件
module.exports = {
// 通过实例添加到plugins数组
  plugins: [new HtmlWebpackPlugin({ template: "./src/index.html" })],
};

常见的plugin

名称 描述
define-plugin 定义环境变量(Webpack4之后指定mode会自动配置)
ignore-plugin 忽略部分文件
clean-webpack-plugin 清理构建目录
html-webpack-plugin 简化html创建,创建html文件去承载 Webpack 打包后的静态资源
webpack-parallel-uglify-plugin 多进程执行代码压缩,提升构建速度
webpack-parallel-uglify-plugin 分离样式文件,CSS 提取为独立文件,支持按需加载
zip-webpack-plugin 将打包后的资源生成zip包
### 更多 Plugin 可参考官网
### 5.Mode
Mode 是用来指定当前的构建环境是:productiondevelopmentnone,默认值为 production。设置 mode 可以自动触发 Webpack 的内置函数。
Mode的内置函数
名称 描述 特点
development 会将process.env.NODE_ENV设置为 development,开启 NamedChunksPluginNamedModulesPlugin 能让代码本地调试运行的环境
production 设置 process.env.NODE_ENVproduction,开启 FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginOccurrenceOrderPluginSideEffectsFlagPluginTerserPlugin 能让代码优化上线运行的环境
none 不开启任何优化选项

说说loader与plugin的区别

Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。 因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。

Plugin 就是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。

Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

webpack的打包流程

大致划分为三个阶段:初始化、编译、输出

  1. 初始化参数:从配置文件和Shell语句中读取与合并参数,得出webpack最终的参数
  2. 开始编译:用上一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译
  3. 读取入口文件:根据配置中的entry找出所有入口文件,从入口文件出发,读取这些文件及其依赖的模块,递归遍历分析,形成一个依赖图
  4. 编译模块:根据上一步得出的的模块之间的依赖关系,调用所有配置的loader对模块进行编译,最终转为JavaScript文件
  5. 转换代码:根据配置中的插件,对加载的模块进行一系列转换操作,如压缩、合并、优化等
  6. 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk代码块,再把每个Chunk转换成一个单独的文件,并输出到指定的输出目录中

webpack生命周期

  • beforeRun:Webpack 进入编译前的阶段,此时会初始化 Compiler 对象。

  • run:Webpack 开始编译前的阶段,此时会读取入口文件和依赖,并创建依赖图。

  • compilation:Webpack 进入编译阶段,此时会开始编译入口文件和依赖的模块,并生成输出文件。

  • emit:Webpack 生成输出文件前的阶段,此时可以在插件中处理生成的输出文件。

  • done:Webpack 完成打包后的阶段,此时可以在插件中进行一些清理工作。

webpack的热更新原理

Webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。是一种在开发环境中实现代码修改后无需刷新页面即可实时更新的功能。它可以提高开发效率,减少开发者的等待时间。

热更新原理:

  1. Webpack会在启动时,为每个模块生成一个唯一的标识符(hash)

  2. 当文件发生改变时,Webpack会监听文件系统的变化,检测到文件改变后,会重新编译发生变化的模块,并生成新的hash。

  3. 在编译完成后,Webpack会通过热更新服务器(Hot Update Server)将编译的更新代码发送到浏览器端。

  4. 浏览器端的热更新运行时(Hot Update Runtime)会接收到新的更新代码,并通过热更新模块(Hot Module)与当前模块进行比较。

  5. 如果新的更新代码与当前模块不一致,热更新模块会将新的模块与当前模块进行合并,保留当前模块的状态,并将更新后的模块应用到页面上,实现局部刷新。

注意:热更新在应用程序运行过程中,替换、添加或删除模块,只会对发生变化的模块进行更新,而不会刷新整个页面。这样可以避免页面的重新加载,提高开发效率。

sourceMap

Webpack的sourceMap是一种文件,它存储了编译后的代码与原始源代码之间的映射关系。它的作用是在调试过程中,帮助开发者定位到源代码的位置,从而更方便地进行错误追踪和调试,准确定位到源代码中的问题,并进行修复。

使用步骤:

  1. 在Webpack配置文件中,确保开启了sourceMap的生成。在devtool配置项中,可以选择不同的sourceMap生成方式。常用的选项有:

    • eval-source-map:每个模块使用eval执行,并且sourceMap以DataUrl的形式嵌入到eval中。
    • source-map:生成独立的sourceMap文件。
    • cheap-module-source-map:生成独立的sourceMap文件,但不包含列信息。
    • cheap-module-eval-source-map:每个模块使用eval执行,并且sourceMap以DataUrl的形式嵌入到eval中,不包含列信息。
  2. 在开发环境中,确保浏览器的开发者工具中启用了sourceMap支持。

  3. 在Webpack构建时,确保生成的sourceMap文件与编译后的代码文件一起部署到服务器上。

一旦sourceMap生成并部署完成,当在浏览器中进行调试时,开发者工具会自动加载并使用sourceMap来将编译后的代码映射回原始源代码,从而在调试器中显示原始源代码的位置。

最后

Webpack一个优秀的打包的工具

Webpack牛逼!!!

相关推荐
丁总学Java19 分钟前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
懒羊羊大王呀30 分钟前
CSS——属性值计算
前端·css
无咎.lsy1 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec1 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
fishmemory7sec1 小时前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
豆豆2 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建
twins35203 小时前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
qiyi.sky3 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~3 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
安冬的码畜日常3 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺