带你了解webpack的使用
本文是一篇webpack的入门文章,简单的介绍webpack的使用,大部分来自官网指导手册:https://www.webpackjs.com/。如果想进一步学习webpack的使用,请移步官网。
一 webpack基本安装
webpack is a module bundler.(模块打包工具)
webpack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到javascript模块以及其它的一些浏览器不能直接运行的拓展语⾔言(scss,typescript等),并将其打包为合适的格式以供浏览器使用。
1.1 准备工作
在开始之前,请确保安装了 Node.js 的最新版本。使用 Node.js 最新的长期支持版本(LTS - Long Term Support),是理想的起步。使用旧版本,你可能遇到各种问题,因为它们可能缺少 webpack 功能以及/或者缺少相关 package 包。
1.2 本地安装
最新的webpack版本是:webpack v5.0.0。
首先我们创建一个目录,初始化 npm:
mkdir webpack-example
cd webpack-example
npm init -y
然后在本地安装 webpack,要安装最新版本或特定版本,请运行以下命令之一:
npm install --save-dev webpack
npm install --save-dev webpack@<version>
如果你使用 webpack 4+ 版本,你还需要安装 cli,webpack-cli 可以帮助我们在命令行里使用npx ,webpack等相关指令。
npm install --save-dev webpack-cli
当你在本地安装 webpack 后,你能够从 node_modules/.bin/webpack 访问它的 bin 版本。
我们可以通过运行一下命令,检测webpack是否安装成功:
webpack -v //command not found 默认在全局环境中查找
npx webpack -v // npx帮助我们在项⽬目中的node_modules⾥查找webpack
1.3 全局安装(不推荐)
以下的 npm安装方式,将使 webpack 在全局环境下可用:
npm install -g webpack
不推荐全局安装 webpack。这会将你项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中,可能会导致构建失败。
二 webpack的入口和出口
之前我们曾经说过webpack是一个打包工具,既然是打包工具,那它就应该有一个入口,当webpack处理应用程序时,就会从入口递归的构建一个依赖图,其中包含应用程序所需的每个模块,然后将所有这些木块打包成一个或多个bundle。
webpack支持高度可配置的,我们可以通过创建webpack.config.js文件,配置webpack的入口和出口。
2.1 入口
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
每个依赖项随即被处理,最后输出到称之为 bundle的文件中。
可以通过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src。
接下来我们看一个 entry 配置的最简单例子:
webpack.config.js
module.exports = {
entry: "./src/index.js", //默认的⼊入⼝⽂件
};
2.2 出口
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output 字段,来配置这些处理过程:
webpack.config.js
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
在上面的示例中,我们通过 output.filename 和 output.path 属性,来告诉 webpack 打包后的文件名称,以及文件生成到哪里。可能你想要了解在代码最上面导入的 path 模块是什么,它是一个 Node.js 核心模块,用于操作文件路径。
2.3 修改package.json
修改package.json scripts字段:有过vue react开发经验的同学习惯使用npm run来启动,我们也可以修改下,原理就是模块局部安装会在node_modules/.bin目录下创建一个软链接。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build":"webpack"
},
我们创建src/index.js文件:
function component(){
let element = document.createElement('div');
element.innerHTML = `<pre>这是一个webpack demo</pre>`;
return element;
}
document.body.appendChild(component());
此时在命令行运行npm run build,就相当于直接运行webpack(或者npx webpack)命令,此时就会使用webpack进行打包,会在当前项目下生成一个dist文件夹:
由于webpack打包使用的默认配置文件名称为webpack.config.js,因此我们不用指定配置文件名称,但是我们可以通过--config指定其它的配置文件,比如:
npm run build --config webpackconfig.js //指定webpack使用webpackconfig.js⽂文件来作为配置文件并执行
三 mode
webpack提供mode配置选项,告知 webpack 使用相应模式的内置优化.
module.exports = {
mode: 'production'
};
或者从命令行参数中传递:
webpack --mode=production
mode支持以下字符串值:
- development:会将 process.env.NODE_ENV的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。
- production:会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin.
如果没有设置,webpack会将mode的默认值设置为production。开发阶段的开启会有利于热更新的处理,识别哪个模块变化。生产阶段的开启会有帮助模块压缩,处理副作用等一些功能。
四 loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
在更高层面,在 webpack 的配置中 loader 有两个目标:
- test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
- use 属性,表示进行转换时,应该使用哪个 loader。
4.1 简单示例
例如,你可以使用 loader 告诉 webpack 加载 CSS 文件,或者将 TypeScript 转为 JavaScript。为此,首先安装相对应的 loader:
npm install --save-dev css-loader
npm install --save-dev ts-loader
然后指示 webpack 对每个 .css 使用 css-loader,以及对所有 .ts 文件使用 ts-loader:
webpack.config.js
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
mode: 'production',
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}
};
4.2 常见的loader
style-loader
css-loader
less-loader
sass-loader
ts-loader //将Ts转换成js
babel-loader//转换ES6、7等js新特性语法
file-loader//处理图片子图
eslint-loader
...
4.3 file-loader示例
我们具体介绍以下file-loader的使用,file-loader主要用于处理静态资源模块。
原理是把打包入口中识别出的资源模块,移动到输出目录,并且返回一个地址名称。
所以我们什么时候⽤用file-loader呢?
场景:就是当我们需要模块,仅仅是从源代码挪移到打包目录,就可以使用file-loader来处理,txt,svg,csv,excel,图片资源啦等等
npm install --save-dev file-loader
案例webpack.config.js:
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
mode: 'production',
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
{
test: /\.(png|jpe?g|gif)$/,
//use使⽤用⼀一个loader可以⽤用对象,字符串串,两个loader需要⽤用数组
use: {
loader: "file-loader",
// options额外的配置,⽐如资源名称
options: {
//生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名
name: "[hash].[ext]",
//打包后的存放位置
outputPath: "images/",
}
}
}
]
}
};
修改src/index.js文件:
import image from './image.jpg';
function component(){
let element = document.createElement('img');
element.src = image;
return element;
}
document.body.appendChild(component());
运行npm run build重新打包:
4.4 样式处理
css-loader 分析css模块之间的关系,并合成一个css。
style-loader将css插入到页面的style标签中。
npm install style-loader css-loader --save-dev
less-load 把less语法转换成css。
npm install less less-loader --save-dev
更多样式相关的配置可以参考https://www.cnblogs.com/zyly/p/12631745.html#_label4。
4.5 自己实现一个loader
如果向自己定义一个loader,可以参考https://www.webpackjs.com/contribute/writing-a-loader/。
五 模块
5.1 什么是webpack模块
在webpack里一切皆模块,一个模块对应着一个文件。对比 Node.js 模块,webpack 模块能够以各种方式表达它们的依赖关系,几个例子如下:
- ES2015
import
语句 - CommonJS
require()
语句 - AMD
define
和require
语句 - css/sass/less 文件中的
@import
语句。 - 样式(
url(...)
)或 HTML 文件(<img src=...>
)中的图片链接(image url)
webpack会从配置的entry开始递归找出所有依赖的模块。
module:{
rules:[
{
test:/\.xxx$/,//指定匹配规则
use:{
loader: 'xxx-load'//指定使⽤用的loader
}
}
]
}
当webpack处理到不认识的模块时,需要在webpack中的module选项进行配置,当检测到是什么格式的模块,使用什么loader来处理。
5.2 模块方法
5.3 模块变量
webpack中的模块变量主要有:
module.hot
module.exports
module.process
六 插件
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
想要使用一个插件,你只需要 require()
它,然后把它添加到 plugins
数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new
操作符来创建它的一个实例。
6.1 HtmlWebpackPlugin
htmlwebpackplugin会在打包结束后,自动生成一个html文件,并把打包生成的js模块引入到该html中。
npm install --save-dev html-webpack-plugin
配置:
- title: 用来生成页面的title元素
- filename: 输出的 HTML文件名,默认是 index.html, 也可以直接配置带有子目录
- template: 模板文件路径,支持加载器,比如 src/index.html
- inject: true | 'head' | 'body' | false ,注入所有的资源到特定的template或者 templateContent 中,如果设置为 true 或者body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中
- favicon: 添加特定的 favicon 路径到输出的 HTML 文件中
- minify: {} | false , 传递 html-minifier 选项给 minify 输出
- hash: true | false, 如果为 true, 将添加一个唯一的 webpack 编译
- hash 到所有包含的脚本和 CSS文件,对于解除 cache 很有用。
- cache: true | false,如果为 true, 这是默认值,仅仅在文件修改之后才会发布文件。
- showErrors: true | false, 如果为 true, 这是默认值,错误信息会写入到 HTML页面中
- chunks: 允许只添加某些块 (比如,仅仅 unit test 块)
- chunksSortMode: 允许控制块在添加到页面之前的排序方式,支持的值:'none' | 'default' | {function}-default:'auto'
- excludeChunks: 允许跳过某些块,(比如,跳过单元测试的块)
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
mode: 'production',
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
],
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
{
test: /\.(png|jpe?g|gif)$/,
//use使⽤用⼀一个loader可以⽤用对象,字符串串,两个loader需要⽤用数组
use: {
loader: "file-loader",
// options额外的配置,⽐如资源名称
options: {
//生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名
name: "[hash].[ext]",
//打包后的存放位置
outputPath: "images/",
}
}
}
]
}
};
src/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,
initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
测试在命令行运行npm run build,会在dist下生成index.html文件,并把打包生成的js模块引入到该html中。
右键dist/index.html文件,run 'index/html':
6.2 CleanWebpackPlugin
由于我们每次重新打包时都会在dist下生成文件,而dist目录并不会在打包前自动清理,这回导致我们不知道哪些文件时本次打包生成的。因此,在每次构建前清理 /dist 文件夹,是比较推荐的做法。
clean-webpack-plugin 是一个比较普及的管理插件,让我们安装和配置下。
npm install clean-webpack-plugin --save-dev
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
mode: 'production',
devServer: {
contentBase: "./dist",
open:true,
port:8081
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'}),
new CleanWebpackPlugin(),
],
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
{
test: /\.(png|jpe?g|gif)$/,
//use使⽤用⼀一个loader可以⽤用对象,字符串串,两个loader需要⽤用数组
use: {
loader: "file-loader",
// options额外的配置,⽐如资源名称
options: {
//生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名
name: "[hash].[ext]",
//打包后的存放位置
outputPath: "images/",
}
}
}
]
}
};
webpack 提供许多开箱可用的插件!查阅我们的插件列表获取更多信息。
在 webpack 配置中使用插件是简单直接的,然而也有很多值得我们进一步探讨的用例。
6.3 自己定义一个插件
如果想自己定义一个插件,可以参考博客https://www.webpackjs.com/contribute/writing-a-plugin/。
七 开发
7.1 source map
当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原始位置。例如,如果将三个源文件(a.js
, b.js
和 c.js
)打包到一个 bundle(bundle.js
)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会简单地指向到 bundle.js
。这并通常没有太多帮助,因为你可能需要准确地知道错误来自于哪个源文件。
为了更容易地追踪错误和警告,JavaScript 提供了 source map 功能,将编译后的代码映射回原始源代码。如果一个错误来自于 b.js
,source map 就会明确的告诉你。
source map 有很多不同的选项可用,请务必仔细阅读它们,以便可以根据需要进行配置。
在这里,我们使用 inline-source-map
选项,这有助于解释说明我们的目的(仅解释说明,不要用于生产环境):
webpack.config.js推荐配置:
devtool:"cheap-module-eval-source-map",// 开发环境配置
devtool:"cheap-module-source-map", // 线上⽣生成配置
devtool,选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。
7.2 WebpackDevServer
每次改完代码都需要重新打包⼀次,打开浏览器器,刷新⼀次,很麻烦。我们可以安装使⽤WebpackDevServer来改善这块的体验。
启动服务后,会发现dist目录没有了,这是因为devServer把打包后的模块不会放在dist目录下,而是放到内存中,从而提升速度。
npm install webpack-dev-server --save-dev
在webpack.config.js配置
devServer: {
contentBase: "./dist",
open:true,
port:8081
},
由于我安装的最新的webpack v5.0.0,webpack-cli v4.0.0,和webpack-dev-server不兼容,所以我卸载了webpack、webpack-cli和webpack-dev-server:
npm uninstall webpack webpack-cli webpack-dev-server
然后安装指定版本:
npm install webpack-dev-server@3.10.3 webpack@4.42.0 webpack-cli@3.1.2 --save-dev
修改下package.json,添加start脚本:
{
"name": "webpack-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack-dev-server"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"file-loader": "^6.1.1",
"html-webpack-plugin": "^4.5.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.10.3"
}
}
运行npm run start,打开页面:
如果现在修改和保存任意源文件,web 服务器就会自动重新加载编译后的代码。webpack-dev-server
带有许多可配置的选项。转到相关文档以了解更多。
7.3 WebpackDevMiddleware
webpack-dev-middleware 是一个容器(wrapper),它可以把 webpack 处理后的文件传递给一个服务器(server)。 webpack-dev-server 在内部使用了它,同时,它也可以作为一个单独的包来使用,以便进行更多自定义设置来实现更多的需求。具体使用可以移步官网,官网例子展示了如何使用webpack-dev-middleware启动一个应用程序。
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了