主题
webpack 概述与安装 webpack(Webpack 1/3)
本页对应 课堂视频,共 5 段视频,约 1 小时 55 分。
学习目标
- 能用自己的话说明 webpack 的作用、适用阶段及 entry、output、loader、plugin、mode 五大核心概念,并举例说明开发模式与生产模式打包产物的差异。
- 能在一个 Node 环境中本地安装 webpack 与 webpack-cli,将其加入开发依赖,并使用
npx webpack -v验证安装及版本。 - 能使用零配置方式完成一次打包,并通过命令行参数指定入口、输出目录、输出文件名、多个入口和 mode,解释缺少
src/index.js、未设置 mode、Windows 路径斜杠等常见问题的原因与处理方式。 - 能创建
webpack.config.js,使用 CommonJS 导出 entry、output、mode、clean 等配置,并说明该配置文件为何由运行在 Node 上的 webpack 读取,而业务源码使用 ES Module。 - 能配置单入口/多入口、单出口/多出口,使用
[name]、[contenthash]等占位符生成输出文件,并通过打包结果验证模块化代码被正确合并与执行。 - 能演示将多个 JS/JSON 模块导入入口文件后完成打包,并在 HTML 中引入打包产物验证其可正常运行。
知识点
为什么需要 webpack:从“散装文件”到可运行产物
为什么需要:前端项目越做越大,代码会拆成很多模块;浏览器对 ES Module 的支持并不完整,CSS、图片、字体等资源也不能直接被 JS 入口统一处理。课堂用 ExcelJS、Bootstrap 的源码举例:源码里文件很散,Bootstrap 还通过 less、JS 等文件组织,并借助 Grunt 这类构建工具产出 dist 中可直接使用的文件。怎么想:webpack 是“静态模块打包工具”,它从入口出发构建依赖图,把项目需要的模块组合成浏览器能用的产物。怎么做:记住五大核心概念:entry 入口、output 输出、loader 加载非 JS/JSON 资源、plugins 扩展功能、mode 模式。易错点:不要把 webpack 当成运行时依赖;它主要在开发阶段使用,上线时用户拿的是打包后的产物。
安装:先有 Node,再本地安装 webpack
为什么需要:webpack 运行在 Node 环境上,没有 Node 就谈不上运行 webpack;而 webpack 本身及大量 loader/plugin 又运行在 webpack 之上。怎么想:课堂用“厨房—灶—锅”比喻:Node 是厨房,webpack 是灶,loader/plugin 是各种锅。怎么做:在项目目录安装到开发依赖:
bash
npm i webpack webpack-cli -D
npx webpack -v易错点:不推荐全局安装。全局安装的版本不会写进 package.json,协同开发时容易版本不一致;本地安装可写入开发依赖,并用 npx 执行本地命令。直接运行 webpack -v 可能失败,因为没装全局,要加 npx。
零配置使用:默认入口、默认出口与 mode 警告
为什么需要:webpack 4 起宣传“零配置”,降低上手成本。怎么想:零配置不是万能,只是默认约定:入口 src/index.js,输出 dist/main.js。怎么做:先建 src/index.js,再运行:
bash
npx webpack
npx webpack --mode=development课堂调试时,没有 src/index.js 会报“找不到入口”;运行后出现 dist/main.js。未指定 mode 会警告并 fallback 到 production。开发模式产物不压缩,代码被放进 eval 字符串中,便于统计;生产模式会压缩、优化,简单表达式甚至会被提前计算。易错点:零配置只适合极简场景;真实项目有 HTML、CSS、图片等资源,仍要写配置和 loader/plugin。
指定入口、出口:命令行演示与路径坑
为什么需要:真实入口不一定叫 index.js,输出目录和文件名也常要改。怎么想:命令行参数可临时覆盖默认值,但命令会越来越长。怎么做:
bash
npx webpack ./src/one.js --mode=development
npx webpack ./src/one.js --output-path ./build --output-filename index.js --mode=development多入口可用数组,但仍是“多入口单出口”;若要“多入口多出口”,入口用对象,输出文件名用 [name] 配合。易错点:入口路径要写 ./src/...,不写 ./ 可能被当成模块名而找不到;Windows 下 Tab 补全可能给反斜杠,webpack 读不了,建议手写正斜杠,或把终端换成 Git Bash;项目路径尽量不用中文。
配置文件:webpack.config.js 是 Node 模块
为什么需要:命令行参数太长、难维护。怎么想:webpack 运行在 Node 上,会 require 配置文件,所以配置文件用 CommonJS 的 module.exports;而 src 里给浏览器用的代码用 ES Module 的 import/export。怎么做:
js
const path = require('path')
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name]-[hash].js',
clean: true
},
mode: 'development'
}然后直接运行 npx webpack,它会自动读取配置。output.path 要用绝对路径,课堂用 path.resolve(__dirname, 'dist');clean: true 表示每次打包先清空输出目录;[hash] 会随内容变化,常用于刷新缓存。易错点:output.path 不要只写相对路径;filename 用 [name] 时,多入口对象里的 key 会成为文件名;改内容后 hash 变化,浏览器才会请求新资源。
打包应用演示:入口是 JS,其他资源都是模块
为什么需要:展示模块化前端怎么组织。怎么想:入口仍是 JS,import 其他 JS、JSON;JSON 导入后会被处理成对象/数组。怎么做:建 src/app.js,导入 one.js、two.js、three.js 和 JSON,打包后在 HTML 中引入 dist 产物,而不是直接引入 src/app.js。易错点:浏览器不能直接跑散装源码;dist 可重新生成,src 才是心血,不要误删;开发模式产物含 eval,生产模式更干净、压缩。
webpack 是什么:先把“打包”想明白
为什么需要:前端项目不可能永远只写一个 JS 文件。模块化开发会把代码拆成很多文件,用 import/export 组织;但浏览器对 ES Module 的支持并不完整,源码目录里的文件不能直接丢给浏览器运行。
怎么想:webpack 是“现代 JavaScript 应用程序的打包工具”。它从入口出发,构建依赖图,把项目需要的模块组合成浏览器可运行的结果;前端资源在 webpack 视角下都可以作为模块处理。
怎么做:先建立“源码目录”和“输出目录”的意识:开发时写 src,打包后看 dist。转写中演示 ExcelJS、Bootstrap 时也强调:源码很多很散,最终给浏览器用的是打包后的文件。
易错点:不要把 webpack 当成运行时库。它主要在开发阶段使用;上线给用户的是打包产物。也不要把“零配置”理解成真实项目永远不写配置——只有 JS/JSON 这类资源时它才比较省事。
运行层次与安装:Node → webpack → loader/plugin
为什么需要:webpack 本身是运行在 Node 上的程序,安装和使用都离不开 Node/npm。
怎么想:层次是:电脑装 Node;项目里本地安装 webpack 和 webpack-cli;再按需安装 loader、plugin。转写里用“厨房、灶、各种锅”比喻这个关系。
怎么做:
bash
npm i webpack webpack-cli -D
npx webpack -vwebpack 是核心,webpack-cli 提供命令行能力;-D 表示开发依赖,因为打包工具只在开发阶段用。
易错点:不推荐全局安装。全局安装不会写进 package.json,协同开发时版本可能不一致;本地安装配合 npx 才能在当前项目里执行命令。转写中还提醒:npx webpack -v 会输出 Node、系统、浏览器和 webpack 版本,说明它确实在 Node 环境里跑。
零配置使用:默认入口、默认出口与 mode
为什么需要:webpack 4 之后支持零配置起步,方便先感受打包流程。
怎么想:默认约定是入口 src/index.js,输出 dist/main.js。先不写配置,运行一次看它做什么。
怎么做:
bash
npx webpack
npx webpack --mode development转写中的调试过程是:第一次运行报错,因为项目里没有 src;创建 src/index.js 后再运行,生成 dist/main.js。不指定模式会警告并默认 production;指定 development 后警告消失。开发模式产物中能看到 eval,且不压缩、不做复杂优化;生产模式会压缩优化。
易错点:默认入口不是任意文件;没有 src/index.js 会报错。命令行指定入口时路径要写 ./src/one.js,不写 ./ 可能被当成模块名而找不到。Windows 终端按 Tab 补全可能给出反斜杠,webpack 读不了;转写中通过切换 Git Bash 或手动改正斜杠解决。
命令行改入口、出口与多入口
为什么需要:实际项目入口未必叫 index.js,输出也未必叫 main.js。
怎么想:入口用 --entry 思路指定;输出目录用 --output-path,输出文件名用 --output-filename。多个入口可以先理解为“多个文件一起打包”。
怎么做:
bash
npx webpack ./src/one.js --mode development
npx webpack ./src/one.js ./src/two.js --mode development
npx webpack ./src/two.js --output-path build --output-filename index.js --mode development转写演示了:指定 one.js 后,dist/main.js 里变成 one 的代码;指定两个入口时,最终仍可输出到一个文件里,两个模块的代码都在。
易错点:多个入口用数组时,默认仍是“多入口单出口”;命令行太长易写错,所以后面要用配置文件。输出目录可写多层,但路径规则要清楚。
打包应用演示:ES Module 与 JSON 导入
为什么需要:真实前端要用模块拆分作用域,还要导入 JSON 等资源。
怎么想:前端主流用 ES6 模块规范:export default 暴露,import 引入;webpack 加持后,扩展名可省略,JSON 也能被处理成对象/数组。
怎么做:转写中建 app.js、one.js、two.js、three.js,各自 export default 函数;app.js 中 import 后调用。再建 data.json,用 import users from './json/data.json' 引入并输出。打包后 HTML 不能直接引 src/app.js,而要引 dist/main.js。
易错点:HTML 直接引源码里的模块文件,浏览器可能不认识;JSON 属性名必须用双引号。打包后要看输出目录里的成品。
配置文件:CommonJS 写配置,entry/output 落地
为什么需要:命令行参数一长就难维护;CSS、图片等资源也需要 loader/plugin,必须写配置。
怎么想:webpack 运行在 Node 上,会 require 配置文件,所以 webpack.config.js 用 CommonJS:module.exports = {}。而 src 里写的是给浏览器用的 ES Module,两者不要混。
怎么做:
js
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
clean: true
},
mode: 'development'
};运行 npx webpack 会自动读取配置文件。path.resolve(__dirname, 'dist') 用 Node 的 path 模块生成绝对路径;clean: true 表示每次打包先清空输出目录。
易错点:output.path 需要绝对路径,转写中专门用 __dirname 推导;filename 和 path 分工不同。不要忘记逗号,mode 拼写要准确:development / production。
多入口多出口与 hash:名字由 [name] 决定
为什么需要:极端情况下一个项目要多入口多出口;文件名还常带 hash 便于缓存控制。
怎么想:入口用对象给每个入口起名,出口用 [name] 接收名字;[hash] 根据内容生成,内容变则文件名变。
怎么做:
js
module.exports = {
entry: {
first: './src/one.js',
second: './src/two.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name]-[hash:8].js',
clean: true
},
mode: 'development'
};转写演示生成 first-...js、second-...js;再次打包若内容没变,hash 不变,内容改了才变。
易错点:多入口多出口必须让入口对象和 [name] 配合;不要把所有入口都硬写成同一个固定文件名。hash 主要用于避免浏览器缓存旧资源,不是加密。
先理解:webpack 装在哪里、为什么先装 Node
webpack 本身是一个运行在 Node 环境里的程序,所以安装 webpack 之前,电脑上必须先有 Node。转写稿里反复强调“先安装 Node,再安装 webpack”,因为 webpack 以及它上面的一堆 loader、plugin 都依赖 Node 运行。这里不要把它理解成“我要用 Node 写后端”,在当前阶段,Node 的意义主要是给 webpack 提供运行环境。
为什么需要先弄清这一点?因为后面会看到两种安装方式:全局安装和本地安装。它们装的位置不同,命令能不能直接执行、版本能不能跟着项目走,也完全不同。怎么想?先把 webpack 当成“开发阶段用的工具”,不是上线后还要带到浏览器里的代码。怎么做?先确认本机已安装 Node,再进入项目目录执行安装命令。易错点:不要在任意目录随手安装本地依赖,本地安装会装到当前目录的 node_modules 里,所以要先 cd 到项目根目录。
全局安装:能装,但不推荐作为项目方案
全局安装的写法是:
shell
# 安装
npm install webpack webpack-cli -g
# 使用
webpack -v为什么需要了解全局安装?因为它能让你在命令行任意位置直接使用 webpack 命令,看起来很方便。转写稿里也提到,早期官方文档确实推荐过全局安装,感觉“装一次,一劳永逸”。怎么想?全局安装的问题是:它装在整个电脑上,不会写进当前项目的 package.json。协同开发时,你电脑上的 webpack 版本和别人电脑上的版本可能不一致,打包结果就可能不同。怎么做?如果只是临时了解,可以按上面的命令安装并用 webpack -v 验证;但真实项目更推荐下面的本地安装。易错点:全局安装后命令能直接用,不代表项目依赖被记录;换一台电脑或换一个同事,版本就不一定对得上。
本地安装:推荐方式,让版本跟着项目走
本地安装的写法是:
bash
# 安装
npm install webpack webpack-cli -D
# 使用
npx webpack -v为什么推荐本地安装?转写稿给了两个关键原因:第一,webpack 版本会更新,本地安装会写进 package.json 的开发依赖,别人同步代码后安装到的版本更容易一致;第二,有了 npx,安装在当前项目 node_modules 里的命令行工具也能被执行,不必非得装到全局。怎么想?项目依赖应该由项目自己管理,而不是依赖某台电脑的全局环境。怎么做?在项目根目录执行 npm install webpack webpack-cli -D,其中 -D 表示开发依赖,因为 webpack 只在开发阶段使用。安装后执行 npx webpack -v 验证。易错点:本地安装后直接敲 webpack -v 可能报“找不到命令”,因为当前项目没有全局命令;这时要加 npx。另外,-D 不要漏,漏了默认会进生产依赖,语义就不对了。
webpack 与 webpack-cli 的关系
笔记里特别注明:
① webpack 是核心内容,webpack-cli 是在运行 webpack 命令时,所依赖的一个工具。
② 使用 npx 可以执行安装在本地的命令行可执行命令。
为什么需要同时装两个包?因为 webpack 是核心打包程序,但我们在终端里敲的 webpack 命令需要 webpack-cli 来承接。怎么想?可以把它理解成“核心能力”和“命令行入口”的配合:没有 webpack-cli,命令行工具就跑不起来。怎么做?安装时两个一起装:npm install webpack webpack-cli -D。易错点:只装 webpack 不装 webpack-cli,执行命令时可能提示缺少 CLI;不要把包名写错,也不要以为 webpack-cli 可以替代 webpack 核心。
验证安装:从报错到 npx webpack -v
转写稿里有一个很真实的调试过程:本地安装完成后,直接执行 webpack -v 不好使,因为并没有做全局安装;加上 npx 后执行 npx webpack -v 才成功。成功后会显示 webpack 版本,转写稿里显示的是 5 点几,同时还带出了 Node、npm、操作系统等信息,这是正常现象。
为什么需要验证?安装不是“命令敲完就算”,要确认命令能执行、版本能读到。怎么想?先判断自己是全局安装还是本地安装,再决定命令前面要不要加 npx。怎么做?本地安装后运行:
bash
npx webpack -v易错点:看到一长串系统信息不要慌,重点是确认 webpack 版本存在;如果命令失败,先检查是否在项目根目录、node_modules 是否装好、包名是否写对。
安装时容易忽略的细节
第一,安装本地依赖时,npm 可能会自动创建或更新 package.json,并把 webpack、webpack-cli 写进开发依赖。第二,npx 会优先在当前项目的 node_modules/.bin 里找命令,所以它适合执行本地安装的命令行工具。第三,项目目录尽量不要用中文路径,转写稿在后文也提醒过:虽然现在系统兼容性好一些,但路径、编码相关问题能提前规避就规避。第四,安装成功后只是“工具就绪”,真正打包还要有入口文件;如果项目里没有 src/index.js,直接运行 webpack 会报找不到入口,这属于下一节“零配置使用”的内容,不要和安装失败混为一谈。
从模块化开发理解 webpack 的打包职责
为什么需要。 现在的前端项目不会把所有代码写进一个文件,而是拆成多个模块:import 引入、export 暴露。浏览器虽然支持一部分 ES6 模块语法,但支持并不完整;项目里还会有 CSS、Less、图片、JSON、字体等资源,浏览器更不可能直接识别所有写法。所以需要一个工具,把入口文件开始涉及到的模块和资源整理、转换成浏览器能运行的结果。
怎么想。 webpack 的核心职责是“打包”:从一个入口出发,构建依赖图,把项目需要的模块组合起来。它本身主要能处理 JavaScript 和 JSON;CSS、图片等需要 loader 或 plugin 扩展。要记住它的五大核心概念:入口 entry、出口 output、加载器 loader、插件 plugins、模式 mode。本节先不写配置,先看“零配置”能做什么。
怎么做。 先安装 Node,再在项目目录本地安装 webpack:
bash
npm install webpack webpack-cli -D
npx webpack -v这里 webpack 是核心程序,webpack-cli 提供命令行能力;-D 表示开发依赖,因为打包工具只在开发阶段使用。安装后不要直接敲 webpack,本地安装的命令要用 npx webpack 运行。
易错点。 不要全局安装后以为版本一定一致;团队协作时本地安装能把版本写进 package.json,避免“你打包正常、我打包报错”。另外,npx webpack -v 输出里会带环境信息,不只看最后一行版本。
零配置默认入口和出口
为什么需要。 webpack 4 之后支持“零配置”,目的是降低上手成本。过去一上来就要写 webpack.config.js,入口、出口、模式都要配,容易劝退。
怎么想。 零配置不是永远不写配置,而是先约定默认值:默认入口是 src/index.js,默认输出是 dist/main.js。如果项目里没有 src/index.js,直接运行就会报错。
怎么做。 在项目根目录建立:
text
src/index.js然后运行:
bash
npx webpack第一次如果没建 src/index.js,会报“找不到 src 目录/入口”之类的错误;建好后再次运行,就会生成 dist/main.js。如果 index.js 是空文件,main.js 也基本是空的。
易错点。 dist 是打包产物,可以删除后重新生成;src 是源码,不能随便删。零配置只适合只有 JS/JSON 的极简场景,真实项目通常还要处理 HTML、CSS、图片等资源,后面仍然要写配置或安装 loader/plugin。
用 --mode 区分开发模式和生产模式
为什么需要。 不指定模式时,webpack 会给出警告,并默认使用 production。开发阶段如果直接压缩代码,报错行号、调试都不方便;生产阶段又需要压缩和优化。
怎么想。 mode 是告诉 webpack “当前按什么目标打包”。开发模式 development 重在可调试,不做压缩优化;生产模式 production 重在体积和运行性能。
怎么做。 开发模式:
bash
npx webpack --mode=development生产模式:
bash
npx webpack --mode=production开发模式产物里可能看到 eval 包裹代码,这不是乱码,也不影响浏览器运行;生产模式产物通常更短、更干净。
易错点。 单词别拼错:development、production。不写 mode 不是没有模式,而是默认 production,所以会出现警告。开发模式不会替你压缩代码,这是正常的。
改入口、改出口:先用命令行跑通
为什么需要。 实际项目入口不一定叫 index.js,输出也不一定叫 dist/main.js。先通过命令行参数理解“入口、出口可配置”,再写配置文件会更清楚。
怎么想。 命令行里写的相对路径,是相对于当前终端所在目录。入口路径要写 ./src/one.js 这种形式,不能漏掉 ./。
怎么做。 改入口:
bash
npx webpack ./src/one.js --mode=development改输出目录和文件名:
bash
npx webpack ./src/one.js --output-path=build --output-filename=index.js --mode=development多入口也可以先试:
bash
npx webpack ./src/one.js ./src/two.js --mode=development多个入口默认仍会打到一个输出文件里,代码会合并进同一个 bundle。
易错点。 入口路径漏写 ./ 可能被当成模块名而找不到。Windows 下用 Tab 补全可能补出反斜杠 `,webpack 路径容易出问题;建议手写正斜杠,或使用 Git Bash 这类终端。--output-path 指定的是目录,--output-filename` 指定的是文件名。
写 webpack.config.js:零配置的边界
为什么需要。 命令行参数一长串很难维护,而且真实项目需要 loader、plugin、清理输出目录等能力。配置文件让 webpack 自动读取入口、出口、模式等设置。
怎么想。 webpack.config.js 是给 webpack 程序读取的,webpack 运行在 Node 上,所以配置文件里用 CommonJS 的 module.exports 和 require;而 src 里写的 ES Module 是给打包后的前端代码用的,两者不要混。
怎么做。 基础配置示例:
js
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
clean: true
},
mode: 'development'
};多入口时:
js
module.exports = {
entry: {
first: './src/one.js',
second: './src/two.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
clean: true
},
mode: 'development'
};[name] 会替换成入口对象里的键名,生成 first.js、second.js。也可以写成 [name].[contenthash:8].js 生成带哈希的文件名,用于避免缓存问题;内容变化后哈希通常变化,内容不变则一般不变。
易错点。 output.path 必须是绝对路径,常用 path.resolve(__dirname, 'dist')。clean: true 会在每次打包前清理输出目录,避免旧文件残留。配置里属性之间用逗号,mode 别忘了。零配置只能算“开箱可试用”,不是真实项目的万能方案;要处理 CSS、图片等资源,仍然需要继续学习 loader 和 plugin。
为什么需要 webpack 配置文件
命令行里也能指定入口、出口和模式,例如 npx webpack ./src/app.js --output-path ./dist --output-filename index.js --mode development。但转写稿里反复出现一个感受:命令越写越长,“这命令不想活了”。项目一复杂,入口、出口、文件名、模式都要改,靠手敲既容易漏,也不方便团队统一。
怎么想:webpack 是运行在 Node 上的程序,它会自动读取项目根目录的 webpack.config.js。这个文件在 webpack 眼里就是一个 CommonJS 模块,webpack 内部用 require 引入它,拿到 module.exports 暴露的配置对象。所以配置文件里写 require、module.exports 是合理的;而 src 里给浏览器用的代码才写 import/export。
怎么做:在项目根目录创建 webpack.config.js。笔记给出的总配置如下,入口、出口、loader、插件、模式五大部分先留好位置:
js
const path = require('path');
module.exports = {
/********* 入口 **********/
// 字符串指定单一入口
entry: "./src/app.js",
// 数组指定多入口
//entry: ['./src/js/one.js', './src/js/two.js'],
// 对象指定多入口
// entry: {
// frist: './src/js/one.js',
// second: './src/js/two.js',
// },
/********* 出口 **********/
output: {
path: path.resolve(__dirname, './dist'),
// 固定的输出文件名
// filename: 'index.js',
// filename: '[name].js',
// filename: '[name][hash:8].js',
filename: 'index-[hash:12].js',
clean: true // 每次打包会把清空原来的输出目录
},
/********* loader **********/
/********* 插件 **********/
/********* 模式 **********/
mode: "development"
}易错点:入口路径不能只写 src/app.js,要写 ./src/app.js;不写 ./ 时 webpack 可能按模块名查找而报“找不到”。出口的 path 要用绝对路径,常用 path.resolve(__dirname, './dist') 或 path.join(__dirname, '/build'),因为命令行所在目录不一定和配置文件同目录。Windows 终端按 Tab 补全可能生成反斜杠,webpack 读取会出问题,建议手写正斜杠,或改用 Git Bash。
单入口单出口
为什么需要:最常见的前端项目只有一个总入口,例如 app.js,其他模块都从它导入。此时输出一个 JS 文件即可。
怎么想:entry 用字符串表示单一入口;output.filename 固定为 index.js,path 指向 build 或 dist。
怎么做:
js
const path = require("path");
module.exports = {
/**************** 入口 ***********************************/
entry:"./src/app.js",
/**************** 出口 *************************************/
output:{
filename: "index.js",
path:path.join(__dirname,"/build"),
clean:true
},
}易错点:clean: true 会在每次打包前清空输出目录,避免旧文件残留;但不要把它指向源码目录。
多入口单出口
为什么需要:有时想把 one.js、two.js 都作为起点,但最终仍合并成一个出口文件。
怎么想:entry 用数组。webpack 会把这些入口一起处理,输出仍由 filename: "index.js" 决定。
怎么做:
js
const path = require("path");
module.exports = {
/**************** 入口 ***********************************/
entry:['./src/js/one.js', './src/js/two.js'],
/**************** 出口 *************************************/
output:{
filename: "index.js",
path:path.join(__dirname,"/build"),
clean:true
},
}易错点:数组多入口不等于多出口;如果仍写死 index.js,结果就是一个文件。转写稿演示过:打包后 one 和 two 的代码会出现在同一个输出文件里。
多入口多出口与文件名占位符
为什么需要:对象形式的多入口希望“一个入口对应一个出口文件”,例如 first.js、second.js。
怎么想:entry 用对象,键名就是入口名;output.filename 用 [name] 占位符接收键名。若还要防止缓存,可加 [hash:8],内容变化后哈希变化,浏览器会请求新资源。
怎么做:
js
const path = require("path");
module.exports = {
/**************** 入口 ***********************************/
entry: {
frist: './src/js/one.js',
second: './src/js/two.js',
},
/**************** 出口 *************************************/
output:{
// filename: '[name].js',
filename: '[name][hash:8].js',
path:path.join(__dirname,"/build"),
clean:true
},
}易错点:对象多入口时不能仍写死 filename: 'index.js',否则多个入口会争抢同一个文件名;要用 [name]。[hash] 的位数可写 [hash:8]、[hash:12],转写稿说明它主要服务于开发阶段的缓存刷新,不是让你手写乱码文件名。
mode 与调试过程
为什么需要:不写 mode 时 webpack 会警告并默认使用 production。开发模式不压缩、便于定位;生产模式会压缩和优化,体积更小。
怎么想:开发时用 development,发布时用 production。转写稿中开发模式打包结果里能看到 eval,生产模式则直接压缩;这不是让你在业务代码里用 eval,只是 webpack 开发模式内部的调试处理。
怎么做:在配置对象末尾写 mode: "development",然后运行 npx webpack,webpack 会自动读取 webpack.config.js,不用再敲一长串参数。
易错点:development 和 production 拼写要准确;clean: true 与 mode 是两件事,前者清目录,后者决定优化策略。调试时先确认入口路径、输出绝对路径、文件名占位符,再检查模式,基本就能定位大部分配置问题。
先明确本节要解决的问题
本节笔记只有一条核心原则:Webpack 本身不能识别样式资源,所以需要借助 Loader 帮助 Webpack 解析样式资源;找 Loader 应先去官方文档,官方文档找不到,再去社区 GitHub 搜索。 笔记没有给出某一样式 Loader 的具体名称和配置代码,因此下面不臆造具体配置,而是把“为什么需要、怎么想、怎么做、易错点”讲清楚,具体 Loader 的安装命令和配置片段以你查到的官方文档为准。
为什么需要: 转写稿反复强调,Webpack 会把“前端的所有资源文件都作为模块处理”,但它原生能直接处理的资源是有限的,主要是 JS、JSON 等;样式资源不是 JS,Webpack 的打包链路不能直接认识它。怎么想: 不要一上来就背某个 Loader 的配置,而要先判断:这个资源是不是被入口 JS 当作模块引入了?Webpack 不认识它时,缺的是 Loader 还是 Plugin?怎么做: 把样式资源放进模块依赖图,再按官方文档找对应 Loader。易错点: 把 Loader 和 Plugin 混为一谈。转写稿明确说:Loader 负责加载资源,Plugin 负责扩展更多功能;样式资源首先缺的是 Loader,不是随便加一个 Plugin 就能解决。
为什么样式资源要交给 Loader
为什么需要: 转写稿里讲得很直白:Webpack 像一个“集成灶”,本身只带一个“蒸烤箱”,你要炒菜,还得配锅。样式资源就是那口“锅”要处理的东西。Webpack 不识别样式资源,不是样式没有用,而是它不在 Webpack 原生能解析的模块类型里。
怎么想: 先回到模块化开发的基本事实:入口通常是一个 JS 文件,其他资源要在入口的“眼里”都是模块,被 import 进来,才会进入依赖图。转写稿说“入口一定是个 JS,然后其他文件在这个 JS 的眼里都是模块”。所以样式资源不是孤立地丢给 Webpack,而是要通过入口或入口依赖链被引用。
怎么做: 先确认你的项目已经能被 Webpack 打包,再在入口中按模块方式引入样式资源,然后去官方文档找对应 Loader。不要凭记忆猜 Loader 名,也不要从旧博客抄一段过时配置。
易错点: 样式文件没有被入口引用,却怪 Loader 不生效;或者把样式资源当成“Webpack 自动会扫到”的文件。转写稿的零配置演示也说明:默认只认 src/index.js 这类入口,其他资源要进入打包流程,必须被模块链路带上。
找 Loader 的正确路径
为什么需要: Loader 是外部小工具,不是 Webpack 内核自带的万能能力。转写稿说,Webpack 之上还要运行很多工具,这些工具要单独安装;Loader 的版本、名称、用法都可能变化,所以不能靠猜。
怎么想: 找 Loader 的顺序应当是:先查 Webpack 官方文档,官方文档找不到,再去社区 GitHub 搜索。转写稿还提到,文档类网站可能是程序员自发维护的,有时会打不开,所以要多留几个来源,但第一优先级仍是官方文档。
怎么做: 找到对应 Loader 后,先看它的安装命令、版本要求、配置示例和适用 Webpack 版本;再把它安装到本项目。转写稿强调推荐本地安装,不要全局安装,并且 Webpack 只在开发阶段用,所以安装时要加到开发依赖,命令末尾用 -D。
易错点: 全局安装导致 package.json 不记录版本,团队协同开发时版本不一致;忘记 -D 把开发工具塞进生产依赖;看到旧版本配置直接抄,结果和当前 Webpack 版本冲突;把社区里某个插件当成 Loader 用。
安装与配置的操作路径
为什么需要: 样式 Loader 不是装完就自动生效,它要进入 Webpack 配置的 Loader 部分。转写稿把 Webpack 配置总结为五大部分:入口、出口、Loader、Plugin、模式。样式资源处理属于 Loader 这一部分。
怎么想: 配置文件 webpack.config.js 会被 Webpack 当作 Node 模块读取,所以里面可以用 Node 的写法;而 src 里写给浏览器运行的代码,才主要是前端模块语法。不要把两套语法混到“记不住”,而要按运行环境理解。
怎么做: 先保证 Webpack 能在本地运行。转写稿中的环境命令可以保留为:
bash
npm i webpack webpack-cli -D
npx webpack -v
npx webpack --mode development安装后先验证 npx webpack -v 能输出版本;再在项目根目录创建 webpack.config.js,按官方文档把样式 Loader 写进 Loader 配置部分;最后运行 npx webpack 打包,观察输出目录和终端警告。转写稿还演示了:不指定模式时会出现 mode 警告,并回退到 production;用 --mode development 可以消除该警告。这个调试思路同样适用于样式 Loader:先让基础打包跑通,再加 Loader,再逐项看报错。
易错点: 在 Windows 的 PowerShell 或 CMD 里按 Tab 补全路径,可能补出反斜杠 `,Webpack 读取路径会报错;转写稿的建议是手写正斜杠,或改用 Git Bash。另一个易错点是输出路径:转写稿用 path.resolve(__dirname, 'dist')` 这类 Node 写法得到绝对路径,避免相对路径受命令执行目录影响。样式 Loader 的配置同理,路径和版本都要按文档核对。
调试时先看什么
为什么需要: 样式资源处理失败时,报错可能来自 Loader 未安装、Loader 名称写错、版本不匹配、入口没引用样式、路径斜杠错误,或者模式未设置。盲目改配置效率很低。
怎么想: 按依赖链排查:入口是否引用了样式 → Loader 是否本地安装并写入开发依赖 → 配置是否写在 Loader 部分 → 运行命令是否在项目根目录 → 终端警告是否提示 mode 或路径问题。
怎么做: 先跑 npx webpack -v 确认本地 Webpack 可用;再用 npx webpack --mode development 打包;看 dist 是否生成、终端是否还有警告;最后按官方文档逐字核对 Loader 配置。转写稿里“零配置默认入口 src/index.js、默认输出 dist/main.js”的演示说明:默认行为能帮你快速验证环境,但样式资源不能指望零配置全部解决。
易错点: 一看到报错就删配置、换 Loader;或者把 clean、hash、filename 这些输出优化当成样式 Loader 的必需项。它们不是本节重点。本节要守住的原则是:Webpack 不识别样式资源 → 找对应 Loader → 按官方文档安装到本地开发依赖 → 写进 Loader 配置 → 用 npx webpack 验证。 笔记没有给出具体样式 Loader 配置,就不要编造;查到哪一份官方文档,就以哪一份为准。
课堂画面





代码示例
示例 1:本地安装 + 最基础的 webpack.config.js(单入口单出口)
package.json
json
{
"name": "webpack-demo",
"version": "1.0.0",
"scripts": {
"start": "webpack --mode development",
"build": "webpack --mode production"
},
"devDependencies": {
"webpack": "^5.88.0",
"webpack-cli": "^5.1.4"
}
}webpack.config.js(放在项目根目录)
js
const path = require('path');
module.exports = {
/********* 入口 **********/
entry: "./src/app.js",
/********* 出口 **********/
output: {
path: path.join(__dirname, '/build'),
filename: 'index-[hash:12].js',
clean: true // 每次打包先清空输出目录
},
/********* 模式 **********/
mode: "development"
}安装与运行
bash
# 本地安装(推荐),-D 表示加到开发依赖
npm install webpack webpack-cli -D
# 验证本地版本(不写 npx 会找不到命令)
npx webpack -v
# 打包
npx webpack要点解释 / 易错点
webpack是核心,webpack-cli是运行webpack命令时依赖的命令行工具,两个必须一起装。- 本地安装后不能直接敲
webpack -v,必须加npx;本地安装会写进package.json的devDependencies,保证团队打包版本一致。 output.path必须是绝对路径,所以要path.join(__dirname, ...);entry写相对路径,基准是执行命令时所在的目录。- 不写
mode会有黄色警告,并退而求其次默认用production;development打包产物带eval便于调试和统计,production会压缩、直接执行简单运算(如100+200被算成300)。 [hash:12]取的是内容哈希,内容变了文件名才变,用来刷缓存。- 输出目录(
build/dist)和src不同:dist里是产物,随时可以删;src里是源码,删了就白干了。
示例 2:多入口多出口([name] 变量)
webpack.config.js
js
const path = require("path");
module.exports = {
/**************** 入口 ***********************************/
// 情况一:字符串 → 单入口
// entry: "./src/app.js",
// 情况二:数组 → 多入口单出口(合并成一个文件)
// entry: ['./src/js/one.js', './src/js/two.js'],
// 情况三:对象 → 多入口多出口
entry: {
first: './src/js/one.js',
second: './src/js/two.js',
},
/**************** 出口 *************************************/
output: {
// filename: '[name].js',
filename: '[name][hash:8].js',
path: path.join(__dirname, "/build"),
clean: true
},
mode: "development"
}打包
bash
npx webpack
# 输出:build/first8a3f2c1d.js、build/second5e9b7a20.js要点解释 / 易错点
- 三种
entry写法对应三种关系:字符串 = 单入口单出口;数组 = 多入口单出口(打包进同一个文件);对象 = 多入口多出口(必须配合[name])。 [name]会被替换成entry对象的 key(这里是first/second),文件名写死index.js会导致后一个覆盖前一个。- 输出文件名里不要再套一层目录之外的奇怪字符,也尽量避免中文路径和中文文件名,防止编码问题。
- Windows 坑:用 Tab 补全路径时会补成反斜杠
src\js\one.js,webpack 读不了会报“找不到模块”。手写正斜杠,或把 VS Code 默认终端换成 Git Bash(Git Bash 的补全规则跟 Linux 一致,是正斜杠)。 - 命令行也能配(
--entry、--output-path、--output-filename、--mode),但参数一长就没法维护——这正是需要webpack.config.js的原因。
示例 3:完整模块化应用(JS 模块 + JSON + HTML 引入产物)
src/js/one.js
js
export default function () {
console.log('one one one');
}src/js/two.js
js
export default function () {
console.log('two two two');
}src/js/three.js
js
export default function () {
console.log('three three three');
}src/data/data.json(JSON 的属性名必须是双引号)
json
[
{ "name": "高小乐", "age": 19 },
{ "name": "王小明", "age": 20 }
]src/app.js(入口)
js
import one from './js/one.js';
import two from './js/two.js';
import three from './js/three.js';
import users from './data/data.json'; // webpack 5 默认支持 JSON
one();
two();
three();
console.log(users);webpack.config.js
js
const path = require('path');
module.exports = {
entry: './src/app.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, './dist'),
clean: true
},
mode: 'development'
}public/index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpack 打包应用演示</title>
</head>
<body>
<!-- 不能直接引 src/app.js,浏览器不认 import 语法 -->
<script src="../dist/index.js"></script>
</body>
</html>要点解释 / 易错点
- 入口一定是 JS,CSS、图片、JSON、HTML 在入口眼里都是“模块”,必须被
import进入口才会参与打包。 - 配置文件和源码是两套模块规范,别混:
src里是给浏览器跑的,用import/export(ES6);webpack.config.js是被 webpack 用require读的,用require/module.exports(CommonJS)。 - 省略扩展名时按
.js→.json→ 目录index的顺序查找,所以import one from './js/one'也能跑,但文件名有歧义时建议写全。 - 引 JSON 得到的是自动解析后的对象/数组,不需要
JSON.parse。 - HTML 里只能引
dist里的产物,引src/app.js会直接报错——因为浏览器对 ES 模块支持不完整,这也正是需要打包工具的原因。 - 默认零配置只认
src/index.js→dist/main.js;一旦要改入口、改出口、要处理 CSS/图片,就必须写webpack.config.js,所谓“零配置”只对纯 JS + JSON 的项目成立。
常见错误
1. 敲了 webpack -v 提示"不是内部或外部命令"
- 现象:本地装完 webpack 后直接运行
webpack,命令找不到。 - 原因:本地安装的包只把可执行文件放在当前项目的
node_modules/.bin,没有进入系统 PATH。 - 修法:命令前加
npx(npx webpack -v),或写进package.json的 scripts 用npm run调起。
2. 命令行指定入口写成 src/one.js,打包"成功"但 dist 是空的 / 报模块找不到
- 现象:把
./src/one.js写成src/one.js后打包无产物或报错。 - 原因:路径解析规则与
require一致——不带./会被当成"包名"去node_modules里找,找不到就失败。 - 修法:自定义路径一律以
./或../开头;这类问题先看报错里的"解析到哪个目录",比反复改配置快。
3. Windows 下按 Tab 补全,路径变成反斜杠 src\one.js
- 现象:补全后回车,webpack 报找不到入口。
- 原因:CMD / PowerShell 的补全按 Windows 习惯给反斜杠,webpack 只认正斜杠。
- 修法:手动改成
/;更彻底的做法是把 VS Code 默认终端切到 Git Bash,从源头上让补全产出正斜杠。
4. 多入口多出口时,dist 里只剩一个 js
- 现象:entry 写了两个 key,output.filename 仍是
index.js,产物互相覆盖。 - 原因:多个 chunk 输出到同一个文件名,后写的覆盖先写的。
- 修法:
filename: '[name].js'(需要缓存控制再加[hash:8]),并保证 entry 是对象形式——[name]的值就来自对象的 key。
5. 单入口/数组入口用 [name],产物叫 main.js 而不是 index.js
- 现象:以为
[name]会取入口文件名,结果拿到main。 - 原因:字符串入口和数组入口没有自定义 chunk 名,默认名是
main。 - 修法:要么直接写死
filename: 'index.js',要么把 entry 改成对象{ index: './src/app.js' }显式命名。
6. 改了代码,页面还是旧的
- 现象:重新打包后浏览器行为没变,或 HTML 引用的文件名对不上。
- 原因:文件名带 hash 时旧产物没被清理,dist 里堆着一堆历史文件;也可能撞上了浏览器缓存。
- 修法:
output.clean: true每次清空输出目录;引用路径用打包后的真实文件名,别手写。
7. output.path 写成 './dist'
- 现象:产物出现在意料之外的目录,或直接报错。
- 原因:
output.path必须是绝对路径,相对路径不按你的直觉解析。 - 修法:
path.resolve(__dirname, 'dist'),配合require('path');注意这段是 Node 环境代码,可以用 Node 的模块。
8. 引入 CSS/图片直接报 Module parse failed
- 现象:
import './style.css'后打包失败。 - 原因:webpack 开箱只认 JS/JSON,"零配置"的边界就在这里,样式、图片、字体、HTML 都得靠 loader 接。
- 修法:按官方文档装对应 loader,写进
module.rules;报错信息里其实已经点名了需要哪种 loader。
练习
练习 1|三种入口形态对照 用同一个项目分别以「字符串单入口」「数组多入口」「对象多入口」打包三次,把三次的 dist 产物截图对比,并解释:为什么数组入口只出一个文件,对象入口出两个?[name] 在各次里分别取到了什么值?
练习 2|路径与终端的坑 先在 CMD/PowerShell 里用 Tab 补全写一次入口路径并打包(记录报错),再把默认终端切成 Git Bash 重做一遍。写出两段命令的差异,并说明为什么团队协作时更推荐后者。
练习 3|hash 的行为验证 用 filename: '[name]-[hash:8].js' 打包一次,然后:(a) 不改任何源码再打包一次,比较文件名;(b) 只改源码里一个字符串再打包,比较文件名。用两次结果解释 hash 值和"刷缓存"的关系。
练习 4|npm scripts 收口 把之前手写的超长命令(入口、输出目录、输出文件名、mode)全部搬进 webpack.config.js,然后在 package.json 里配两条脚本:dev 走开发模式、build 走生产模式。分别运行,对比产物大小与可读性,说明开发模式为什么不做压缩。
练习 5|制造并读懂报错 新建 src/style.css 并在入口里 import 它,故意不配 loader,完整抄下报错信息。逐句说明:报错在哪一步发生、webpack 缺的是什么能力、需要补的是 loader 还是 plugin、为什么。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | webpack介绍 | 21:46 |
| 2 | webpack的安装 | 08:28 |
| 3 | 零配置使用 | 40:11 |
| 4 | 打包应用演示 | 15:45 |
| 5 | webpack配置文件 | 29:37 |
小结
- webpack 只在开发阶段存在,产物才是交付物;把"开发期工具"和"运行期代码"分清楚,后面所有困惑都会少一半。
- 配置文件的语法归属要看它跑在谁身上:
webpack.config.js被 webpack 用require读,所以用 CommonJS;src里的代码跑在浏览器,所以用 ESM。混着记必乱,理解层次就不会乱。 - 能换的和不能换的,取决于你有没有显式指定它。入口位置、入口数量、输出目录、输出文件名,只要写出来就能改;不要背规则,要看命令行/配置里哪些是写死的。
- 本地安装 + npx/npm scripts 是团队协作的底线,全局安装的版本不受
package.json管控,是"我这儿能跑"的经典来源。 [name]和[hash]不是装饰:前者解决多入口命名冲突,后者解决缓存失效;用之前先想清楚"我要解决哪个问题"。- 零配置是个营销词,真实项目必然要写配置;但配置不用背,五大块(entry / output / loader / plugin / mode)就是它的骨架,其余按文档查。
- 报错优先读,别急着改:webpack 的报错通常会告诉你缺什么 loader、路径解析到了哪里、哪个选项没设,读懂了比试十次快。
- 工具会换代,模块化思维不会。Grunt、Gulp 到 webpack 到更新的构建器,换的是壳;把"入口—依赖图—产物"这条链路想明白,换工具只是换语法。