开发环境
开发环境
T> 本指南基于输出管理指南中的代码示例展开。
如果你一直跟着前面的指南走,应该已经对 webpack 的基础知识有了扎实的理解。在继续之前,我们先来搭建一个开发环境,让我们的生活更轻松一些。
W> 本指南中的工具仅用于开发,请避免在生产环境中使用它们!
让我们首先将 mode 设置为 'development',并将 title 设置为 'Development'。
webpack.config.js
diff
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
+ mode: 'development',
entry: {
index: './src/index.js',
print: './src/print.js',
},
plugins: [
new HtmlWebpackPlugin({
- title: 'Output Management',
+ title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
};
使用 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
diff
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
mode: 'development',
entry: {
index: './src/index.js',
print: './src/print.js',
},
+ devtool: 'inline-source-map',
plugins: [
new HtmlWebpackPlugin({
title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
};
现在,让我们确保有东西可以调试,所以在 print.js 文件中创建一个错误:
src/print.js
diff
export default function printMe() {
- console.log('I get called from print.js!');
+ cosnole.log('I get called from print.js!');
}
运行 npm run build,它应该会编译出类似如下的内容:
bash
...
[webpack-cli] Compilation finished
asset index.bundle.js 1.38 MiB [emitted] (name: index)
asset print.bundle.js 6.25 KiB [emitted] (name: print)
asset index.html 272 bytes [emitted]
runtime modules 1.9 KiB 9 modules
cacheable modules 530 KiB
./src/index.js 406 bytes [built] [code generated]
./src/print.js 83 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 706 ms
现在在浏览器中打开生成的 index.html 文件。点击按钮,查看控制台中显示的错误。错误信息应该类似这样:
bash
Uncaught ReferenceError: cosnole is not defined
at HTMLButtonElement.printMe (print.js:2)
我们可以看到,错误还包含了发生错误的文件(print.js)和行号(2)的引用。这很好,因为我们现在确切地知道去哪里查找并修复问题。
选择开发工具
W> 某些文本编辑器具有“安全写入”功能,可能会干扰下面的一些工具。请阅读调整文本编辑器以解决这些问题。
每次编译代码时都手动运行 npm run build 很快就会变得很麻烦。
webpack 提供了几种不同的选项,可以帮助你在代码更改时自动编译代码:
- webpack 的监视模式
- webpack-dev-server
- webpack-dev-middleware
在大多数情况下,你可能希望使用 webpack-dev-server,但让我们探索以上所有选项。
使用监视模式
你可以指示 webpack “监视”依赖图中所有文件的更改。如果这些文件之一被更新,代码将被重新编译,这样你就不必手动运行完整构建。
让我们添加一个 npm 脚本,用于启动 webpack 的监视模式:
package.json
diff
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "webpack --watch",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^5.6.6",
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
现在在命令行中运行 npm run watch,看看 webpack 如何编译你的代码。
你可以看到它没有退出命令行,因为脚本当前正在监视你的文件。
现在,当 webpack 监视你的文件时,让我们移除之前引入的错误:
src/print.js
diff
export default function printMe() {
- cosnole.log('I get called from print.js!');
+ console.log('I get called from print.js!');
}
现在保存文件并检查终端窗口。你应该看到 webpack 自动重新编译了更改的模块!
唯一的缺点是必须刷新浏览器才能看到更改。如果这也能自动发生就更好了,所以让我们试试 webpack-dev-server,它可以做到这一点。
使用 webpack-dev-server
webpack-dev-server 为你提供了一个基础的 Web 服务器,并具备实时重新加载的功能。让我们设置它:
bash
npm install --save-dev webpack-dev-server
修改配置文件,告诉开发服务器在哪里查找文件:
webpack.config.js
diff
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
mode: 'development',
entry: {
index: './src/index.js',
print: './src/print.js',
},
devtool: 'inline-source-map',
+ devServer: {
+ static: './dist',
+ },
plugins: [
new HtmlWebpackPlugin({
title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
+ optimization: {
+ runtimeChunk: 'single',
+ },
};
这告诉 webpack-dev-server 在 localhost:8080 上提供 dist 目录中的文件。
T> 添加 optimization.runtimeChunk: 'single' 是因为在这个例子中,我们在单个 HTML 页面上有多个入口点。如果没有这个,我们可能会遇到这里描述的问题。有关更多详细信息,请阅读代码分离章节。
T> webpack-dev-server 从 output.path 中定义的目录提供打包文件,即文件将在 http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename] 下可用。
W> webpack-dev-server 编译后不会写入任何输出文件。相反,它将 bundle 文件保存在内存中,并将它们当作挂载在服务器根路径上的真实文件来提供。如果你的页面期望在另一个路径上找到 bundle 文件,可以通过开发服务器配置中的 devMiddleware.publicPath 选项来更改。
让我们也添加一个脚本,方便地运行开发服务器:
package.json
diff
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
+ "start": "webpack serve --open",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^5.6.6",
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0",
"webpack-dev-server": "^5.2.3"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
现在我们可以从命令行运行 npm start,我们会看到浏览器自动加载我们的页面。如果你现在更改任何源文件并保存,Web 服务器将在代码编译后自动重新加载。试试看!
webpack-dev-server 带有许多可配置的选项。前往文档了解更多信息。
T> 既然你的服务器已经工作了,你可能想尝试一下模块热替换!
使用 webpack-dev-middleware
webpack-dev-middleware 是一个包装器,它将 webpack 处理的文件发送到服务器。这在 webpack-dev-server 内部使用,但也可以作为单独的包使用,以便在需要时允许更自定义的设置。我们将看一个将 webpack-dev-middleware 与 express 服务器结合的示例。
让我们安装 express 和 webpack-dev-middleware 以便开始:
bash
npm install --save-dev express webpack-dev-middleware
现在我们需要对 webpack 配置文件进行一些调整,以确保中间件能正常工作:
webpack.config.js
diff
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
mode: 'development',
entry: {
index: './src/index.js',
print: './src/print.js',
},
devtool: 'inline-source-map',
devServer: {
static: './dist',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Development',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
+ publicPath: '/',
},
};
publicPath 也将在我们的服务器脚本中使用,以确保文件在 http://localhost:3000 上正确提供。我们稍后指定端口号。下一步是设置我们的自定义 express 服务器:
project
diff
webpack-demo
├── package.json
├── package-lock.json
├── webpack.config.js
+ ├── server.js
├── /dist
├── /src
│ ├── index.js
│ └── print.js
└── /node_modules
server.js
js
import express from "express";
import webpack from "webpack";
import webpackDevMiddleware from "webpack-dev-middleware";
import config from "./webpack.config.js";
const app = express();
const compiler = webpack(config);
// 告诉 express 使用 webpack-dev-middleware,
// 并使用 webpack.config.js 配置文件作为基础。
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
}),
);
// 在 3000 端口上提供文件。
app.listen(3000, () => {
console.log("Example app listening on port 3000!\n");
});
现在添加一个 npm 脚本,以便更容易运行服务器:
package.json
diff
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"start": "webpack serve --open",
+ "server": "node server.js",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"express": "^5.2.1",
"html-webpack-plugin": "^5.6.6",
"webpack": "^5.105.0",
"webpack-cli": "^7.0.0",
"webpack-dev-middleware": "^8.0.3",
"webpack-dev-server": "^5.2.3"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
现在在你的终端中运行 npm run server,它应该会给你类似以下的输出:
bash
Example app listening on port 3000!
...
<i> [webpack-dev-middleware] asset index.bundle.js 1.38 MiB [emitted] (name: index)
<i> asset print.bundle.js 6.25 KiB [emitted] (name: print)
<i> asset index.html 274 bytes [emitted]
<i> runtime modules 1.9 KiB 9 modules
<i> cacheable modules 530 KiB
<i> ./src/index.js 406 bytes [built] [code generated]
<i> ./src/print.js 83 bytes [built] [code generated]
<i> ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
<i> webpack 5.x.x compiled successfully in 709 ms
<i> [webpack-dev-middleware] Compiled successfully.
<i> [webpack-dev-middleware] Compiling...
<i> [webpack-dev-middleware] assets by status 1.38 MiB [cached] 2 assets
<i> cached modules 530 KiB (javascript) 1.9 KiB (runtime) [cached] 12 modules
<i> webpack 5.x.x compiled successfully in 19 ms
<i> [webpack-dev-middleware] Compiled successfully.
现在打开你的浏览器并访问 http://localhost:3000。你应该看到你的 webpack 应用正在运行!
T> 如果你想了解更多关于模块热替换的工作原理,我们推荐你阅读模块热替换指南。
调整文本编辑器
使用自动编译代码时,在保存文件时可能会遇到问题。某些编辑器具有“安全写入”功能,可能会干扰重新编译。
要在一些常见的编辑器中禁用此功能,请参阅以下列表:
- Sublime Text 3:在你的用户偏好设置中添加
atomic_save: 'false'。 - JetBrains IDE(如 WebStorm):在
Preferences > Appearance & Behavior > System Settings中取消勾选“Use safe write”。 - Vim:在你的设置中添加
:set backupcopy=yes。
总结
现在你已经学会了如何自动编译代码并运行开发服务器,你可以查看下一个指南,它将介绍代码分离。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
