webpack5 小记-开发体验篇

前言

在实际的项目开发中,基于框架提供的脚手架等工具,我们可以非常方便地实现监听文件变化,并自动打包、打包完成后再开启本地服务,通过浏览器访问打包后的页面。整个过程都是自动的,不需要手动处理。本文会分拆这几个过程,针对每个过程涉及的工具,一步一步完成各个过程中涉及的工具链引入及基本使用。

自动打包

给 webpack 执行命令添加 --watch 参数即可实现自动编译打包。

javascript 复制代码
yarn webpack --watch

当 webpack 监听到源码文件内容有变化时,会重新执行打包命令,生成 dist 文件。

自动刷新

使用 BrowserSync 实现。安装及使用命令如下:

javascript 复制代码
// 安装 browser-sync
yarn add browser-sync dist --files "**/*"
// 监听 dist 文件夹下面所有文件的变化
yarn browser-sync dist --files "**/*"

自动打包+页面刷新的实现:

  1. 修改源代码;
  2. webpack 监听到代码文件内容有变化变更,自动打包,生成一个新的 dist 包;
  3. 使用 browser-sync 监听到 dist 文件夹,会重新触发浏览器页面刷新。

本地开发服务器

DevServer

webpack 的 DevServer 自动集成了【自动打包】和【浏览器刷新】的功能。

  1. 在项目中安装开发依赖 webpack-dev-server。
javascript 复制代码
yarn add webpack-dev-server --dev
  1. 启动 webpack-dev-server
javascript 复制代码
yarn webpack-dev-server
  1. 启动并同时打开浏览器
javascript 复制代码
yarn webpack-dev-server --open

PS:webpack-dev-server 启动时,会将打包后的 dist 文件夹存放在内存中,浏览器访问的是内存中的 dist 文件夹,所以在项目根目录中不会出现 dist 文件夹。

静态资源访问

默认情况下,通过 webpack-dev-server 我们访问的是 dist 文件夹中的资源。不仅如此,它还支持其他静态资源文件的访问。

在 webpack.config.js 中添加以下配置:

javascript 复制代码
devServer: {
    static: {
      directory: path.join(__dirname, "public"),
    },
    compress: true,
    port: 9000
}

static 中配置的是额外的静态资源访问路径。webpack 针对静态资源的访问策略是这样的:浏览器访问 index.html 文件时,若 dist 文件夹中存在同名文件,本地服务会优先返回 dist 文件中的 html 文件。若访问不同文件时,则本地服务器会在不同查找同名文件。

本地代理服务

wepack 支持在开发阶段给我们提供代理服务,当项目打包并进行同源部署后。此代理服务配置就不会再起作用了。

javascript 复制代码
devServer: {
    ...
    proxy: {
      "/api/": {
        target: "https://api.github.com",
        pathRewrite: {
          "^/api": "",
        },
        changeOrigin: true,
      },
    },
},

proxy 配置说明如下:

https://localhost:8088/api/users' 变成 'api.github.com/users'

  • changeOrigin: 设置为 true,会将 http 请求中的 host 字段改为非 localhost 的请求 ip。因为有些服务器针对 host 字段为 localhost 的请求时,不会正常响应。

devtool 设置

source map

开发过程中的代码和实际生产运行的代码会存在较大差异,Source Map 是源码和编译后代码之间的映射。当生产代码出现问题时,通过 source map 我们可以定位到出错的源代码。

在压缩后的 JS 中添加注释,注释中指定 source map 的文件路径即可。

javascript 复制代码
//# sourceMappingURL=jquery-3.4.1.min.map

开启 source map,webpack.config.js 添加以下配置即可:

javascript 复制代码
module.exports = {
  ...
  devtool: "source-map",
  ...
};

eval 模式

浏览器控制台中以 eval 方式执行 js 代码,通过 sourceURL 可以指定 JS 执行环境所属的上下文。

javascript 复制代码
eval('console.log(123) //# sourceURL=./foo/bar.js')

webpack 设置 devtool 为 eval 值,打包后,报错源码会直接定位到 webpack mode 为 development 的模块代码中。

javascript 复制代码
module.exports = {
  ...
  devtool: "eval",
  ...
};

配置项

webpack 提供 20 余种 devtool 选项供我们选择。具体可参考:webpack.js.org/configurati... webpack 创建多个打包配置,针对 devtool 的不同选项生成不同的打包页面。并在源码中添加异常代码。访问打包页面后控制台的异常报错信息,再定位异常代码位置。

webpack.config.js 如下:

javascript 复制代码
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");

const allModes = [
  "eval",
  ...
  "hidden-cheap-source-map",
  "hidden-cheap-module-source-map",
  "hidden-source-map",
];

module.exports = allModes.map((mode) => {
  return {
    mode: "none",
    devtool: mode,
    entry: "./src/main.js",
    output: {
      filename: `js/${mode}.js`,
    },
    module: {
      rules: [
        {
          test: /.js$/,
          use: {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
            },
          },
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: "./src/index.html",
        filename: path.join(__dirname, `./dist/html/${mode}.html`),
      }),
    ],
  };
});

配置项说明如下:

  • eval 模式:模块代码会被放到 eval 函数中执行。只能定位到模块代码所在文件,无法具体到实际位置。
  • eval-source-map:可以定位到具体代码的行和列。
  • cheap-eval-source-map: 只能定位到具体的行,没有具体的列信息,显示的是代码经过 ES6 转换的结果,空行也会被剔除。
  • cheap-module-eval-source-map: 打包后的代码不会被 loader 进行处理,在开发阶段建议使用此模式。
  • inline-source-map: 打包后 js 文件引入 map 文件的方式为 DataURL 形式,不是直接文件形式,基本用不上。
  • hidden-source-map: 在开发工具中无法查看 source-map 文件信息,是因为在 js 文件中没有进行引用。开发第 3 方包的时候可以用到。
  • nosources-source-map: 只能查看源代码的信息,在开发者工具中看不到具体源代码的位置和内容。

总结:

以不同关键字开头的配置项表示不同类型的模块代码压缩配置。

  • eval-标识是否使用 eval 执行模块代码
  • cheap: source-map 是否包含行信息
  • module: 是否能够得到 Loader 处理之前的源代码

使用场景:

  • 开发模式下,使用 cheap-module-eval-source-map 模式。
  • 生产模式:使用 none,不生成 source-map。避免暴露源代码,这种情况不能定位到具体源码位置。
  • nosources-source-map: 可以定位到代码位置,但是在开发者工具中看不到源码内容。

HMR(Hot Module Replacement)

模块热替换,实时替换应用程序中的某个模块,不改变应用的运行状态。简单点说,当我们对某个模块进行修改后,页面只更新修改后的模块,其他模块不受影响。通过这种方式可以避免页面刷新导致的状态丢失。在 Vue 或 React 等前端框架中,已内置了 HMR 的特性。下面介绍的是非前端框架的 HMR 处理。

开启 HMR

HMR 已集成在 webpack-dev-server 中,使用 webpack-dev-server 命令时添加 --hot 参数即可启用。

javascript 复制代码
yarn webpack-dev-server --hot

webpack.config.js 添加配置

javascript 复制代码
const webpack = require("webpack");

module.exports = {
    devServer: {
        hot: true,
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
    ]
}

此配置添加后,修改样式文件不会影响运行状态,因为 style-loader 已经内置了样式的 HMR 处理。但是修改 JS 文件还是会导致页面自动刷新。这时候我们需要手动处理。

在 bundle.js 中搜索 "module.hot.accept" 可以找到关键字:

javascript 复制代码
module.hot.accept(
      /*! !!../node_modules/css-loader/dist/cjs.js!./global.css */ "./node_modules/css-loader/dist/cjs.js!./src/global.css",
      __WEBPACK_OUTDATED_DEPENDENCIES__ => { /* harmony import */ _node_modules_css_loader_dist_cjs_js_global_css__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! !!../node_modules/css-loader/dist/cjs.js!./global.css */ "./node_modules/css-loader/dist/cjs.js!./src/global.css");
(function () {
        if (!isEqualLocals(oldLocals, isNamedExport ? _node_modules_css_loader_dist_cjs_js_global_css__WEBPACK_IMPORTED_MODULE_6__ : _node_modules_css_loader_dist_cjs_js_global_css__WEBPACK_IMPORTED_MODULE_6__["default"].locals, isNamedExport)) {
                module.hot.invalidate();

                return;
              } 

手动处理 JS 模块 HMR

在 module.hot.accept 函数的回调参数中添加处理逻辑。

javascript 复制代码
let lastEditor = editor;
module.hot.accept("./editor", () => {
  console.log("editor module updated...", lastEditorText);

  const lastEditorText = editor.innerHTML;
  document.body.removeChild(lastEditor);
  const newEditor = createEditor();
  newEditor.innerHTML = lastEditorText;
  document.body.append(newEditor);
  lastEditor = newEditor;
});

手动处理图片模块 HMR

javascript 复制代码
// 手动图片模块
module.hot.accept("./editor-wrapper-bg.jpg", () => {
  img.src = editorWrapperBg;
  console.log("img module updated...");
});

注意事项

  • 在 hot 模式下,手动添加的 HMR 代码出现异常时,会导致页面自动刷新。
  • 使用 only 模式,添加配置后重启解决 hot 模式产生的问题。
javascript 复制代码
devServer: {    
    hot: "only"
}

总结

没啥总结的,以上...

相关推荐
守城小轩1 小时前
JavaScript vs Python 用于 Web Scraping(2025):终极对比指南
前端·chrome·chrome devtools·指纹浏览器·浏览器开发·超级浏览器
风逸hhh4 小时前
python打卡day29@浙大疏锦行
开发语言·前端·python
LuckyLay4 小时前
Vue百日学习计划Day33-35天详细计划-Gemini版
前端·vue.js·学习
ᖰ・◡・ᖳ4 小时前
JavaScript:PC端特效--缓动动画
开发语言·前端·javascript·css·学习·html5
会飞的鱼先生5 小时前
vue2、vue3项目打包生成txt文件-自动记录打包日期:git版本、当前分支、提交人姓名、提交日期、提交描述等信息 和 前端项目的版本号json文件
前端·vue.js·git·json
!win !6 小时前
uni-app项目从0-1基础架构搭建全流程
前端·uni-app
c_zyer6 小时前
使用 nvm 管理 Node.js 和 npm 版本
前端·npm·node.js
布Coder6 小时前
前端 vue + element-ui 框架从 0 - 1 搭建
前端·javascript·vue.js
i_am_a_div_日积月累_6 小时前
Element Plus 取消el-form-item点击触发组件,改为原生表单控件
前端·vue.js·elementui
集成显卡6 小时前
网页 H5 微应用接入钉钉自动登录
前端·后端·钉钉