webpack project setup
在本练习中,我们将从一个空文件夹开始,创建一个 Webpack 项目。
- 配置package.json
webpack是一个Node.js包,要使用node.js包,我们需要package.json来存储项目的元数据
在终端运行以下命令来初始化一个 package.json 文件:
npm init -y
-y 标志表示使用默认值,无需手动输入信息。
- 安装 Webpack 和 Webpack CLI
我们需要安装两个软件包:
webpack(Webpack 的核心功能)webpack-cli(提供命令行访问 Webpack 的能力)
因为这些工具仅在开发环境中使用,不会影响最终的产品,所以我们将它们作为 开发依赖(devDependencies) 安装:
npm install --save-dev webpack webpack-cli
安装后,package.json 文件中的 devDependencies 字段会列出这些依赖项。
- 创建 Webpack 入口文件
webpack需要一个入口文件(entry point)作为项目的主文件,如果没有入口文件,webpack会报出错误。Webpack 默认的入口文件 是 src/index.js,我们需要手动创建它:
mkdir src
touch src/index.js
webpack是一个 模块打包工具(module bundler) ,它的主要功能是分析依赖关系并打包代码。Webpack 需要一个起点(入口文件,entry point) 来确定从哪里开始分析依赖,然后构建整个依赖图(dependency graph) ,并把所有用到的模块打包成一个或多个文件。 **简单来说,入口文件的作用是: ** ✅ 告诉 Webpack 从哪里开始 分析项目
✅ 让 Webpack 找到所有被依赖的文件
✅ 生成最终的 打包文件(bundle.js 或其他格式)
- 定义build命令
在 package.json 的 scripts 部分,我们可以添加一个 build 命令,方便运行 Webpack:
"scripts": {
"build": "webpack --watch"
}
webpack:运行 Webpack--watch:监听文件变化,自动重新打包
- 运行webpack构建
现在,我们可以在终端运行以下命令来执行 build:
npm run build
打包一个JavaScript文件
在本次练习中,我们将用Webpack来处理项目中的一个JavaScript文件。
大文件加载时间比较长,然而,随着项目变得越来越庞大和复杂,代码量也会随之增加。我们可以尝试用尽可能少的字符来编写代码,但这样会使代码变得难以阅读。那么,有没有办法既能写出易读的代码,又能让它下载得更快呢?
构建工具(Build Tools) 让我们能够做到这一点。我们可以使用函数、注释等方式来提高代码的可读性,而 Webpack 在创建供最终用户使用的内容时,会移除大部分不必要的部分。这样,我们可以编写易读的代码,并通过 Webpack 处理它,然后将优化后的版本提供给用户。两者显示的内容相同,而用户不会察觉其中的区别。
现在,让我们来练习使用 Webpack 处理 JavaScript 文件,并查看 Webpack 优化后的输出!
运行npm run build
index.js:
const greetUser = () => {
console.log('Hello User!');
}
const askUserStatus = () => {
console.log('How are you?');
}
greetUser();
askUserStatus();
webpack处理后的代码:
console.log("Hello User!"),console.log("How are you?");
打包多个JavaScript文件
在本练习中,我们将练习使用 Webpack 来打包多个 JavaScript 文件。
点击右侧的文件夹图标,查看项目的文件结构。我们的 src 目录中有三个 JavaScript 文件:greetUser.js 和 myUser.js 提供工具函数和数据,而 index.js 负责使用这些功能。
在传统的静态 Web 项目中,我们通常需要在 HTML 页面中手动引入所有这三个脚本文件,并且要确保它们按照正确的顺序加载。随着项目变得越来越复杂,管理和导入这些脚本会变得更加困难。而 Webpack 这样的构建工具可以让资源的引入更加简单。
Webpack 允许我们在前端文件(不仅限于 JavaScript)中使用 import 和 export 语句。当我们运行 Webpack 进行构建时,它会自动将所有文件整合在一起,就像它们原本是一个单独的文件一样。如果你需要复习 ES6 模块语法,可以参考**《使用 ES6 语法实现模块化》**文章。
现在,让我们来练习使用 Webpack 打包多个 JavaScript 文件吧!
- 导入greetUser和myUser中的数据到index greetUser:
const greet = (username, firstName) => {
console.log(`Hello ${username}, or should I call you ${firstName}?`);
}
export {greet};
myUser:
onst user = {
username: 'Beepum',
firstName: 'Gert'
};
export {user};
index.js:
import {user} from './myUser.js';
import {greet} from './greetUser.js';
greet(user.username, user.firstName);
npm run build之后,可以看到webpack打包后的结果:
(()=>{"use strict";console.log("Hello Beepum, or should I call you Gert?")})();
创建webpack config
到目前为止,我们一直在没有任何配置或设置的情况下使用webpack,现在让我们开始自定义webpack
Webpack 会自动查找名为 webpack.config.js 的配置文件。我们可以使用 module.exports 语法在其中定义 Webpack 的设置。可以先定义一个空的配置文件,如下所示:
module.exports = {
}
Webpack 一直在警告我们未设置 mode,你可能已经在输出中看到类似的提示:
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
现在,我们有了一个配置文件,可以在其中设置 mode:
module.exports = {
mode: 'development'
}
development 模式用于开发阶段,会生成更易读的输出版本。而当我们的项目开发完成后,我们会切换到 production 模式,使输出更紧凑,减少文件大小,提高性能。你可以在 Webpack 官方文档中了解更多关于 mode 的信息。
定义入口和出口文件
在本练习中,我们将使用 Webpack 的配置文件来更改 Webpack 查找要打包的文件的位置,以及存放输出文件的位置。
到目前为止,我们一直使用 Webpack 的默认入口文件 ./src/index.js。然而,在项目开发中,主文件通常存储在不同的文件夹或采用不同的命名方式。
假设我们希望在 application/home.js 中编写我们的主要应用程序代码。我们可以在 Webpack 配置文件中定义一个入口点,告诉 Webpack 这是主文件,并应从这里开始打包:
entry: './application/home.js'
入口点允许我们定义一个相对于 webpack.config.js 位置的路径。
此外,我们可能还想指定输出文件的名称或存放的目录。例如,如果我们希望打包后的 JavaScript 文件存放在 built 目录下,并命名为 fast.js,则可以定义一个出口点。
与入口点不同,出口点需要一个绝对路径,最好的做法是使用 Node 的 path 模块来指定路径。我们可以在 output 选项下进行如下设置:
const path = require('path');
module.exports = {
entry: './application/home.js',
output: {
filename: 'fast.js',
path: path.resolve(__dirname, 'built'),
},
// ...
}
const path = require('path');
module.exports = {
entry: './uncooked/ingredients.js',
mode: 'development',
output: {
filename: 'soup.js',
path: path.resolve(__dirname, 'steamy')
}
}
filename指定打包后的 JavaScript 文件名称。path指定打包文件存放的目录,path.resolve(__dirname, 'built')会将当前目录路径 (__dirname) 与built目录合并,生成绝对路径。- path.resolve(__dirname, 存放文件目录)
根据以上配置,运行 Webpack 后会生成 built/fast.js 文件。
使用 Webpack Dev Server 预览我们的应用
在本练习中,我们将使用一个名为 webpack-dev-server 的工具来预览代码,并在我们进行更改时自动更新页面。
- 安装 webpack-dev-server
首先,我们需要将
webpack-dev-server作为开发依赖项安装到本地环境中:
npm install --save-dev webpack-dev-server
- 创建 HTML 文件 接下来,我们需要一个 HTML 文件,并且它应该引入 Webpack 生成的 JavaScript 文件(也就是出口文件):
<script src="./dist/main.js"></script>
- 修改 package.json 添加启动命令
我们需要在 package.json 文件的 scripts 部分添加 start 命令,以便使用 webpack-dev-server:
"scripts": {
"build": "webpack --watch",
"start": "webpack serve"
}
- 运行 Webpack Dev Server
这两个命令的作用:
build命令用于编译项目,并在文件变更时重新构建。start命令用于运行 Webpack 开发服务器,并在构建变更时自动刷新页面。
为了使项目在我们修改代码时自动更新,通常我们需要在 两个终端窗口 中运行这些命令:
- 在第一个终端窗口 运行
build命令,创建bundle.js并监听更新:
npm run build
- 在第二个终端窗口 运行
start命令,启动 Webpack 开发服务器并在浏览器中预览:
npm run start
webpack规则
在本练习中,我们将介绍 Webpack 的规则系统,并练习为项目中的 .txt 文件定义一条规则。
Webpack 使用 规则(rules) 来决定如何处理不同类型的文件。Webpack 期望在 module 配置选项中提供一个规则数组,其语法如下:
module.exports = {
module: {
rules: []
}
}
定义规则
规则中需要定义 test 选项,它是一个 正则表达式。如果某个文件的名称匹配该正则表达式,Webpack 就会对该文件应用相应的规则。例如,如果我们定义 test 为 /.txt$/i,那么这个规则就会适用于所有以 .txt 结尾的文件。
除了 test 之外,我们还需要告诉 Webpack 如何处理匹配的文件。不同的文件类型,处理方式也不同。
对于 .txt 文件,我们可以在 rules 数组中添加以下规则:
rules: [
{
test: /\.txt$/i,
type: 'asset/source'
}
]
其中,type: 'asset/source' 表示 .txt 文件是一个 资源文件,可以直接作为 源代码 引入,无需额外处理。
使用规则
定义规则后,我们可以在代码中导入 .txt 文件,例如:
import Text from './example.txt';
document.querySelector('h1').innerHTML = Text;
运行后,页面上 h1 元素的内容将被 .txt 文件的内容替换。
将css添加到webpack构建中
现在,我们将把 CSS 样式表 添加到 Webpack 项目中。
CSS 规则的配置
CSS 规则的 test 选项结构与 .txt 文件规则类似:
test: /\.css$/i
不过,与 .txt 文件不同,CSS 文件 需要加载器(loaders) 来让 Webpack 处理。对于需要加载器的文件,规则中不能使用 type 选项,而是要使用 use 选项。
CSS 需要 两个加载器:
css-loader:从.css文件中提取 CSS 并添加到 JavaScript 代码中。style-loader:将css-loader处理后的 CSS 代码注入到 HTML 的<style>标签中。
注意:Webpack 按从右到左的顺序 应用加载器,因此我们要 先 使用 css-loader,再使用 style-loader。
完整的 CSS 规则如下:
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
}
我们可以将这条规则添加到 rules 数组中的任意位置。
安装 CSS 加载器
在本地环境下,我们需要将这些加载器安装为 开发依赖(devDependencies) :
npm install --save-dev style-loader css-loader
在 JavaScript 中导入 CSS
安装完成后,我们可以直接在 JavaScript 文件中 导入 CSS,方法如下:
import './style.css';
import Text from './example.txt';
document.querySelector('h1').innerHTML = Text;
当我们构建项目并启动 Webpack 预览服务器后,CSS 就会自动应用到 HTML 页面上!
通过link导入css与在webpack通过JavaScript导入css的区别:
- 代码模块化 & 依赖管理
Webpack 允许我们 在组件级别 直接导入 CSS,而不是全局引入。
假设我们有一个 Button.js 组件,并且它有自己的样式 button.css:
import './button.css';
export function Button() {
const btn = document.createElement('button');
btn.textContent = 'Click Me!';
return btn;
}
这样,每个组件可以管理自己的 CSS,而不需要在 HTML 中手动引入所有的样式文件。
- CSS 代码优化 & 按需加载
当 Webpack 处理 CSS 时,它可以:
去掉未使用的 CSS 代码(Tree Shaking)
自动优化 CSS(压缩、去除空格等)
支持代码拆分(Code Splitting) ,只加载当前页面需要的 CSS,而不是整个站点的所有 CSS。
例如,在一个单页应用(SPA)中,Webpack 可以让不同页面的 CSS 按需加载,减少首屏加载时间。
- 让 CSS 兼容所有浏览器
通过 css-loader,Webpack 可以自动处理 CSS 兼容性问题,比如:
- 自动添加厂商前缀(Autoprefixer) ,让 CSS 适配不同浏览器:
.box {
display: flex;
}
经过处理后,Webpack 可能会自动生成:
.box {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
- 适配不同的构建环境
Webpack 可以根据不同的模式(development 或 production)使用不同的 CSS 处理方式:
- 开发环境:通过
style-loader直接在 HTML 里插入<style>,支持热更新(HMR)。 - 生产环境:用
MiniCssExtractPlugin把 CSS 提取到独立文件,减少 JS 体积,提高性能。
将图片添加到 Webpack 构建中
让我们看看如何使用 Webpack 打包图片资源。
自 Webpack 5 以来,图片和字体不再需要额外的 loader,而是可以直接使用 Webpack 的 asset 资源系统。其规则与 .txt 文件的处理方式类似:
{
test: /\.png$/i,
type: 'asset/resource'
}
请注意,我们使用 type: 'asset/resource' 而不是 asset/source。
asset/resource会在构建时生成一个独立的文件,并将其作为 URL 引入代码中。- 如果你想了解更多 Webpack 资源类型,可以进行深入探索。
上面的规则仅适用于 .png 文件,但我们也可以让它同时处理多种图片格式,如:
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
}
如何在 JavaScript 中使用图片?
import Square from '../square.png';
const img = document.createElement('img');
img.src = Square;
const body = document.querySelector('body');
body.appendChild(img);
这样,当我们执行 Webpack 构建时,图片将会被打包并正确加载到网站中!
webpack添加图片的好处
- 资源路径处理
HTML 方式 (<img src="xxx.png">)
-
你必须手动确保
src指向正确的路径,比如src="./images/pic.png"。 -
如果文件路径变了(比如 Webpack 生成的路径是
dist/abc123.png),你需要手动更新 HTML 代码,否则图片可能无法加载。
Webpack 方式 (import Square from '../square.png')
-
Webpack 会自动处理路径,比如它可能会重命名图片文件(如
abc123.png)并自动更新src,避免缓存问题。 -
你不用关心图片的最终存放位置,Webpack 会在
dist/目录下生成正确的文件,并自动调整引用路径。
- 图片优化
-
HTML 方式
- 浏览器直接请求
img src="xxx.png",不会进行额外优化。 - 需要手动使用工具(如 TinyPNG)压缩图片,或者使用 WebP 等格式。
- 浏览器直接请求
-
Webpack 方式
-
Webpack 可以自动优化图片,比如:
- 压缩图片(需要
image-webpack-loader) - 转换格式(比如
png变webp) - 懒加载(lazy load) ,减少不必要的加载,提高性能。
- 压缩图片(需要
-
- 代码可维护性
-
HTML 方式
-
适用于静态图片(如 logo)。
-
但如果是动态内容(比如用户头像、商品图片等),你可能需要用 JavaScript 手动修改
src,例如:js 复制编辑 document.querySelector('img').src = 'new-image.png';
-
-
Webpack 方式
-
适用于动态管理资源,比如根据逻辑动态加载不同的图片:
js 复制编辑 import DayImage from './day.png'; import NightImage from './night.png'; const img = document.createElement('img'); img.src = isDaytime ? DayImage : NightImage; document.body.appendChild(img); -
Webpack 还能配合 tree shaking,只打包真正用到的图片,而不会把所有图片都塞进最终构建。
-
将字体添加到我们的构建中
在本练习中,我们将向项目中添加字体。
字体的 Webpack 规则与图片的规则类似:
{
test: /\.ttf$/i,
type: 'asset/resource'
}
上面的规则用于处理 .ttf 格式的字体文件,但我们可能希望支持多种字体格式:
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource'
}
上面的规则可以处理 .woff、.woff2、.eot、.ttf 和 .otf 格式的字体文件。
与我们之前见过的其他资源不同,字体文件通常在 CSS 中导入,而不是在 JavaScript 中。我们可以在 CSS 中这样使用字体:
@font-face {
font-family: 'Roboto-Black';
src: url('../Roboto-Black.ttf');
}
h1 {
font-family: 'Roboto-Black';
}
url 指定了字体文件的位置,font-family 定义了字体的名称,我们可以在 CSS 其他地方引用它。
当我们构建项目后,就可以看到字体效果了!