重学webpack系列(二) -- webpack解决的问题与实现模块化的具体实践

news2024/11/18 4:43:01

只是根据几个想法,我们便创造出了webpack打包工具,它能够根据我们在前端项目中遇到的疑难杂症对症下药,那么这一章我们就一起来探讨一下我们项目落地所遇到的种种问题。

前端实践中的问题

  • Jsx / Tsx编译问题
  • Less / Scss编译问题
  • TypeScript编译问题
  • 语法 / 环境兼容问题
  • 代码压缩问题
  • 不同类型的静态资源处理问题
  • 模块化文件的统一管理问题

上面的这些问题,都是在开发中遇到的实际问题,每当启动一个项目的时候,我们首先需要去手动tsc、手动编译jsx,手动去编译.less文件等等,初始化的时候我们需要走一遍这样的编译流程,如果文件中出现一丁点修改的话,那将必定会再走一遍编译流程,前端开发苦不堪言,基于此webpack做的事情,就是把这一套流程所需要的工具,全部集成起来,让前端开发者只用关注于自己的业务代码,而不用操心其是如何编译的。那webpack是怎么去解决这些问题的呢?

  • webpack可以通过加载多种loaders来解决编译的问题。
  • webpack本身机制可以实现将多个js文件打包成一个或者按需打包成多个文件,实现文件的统一管理问题。
  • webpack可以通过各种plugins来解决代码压缩,分割等问题。
  • 如果是html页面所使用到的文件,webpack也能够提供像原生一样的方式进行模块的加载。

我们知道了这么多的概念与做法,那webpack具体是怎么实现的呢?

webpack实现模块化的具体实践

我们应当利用webpack去初始化一个项目,npm init -y ; npm i webpack webpack-cli -S,我们就会生成如下的package.json

{"name": "webpack","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies": {"webpack": "^5.74.0","webpack-cli": "^4.10.0"}
} 

webpack.config.json

const path = require('path')

module.exports = {// 模式mode: 'development',// 入口entry: {// 单入口,或者用数组的形式index: './src/index.js'},// 出口output: {//打包的目录文件夹path: path.resolve(__dirname,'build'),//打包的目录文件名filename: '[name].js',//打包的公共路径,确保在当前域名下可以正常访问publicPath: '/'},// 打包输出源代码,以便于更好的追踪错误devtool: "source-map",
} 

这里webpack5webpack4,打包的的信息是不一样的,比如以下:

webpack4

webpack5

entry

webpack.config.json里面,我们看到了entry配置,这个就是配置可以有三种方式:字符串数组对象

// 配置为数组输出main.js
entry: ['./src/index.js', './src/add.js']
// 配置为对象输出以key命名的的文件
entry: {index:"./src/index.js",add:"./src/add.js"
}
// 配置为字符串输出main.js
entry: './src/index.js', 

多入口打包有什么用呢?多入口打包也算作性能优化的一种吧,他能够帮我们把一个文件所依赖的模块进行另外的输出,从而在某个层面减少了加载一个大文件的网络耗时。

output

webpack.config.json里面,我们看到了output配置,下面我们来讲解一下其中的属性。

output: {//打包的目录文件夹path: path.resolve(__dirname,'build'),//打包的目录文件名filename: '[name].js',//打包的公共路径,确保在当前域名下可以正常访问publicPath: '/'
}, 

output是一个对象,其中path指定的输出文件目录位置,filename为打生成的文件的名字,我们可以在文件名字后面加上hash值,这样做的好处有很多,比如利用缓存优化,浏览器网络请求优化等,具体如下:

output: {//打包的目录文件夹path: path.resolve(__dirname,'build'),//打包的目录文件名filename: '[name].[hash].js',//打包的公共路径,确保在当前域名下可以正常访问publicPath: '/'
} 

上述代码我们可以实践一下(index.js依赖了add.js)

第一次打包的文件hash
只修改了index.js之后打包的文件hash
只修改了add.js之后打包的文件hash

可见对于hash来讲,只要项目里面的内容改变了,就会生成新的hash,如果不想因为index.js修改影响到了整个文件的hash值,那么这里就要使用chunkhash了,还有一种contenthash用来描述文件内容的hash值,适用于js文件中引入css文件,一般的当js文件改变,就会重新构建js与引入的css文件,contenthash就可以避免在js文件改变的同时,会去重新构建css的情况。

publicPath属性的作用在于提供一个公共路径,能够保证在服务器上JavaScript能够正确的访问到资源所在的位置。

mode

webpack对于mode,提供了三种基本内置优化预设。

  • development:自动优化打包速度,启用内置插件更好的捕捉错误,便于代码调试。
  • production:启动内置插件优化打包结果,不过打包速度偏慢,便于生产模式访问效率
  • none:基本上不使用

关于上述mode的实际配置,参考webpack官网介绍的mode 。通过配置modeentryoutput我们就可以实现一个基本的模块化构建了。

webpack打包的结果分析

我们以build/add.xxx.js为例简单的分析一下,在打包(webpack5.x打包版本)的源文件中,我们可以看到他的外层其实就是一个自执行函数。

稍微调试一下

我们可以看到在_webpack_require_中,这个moduleId为依赖的模块路径,最后把依赖的模块,通过moduleexports属性当做对象暴露出去。其中__webpack_module_cache__为缓存内容,可以在二次调用的时候直接读取,不用重新构建生成。

_webpack_require_.d_webpack_require_.r_webpack_require_.o到底是怎么实现的呢?这些方法由自执行函数包裹起来,以便于每一次执行脚本自动挂到主函数_webpack_require_上面去。

// __webpack_require__.d
(() => {
	__webpack_require__.d = (exports, definition) => {// 如果definition有key而exports中没有
		for(var key in definition) {
			if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {// 给exports上添加key属性,value为definition[key]
				Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
			}
		}
	};
})();

// __webpack_require__.o
(() => {// 用来检测key是不是definition得一个私有属性
	__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
})();

// __webpack_require__.r
(() => {
	// define __esModule on exports
	__webpack_require__.r = (exports) => {// 如果兼容Symbol 
		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {// 给exports添加上{[Symbol.toStringTag]:'Module'}
			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
		}// 给exports添加上{'__esModule':true}
		Object.defineProperty(exports, '__esModule', { value: true });
	};
})(); 

这里的_esModule是一个什么东西呢?__esModule是用来兼容ESM模块导入CommonJS模块默认导出方案,但是在vscode编辑器里面单独去执行文件的话,这种方案还是不可以的,可见webpack之强大。

总结

其实webpack的使用并不复杂,在webpack4以后很多的配置都被简化掉了,还是那句话,作为一个高级前端开发工程师,我们不仅要关注表层的东西,我们还必须要去深入理解底层机制原理。很多同学觉得难大部分原因是因为没有那种耐心去过多的关注枯燥而又乏味的东西吧。如果同学们也有这种探索底层原理或者更深层次的东西的想法,欢迎大家点赞、关注,跟我一起来学习吧。webpack强大是因为他集成了超多的工具来一起实现前端项目落地,下一章我们将会来探索一下webpackloaders系统

最后

最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Pintos】实现自定义 UserProg 系统调用 | 添加 syscall-nr 系统调用号 | 编写新的参数调用宏

💭 写在前面:本文讲解的内容不属于 Pintos 的 Project 项目,而是关于 userprog 如何添加系统调用的,学习如何额外实现一些功能到系统调用中以供用户使用。因为涉及到 src/example 下的Makefile 的修改、lib 目录下 syscall-nr 系统…

门诊排队叫号系统,有序叫号就诊,适用医院医院、门诊部、诊所等

排队叫号系统,是将互联网信息技术与门诊预约、签到、提醒、叫号、接诊等环节相结合,实现门诊流程式便捷叫号服务。 为助力门诊营造一个良好有序的就诊环境,打造科学合理的就诊流程,今天给大家推荐一款一款便捷排队叫号系统&#x…

Linux基本权限(2)

Linux基本权限(2) 📟作者主页:慢热的陕西人 🌴专栏链接:Linux 📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言 本博客主要讲解了目录权限,和目录&#…

2022年底,我手里一共负责了30套系统

2022年真是不平凡的一年,往常熙熙攘攘的办公室人越来越少,真是像曹操说的兄弟相继凋零,好似风中落叶啊。 结果人少了,手里的系统一个没少,慢慢年底了,我汇总了一下,手里的系统达到了30来个。 搞…

Linux--基础IO

目录 C文件IO 系统文件IO 接口介绍 系统调用和库函数 文件描述符 open返回值 文件描述符的分配规则 重定向 代码演示 使用dup2系统调用 缓冲区 FILE 理解文件系统 文件系统 inode 软硬链接 静态库和动态库 概念 生成静态库 生成动态库 C文件IO 写文件 #in…

SpringBoot+Prometheus+Grafana 实现自定义监控

1.Spring Boot 工程集成 Micrometer 1.1引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency><groupId>io.micrometer<…

E1. Erase and Extend (Easy Version)(纯暴力+string)

Problem - 1537E1 - Codeforces 这是该问题的简单版本。唯一的区别是对n和k的约束。只有当所有版本的问题都解决了&#xff0c;你才能进行黑客攻击。 你有一个字符串s&#xff0c;你可以对它进行两种类型的操作。 删除字符串的最后一个字符。 复制字符串&#xff1a;s:ss&…

数据结构---堆排序

堆排序JAVA实现和快速排序区别二叉堆的构建&#xff0c;删除&#xff0c;调整是实现堆排序的基础之前博客写了二叉堆&#xff1a; 二叉堆最大堆的堆顶是整个堆中的最大元素。最小堆的堆顶是整个堆中的最小元素。 堆排序步骤&#xff1a; 把无序数组构建成二叉堆。(需要从小到…

ArcGIS基础:等高线数据生成栅格DEM数据

以下操作为生成栅格DEM数据的方法。 一般方法是先创建TIN&#xff0c;然后在转为栅格DEM数据。 原始数据如下&#xff1a;为等高线数据&#xff0c;创建TIN数据需要用到等高线数据的【高程】字段。 声明&#xff1a;数据来源于网络。 工具位于【3D分析工具】下的【TIN】下…

BeanDefinition

1. 前言 Spring最重要的一个概念当属Bean了&#xff0c;我们写的Controller、Service、Dao凡是加了对应注解交给Spring管理的&#xff0c;都是Spring容器中的一个Bean。把我们自己写的类变成一个Bean交给Spring管理有很多的好处&#xff0c;比如我们不用自己去new对象了&#…

ssh+mysql实现的Java web企业人事人力资源管理系统源码+运行教程+参考论文+开题报告

今天给大家演示的是一款由sshmysql实现的Java web企业人事人力资源管理系统&#xff0c;其中struts版本是struts2&#xff0c;本系统功能非常完善&#xff0c;已经达到了可以商用的地步&#xff0c;基本全部实现了整个人力资源管理的所有功能&#xff0c;包括员工档案信息、部门…

jekins集成部署

jekins集成部署1.jekins简介2.Jenkins部署环境3. jekins安装4.配置jekins启动和停止脚本5.插件安装5.1.安装maven插件安装5.2 安装gitee插件5.3 安装Publish Over SSH插件5.4 安装 事件机制插件6.任务构建6.1 构建任务6.2 配置giteeApi令牌6.3 配置gitee源码地址6.4 在build中配…

3D激光里程计其二:NDT

3D激光里程计其二&#xff1a;NDT1. 经典NDT2. 计算方式2.1 2D场景求解:2.2 3D场景求解&#xff1a;3. 其他 NDTReference:深蓝学院-多传感器融合 1. 经典NDT NDT 核心思想&#xff1a;基于概率的匹配。目标是将点集 Y 匹配到固定的点集 X 中。这里的联合概率说的是将 X 划分成…

计算机毕业设计springboot+vue社区疫情防控系统

项目介绍 本系统运用最新的技术springboot框架,此框架是现在社会公司生产中所用的必需框架,非常实用,相比于以前的ssm框架,简单很多。前端框架运用vue框架,vue框架是最近几年非常流行的前端技术,适合很多开发语言。主要可以是系统的前端和后端进行解耦,分离,有利于开发者分别注…

设计模式——中介者模式

中介者模式一、基本思想二、应用场景三、结构图四、代码五、优缺点优点缺点一、基本思想 定义一个中介对象来封装一系列对象之间的交互&#xff0c;使原有对象之间的耦合松散&#xff0c;且可以独立地改变它们之间的交互。中介者模式又叫调停模式&#xff0c;它是迪米特法则的…

Proteus8仿真:51单片机LCD1602显示

51单片机LCD1602显示元器件原理图部分代码main.c工程文件元器件 元器件名称排阻RESPACK-851单片机AT89C51LCD1602LM016L按键BUTTON 原理图部分 LCD1602驱动: HD44780显示主要有8位操作8位两行显示&#xff0c;4位操作8位一行显示&#xff0c;8位操作8位一行显示。 LCD1602主要…

【Python】循环语句

目录 1.while 循环 2. for 循环 3. continue 4. break 1.while 循环 基本语法格式 while 条件&#xff1a; 循环体 条件为真&#xff0c;则执行循环体代码 条件为假&#xff0c;则结束循环 例1&#xff1a;打印 1 - 10 的整数 num 1 while num < 10:print(num)num 1 …

【AI with ML】第 10 章 :创建 ML 模型以预测序列

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

MySQL底层索引

目录 一、什么是索引&#xff1f; 二、MySQL索引结构分析【MySQL底层采用的是BTree】 1、为什么不使用二叉树&#xff1f; 2、为什么不使用红黑树&#xff1f; 3、为什么不使用Hash&#xff1f; 4、BTree与B-Tree的区别&#xff1f; 三、MySQL数据库的表结构、索引、数据 1、M…

基于Sharfetter-Gummel和改进的Sharfetter-Gummel计算对流扩散方程的通量(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…