inputFileSystem и outputFileSystem являются ключевыми абстракциями в архитектуре Webpack, через которые происходит вся работа с файловой системой при компиляции. Эти интерфейсы позволяют Webpack быть независимым от конкретной реализации файлового хранилища, обеспечивая возможность подмены источника и назначения данных: от реального диска до виртуальной памяти, сетевых хранилищ или специализированных кэширующих слоёв.
Внутри экземпляра компилятора Webpack (Compiler)
файловая система не используется напрямую через fs Node.js.
Вместо этого применяется абстракция, которая позволяет унифицировать
операции чтения и записи:
compiler.inputFileSystem — слой чтения исходных файлов
и зависимостейcompiler.outputFileSystem — слой записи собранных
ассетовТакое разделение критично для процессов:
Webpack ожидает, что эти объекты реализуют API, совместимый с Node.js
fs (частично), включая методы readFile,
stat, readdir, readlink и другие,
используемые резолвером и загрузчиком модулей.
inputFileSystem используется на этапе резолвинга модулей
и анализа зависимостей. Когда Webpack встречает импорт или require, он
не обращается напрямую к диску, а вызывает методы абстрактной файловой
системы.
Ключевые сценарии использования:
.js, .ts,
.css)Типичный набор методов:
readFile(path, callback)stat(path, callback)readdir(path, callback)readlink(path, callback)lstat(path, callback)В реальной конфигурации Webpack часто использует обёртку
CachedInputFileSystem, которая добавляет слой кэширования
поверх базовой FS:
const fs = require("fs");
const CachedInputFileSystem = require("enhanced-resolve").CachedInputFileSystem;
compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
Здесь происходит важный момент: Webpack ускоряет резолвинг за счёт кеширования результатов чтения файлов и статусов, снижая количество обращений к диску.
В режиме watch это особенно важно, поскольку один и тот же модуль может проверяться многократно при пересборке графа зависимостей.
outputFileSystem отвечает за сохранение итоговых
ассетов, которые генерирует компилятор после прохождения всех
стадий:
По умолчанию в Node.js-среде используется стандартный
fs, но в dev-сценариях почти всегда происходит подмена.
Методы, которые ожидаются от outputFileSystem:
writeFile(path, data, callback)mkdirp(path, options, callback) или
mkdir(path, callback)stat(path, callback)unlink(path, callback)rmdir(path, callback)Важный момент: Webpack сам по себе не обязан записывать файлы на диск. Он может работать полностью в памяти, а запись становится задачей внешнего слоя (например, dev middleware).
В development-среде часто применяется виртуальная файловая система.
Один из распространённых вариантов — memfs:
const { Volume } = require("memfs");
const memoryFs = new Volume();
compiler.outputFileSystem = memoryFs;
Это позволяет:
webpack-dev-middleware и webpack-dev-server
активно используют этот подход, создавая слой между компилятором и
HTTP-ответами.
В связке с middleware файловая система становится ключевым элементом потока данных:
outputFileSystemПри этом физический диск может вообще не участвовать.
Типичная архитектура:
compiler.outputFileSystem = memfscompiler.outputFileSystemЭто обеспечивает минимальную задержку между изменением кода и обновлением браузера.
Webpack позволяет полностью заменить файловую систему, что используется в сложных интеграциях:
Пример кастомной input FS:
class CustomInputFS {
readFile(path, callback) {
// чтение из базы данных или API
}
stat(path, callback) {
// эмуляция структуры файлов
}
readdir(path, callback) {
// генерация виртуальной структуры
}
}
compiler.inputFileSystem = new CustomInputFS();
Такой подход позволяет Webpack работать с источниками, которые не существуют как физические файлы.
Одним из самых важных компонентов является
CachedInputFileSystem. Он уменьшает нагрузку на диск за
счёт:
statМеханика:
Это особенно критично при больших проектах, где число модулей достигает десятков тысяч.
В режиме наблюдения (watch) Webpack постоянно проверяет
изменения файлов. Здесь inputFileSystem играет роль
источника истины.
Процесс выглядит так:
inputFileSystem.stat проверяет изменения mtimeЕсли используется кэшированная FS, сравнение метаданных происходит быстрее, что уменьшает задержку пересборки.
Модуль enhanced-resolve тесно связан с
inputFileSystem. Он использует FS для:
node_modulesКаждый вызов резолвера опирается на:
statreadlinkreaddirТаким образом, любая кастомизация FS напрямую влияет на процесс построения dependency graph.
Webpack не требует полного соответствия Node.js fs, но
ожидает:
ENOENT,
EACCES)При создании кастомной FS важно учитывать:
stat-метаданных (mtime, size)Нарушение этих контрактов может привести к некорректному кешированию и “фантомным” пересборкам.
В тестовых сценариях Webpack часто запускается с виртуальной FS:
Пример:
const { Volume } = require("memfs");
const fs = new Volume();
compiler.inputFileSystem = fs;
compiler.outputFileSystem = fs;
Это позволяет полностью изолировать сборку.
В production-сборке outputFileSystem чаще всего:
fs)В development:
Это разделение позволяет Webpack адаптироваться к разным стратегиям доставки кода без изменения core логики.
Файловые системы тесно связаны с lifecycle hooks:
beforeRunrunwatchRunemitafterEmitНа этапе emit происходит финальная запись ассетов в
outputFileSystem. Здесь важно, чтобы FS корректно
реализовывала методы записи и создания директорий.
Ошибки на этом этапе часто связаны с:
mkdirРазделение input и output FS превращает Webpack в полностью абстрагированный компилятор, независимый от среды выполнения. Это даёт возможность:
Фактически, файловая система становится не инфраструктурным ограничением, а частью конфигурации компиляции, влияющей на производительность, архитектуру и поведение сборочного процесса.