webpack5学习进阶:模块、依赖与扩展功能(PostCSS、Web Works、TypeScript)


在开发过程中,我们会把程序分解为功能离散的文件,这些文件就是模块;

一、webpack 模块

1、webpack 支持的模块

ES6 的 import/export/export default 语句
commonJS 的 require/module.exports 语句
AMD 的 define 和 require 语句
CSS 等样式库的 @import 语句
样式里面 url 引入的资源

总体来说 webpack 天生就支持 ECMAScript、CommonJS、AMD、Assets 等模块;同时 webpack 的 loader 也可以使 webpack 可以支持多种语言和预处理语法来编写模块;

2、webpack 模板解析的简易原理

webpack 将 js、css、less、img、html 等文件通过 loader 以及 webpack 内置的一些模块方法解析成模块化文件;

打包编译的解析过程:
1、webpack 执行会返回一个描述 webpack 打包编译整个流程的对象:compiler ;
2、compiler 对象内置了一个打包状态,随着打包的进行状态也会实时的发生变更,同时会触发相应状态的 webpack 钩子函数;
3、每一个 webpack 打包都会创建一个 compiler 对象,它会走完整个生命周期的过程,webpack 所有模块的解析都是 compiler 对象内置模块的解析器(resolvers)去工作的;
4、resolver 的主体功能就是解析模块,它是基于 enhanced-resolve 这个包来实现的,所以在 webpack 中无论使用什么样的模块引用语句,最终都是使用 enhanced-resolve 这个包的 API 来实现模块解析的;

二、模块解析(resolve)

webpack 通过 resolvers 实现模块之间的依赖和引用;resolver 帮助 webpack 从每一个 require/import 语句中找到需要引入的模块代码;当打包的时候 webpack 使用 enhanced-resolve 来解析文件路径;

1、解析路径

webpack 能解析三种文件路径:相对路径、绝对路径、模块路径;
1、绝对路径:相对于项目的根目录作为参考的路径(‘/src/util/test.js’),第一个 / 就代表根目录;
2、相对路径:相对于文件本身作为参考的路径(‘./util/test.js’),./ 表示进入文件;
3、模块路径:引入第三方模块的时候,直接通过模块名(‘lodash’);

2、目录(路径)配置别名

如果我们的目录层级比较深,那么我们在内部的文件中引入外部的文件就会需要多次使用 ‘…/’ 来找到外部的文件;这也操作起来会比较麻烦;所以我们可以给特定文件夹下的目录起个别名:

const path = require('path')
module.exports={
	resolve:{
		alias:{
			"@":path.resolve(__dirname,'./src')
		}
	}
}

这样 @ 就可以直接访问到 src 这个目录下的文件了,此时 @ 指向就是 src;

"../../../../../../../../util/tset"
//替换为
"@/util/test"

3、配置文件的扩展名

在引入文件的时候,webpack 会默认帮我们查找一些具有某个文件名的文件,因此我们在引入文件时可以不用带上后缀名;但是如果我们有相同文件名后缀不一样的两个文件(test.js、test.json),在引入时不携带后缀名,webpack 会帮我们找到对应名称的 js 文件,而不是 json 文件;这是因为 webpack 默认的优先级配置;

当然我们也可以修改 webpack 默认的配置:

module.exports = {
	extensions:[".json", ".js", ".vue"]
}

这样上面的引入,webpack 会帮我们找到 json 文件;

三、外部扩展(Externals)

1、引入 cdn 文件

有时候为了减小 bundle 文件的体积,我们需要把一些不变的第三方库用 cdn 的形式引入进来;

//index.html
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>

这个时候我们想在代码中使用引入的 jquery ,但是三种模块引入方式都不行,webpack 给我们提供了 Externals 的配置属性,让我们配置外部扩展模块:

module.exports = {
	plugins:[
		new HtmlPlugin({
			template:'./index.html'
		})
	],
	externals:{
		jquery:'jQuery'
	}
}

然后在页面中引入

import $ from 'jquery'

这也就可以正常使用 JQuery 了;

2、改造

如果我们不想自己手动引入 cdn 在 html 文件中,想让 webpack 自动生成一个 html 并且帮我们自动引入 script 标签,并且引入 cdn;我们只需要下面的操作:首先删除 index.html;

module.exports = {
	plugins:[
		new HtmlPlugin()
	],
	externalsType:'script',
	externals:{
		jquery:[
			"https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js",
			"jQuery"
		]
	}
}

不需要手动 Html 引入,只需要上面的配置就可以自动生成的 HTML 文件中自动引入 jquery 的 cdn 文件;

四、依赖图(dependency graph)

每当一个文件依赖另一个文件时, webpack 就会认为这两个文件存在依赖关系;这也就让 webpack 可以获取非代码资源(图片,字体)等,并把它们作为依赖提供给应用程序;
当 webpack 开始工作时,它会根据我们写的配置,从入口(entyr)开始,递归构建一个依赖关系图,这个依赖图包含应用程序所有的模块,然后将所有模块打包为 bundle(也就是出口(output)配置项);

1、bundle 分析工具

1、webpack-chart:生成一个可交互的饼图;
2、webpack-visualizer:可视化,并分析你的 bundle ,检查那些模块占用空间,那些是可以重复使用的;
3、webpack-bundle-analyzer:一个 plugin 和 cli 工具,将 bundle 内容展示成一个便捷的、交互式、可缩放的树状图;
4、webpack bundle optimize helper:分析 bundle 并提供可操作的改进措施,以减少 bundle 的大小;
5、bundle-stats:生成 bundle 报告(大小、资源、模块)并比较不同构建之间的结果;

2、webpack-bundle-analyzer

安装

npm i webpack-bundle-analyzer -D

安装成功之后在 webpack.config.js 中引入使用

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
	plugins:[
		new BundleAnalyzerPlugin()
	]
}

然后运行项目,就可以自动打开一个浏览器,里面可以看到下面这种关系图:
在这里插入图片描述
stat:统计信息,可以看到每个模块的互相依赖的图,以及每个模块的大小信息;
parsed:解析以后的模块结果,以及模块大小信息;
gzipped:压缩以后的模块,以及模块大小信息;

五、扩展功能

1、PostCSS 与 css 模块

PostCSS :是一个用 JavaScript 工具和插件转换 CSS 代码的工具;比如可以使用 Autoprefixer 插件自动获取浏览器的流行度和能够支持的属性,并根据这些数据自动为 CSS 添加前缀,将最新的 CSS 语法转换成大多数浏览器能够理解的语法;
CSS模块:就是所有的类名都只有局部作用域的 CSS 文件;CSS 模块不是浏览器中的官方标准,是改变类名和选择器的作用域到当前文件的构建过程;

1.1、PostCSS 使用

webpack 中使用 PoseCSS 需要安装 style-loader、css-loader、postcss-loader:
安装:

npm i style-loader css-loader postcss-loader -D

安装之后使用

module.exports={
	module:{
		rules:[
			{
				test:/\.css$/,
				use:['style-loader','css-loader','postcss-loader']
			}
		]
	}
}

这个时候我们可以在浏览器上查看,并没有做浏览器的兼容设置;

我们想要使用具体的功能还需要安装对应的插件:我们在安装一个插件 autoprefixer 来加载样式的前缀;

npm i autoprefixer -D

新增文件 postcss.config.js 来配置 css 的插件;

module.exports = {
	plugins:[
		require('autoprefixer')
	]
}

在 package.json 中约定浏览器的版本:

"browserslist": [
    "> 1%", //全球浏览器的使用率要大于1%
     "last 2 versions"//每个浏览器最新的两个版本
 ],

这样浏览器的样式就会出现带有前缀的:
在这里插入图片描述
插件会自动帮助我们找到当前浏览器支持的样式,并添加前缀;

如果想在样式里面写嵌套可以安装插件: postcss-nested(这种嵌套样式会被编译成浏览器可以识别的样式)

1.2、CSS 模块给样式类添加唯一的名字

开启 CSS 模块;

module.exports={
	module:{
		rules:[
			{
				test:/\.css$/,
				use:[
					'style-loader',
					{
						loader:'css-loader',
						options:{
							modules:true
						}
					},
					'postcss-loader'
				]
			}
		]
	}
}

这个时候我们的类名就会变成一个 hash 字符串类型的唯一标识;
在这里插入图片描述
由于编译后的类名变了,我们在使用的时候也需要换一种方式来使用:在引入css的时候把 css 文件作为一个模块来引入

import styles from ''./app.css"

const div = document.createElement('div')
div.textContent = 'hello webapck'
div.classList.add(styles.box) //使用
document.body.appendChild(div)
1.3、部分开启 CSS 模块

css 文件名统一使用 module 关键字进行识别,在 module 里面增加一个规则来匹配这种类型的文件:xxx.module.css

{
	test:new PegExp(`^(.*\\.module).*\\.css`),
	use:[
		'style-loader',
		{
			loader:'css-loader',
			options:{
				modules:true
			}
		},
		'postcss-loader'
	]
}

2、Web Works

如果一个 js 运算量比较大,执行时间比较长,我们又不想让它阻塞 js 的循环以及 ui 的渲染,这时候我们考虑使用一下 Web Works ;

Web Works 提供了 js 的后台处理线程的 API,允许我们将复杂的、耗时的 js 逻辑放在浏览器的后台线程里进行处理,让 js 线程不阻塞 ui 线程从渲染;
定义works:

new Worker(scriptURL:string | URL,options?:WorkerOptions)

新建 work.js 文件,放置线程运行的代码

self.onmessage = (message) => {
	self.postMessage({//发送
		msg:123
	})
}

在入口文件中创建一个 web works 来引用刚才的 worker;

const worker = new Worker(new URL('./work.js',import.meta,url))
worker.postMessage({
	question:"hello"
})
worker.onmessage = (message) =>{//接收消息
	console.log(message)
}

这样,打包的时候 webpack 会帮 Web Works 做一个额外的打包;

3、TypeScript

安装 TS 及相应的 loader

npm i typescript ts-loader -D

安装成功之后配置

module:{
	rules:[
		{
			test:/\.ts$/,
			use:'ts-loader',
			exclude:/node_modules/
		}
	]
},
resolve:{
	extensions:['.ts', '.js']
}

配置好之后 ,执行命令 初始化 ts

npx tsc --init

将 rootDir 指向当前文件夹 “./src”,outDir 指向 “./dist”;然后就可以正常编译打包 ts 文件了;

注意:我们在使用 TS 加 webpack 的时候,如果引入其他第三方插件、库、工具,都需要引入一个类型文件;想要查询相关类型文件包可以访问:https://www.typescriptlang.org/dt/search?search=

猜你喜欢

转载自blog.csdn.net/weixin_43299180/article/details/125935800
今日推荐