什么是Webpack
Webpack 本质上是一个模块化打包工具,它通过“万物皆模块”这种设计思想,巧妙地实现了整个前端项目的模块化。在 Webpack 的理念中,前端项目中的任何资源都可以作为一个模块,任何模块都可以经过 Loader 机制的处理,最终再被打包到一起。
最初的时候,具体做法是将每一个功能及其相关状态数据各自放到不同的js文件中,一个script标签对应一个模块。
├── module-a.js
├── module-b.js
└── index.html
缺点:
-
模块直接在全局工作,大量模块成员污染全局作用域。
-
不好管理模块与模块间的依赖关系。
-
模块越多,容易产生命名冲突。
其他方式
使用立即执行函数
(function () {
var name = 'module-a'
function foo () {}
window.moduleA = {
foo: foo
}
})()
模块化规范
在最早期以AMD、CMD模块化规范这样的方式出现。再到后来的ES6的模块化(export、import),还有CommonJS规范。
Webpack工作过程简介
Webpack 官网首屏很清楚地描述了它的工作原理,如下图所示:
[图片上传失败...(image-2ae33a-1693882368824)]
项目中一般都会散落着各种各样的代码及资源文件,比如 JS、CSS、图片、字体等,这些文件在 Webpack 的思想中都属于当前项目中的一个模块。Webpack 可以通过打包,将它们最终聚集到一起。
具体来看打包的过程,Webpack 启动后,会根据我们的配置,找到项目中的某个指定文件(一般这个文件都会是一个 JS 文件)作为入口。然后顺着入口文件中的代码,根据代码中出现的 import(ES Modules)或者是 require(CommonJS)之类的语句,解析推断出来这个文件所依赖的资源模块,然后再分别去解析每个资源模块的依赖,周而复始,最后形成整个项目中所有用到的文件之间的依赖关系树,下面这个动画生动的演示了这个过程:
[图片上传失败...(image-28b3ec-1693882368824)]
Webpack 5 个核心概念
- Entry:
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部依赖图(dependency graph)的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
- output:
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js
,其他生成文件默认放置在 ./dist
文件夹中。
- loader:
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块以供应用程序使用,以及被添加到依赖图中。
-
plugins: loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:代码压缩,生成 html ,打包优化,资源管理,注入环境变量等。
-
mode:
通过选择 development
, production
或 none
之中的一个,来设置 mode
参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production
。
示例:
// 首先初始化一个项目
npm init -y
// 在项目里面安装 webpack 以及 webpack-cli
npm i webpack webpack-cli
// 接下来创建 src 目录,下面创建 index.js 以及 data.json 这两个文件。
// index.js
import data from './data.json'
console.log(data);
function add(x, y) {
return x + y;
}
console.log(add(1, 2));
// data.json
{
"name" : "zhangran",
"age" : 18
}
接下来使用如下命令进行打包:
webpack ./src/index.js -o ./build/built.js --mode=development
webpack ./src/index.js -o ./build/built.js --mode=production
在项目根目录下面创建 webpack.config.js,然后将 Webpack 配置中的入口文件路径指定为 main.css 的文件路径,让 Webpack 直接打包 CSS 资源文件,具体配置如下所示:
module.exports = {
// 样式文件路径
entry: './src/main.css',
output: {
filename: 'bundle.js'
}
}
运行npx webpack
,这时控制台会出现报错,需要适当的加载程序来处理此文件类型,目前没有配置加载程序来处理此文件。
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
加载 CSS 模块的 Loader,最常用到的是 css-loader。我们需要通过 npm 先去安装这个 Loader,然后在配置文件中添加对应的配置。
module.exports = {
entry: './src/main.css',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/, // 根据打包过程中所遇到文件路径匹配是否使用这个 loader
use: 'css-loader' // 指定具体的 loader
}
]
}
}
[图片上传失败...(image-7cf211-1693882368823)]
添加完这个loader过后,打包过程就不会报错了。CSS 文件会交给 css-loader 处理过后再由 Webpack 打包,最后输出bundle.js。
我们在页面中使用这里输出的 bundle.js 文件,你会发现刚刚的这个 main.css 模块并没有工作。这里就需要用到另外一个loader
style-loader
。运行以下命令,并添加配置:
npm i style-loader
module.exports = {
mode:'development',
entry: './src/main.css',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.css$/, //正则表达式, 根据打包过程中所遇到文件路径匹配是否使用这个 loader
use: ['style-loader','css-loader'] // 指定具体的 loader // 对同一个模块使用多个 loader,注意顺序
}
]
}
}
plugins
打包 html 资源,需要使用 html-webpack-plugin 这个插件。每次完整打包之前,自动清理 dist 目录需要使用clean-webpack-plugin
。运行以下命令,并添加配置:
npm i html-webpack-plugin clean-webpack-plugin -D
//...
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins : [
// 自动为你生成一个 html 文件,并且引入你打包好的 js 文件
new HtmlWebpackPlugin({
title:'webpack test',
// template:'./src/index.html',// 生成html模版文件
}),
// 自动清理dist目录
new CleanWebpackPlugin()
],
//...
其实 Webpack 不仅是建议我们在 JavaScript 中引入 CSS,还会建议我们在代码中引入当前业务所需要的任意资源文件。因为真正需要这个资源的并不是整个应用,而是你此时正在编写的代码。这就是 Webpack 的设计哲学。(所有资源的加载都是由 JS 代码控制,后期也就只需要维护 JS 代码这一条线)
plugins最常见的应用场景:
-
实现自动在打包前清除dist目录(上一次打包后的文件)。
-
自动生成应用所需要的html文件。
-
压缩Webpack打包完成后的输出文件。
-
......
开发一个loader
一个可以加载 markdown 文件的加载器,以便可以在代码中直接导入 md 文件。我们都应该知道 markdown 一般是需要转换为 html 之后再呈现到页面上的,所以我希望导入 md 文件后,直接得到 markdown 转换后的 html 字符串,如下图所示:
[图片上传失败...(image-afa9-1693882368823)]
现在更目录下新建一个markdown-loader.js文件。
// webpack.config.jsmarkdown-loader.js
const marked = require('marked');
module.exports = source => {
const html = marked(source);
console.log(html)
// 返回值就是最终被打包的内容
return `module.exports = ${JSON.stringify(html)}`
}
每个 Webpack 的 Loader 都需要导出一个函数,这个函数就是我们这个 Loader 对资源的处理过程。它的输入就是加载到的资源文件内容,输出就是我们加工后的结果。我们通过 source 参数接收输入,通过返回值输出。
*函数返回的结果必须是一段标准的 JS 代码字符串。
// webpack.config.js
// ...
rules: [
{
test: /\.css$/, //正则表达式, 根据打包过程中所遇到文件路径匹配是否使用这个 loader
use: ['style-loader', 'css-loader'] // 指定具体的 loader
},
{
test:/\.md/,
use:'./markdown-loader' // 直接使用相对路径
}
]
// ...
最后我们把导入到markdown文件显示到html文件中
// index.html
// ...
<div id="test"></div>
//index.js
import html from './test.md';
document.querySelector("#test").innerHTML = html;
网友评论