解决 webpack/webpack-dev-server 监听文件时频繁触发编译和回调的问题

问题背景

webpack 的使用其实并无太多难点,对于开发者来讲,webpack 是一个黑盒,按照官方配置便可快速的配置开发环境。node

一样的,若是使用过程当中有一些不常见的报错或异常行为,这个 webpack 黑盒 产生报错或异常的缘由就较难排查。webpack

好比,若是文件 index.js 在被修改后,马上做为 webpack 的入口文件,并启动 webpack 且监听,会引发持续时间大约 10s 的频繁的编译和回调。web

这个现象在 webpack-dev-server 上能够重现。bash

问题还原

以 webpack 为例,代码以下:webpack-dev-server

const webpack = require('webpack');
const fse = require('fs-extra');
const fs = require('fs');
const path = require('path');
    
const entryFile = path.join(__dirname, './src/index.js');
const tmpFile = path.join(__dirname, './src/tmp.js');
    
// 临时文件复制到入口文件,会触发持续时间大约 10s 的回调
fse.copySync(tmpFile, entryFile);
    
// 入口文件被修改,一样会触发持续时间大约 10s 的回调
// fs.writeFileSync(entryFile, (fs.readFileSync(entryFile).toString() + ''));
    
const webpackConfig = {
    
   // 启动 webpack 监听
   watch: true,
    
   entry: {
       index: './src/index.js'
   },
   output: {
       path: path.resolve(`./dist/`), // 绝对路径
       filename: '[name].js'
   }
};
    
let startTime = Date.now();
let loopCount = 0;
const compiler = webpack(webpackConfig, function() {

    console.log(
      `webpack 触发回调, 距离 webpack 启动的时间: ${(Date.now() - startTime) / 1000} s`,
      `回调次数: ${++loopCount}`
    );

});
复制代码

效果:oop

image

原理分析

  • 寻找相关代码ui

    node_modules/watchpack/lib/DirectoryWatcher.js 中有这样一段代码:spa

    image

    image

  • 是 watchpack 的问题,仍是 webpack 的问题,仍是 webpack 和 watchpack 的配合的问题?3d

    分析这个问题,可能须要一层层理解相关的逻辑,成本很大,那么,咱们可否经过一些蛛丝马迹猜测一下问题可能出在哪里呢?code

    注意到 node_modules/watchpack/lib/DirectoryWatcher.js 中有大量的逻辑涉及到 mtime,也就是文件的修改时间。咱们发现的编译和回调持续 10s 左右极有可能和 FS_ACCURACY 的值 10000 有关。

  • 可能的解决方案

    既然可能和文件的 mtime 有关,那就尝试把被修改的入口文件的 mtime 修改到 10s(保险起见,大于 10s 更好) 之前,看看可否解决问题。

    代码以下:

    // 临时文件复制到入口文件,会触发持续时间大约 10s 的回调
    fse.copySync(tmpFile, entryFile);
    
    // 修改入口文件的 mtime
    fs.utimesSync(entryFile, ((Date.now() - 10 * 1000)) / 1000, (Date.now() - 10 * 1000) / 1000);
    
    // 启动 webpack...
    复制代码

    结果是:

    image

    问题解决!

后续

若是入口文件有依赖其余的模块且这些模块也有修改的话,该模块的文件时间戳也须要修改,这是须要注意的一点。

不过这个方案仍是比较 hack。这个问题已反馈到 webpack 和 watchpack,但从官方的反馈来看,近期修复的可能性不大。

相关文章
相关标签/搜索