解決 webpack/webpack-dev-server 監聽文件時頻繁觸發編譯和回調的問題

問題背景

webpack 的使用其實並無太多難點,對於開發者來講,webpack 是一個黑盒,按照官方配置便可快速的配置開發環境。node

一樣的,若是使用過程當中有一些不常見的報錯或異常行爲,這個 webpack 黑盒 產生報錯或異常的緣由就較難排查。webpack

好比,若是文件 index.js 在被修改後,馬上做爲 webpack 的入口文件,並啓動 webpack 且監聽,會引發持續時間大約 10s 的頻繁的編譯和回調。web

這個現象在 webpack-dev-server 上能夠重現。webpack-dev-server

問題還原

以 webpack 爲例,代碼以下:oop

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}`
    );

});

效果:ui

image

原理分析

  • 尋找相關代碼

    node_modules/watchpack/lib/DirectoryWatcher.js 中有這樣一段代碼:spa

    image

    image

  • 是 watchpack 的問題,仍是 webpack 的問題,仍是 webpack 和 watchpack 的配合的問題?

    分析這個問題,可能須要一層層理解相關的邏輯,成本很大,那麼,咱們可否經過一些蛛絲馬跡猜測一下問題可能出在哪裏呢?3d

    注意到 node_modules/watchpack/lib/DirectoryWatcher.js 中有大量的邏輯涉及到 mtime,也就是文件的修改時間。咱們發現的編譯和回調持續 10s 左右極有可能和 FS_ACCURACY 的值 10000 有關。code

  • 可能的解決方案server

    既然可能和文件的 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,但從官方的反饋來看,近期修復的可能性不大。

相關文章
相關標籤/搜索