Webpack 2024 前端架构老鸟的分享(一)
简述
嘿,各位!作为一个Webpack的老用户,我得吐槽一句,这玩意儿一开始真是够折腾人的!别说配置文件了,就像是在写某种古老的神秘仪式的咒语。刚开始的时候,我简直是摸不着头脑啊!但是别慌,慢慢来,慢慢琢磨,你会发现Webpack这个家伙,虽然有点拗口,但一旦掌握了它的精髓,就像是驾驭了一匹烈马一样,带你疾驰在前端的征途上!
你可能收货
关于webpack暂时计划是出三期,你将会学到基本的配置,和常用的插件的使用,以及一些基础原理和生命周期的流转,第三篇会教大家如何编写一个自己的loader,以及深入理解loader的原理。
读白
当然说到这里,很多人会说:"现在vite这么火为什么我不直接去用Vite呢?🙄"
统一回复:"新鲜事物赞成积极尝试,且Vite后面我们也会单独说,但是旧的事物必然有存在的意义,😄且企业并不希望你用什么新技术炫技或者变动太大,所有我们温故,遂而知新,认同这种观点你可以继续看下去 第一章也比较简单,但是如果你的动手能力强直接去官网研究是最好的,好了废话有点多,不影响大家继续学习🌹。"
一、Webpack 概念和基础知识
1.1 Webpack 简介
Webpack 不仅是一个模块打包工具,更是一个强大的构建工具。它可以充分利用现代 JavaScript 的优势,并将其内置的丰富功能发挥到极致。Webpack 的主要应用场景有:
- 单页面应用程序(SPA)
- 与框架如 React、Vue 等配合使用
- 适用于需要对代码、资源进行复杂处理的大型项目
Webpack 优势:
- 代码拆分 自动化资源文件的拆分,有利于减少首次加载时间和提高文件缓存利用率。
- Loader Webpack 本身只能处理 JavaScript 模块,通过 Loader 可以使它支持其他格式的文件。
- 智能解析 能够解析常用的模块化方案,例如 CommonJS、AMD、ES Module。
- 插件系统 通过插件系统可以实现更加复杂、自动化的功能。
- 环境支持 既可以运行在开发环境,又可以供生产环境使用。
1.2 Webpack 核心概念
- 入口(Entry) 指定 Webpack 构建的入口模块文件,可以是单个文件,也可以是多个文件组成的数组或对象。
示例:
js
module.exports = {
entry: './src/index.js' // 单入口
entry: ['./src/index.js', './src/app.js'] // 多入口数组
entry: {
main: './src/index.js',
app: './src/app.js'
} // 多入口对象
}
- 输出(Output) 指定 Webpack 构建后的资源输出位置和输出文件名称。
示例:
js
const path = require('path');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'), // 输出目录
filename: 'bundle.js' // 输出文件名
}
}
- Loader Loader 用于对模块的源代码进行转换,扩展 Webpack 的能力。
示例:
js
module.exports = {
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
}
}
- 插件(Plugins) 插件用于执行更广泛的任务,例如打包优化、资源管理等。
示例:
js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
二、Webpack 配置文件详解
2.1 入口(Entry)
入口是 Webpack 构建的起点,可以按需配置单个或多个入口。
单入口语法
js
module.exports = {
entry: './src/index.js'
}
多入口语法
js
module.exports = {
entry: {
app: './src/app.js',
admin: './src/admin.js'
}
}
以上示例中,Webpack 会为每个入口构建一个 Chunk(输出文件)。
动态入口语法
什么是动态入口?
动态入口是指在 Webpack 构建过程中动态生成入口模块路径的一种机制。与传统的静态入口不同,动态入口可以根据不同的条件或环境生成不同的入口模块路径,从而实现更灵活的构建配置。
基础配置:
js
entry: () => './src/index.js'
动态入口的优势
动态入口具有以下优势:
- 提高可扩展性: 可以根据不同的需求或环境动态生成入口模块路径,从而提高 Webpack 配置的可扩展性。
- 简化配置: 可以避免重复的配置,使 Webpack 配置更加简洁易懂。
- 提高代码复用: 可以将通用的代码提取到单独的模块中,并在不同的入口模块中进行复用。
动态入口的实现
动态入口可以通过以下两种方式实现:
- 使用函数: 可以使用函数返回一个入口模块路径字符串或数组。
- 使用
webpack.DefinePlugin
插件: 可以使用webpack.DefinePlugin
插件定义一个全局变量,并使用该变量来动态生成入口模块路径。
使用函数实现动态入口
js
entry: () => {
const env = process.env.NODE_ENV;
if (env === 'development') {
return './src/index.dev.js';
} else {
return './src/index.prod.js';
}
}
上述代码根据 NODE_ENV
环境变量来动态生成入口模块路径。在开发环境下,入口模块路径为 ./src/index.dev.js
;在生产环境下,入口模块路径为 ./src/index.prod.js
。
使用 webpack.DefinePlugin
插件实现动态入口
js
module.exports = {
entry: './src/index.js',
plugins: [
new webpack.DefinePlugin({
'process.env.ENTRY_MODULE': JSON.stringify('./src/index.dev.js'),
}),
],
};
上述代码使用 webpack.DefinePlugin
插件定义了一个全局变量 process.env.ENTRY_MODULE
,并将其值设置为 ./src/index.dev.js
。然后,可以在入口模块中使用该变量来动态生成入口模块路径。
小结
动态入口是一种灵活的 Webpack 构建机制,可以根据不同的需求或环境生成不同的入口模块路径,从而提高 Webpack 配置的可扩展性、简化配置和提高代码复用。
2.2 输出(Output)
output 选项用于控制 Webpack 构建后的资源输出位置和文件名称。
js
const path = require('path');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'), // 输出路径
filename: 'bundle.js', // 输出文件名
publicPath: '/', // 公共路径
chunkFilename: '[name].bundle.js', // 代码分割后的命名
libraryTarget: 'var', // 库导出方式
library: 'MyLibrary' // 库名称
}
}
2.3 模式(Mode)
mode 用于指定当前的构建环境,可选值有 production、development 或 none。
js
module.exports = {
mode: 'production' // 生产环境
mode: 'development' // 开发环境
}
2.4 模块(Module)
module 选项用于配置模块的解析规则,例如使用哪些 Loader。
js
module.exports = {
module: {
rules: [
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
}
2.5 解析(Resolve)
resolve 选项用于设置模块解析规则,例如别名、扩展名等。
js
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
},
extensions: ['.js', '.jsx', '.json'],
modules: ['node_modules']
}
}
2.6 插件(Plugins)
plugins 选项用于应用各种 Webpack 插件。
js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new CleanWebpackPlugin(['dist'])
]
}
2.7 优化(Optimization)
optimization 选项用于优化构建结果。
js
module.exports = {
optimization: {
minimize: true, // 开启代码压缩
splitChunks: {
chunks: 'all' // 代码分割
}
}
}
2.8 devServer
devServer 选项用于配置 Webpack 开发服务器。
js
module.exports = {
devServer: {
contentBase: './dist',
hot: true, // 热更新
open: true, // 自动打开浏览器
port: 8080, // 端口号
proxy: { // 代理设置
'/api': 'http://localhost:3000'
}
}
}
基础小节
示例:
为了演示三级标题提到的Webpack配置,我们将创建一个简单的项目结构,并添加一个入口文件和一个HTML模板文件。然后,我们将使用Webpack进行打包,并通过Webpack DevServer在开发服务器上进行实时预览。
首先,创建一个名为webpack-demo
的新目录,并在其中创建以下文件和目录结构:
bash
webpack-demo/ // 项目根目录
|- src/ // 存放项目的源代码
| |- index.js // 项目的入口文件
|- dist/ // Webpack 构建后的输出目录
|- index.html // 项目的 HTML 模板文件
|- package.json // npm 包的配置文件
|- webpack.config.js // Webpack 的配置文件
接下来,我们按照以下步骤编辑这些文件:
src/index.js
- 这是我们的入口文件,内容可以是简单的JavaScript代码,作为演示,我们将在这里输出一条简单的日志信息:
js
console.log("Hello from webpack!");
index.html
- 这是我们的HTML模板文件,Webpack会根据配置在dist
目录中生成一个新的HTML文件,并注入打包后的JavaScript文件。这里我们简单写一个HTML框架:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack Demo</title>
</head>
<body>
<div id="app">Hello Webpack </div>
</body>
</html>
webpack.config.js
- 这是我们的Webpack配置文件,我们按照之前提到的配置内容来编写:
js
const path = require('path'); // 引入 Node.js 的 path 模块,用于处理文件路径
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入 HtmlWebpackPlugin 插件,用于生成 HTML 文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 引入 CleanWebpackPlugin 插件,用于清理构建目录
module.exports = {
mode: 'development', // 指定构建模式为开发模式
entry: './src/index.js', // 指定入口文件为 src 目录下的 index.js 文件
output: {
path: path.resolve(__dirname, 'dist'), // 指定输出目录为当前目录下的 dist 文件夹
filename: 'bundle.js', // 指定输出文件名为 bundle.js
},
module: {
rules: [ // 配置 Loader 规则
{
test: /.js$/, // 匹配以 .js 结尾的文件
exclude: /node_modules/, // 排除 node_modules 目录下的文件
use: { // 使用 babel-loader 进行转译
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'] // 使用 @babel/preset-env 进行转译
}
}
}
]
},
plugins: [ // 配置插件
new CleanWebpackPlugin(), // 在每次构建前清理 dist 目录
new HtmlWebpackPlugin({ // 生成 HTML 文件
template: './index.html' // 指定 HTML 模板文件
})
],
devServer: { // 配置开发服务器
static: {
directory: path.resolve(__dirname, 'dist'), // 指定服务器内容的基础目录
},
port: 8080, // 指定端口号为 8080
open: true, // 自动在浏览器中打开
hot:true //开启热更新
}
};
package.json
- 添加必要的依赖和脚本:
js
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "A simple webpack demo",
"main": "index.js",
"scripts": {
"start": "webpack serve --open",
"build": "webpack"
},
"keywords": [
"webpack",
"demo"
],
"author": "Your Name",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/preset-env": "^7.16.0",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^4.0.0",
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.66.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.8.0"
}
}
安装所需的依赖:
bash
npm install //安装所有依赖 这里就不一一安装了直接使用我的package.json就好了
现在,我们已经准备好了我们的Webpack配置和项目文件。要执行打包并启动开发服务器,请运行以下命令:
bash
npm start
Webpack将开始构建项目,并在浏览器中打开一个新的选项卡,显示我们的页面。你可以在控制台中看到来自Webpack的输出信息,以及我们在src/index.js
中添加的日志信息。
这样就完成了简单的Webpack配置和项目设置。你自己可以根据需要扩展配置,并添加更多的功能和插件来满足项目的需求。