Можно ли очистить кеш загруженных модулей в Node.js во время выполнения?

Ответ

Да, это возможно через глобальный объект require.cache. Он представляет собой объект, где ключами являются абсолютные пути к модулям, а значениями — сами закешированные модули.

Как очистить кеш конкретного модуля:

const pathToModule = require.resolve('./my-config.js');
delete require.cache[pathToModule];
// Следующий require('./my-config.js') загрузит модуль заново.

Как очистить весь кеш модулей:

Object.keys(require.cache).forEach((cacheKey) => {
  delete require.cache[cacheKey];
});

Важные предостережения из практики:

  1. Сброс состояния: Если модуль экспортирует объект с состоянием (синглтон, кэш в памяти), его очистка приведет к потере этого состояния, что может сломать логику приложения.
  2. Утечки ресурсов: Если модуль инициализирует таймеры, открывает соединения с БД или создает другие ресурсы, их необходимо корректно закрывать перед удалением из кеша, иначе возникнут утечки.
  3. Производительность: Постоянная перезагрузка модулей негативно скажется на производительности.

Практическое применение: Я использовал очистку кеша в основном в двух сценариях:

  • При разработке инструментов CLI, где нужно гарантировать загрузку самой свежей версии пользовательского конфига при каждом вызове.
  • В режиме разработки «горячей перезагрузки» (hot reload) для серверов, где перезагрузка всего процесса нежелательна. Однако для этого сейчас чаще используются специализированные решения вроде nodemon или node --watch (с Node.js v18.11.0+).

Ответ 18+ 🔞

Ах ты ж ёпта, ну и тема подкинули! Сижу тут, кофе попиваю, и вдруг — бац! — вопрос про require.cache. Ну, мужик, это ж классика, как водка с огурцом! Слушай сюда, сейчас всё разжуем.

Вот представь: Node.js, он такой хитрая жопа, когда модуль загружает — в кеш его пихает, чтобы второй раз не париться. А кеш этот — обычный объект, require.cache, где ключики — пути к файлам, а значения — уже скомпилированные модульчики. Красота, да? Но иногда надо, чтобы он забыл. Например, конфиг переписал, а приложение упёртое, старое не отпускает.

Так вот, если хочешь конкретный модуль заставить перезагрузиться — делай так:

const pathToModule = require.resolve('./my-config.js');
delete require.cache[pathToModule];
// Теперь следующий require('./my-config.js') будет как первый раз — свеженький, с пылу с жару.

А если совсем крыша поехала и надо всё с нуля — можно и всю избушку подмести:

Object.keys(require.cache).forEach((cacheKey) => {
  delete require.cache[cacheKey];
});

Но тут, чувак, внимание, блядь! Это не игрушки. Представь, модуль-то мог уже наделать делов: глобальный объект-синглтон создал, к базе подключился, таймеры настроил. Ты его из кеша выкинешь — а он, сука, как призрак, свои таймеры-то оставил тикать, соединения висеть. Утечка ресурсов — и приложение потом как пьяный ёжик, ебать копать, ползает.

На практике я эту фишку юзал, в основном, в двух случаях, как отличник-извращенец:

  1. В разных CLI-шниках, которые я писал. Там надо было, чтобы конфиг пользователя каждый раз читался заново, а не как вчерашний борщ. Иначе доверия ебать ноль.
  2. Для горячей перезагрузки (hot reload) на сервере в режиме разработки. Раньше это была магия, но сейчас-то, слава богу, есть nodemon или встроенная watch-режима в Node.js. Так что не изобретай велосипед, а то получится манда с ушами.

Короче, инструмент мощный, но острый. Бери в руки, только если точно знаешь, зачем. А то можно так взъебнуть приложение, что сам от себя охуеешь.