webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具
当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图,然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
下面有些核心概念,需要理解和掌握:
# 二、核心概念
# 入口(entry)
入口起点(entry point) 指示 webpack 应该使用哪个模块,作为构建其内部依赖的开始
entry 可以是相对路径,也可以是绝对路径
默认值是 ./src/index.js
,也可以通过 webpack config.js中配置entry
属性,来指定一个(或多个)不同的入口起点,如:
// webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
# 单个入口(简写)语法
entry
属性的单个入口语法,是以下形式的简写:
module.exports = {
entry: {
main: './path/to/my/entry/file.js',
},
};
多入口写法:
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
# 对象语法
用法:entry: { <entryChunkName> string | [string] } | {}
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};
对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。
“webpack 配置的可扩展” 是指,这些配置可以重复使用,并且可以与其他配置组合使用
当你通过插件生成入口时,你可以传递空对象
{}
给entry
。
描述入口的对象
用于描述入口的对象。你可以使用如下属性:
dependOn
: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename
: 指定要输出的文件名称。import
: 启动时需加载的模块。library
: 指定 library 选项,为当前 entry 构建一个 library。runtime
: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为false
以避免一个新的运行时 chunk。publicPath
: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath (opens new window)。
module.exports = {
entry: {
a2: 'dependingfile.js',
b2: {
dependOn: 'a2',
import: './src/app.js',
},
},
};
确保 runtime
不能指向已存在的入口名称,runtime
和 dependOn
不应在同一个入口上同时使用,另外 dependOn
不能是循环引用的
下面的例子都是会出现错误的:
module.exports = {
entry: {
a2: './a',
b2: {
runtime: 'x2',
dependOn: 'a2',
import: './b',
},
},
};
module.exports = {
entry: {
a1: './a',
b1: {
runtime: 'a1',
import: './b',
},
},
};
module.exports = {
entry: {
a3: {
import: './a',
dependOn: 'b3',
},
b3: {
import: './b',
dependOn: 'a3',
},
},
};
# 常见场景
分离 app(应用程序) 和 vendor(第三方库) 入口
多页面应用程序
# 输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js
,其他生成文件默认放置在 ./dist
文件夹中。
output 必须是绝对路径
可以通过在配置中指定一个 output
字段,来配置这些处理过程:
const path = require('path'); // 用于操作文件路径
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
# loader
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力
loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块 (opens new window),以供应用程序使用,以及被添加到依赖图中。
loader:大致分为三类
- 编译转换
- 文件操作
- 代码检查
webpack 的其中一个强大的特性就是能通过
import
导入任何类型的模块(例如.css
文件),其他打包程序或任务执行器的可能并不支持。
在更高层面,在 webpack 的配置中,loader 有两个属性:
test
属性,识别出哪些文件会被转换。use
属性,定义出在进行转换时,应该使用哪个 loader。
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: { // 一个单独的 module 对象
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
loader:css样式编译(注意loader顺序,css-loader第一个执行)
- 依赖:
> npm install css-loader --save-dev
> npm install style/core --save-dev
- 配置:
module: {
rules: [
{
test: /.css$/, // 匹配文件
use: [// use指定使用到的loader
'style-loader', // 将css-loader转换后的结果放到style标签里面
'css-loader' // 先执行css-loader,而且是从后往前执行,所以需要放到下面
]
}
]
}
loader:编译ES6+ => babel
- 依赖:
> npm install babel-loader --save-dev => babel 转换平台
> npm install @babel/core --save-dev => babel 核心模块
> npm install @babel/preset-env --save-dev => babel 转换语言包,env表示es6+全量包
- 配置:
- babel-loader:
{// 转换js代码,es6+=>es5
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
- babel.config.js(配置可以提取出来:.babelrc、.babelrc.js、babel.config.js、package.json 文件):
// .babelrc 只会影响本项目中的代码;babel.config.js 会影响整个项目中的代码,包含node_modules中的代码
// 推荐使用:babel.config.js
module.exports = {
presets: [
'@babel/preset-env'
]
}
loader:文件/图片处理
- 依赖:
> npm install file-loader --save-dev
> npm install url-loader --save-dev
- 功能:
- file-loader 普通处理
{// 将图片文件复制到另一个目录
test: /\.(png|svg|jpg|gif)$/,
loader: 'file-loader',
options: {
name: '[name]-[contenthash:8].[ext]',
outputPath: 'images',
esModule: false // 新版loader需要配置,否则会产生错误:img src=[object Module]
},
},
- url-loader 和 file-loader 二选一 url-loader 对 file-loader 有依赖,需要提前安装; url-loader 将图片编码为 Base64 文件:对于小文件座大小限制进行处理,减少请求次数。
{// 将小于10kb的图片编码成base64
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: 'url-loader', // url-loader对file-loader有依赖,需要提前安装
options: {
name: '[name]-[contenthash:8].[ext]',
outputPath: 'images',
limit: 10 * 1024, // 10 KB 对文件大小进行限制,超过就不转换
esModule: false // 新版loader需要配置,否则会产生错误:img src=[object Module]
},
}
}
loader:html处理(用得少,使用其他插件替代)
依赖:
> npm install html-loader --save-dev
# 插件(plugin)
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。
想要使用一个插件,你只需要 require()
它,然后把它添加到 plugins
数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new
操作符来创建一个插件实例。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};
# 模式(mode)
可以选: development
, production
或 none
之中的一个,来设置 mode
参数,其默认值为 production
。
- production 生产模式下,Webpack 会自动优化打包结果;(例如:代码的压缩混淆等)
- development 开发模式下,Webpack 会自动优化打包速度,添加一些调试过程中的辅助
- none 模式下,Webpack 就是运行最原始的打包,不做任何额外处理
module.exports = {
mode: 'production',
};
# 依赖图(dependency graph)
每当一个文件依赖另一个文件时,webpack 都会将文件视为直接存在 依赖关系。这使得 webpack 可以获取非代码资源,如 images 或 web 字体等。并会把它们作为 依赖 提供给应用程序。
当 webpack 处理应用程序时,它会根据命令行参数中或配置文件中定义的模块列表开始处理。 从 入口 (opens new window) 开始,webpack 会递归的构建一个 依赖关系图,这个依赖图包含着应用程序中所需的每个模块,然后将所有模块打包为少量的 bundle —— 通常只有一个 —— 可由浏览器加载。
# 浏览器兼容性(browser compatibility)
Webpack 支持所有符合 ES5 标准 (opens new window) 的浏览器
# 环境(environment)
Webpack 5 运行于 Node.js v10.13.0+ 的版本。
# 二、webpack的尝试
# 2、webpack作用
把静态模块内容,压缩、转译、打包等(前端工程化)
- 把 less/sass 转成 css 代码
- 把 ES6+ 降级成 ES5 等
- 支持多种模块文件类型,多种模块标准语法
# 3、体验Webpack 打包 2 个 JS 文件内容
# 3.1 目标
封装 utils 包,校验手机号和验证码长度,在 src/index.js 中使用,体验使用 Webpack 打包
# 3.2 实现步骤
新建项目文件夹 Webpack_study,初始化包环境,得到 package.json
文件
npm init -y
新建 src文件夹(书写代码)包括 utils/check.js 封装用户名和密码长度函数,引入到 src/index.js 进行使用
src/utils/check.js
// 封装校验手机号长度和校验验证码长度的函数
export const checkPhone = phone => phone.length === 11
export const checkCode = code => code.length === 6
src/index.js
import { checkPhone, checkCode } from './utils/check.js'
console.log(checkPhone('13900002020'))
console.log(checkCode('123123123123'))
下载 webpack webpack-cli 到项目(版本独立)
npm i webpack webpack-cli --save-dev
配置package.json
"scripts":{
"build": "webpack"
}
项目中运行工具命令,采用自定义命令的方式(局部命令)
npm run build
自动产生 dist 分发文件夹(压缩和优化后,用于最终运行的代码)
注意:Webpack 默认入口和出口分别为:
src/index.js 和 dist/main.js
# 三、Webpack 修改入口和出口
项目根目录,新建 Webpack.config.js 配置文件
导出配置对象,配置入口、出口文件路径(别忘了修改磁盘文件夹和文件的名字)
const path = require('path')
module.exports = {
entry: path.resolve(__dirname, 'src/login/index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js'
}
}
重新打包观察
npm run build
# 四、案例练习
- 初始化项目结构
目录结构:
my-webpack-project/
├── src/
│ ├── assets/
│ │ ├── images/
│ │ │ └── logo.png
│ ├── styles/
│ │ ├── main.scss
│ │ └── variables.less
│ ├── index.js
│ └── index.html
├── dist/
├── package.json
├── webpack.config.js
└── .babelrc
- 初始化项目
npm init -y
- 安装依赖
npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin mini-css-extract-plugin css-loader sass-loader node-sass less-loader style-loader babel-loader @babel/core @babel/preset-env file-loader url-loader
src/index.html
内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webpack Project</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
src/index.js
内容
import "./styles/main.scss";
import logo from "./assets/images/logo.png";
const img = document.createElement("img");
img.src = logo;
img.alt = "Logo";
img.style = "width: 200px; height: auto;";
document.getElementById("app").appendChild(img);
console.log("Webpack setup successful!");
src/styles/main.scss
内容
$primary-color: #3498db;
@import "./variables.less";
body {
font-family: Arial, sans-serif;
background-color: $primary-color;
color: @secondary-color;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
src/styles/variables.less
内容
@secondary-color: #2ecc71;
- Webpack 配置 (
webpack.config.js
)
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
clean: true, // 自动清理 dist 文件夹
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.(css|scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader",
],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"less-loader",
],
},
{
test: /\.(png|jpg|gif|svg)$/,
type: "asset/resource",
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "styles.css",
}),
],
devServer: {
static: path.resolve(__dirname, "dist"),
port: 8080,
open: true,
},
mode: "development", // 或 production
};
.babelrc
文件内容
{
"presets": ["@babel/preset-env"]
}
- npm 脚本 (package.json)
"scripts": {
"start": "webpack serve",
"build": "webpack"
}
使用说明:
npm start
: 启动开发服务器.npm run build
: 打包生产环境代码.
# Vite 知识点与使用
# Vite 简介
Vite 是一个现代的前端构建工具,专注于快速开发和构建。相比 Webpack,Vite 的特点是:
- 快速冷启动:使用原生 ES 模块,省去了传统打包工具的模块预处理步骤。
- 即时热更新(HMR):基于浏览器原生功能,速度更快。
- 简单配置:默认配置开箱即用,支持现代框架如 Vue、React。
- 生产环境优化:基于 Rollup 构建,生成高效的生产环境代码。
# Vite 与 Webpack 的比较
特性 | Vite | Webpack |
---|---|---|
构建速度 | 快速冷启动,适合开发环境 | 初次构建较慢,后续有增量优化 |
热更新(HMR) | 高效,依赖 ES 模块 | 较慢,需重新打包部分模块 |
配置复杂度 | 简单,开箱即用 | 灵活但较复杂 |
生产环境打包 | 使用 Rollup,构建高效 | 自身提供,功能丰富 |
社区生态 | 新兴但快速增长 | 成熟且广泛 |
# 使用 Vite 创建项目
# 1. 初始化 Vite 项目
npm create vite@latest my-vite-project
cd my-vite-project
npm install
# 2. Vite 项目目录结构
my-vite-project/
├── public/ # 静态资源目录
├── src/ # 源码目录
│ ├── assets/ # 资源文件
│ ├── main.js # 入口文件
│ ├── App.vue # Vue 文件(Vue 项目示例)
├── index.html # 主 HTML 文件
├── package.json # 项目信息
├── vite.config.js # Vite 配置文件
# 3. 安装插件
根据需要安装插件,如 Vue、React 支持:
npm install @vitejs/plugin-vue
# 4. 启动开发服务器
npm run dev
# 5. 打包生产环境代码
npm run build
# Vite 配置文件 (vite.config.js
)
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
server: {
port: 3000,
open: true,
},
build: {
outDir: "dist",
sourcemap: true,
},
});
# 总结
- Vite 更适合快速开发,特别是针对 Vue、React 等现代框架。
- Webpack 更适合需要复杂自定义的构建场景。
- 学习两者可以灵活应对各种项目需求。