2025年6月6日 星期五 乙巳(蛇)年 三月初十 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > JavaScript

webpack进阶(一)

时间:02-19来源:作者:点击数:32

一、起步

1、基本安装

首先我们创建一个目录,初始化 npm,然后 在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack):

  • mkdir webpack-demo
  • cd webpack-demo
  • npm init -y
  • npm install webpack webpack-cli --save-dev

现在,我们将创建以下目录结构、文件和内容:

project

  • webpack-demo
  • |- package.json
  • + |- index.html
  • + |- /src
  • + |- index.js

src/index.js

  • function component() {
  • const element = document.createElement('div');
  • // https://www.lodashjs.com/
  • // lodash(目前通过一个 script 引入)对于执行这一行是必需的
  • element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  • return element;
  • }
  • document.body.appendChild(component());

index.html

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  • <title>起步</title>
  • <script src="https://unpkg.com/lodash@4.17.20"></script>
  • </head>
  • <body>
  • <script src="./src/index.js"></script>
  • </body>
  • </html>

我们还需要调整 package.json 文件,以便确保我们安装包是 private(私有的),并且移除 main 入口。这可以防止意外发布你的代码。

package.json

  • {
  • "name": "webpack-demo",
  • "version": "1.0.0",
  • "description": "",
  • - "main": "index.js",
  • + "private": true,
  • "scripts": {
  • "test": "echo \"Error: no test specified\" && exit 1"
  • },
  • "keywords": [],
  • "author": "",
  • "license": "ISC",
  • "devDependencies": {
  • "webpack": "^5.4.0",
  • "webpack-cli": "^4.2.0"
  • }
  • }

启动项目

  • npx http-server

在此示例中,<script> 标签之间存在隐式依赖关系。在 index.js 文件执行之前,还需要在页面中先引入 lodash。这是因为 index.js 并未显式声明它需要 lodash,只是假定推测已经存在一个全局变量 _

使用这种方式去管理 JavaScript 项目会有一些问题:

  • 无法直接体现,脚本的执行依赖于外部库。
  • 如果依赖不存在,或者引入顺序错误,应用程序将无法正常运行。
  • 如果依赖被引入但是并没有使用,浏览器将被迫下载无用代码。

让我们使用 webpack 来管理这些脚本。

2、创建一个bundle

首先,我们稍微调整下目录结构,创建分发代码(./dist)文件夹用于存放分发代码,源代码(./src)文件夹仍存放源代码。

project

  • webpack-demo
  • |- package.json
  • + |- /dist
  • + |- index.html
  • - |- index.html
  • |- /src
  • |- index.js

要在 index.js 中打包 lodash 依赖,我们需要在本地安装 library:

  • npm install --save lodash

src/index.js

  • +import _ from 'lodash';
  • +
  • function component() {
  • const element = document.createElement('div');
  • - // lodash(目前通过一个 script 引入)对于执行这一行是必需的
  • + // lodash,现在通过一个 script 引入
  • element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  • return element;
  • }
  • document.body.appendChild(component());

dist/index.html

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  • <title>起步</title>
  • - <script src="https://unpkg.com/lodash@4.17.20"></script>
  • </head>
  • <body>
  • - <script src="./src/index.js"></script>
  • + <script src="main.js"></script>
  • </body>
  • </html>

开始打包

  • $ npx webpack

3、模块

ES2015 中的 import 和 export 语句已经被标准化。虽然大多数浏览器还无法支持它们,但是 webpack 却能够提供开箱即用般的支持。

事实上,webpack 在幕后会将代码“转译”,以便旧版本浏览器可以执行。如果你检查 dist/main.js,你可以看到 webpack 具体如何实现,这是独创精巧的设计!除了 import 和 export,webpack 还能够很好地支持多种其他模块语法,更多信息请查看 模块 API

注意,webpack 不会更改代码中除 import 和 export 语句以外的部分。如果你在使用其它 ES2015 特性,请确保你在 webpack loader 系统 中使用了 Babel

请查看编译后的代码。

4、使用一个配置文件

project

  • webpack-demo
  • |- package.json
  • + |- webpack.config.js
  • |- /dist
  • |- index.html
  • |- /src
  • |- index.js

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • entry: './src/index.js',
  • output: {
  • filename: 'main.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

现在,让我们通过新的配置文件再次执行构建:

5、npm scripts

package.json

  • {
  • "name": "webpack-demo",
  • "version": "1.0.0",
  • "description": "",
  • "private": true,
  • "scripts": {
  • - "test": "echo \"Error: no test specified\" && exit 1"
  • + "test": "echo \"Error: no test specified\" && exit 1",
  • + "build": "webpack"
  • },
  • "keywords": [],
  • "author": "",
  • "license": "ISC",
  • "devDependencies": {
  • "webpack": "^5.4.0",
  • "webpack-cli": "^4.2.0"
  • },
  • "dependencies": {
  • "lodash": "^4.17.20"
  • }
  • }

现在运行以下命令:

  • $ npm run build

二、管理资源

1、设置

在开始之前,让我们对项目做一个小的修改:

dist/index.html

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  • - <title>起步</title>
  • + <title>管理资源</title>
  • </head>
  • <body>
  • - <script src="main.js"></script>
  • + <script src="bundle.js"></script>
  • </body>
  • </html>

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • entry: './src/index.js',
  • output: {
  • - filename: 'main.js',
  • + filename: 'bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

2、加载 CSS

为了在 JavaScript 模块中 import 一个 CSS 文件,你需要安装 style-loader 和 css-loader,并在 module 配置 中添加这些 loader:

  • npm install --save-dev style-loader css-loader

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • entry: './src/index.js',
  • output: {
  • filename: 'bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • + module: {
  • + rules: [
  • + {
  • + test: /\.css$/i,
  • + use: ['style-loader', 'css-loader'],
  • + },
  • + ],
  • + },
  • };

我们尝试一下,通过在项目中添加一个新的 style.css 文件,并将其 import 到我们的 index.js 中:

project

  • webpack-demo
  • |- package.json
  • |- webpack.config.js
  • |- /dist
  • |- bundle.js
  • |- index.html
  • |- /src
  • + |- style.css
  • |- index.js
  • |- /node_modules

src/style.css

  • .hello {
  • color: red;
  • }

src/index.js

  • import _ from 'lodash';
  • +import './style.css';
  • function component() {
  • const element = document.createElement('div');
  • // Lodash, now imported by this script
  • element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  • + element.classList.add('hello');
  • return element;
  • }
  • document.body.appendChild(component());

现在运行 build 命令:

  • $ npm run build

3、加载 images 图像

假如,现在我们正在下载 CSS,但是像 background 和 icon 这样的图像,要如何处理呢?在 webpack 5 中,可以使用内置的 Asset Modules,我们可以轻松地将这些内容混入我们的系统中:

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • entry: './src/index.js',
  • output: {
  • filename: 'bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • module: {
  • rules: [
  • {
  • test: /\.css$/i,
  • use: ['style-loader', 'css-loader'],
  • },
  • + {
  • + test: /\.(png|svg|jpg|jpeg|gif)$/i,
  • + type: 'asset/resource',
  • + },
  • ],
  • },
  • };

我们向项目添加一个图像,然后看它是如何工作的,你可以使用任何你喜欢的图像:

project

  • webpack-demo
  • |- package.json
  • |- webpack.config.js
  • |- /dist
  • |- bundle.js
  • |- index.html
  • |- /src
  • + |- icon.png
  • |- style.css
  • |- index.js
  • |- /node_modules

src/index.js

  • import _ from 'lodash';
  • import './style.css';
  • +import Icon from './icon.png';
  • function component() {
  • const element = document.createElement('div');
  • // Lodash, now imported by this script
  • element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  • element.classList.add('hello');
  • + // 将图像添加到我们已经存在的 div 中。
  • + const myIcon = new Image();
  • + myIcon.src = Icon;
  • +
  • + element.appendChild(myIcon);
  • +
  • return element;
  • }
  • document.body.appendChild(component());

src/style.css

  • .hello {
  • color: red;
  • + background: url('./icon.png');
  • }

重新构建并再次打开 index.html 文件:

  • $ npm run build

4、加载 fonts 字体

那么,像字体这样的其他资源如何处理呢?使用 Asset Modules 可以接收并加载任何文件,然后将其输出到构建目录。这就是说,我们可以将它们用于任何类型的文件,也包括字体。让我们更新 webpack.config.js 来处理字体文件:

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • entry: './src/index.js',
  • output: {
  • filename: 'bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • module: {
  • rules: [
  • {
  • test: /\.css$/i,
  • use: ['style-loader', 'css-loader'],
  • },
  • {
  • test: /\.(png|svg|jpg|jpeg|gif)$/i,
  • type: 'asset/resource',
  • },
  • + {
  • + test: /\.(woff|woff2|eot|ttf|otf)$/i,
  • + type: 'asset/resource',
  • + },
  • ],
  • },
  • };

在项目中添加一些字体文件:

project

  • webpack-demo
  • |- package.json
  • |- webpack.config.js
  • |- /dist
  • |- bundle.js
  • |- index.html
  • |- /src
  • + |- my-font.woff
  • + |- my-font.woff2
  • |- icon.png
  • |- style.css
  • |- index.js
  • |- /node_modules

配置好 loader 并将字体文件放在合适的位置后,你可以通过一个 @font-face 声明将其混合。本地的 url(...) 指令会被 webpack 获取处理,就像它处理图片一样:

src/style.css

  • +@font-face {
  • + font-family: 'MyFont';
  • + src: url('./my-font.woff2') format('woff2'),
  • + url('./my-font.woff') format('woff');
  • + font-weight: 600;
  • + font-style: normal;
  • +}
  • +
  • .hello {
  • color: red;
  • + font-family: 'MyFont';
  • background: url('./icon.png');
  • }

现在,让我们重新构建,然后看下 webpack 是否处理了我们的字体:

  • $ npm run build

三、管理输出

到目前为止,我们都是在 index.html 文件中手动引入所有资源,然而随着应用程序增长,并且一旦开始 在文件名中使用 hash 并输出 多个 bundle,如果继续手动管理 index.html 文件,就会变得困难起来。然而,通过一些插件可以使这个过程更容易管控。

1、预先准备

首先,调整一下我们的项目:

project

  • webpack-demo
  • |- package.json
  • |- webpack.config.js
  • |- /dist
  • |- /src
  • |- index.js
  • + |- print.js
  • |- /node_modules

我们在 src/print.js 文件中添加一些逻辑:

src/print.js

  • export default function printMe() {
  • console.log('I get called from print.js!');
  • }

并且在 src/index.js 文件中使用这个函数:

src/index.js

  • import _ from 'lodash';
  • +import printMe from './print.js';
  • function component() {
  • const element = document.createElement('div');
  • + const btn = document.createElement('button');
  • element.innerHTML = _.join(['Hello', 'webpack'], ' ');
  • + btn.innerHTML = 'Click me and check the console!';
  • + btn.onclick = printMe;
  • +
  • + element.appendChild(btn);
  • +
  • return element;
  • }
  • document.body.appendChild(component());

还要更新 dist/index.html 文件,来为 webpack 分离入口做好准备:

dist/index.html

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  • - <title>管理资源</title>
  • + <title>管理输出</title>
  • + <script src="./print.bundle.js"></script>
  • </head>
  • <body>
  • - <script src="bundle.js"></script>
  • + <script src="./index.bundle.js"></script>
  • </body>
  • </html>

现在调整配置。我们将在 entry 添加 src/print.js 作为新的入口起点(print),然后修改 output,以便根据入口起点定义的名称,动态地产生 bundle 名称:

webpack.config.js

  • const path = require('path');
  • module.exports = {
  • - entry: './src/index.js',
  • + entry: {
  • + index: './src/index.js',
  • + print: './src/print.js',
  • + },
  • output: {
  • - filename: 'bundle.js',
  • + filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

执行 npm run build

我们可以看到,webpack 生成 print.bundle.js 和 index.bundle.js 文件,这也和我们在 index.html 文件中指定的文件名称相对应。如果你在浏览器中打开 index.html,就可以看到在点击按钮时会发生什么。

但是,如果我们更改了我们的一个入口起点的名称,甚至添加了一个新的入口,会发生什么?会在构建时重新命名生成的 bundle,但是我们的 index.html 文件仍然引用旧的名称。让我们用 HtmlWebpackPlugin 来解决这个问题。

2、设置 HtmlWebpackPlugin

首先安装插件,并且调整 webpack.config.js 文件:

  • npm install --save-dev html-webpack-plugin

webpack.config.js

  • const path = require('path');
  • +const HtmlWebpackPlugin = require('html-webpack-plugin');
  • module.exports = {
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • + plugins: [
  • + new HtmlWebpackPlugin({
  • + title: '管理输出',
  • + }),
  • + ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

在我们构建之前,你应该了解,虽然在 dist/ 文件夹我们已经有了 index.html 这个文件,然而 HtmlWebpackPlugin 还是会默认生成它自己的 index.html 文件。也就是说,它会用新生成的 index.html 文件,替换我们的原有文件。

如果在代码编辑器中打开 index.html,你会看到 HtmlWebpackPlugin 创建了一个全新的文件,所有的 bundle 会自动添加到 html 中。

3、清理 /dist 文件夹

你可能已经注意到,由于遗留了之前的指南和代码示例,我们的 /dist 文件夹显得相当杂乱。webpack 将生成文件并放置在 /dist 文件夹中,但是它不会追踪哪些文件是实际在项目中用到的。

通常比较推荐的做法是,在每次构建前清理 /dist 文件夹,这样只会生成用到的文件。让我们实现这个需求。

clean-webpack-plugin 是一个流行的清理插件,安装和配置它。

  • npm install --save-dev clean-webpack-plugin

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • +const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • plugins: [
  • + new CleanWebpackPlugin(),
  • new HtmlWebpackPlugin({
  • title: 'Output Management',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

现在,执行 npm run build,检查 /dist 文件夹。如果一切顺利,现在只会看到构建后生成的文件,而没有旧文件!

4、manifest

你可能会很感兴趣,webpack 和 webpack 插件似乎“知道”应该生成哪些文件。答案是,webpack 通过 manifest,可以追踪所有模块到输出 bundle 之间的映射。如果你想要知道如何以其他方式来控制 webpack 输出,了解 manifest 是个好的开始。

通过 WebpackManifestPlugin 插件,可以将 manifest 数据提取为一个容易使用的 json 文件。

首先安装 webpack-manifest-plugin:

  • npm install webpack-manifest-plugin --save-dev

webpack.config.js

  • const path = require('path')
  • const HtmlWebpackPlugin = require('html-webpack-plugin')
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin')
  • +const { WebpackManifestPlugin } = require('webpack-manifest-plugin')
  • module.exports = {
  • mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • plugins: [
  • new CleanWebpackPlugin(),
  • new HtmlWebpackPlugin({
  • title: '管理输出',
  • }),
  • + new WebpackManifestPlugin()
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • }
  • };

现在,执行 npm run build,会发现 dist/manifest.json文件,文件内容如下:

  • {
  • "index.js": "autoindex.bundle.js",
  • "print.js": "autoprint.bundle.js",
  • "index.html": "autoindex.html"
  • }

四、开发环境

如果你一直跟随之前的指南,应该对一些 webpack 基础知识有着很扎实的理解。在我们继续之前,先来看看如何设置一个开发环境,使我们的开发体验变得更轻松一些。

在开始前,我们先将 mode 设置为 'development',并将 title 设置为 'Development'

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • + mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • plugins: [
  • new CleanWebpackPlugin(),
  • new HtmlWebpackPlugin({
  • - title: 'Output Management',
  • + title: 'Development',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

1、使用 source-map

当 webpack 打包源代码时,可能会很难追踪到 error(错误) 和 warning(警告) 在源代码中的原始位置。例如,如果将三个源文件(a.jsb.js 和 c.js)打包到一个 bundle(bundle.js)中,而其中一个源文件包含一个错误,那么堆栈跟踪就会直接指向到 bundle.js。你可能需要准确地知道错误来自于哪个源文件,所以这种提示这通常不会提供太多帮助。

为了更容易地追踪 error 和 warning,JavaScript 提供了 source maps 功能,可以将编译后的代码映射回原始源代码。如果一个错误来自于 b.js,source map 就会明确的告诉你。

(1) devtool 配置说明表
devtool performance production quality comment
(none) build: fastest rebuild: fastest yes bundle Recommended choice for production builds with maximum performance.
eval build: fast rebuild: fastest no generated Recommended choice for development builds with maximum performance.
eval-cheap-source-map build: ok rebuild: fast no transformed Tradeoff choice for development builds.
eval-cheap-module-source-map build: slow rebuild: fast no original lines Tradeoff choice for development builds.
eval-source-map build: slowest rebuild: ok no original Recommended choice for development builds with high quality SourceMaps.
cheap-source-map build: ok rebuild: slow no transformed  
cheap-module-source-map build: slow rebuild: slow no original lines  
source-map build: slowest rebuild: slowest yes original Recommended choice for production builds with high quality SourceMaps.
inline-cheap-source-map build: ok rebuild: slow no transformed  
inline-cheap-module-source-map build: slow rebuild: slow no original lines  
inline-source-map build: slowest rebuild: slowest no original Possible choice when publishing a single file
eval-nosources-cheap-source-map build: ok rebuild: fast no transformed source code not included
eval-nosources-cheap-module-source-map build: slow rebuild: fast no original lines source code not included
eval-nosources-source-map build: slowest rebuild: ok no original source code not included
inline-nosources-cheap-source-map build: ok rebuild: slow no transformed source code not included
inline-nosources-cheap-module-source-map build: slow rebuild: slow no original lines source code not included
inline-nosources-source-map build: slowest rebuild: slowest no original source code not included
nosources-cheap-source-map build: ok rebuild: slow no transformed source code not included
nosources-cheap-module-source-map build: slow rebuild: slow no original lines source code not included
nosources-source-map build: slowest rebuild: slowest yes original source code not included
hidden-nosources-cheap-source-map build: ok rebuild: slow no transformed no reference, source code not included
hidden-nosources-cheap-module-source-map build: slow rebuild: slow no original lines no reference, source code not included
hidden-nosources-source-map build: slowest rebuild: slowest yes original no reference, source code not included
hidden-cheap-source-map build: ok rebuild: slow no transformed no reference
hidden-cheap-module-source-map build: slow rebuild: slow no original lines no reference
hidden-source-map build: slowest rebuild: slowest yes original no reference. Possible choice when using SourceMap only for error reporting purposes.
  • 开发环境推荐配置

    以下选项非常适合开发环境:

    eval - 每个模块都使用 eval() 执行,并且都有 //@ sourceURL。此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从 loader 中获取 source map),所以不能正确的显示行数。

    eval-source-map - 每个模块使用 eval() 执行,并且 source map 转换为 DataUrl 后添加到 eval() 中。初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的 source map。

    eval-cheap-source-map - 类似 eval-source-map,每个模块使用 eval() 执行。这是 “cheap(低开销)” 的 source map,因为它没有生成列映射(column mapping),只是映射行数。它会忽略源自 loader 的 source map,并且仅显示转译后的代码,就像 eval devtool。

    eval-cheap-module-source-map - 类似 eval-cheap-source-map,并且,在这种情况下,源自 loader 的 source map 会得到更好的处理结果。然而,loader source map 会被简化为每行一个映射(mapping)。

  • 生产环境推荐配置

    这些选项通常用于生产环境中:

    (none)(省略 devtool 选项) - 不生成 source map。这是一个不错的选择。

    source-map - 整个 source map 作为一个单独的文件生成。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里可以找到它。

    hidden-source-map - 与 source-map 相同,但不会为 bundle 添加引用注释。如果你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会很有用。

    nosources-source-map - 创建的 source map 不包含 sourcesContent(源代码内容)。它可以用来映射客户端上的堆栈跟踪,而无须暴露所有的源代码。你可以将 source map 文件部署到 web 服务器。

(2) 配置示例

webpack 仓库中包含一个 显示所有 devtool 变体效果的示例。这些例子或许会有助于你理解这些差异之处。

example.coffee

  • # Taken from http://coffeescript.org/
  • # Objects:
  • math =
  • root: Math.sqrt
  • square: square
  • cube: (x) -> x * square x
  • # Splats:
  • race = (winner, runners...) ->
  • print winner, runners

webpack.config.js

  • var path = require("path");
  • module.exports = [
  • "eval",
  • "eval-cheap-source-map",
  • "eval-cheap-module-source-map",
  • "eval-source-map",
  • "cheap-source-map",
  • "cheap-module-source-map",
  • "inline-cheap-source-map",
  • "inline-cheap-module-source-map",
  • "source-map",
  • "inline-source-map",
  • "hidden-source-map",
  • "nosources-source-map"
  • ].map(devtool => ({
  • mode: "development",
  • entry: {
  • bundle: "coffee-loader!./example.coffee"
  • },
  • output: {
  • path: path.join(__dirname, "dist"),
  • filename: `./[name]-${devtool}.js`
  • },
  • devtool,
  • optimization: {
  • runtimeChunk: true
  • }
  • }));

Generated source-maps

  • source-map.js and source-map.js.map
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • // Taken from http://coffeescript.org/
  • // Objects:
  • var math, race;
  • math = {
  • root: Math.sqrt,
  • square: square,
  • cube: function(x) {
  • return x * square(x);
  • }
  • };
  • // Splats:
  • race = function(winner, ...runners) {
  • return print(winner, runners);
  • };
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • //# sourceMappingURL=bundle-source-map.js.map
  • {"version":3,"sources":["webpack:///./example.coffee"],"names":[],"mappings":";;;;;;;;;AAEU;;;AAAA;;AACV,OACE;EAAA,MAAQ,IAAI,CAAC,IAAb;EACA,QAAQ,MADR;EAEA,MAAQ,SAAC,CAAD;WAAO,IAAI,OAAO,CAAP;EAAX;AAFR,EAFQ;;;AAOV,OAAO,SAAC,MAAD,KAAS,OAAT;SACL,MAAM,MAAN,EAAc,OAAd;AADK","file":"./bundle-source-map.js","sourcesContent":["# Taken from http://coffeescript.org/\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n"],"sourceRoot":""}
  • hidden-source-map.js and hidden-source-map.js.map
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • // Taken from http://coffeescript.org/
  • // Objects:
  • var math, race;
  • math = {
  • root: Math.sqrt,
  • square: square,
  • cube: function(x) {
  • return x * square(x);
  • }
  • };
  • // Splats:
  • race = function(winner, ...runners) {
  • return print(winner, runners);
  • };
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • {"version":3,"sources":["webpack:///./example.coffee"],"names":[],"mappings":";;;;;;;;;AAEU;;;AAAA;;AACV,OACE;EAAA,MAAQ,IAAI,CAAC,IAAb;EACA,QAAQ,MADR;EAEA,MAAQ,SAAC,CAAD;WAAO,IAAI,OAAO,CAAP;EAAX;AAFR,EAFQ;;;AAOV,OAAO,SAAC,MAAD,KAAS,OAAT;SACL,MAAM,MAAN,EAAc,OAAd;AADK","file":"./bundle-hidden-source-map.js","sourcesContent":["# Taken from http://coffeescript.org/\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n"],"sourceRoot":""}
  • inline-source-map.js
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • // Taken from http://coffeescript.org/
  • // Objects:
  • var math, race;
  • math = {
  • root: Math.sqrt,
  • square: square,
  • cube: function(x) {
  • return x * square(x);
  • }
  • };
  • // Splats:
  • race = function(winner, ...runners) {
  • return print(winner, runners);
  • };
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9leGFtcGxlLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFFVTs7O0FBQUE7O0FBQ1YsT0FDRTtFQUFBLE1BQVEsSUFBSSxDQUFDLElBQWI7RUFDQSxRQUFRLE1BRFI7RUFFQSxNQUFRLFNBQUMsQ0FBRDtXQUFPLElBQUksT0FBTyxDQUFQO0VBQVg7QUFGUixFQUZROzs7QUFPVixPQUFPLFNBQUMsTUFBRCxLQUFTLE9BQVQ7U0FDTCxNQUFNLE1BQU4sRUFBYyxPQUFkO0FBREsiLCJmaWxlIjoiLi9idW5kbGUtaW5saW5lLXNvdXJjZS1tYXAuanMiLCJzb3VyY2VzQ29udGVudCI6WyIjIFRha2VuIGZyb20gaHR0cDovL2NvZmZlZXNjcmlwdC5vcmcvXG5cbiMgT2JqZWN0czpcbm1hdGggPVxuICByb290OiAgIE1hdGguc3FydFxuICBzcXVhcmU6IHNxdWFyZVxuICBjdWJlOiAgICh4KSAtPiB4ICogc3F1YXJlIHhcblxuIyBTcGxhdHM6XG5yYWNlID0gKHdpbm5lciwgcnVubmVycy4uLikgLT5cbiAgcHJpbnQgd2lubmVyLCBydW5uZXJzXG4iXSwic291cmNlUm9vdCI6IiJ9
  • nosources-source-map.js.map
  • {"version":3,"sources":["webpack:///./example.coffee"],"names":[],"mappings":";;;;;;;;;AAEU;;;AAAA;;AACV,OACE;EAAA,MAAQ,IAAI,CAAC,IAAb;EACA,QAAQ,MADR;EAEA,MAAQ,SAAC,CAAD;WAAO,IAAI,OAAO,CAAP;EAAX;AAFR,EAFQ;;;AAOV,OAAO,SAAC,MAAD,KAAS,OAAT;SACL,MAAM,MAAN,EAAc,OAAd;AADK","file":"./bundle-nosources-source-map.js","sourceRoot":""}
  • eval-source-map.js
  • /*
  • * ATTENTION: An "eval-source-map" devtool has been used.
  • * This devtool is neither made for production nor for readable output files.
  • * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
  • * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
  • * or disable the default devtool with "devtool: false".
  • * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
  • */
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • eval("// Taken from http://coffeescript.org/\n\n// Objects:\nvar math, race;\n\nmath = {\n root: Math.sqrt,\n square: square,\n cube: function(x) {\n return x * square(x);\n }\n};\n\n// Splats:\nrace = function(winner, ...runners) {\n return print(winner, runners);\n};\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vZXhhbXBsZS5jb2ZmZWU/MjQxNiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFVTs7O0FBQUEsSUFBQSxJQUFBLEVBQUE7O0FBQ1YsSUFBQSxHQUNFO0VBQUEsSUFBQSxFQUFRLElBQUksQ0FBQyxJQUFiO0VBQ0EsTUFBQSxFQUFRLE1BRFI7RUFFQSxJQUFBLEVBQVEsUUFBQSxDQUFDLENBQUQsQ0FBQTtXQUFPLENBQUEsR0FBSSxNQUFBLENBQU8sQ0FBUDtFQUFYO0FBRlIsRUFGUTs7O0FBT1YsSUFBQSxHQUFPLFFBQUEsQ0FBQyxNQUFELEVBQUEsR0FBUyxPQUFULENBQUE7U0FDTCxLQUFBLENBQU0sTUFBTixFQUFjLE9BQWQ7QUFESyIsInNvdXJjZXNDb250ZW50IjpbIiMgVGFrZW4gZnJvbSBodHRwOi8vY29mZmVlc2NyaXB0Lm9yZy9cblxuIyBPYmplY3RzOlxubWF0aCA9XG4gIHJvb3Q6ICAgTWF0aC5zcXJ0XG4gIHNxdWFyZTogc3F1YXJlXG4gIGN1YmU6ICAgKHgpIC0+IHggKiBzcXVhcmUgeFxuXG4jIFNwbGF0czpcbnJhY2UgPSAod2lubmVyLCBydW5uZXJzLi4uKSAtPlxuICBwcmludCB3aW5uZXIsIHJ1bm5lcnNcbiJdLCJmaWxlIjoiMC5qcyJ9\n//# sourceURL=webpack-internal:///0\n");
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • eval.js
  • /*
  • * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
  • * This devtool is neither made for production nor for readable output files.
  • * It uses "eval()" calls to create a separate source file in the browser devtools.
  • * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
  • * or disable the default devtool with "devtool: false".
  • * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
  • */
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • eval("// Taken from http://coffeescript.org/\n\n// Objects:\nvar math, race;\n\nmath = {\n root: Math.sqrt,\n square: square,\n cube: function(x) {\n return x * square(x);\n }\n};\n\n// Splats:\nrace = function(winner, ...runners) {\n return print(winner, runners);\n};\n\n\n//# sourceURL=webpack:///./example.coffee?../../node_modules/coffee-loader/dist/cjs.js");
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • eval-cheap-source-map.js
  • /*
  • * ATTENTION: An "eval-source-map" devtool has been used.
  • * This devtool is neither made for production nor for readable output files.
  • * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
  • * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
  • * or disable the default devtool with "devtool: false".
  • * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
  • */
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • eval("// Taken from http://coffeescript.org/\n\n// Objects:\nvar math, race;\n\nmath = {\n root: Math.sqrt,\n square: square,\n cube: function(x) {\n return x * square(x);\n }\n};\n\n// Splats:\nrace = function(winner, ...runners) {\n return print(winner, runners);\n};\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy8uL2V4YW1wbGUuY29mZmVlP2VlNTgiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gVGFrZW4gZnJvbSBodHRwOi8vY29mZmVlc2NyaXB0Lm9yZy9cblxuLy8gT2JqZWN0czpcbnZhciBtYXRoLCByYWNlO1xuXG5tYXRoID0ge1xuICByb290OiBNYXRoLnNxcnQsXG4gIHNxdWFyZTogc3F1YXJlLFxuICBjdWJlOiBmdW5jdGlvbih4KSB7XG4gICAgcmV0dXJuIHggKiBzcXVhcmUoeCk7XG4gIH1cbn07XG5cbi8vIFNwbGF0czpcbnJhY2UgPSBmdW5jdGlvbih3aW5uZXIsIC4uLnJ1bm5lcnMpIHtcbiAgcmV0dXJuIHByaW50KHdpbm5lciwgcnVubmVycyk7XG59O1xuIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOyIsInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///0\n");
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • eval-cheap-module-source-map.js
  • /*
  • * ATTENTION: An "eval-source-map" devtool has been used.
  • * This devtool is neither made for production nor for readable output files.
  • * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
  • * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
  • * or disable the default devtool with "devtool: false".
  • * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
  • */
  • (self["webpackChunk"] = self["webpackChunk"] || []).push([[0],[
  • /* 0 */
  • /*!*********************************************************************!*\
  • !*** ../../node_modules/coffee-loader/dist/cjs.js!./example.coffee ***!
  • \*********************************************************************/
  • /*! unknown exports (runtime-defined) */
  • /*! runtime requirements: */
  • /***/ (() => {
  • eval("// Taken from http://coffeescript.org/\n\n// Objects:\nvar math, race;\n\nmath = {\n root: Math.sqrt,\n square: square,\n cube: function(x) {\n return x * square(x);\n }\n};\n\n// Splats:\nrace = function(winner, ...runners) {\n return print(winner, runners);\n};\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vLy4vZXhhbXBsZS5jb2ZmZWU/MjQxNiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFVTs7O0FBQUEsSUFBQSxJQUFBLEVBQUE7O0FBQ1YsSUFBQSxHQUNFO0VBQUEsSUFBQSxFQUFRLElBQUksQ0FBQyxJQUFiO0VBQ0EsTUFBQSxFQUFRLE1BRFI7RUFFQSxJQUFBLEVBQVEsUUFBQSxDQUFDLENBQUQsQ0FBQTtXQUFPLENBQUEsR0FBSSxNQUFBLENBQU8sQ0FBUDtFQUFYO0FBRlIsRUFGUTs7O0FBT1YsSUFBQSxHQUFPLFFBQUEsQ0FBQyxNQUFELEVBQUEsR0FBUyxPQUFULENBQUE7U0FDTCxLQUFBLENBQU0sTUFBTixFQUFjLE9BQWQ7QUFESyIsInNvdXJjZXNDb250ZW50IjpbIiMgVGFrZW4gZnJvbSBodHRwOi8vY29mZmVlc2NyaXB0Lm9yZy9cblxuIyBPYmplY3RzOlxubWF0aCA9XG4gIHJvb3Q6ICAgTWF0aC5zcXJ0XG4gIHNxdWFyZTogc3F1YXJlXG4gIGN1YmU6ICAgKHgpIC0+IHggKiBzcXVhcmUgeFxuXG4jIFNwbGF0czpcbnJhY2UgPSAod2lubmVyLCBydW5uZXJzLi4uKSAtPlxuICBwcmludCB3aW5uZXIsIHJ1bm5lcnNcbiJdLCJmaWxlIjoiMC5qcyJ9\n//# sourceURL=webpack-internal:///0\n");
  • /***/ })
  • ],
  • 0,[[0,1]]]);
  • cheap-module-source-map.js.map
  • {"version":3,"file":"./bundle-cheap-module-source-map.js","sources":["webpack:///./example.coffee"],"sourcesContent":["# Taken from http://coffeescript.org/\n\n# Objects:\nmath =\n root: Math.sqrt\n square: square\n cube: (x) -> x * square x\n\n# Splats:\nrace = (winner, runners...) ->\n print winner, runners\n"],"mappings":";;;;;;;;;AAEA;AACA;;AADA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAFA;AACA;;AAIA;AACA;AADA;AACA;AACA;A;;A","sourceRoot":""}
  • cheap-source-map.js.map
  • {"version":3,"file":"./bundle-cheap-source-map.js","sources":["webpack:///./example.coffee"],"sourcesContent":["// Taken from http://coffeescript.org/\n\n// Objects:\nvar math, race;\n\nmath = {\n root: Math.sqrt,\n square: square,\n cube: function(x) {\n return x * square(x);\n }\n};\n\n// Splats:\nrace = function(winner, ...runners) {\n return print(winner, runners);\n};\n"],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A;;A","sourceRoot":""}
(3) 演练

对于本指南,我们将使用 inline-source-map 选项,这有助于解释说明示例意图(此配置仅用于示例,不要用于生产环境):

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • + devtool: 'inline-source-map',
  • plugins: [
  • new CleanWebpackPlugin(),
  • new HtmlWebpackPlugin({
  • title: 'Development',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

现在,让我们来做一些调试,在 print.js 文件中生成一个错误:

src/print.js

  • export default function printMe() {
  • - console.log('I get called from print.js!');
  • + cosnole.log('I get called from print.js!');
  • }

**运行 npm run build**

现在,在浏览器中打开生成的 index.html 文件,点击按钮,并且在控制台查看显示的错误。错误应该如下:

  • Uncaught ReferenceError: cosnole is not defined
  • at HTMLButtonElement.printMe (print.js:2)

我们可以看到,此错误包含有发生错误的文件(print.js)和行号(2)的引用。这是非常有帮助的,因为现在我们可以确切地知道,所要解决问题的位置。

2、选择一个开发工具

在每次编译代码时,手动运行 npm run build 会显得很麻烦。

webpack 提供几种可选方式,帮助你在代码发生变化后自动编译代码:

多数场景中,你可能需要使用 webpack-dev-server,但是不妨探讨一下以上的所有选项。

(1) 使用 watch mode(观察模式)

你可以指示 webpack “watch” 依赖图中所有文件的更改。如果其中一个文件被更新,代码将被重新编译,所以你不必再去手动运行整个构建。

我们添加一个用于启动 webpack watch mode 的 npm scripts:

package.json

  • {
  • "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": {
  • "clean-webpack-plugin": "^3.0.0",
  • "html-webpack-plugin": "^4.5.0",
  • "webpack": "^5.4.0",
  • "webpack-cli": "^4.2.0"
  • },
  • "dependencies": {
  • "lodash": "^4.17.20"
  • }
  • }

如果不想在 watch 触发增量构建后删除 index.html 文件,可以在 CleanWebpackPlugin 中配置 cleanStaleWebpackAssets 选项 来实现:

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • devtool: 'inline-source-map',
  • plugins: [
  • - new CleanWebpackPlugin(),
  • + new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
  • new HtmlWebpackPlugin({
  • title: 'Development',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

现在,你可以在命令行中运行 npm run watch,然后就会看到 webpack 是如何编译代码。 然而,你会发现并没有退出命令行。这是因为此 script 当前还在 watch 你的文件。

现在,webpack 观察文件的同时,先移除我们之前加入的错误:

src/print.js

  • export default function printMe() {
  • - cosnole.log('I get called from print.js!');
  • + console.log('I get called from print.js!');
  • }

现在,保存文件并检查 terminal(终端) 窗口。应该可以看到 webpack 自动地重新编译修改后的模块!

唯一的缺点是,为了看到修改后的实际效果,你需要刷新浏览器。如果能够自动刷新浏览器就更好了,因此接下来我们会尝试通过 webpack-dev-server 实现此功能。

(2) 使用 webpack-dev-server

webpack-dev-server 为你提供了一个简单的 web server,并且具有 live reloading(实时重新加载) 功能。设置如下:

  • npm install --save-dev webpack-dev-server

修改配置文件,告知 dev server,从什么位置查找文件:

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • devtool: 'inline-source-map',
  • + devServer: {
  • + contentBase: './dist',
  • + },
  • plugins: [
  • new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
  • new HtmlWebpackPlugin({
  • title: 'Development',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • },
  • };

以上配置告知 webpack-dev-server,将 dist 目录下的文件 serve 到 localhost:8080 下。

我们添加一个可以直接运行 dev server 的 script:

package.json

  • {
  • "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": {
  • "clean-webpack-plugin": "^3.0.0",
  • "html-webpack-plugin": "^4.5.0",
  • "webpack": "^5.4.0",
  • "webpack-cli": "^4.2.0",
  • "webpack-dev-server": "^3.11.0"
  • },
  • "dependencies": {
  • "lodash": "^4.17.20"
  • }
  • }

现在,在命令行中运行 npm start,我们会看到浏览器自动加载页面。如果你更改任何源文件并保存它们,web server 将在编译代码后自动重新加载。试试看!

(3) 使用 webpack-dev-middleware

webpack-dev-middleware 是一个封装器(wrapper),它可以把 webpack 处理过的文件发送到一个 server。 webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行更多自定义设置。下面是一个 webpack-dev-middleware 配合 express server 的示例。

首先,安装 express 和 webpack-dev-middleware

  • npm install --save-dev express webpack-dev-middleware

现在,我们需要调整 webpack 配置文件,以确保 middleware(中间件) 功能能够正确启用:

webpack.config.js

  • const path = require('path');
  • const HtmlWebpackPlugin = require('html-webpack-plugin');
  • const { CleanWebpackPlugin } = require('clean-webpack-plugin');
  • module.exports = {
  • mode: 'development',
  • entry: {
  • index: './src/index.js',
  • print: './src/print.js',
  • },
  • devtool: 'inline-source-map',
  • devServer: {
  • contentBase: './dist',
  • },
  • plugins: [
  • new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
  • new HtmlWebpackPlugin({
  • title: 'Development',
  • }),
  • ],
  • output: {
  • filename: '[name].bundle.js',
  • path: path.resolve(__dirname, 'dist'),
  • + publicPath: '/',
  • },
  • };

我们将会在 server 脚本使用 publicPath,以确保文件资源能够正确地 serve 在 http://localhost:3000 下,稍后我们会指定 port number(端口号)。接下来是设置自定义 express server:

project

  • webpack-demo
  • |- package.json
  • |- webpack.config.js
  • + |- server.js
  • |- /dist
  • |- /src
  • |- index.js
  • |- print.js
  • |- /node_modules

server.js

  • const express = require('express');
  • const webpack = require('webpack');
  • const webpackDevMiddleware = require('webpack-dev-middleware');
  • const app = express();
  • const config = require('./webpack.config.js');
  • const compiler = webpack(config);
  • // 告知 express 使用 webpack-dev-middleware,
  • // 以及将 webpack.config.js 配置文件作为基础配置。
  • app.use(
  • webpackDevMiddleware(compiler, {
  • publicPath: config.output.publicPath,
  • })
  • );
  • // 将文件 serve 到 port 3000。
  • app.listen(3000, function () {
  • console.log('Example app listening on port 3000!\n');
  • });

现在,添加一个 npm script,以使我们更方便地运行 server:

package.json

  • {
  • "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": {
  • "clean-webpack-plugin": "^3.0.0",
  • "express": "^4.17.1",
  • "html-webpack-plugin": "^4.5.0",
  • "webpack": "^5.4.0",
  • "webpack-cli": "^4.2.0",
  • "webpack-dev-middleware": "^4.0.2",
  • "webpack-dev-server": "^3.11.0"
  • },
  • "dependencies": {
  • "lodash": "^4.17.20"
  • }
  • }

现在,在 terminal(终端) 中执行 npm run server,将会有类似如下信息输出:

  • 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.4.0 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.4.0 compiled successfully in 19 ms
  • <i> [webpack-dev-middleware] Compiled successfully.

现在,打开浏览器,访问 http://localhost:3000。应该看到 webpack 应用程序已经运行!

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐