Як виправити помилку «Module not found: Can’t resolve 'fs'» у Webpack

Остання перевірка: 11 вересня 2026 року. Помилка «Module not found: Error: Can’t resolve 'fs'» зазвичай означає, що Webpack збирає код для браузера, але ваш вихідний код або одна з його залежностей імпортує модуль файлової системи Node.js. У документації Node node:fs описано як API для взаємодії з файловою системою, тоді як у поточній документації Webpack зазначено, що Webpack 5 більше не додає автоматично поліфіли для основних модулів Node.js у збірках для браузера.

Найважливіше — обрати виправлення, яке відповідає тому, що код насправді намагається зробити. Не існує єдиного налаштування, яке підходить для кожного проєкту. Якщо вашому додатку дійсно потрібно читати файли з диска сервера, перенесіть цю роботу в код Node/сервера. Якщо залежність імпортує fs лише для необов’язкової функції, доступної тільки в Node, яку ваш браузерний бандл ніколи не використовує, може бути доречним resolve.fallback: { fs: false }. Якщо пакет має збірку, сумісну з браузером, використовуйте її. А якщо бандл призначений для запуску в Node, вкажіть цільову платформу Node, замість того щоб удавати, що це веб-бандл.

Швидка таблиця рішень

СитуаціяНайкраще перше виправленняГоловна перевагаГоловний компроміс
Ваш власний браузерний код імпортує fsВидаліть його з браузерного шляху або перенесіть операцію на сервер/APIВідповідає фактичному середовищу виконанняПотребує архітектурної межі між клієнтом і сервером
Залежність імпортує fs, але ця функція ніколи не використовується в браузеріРозгляньте resolve.fallback: { fs: false }Невелике, просте виправлення збіркиЛогічна помилка виникне, якщо пакет пізніше виконає код, залежний від файлової системи
Залежність пропонує збірки для браузера та NodeВикористовуйте або оновіть до точки входу, сумісної з браузеромЗберігає бажану поведінку в браузеріМоже потребувати змін у пакеті/версії
Вихідний код виконується в Node, а не в браузеріВикористовуйте target: "node"Зберігає вбудовані модулі Node доступними під час виконанняВихідний код більше не є браузерним бандлом
Ви намагаєтеся «поліфілити fs» у браузеріПерегляньте вимогиУникає оманливого шару сумісностіМожливо, знадобиться інший робочий процес зберігання/файлів на стороні браузера

У офіційній документації Webpack щодо resolve.fallback зазначено, що Webpack 5 більше не додає автоматично поліфіли для основних модулів Node. У примітках до випуску Webpack 5 пояснюється причина: автоматичні поліфіли могли додавати великий, непотрібний код сумісності до фронтенд-бандлів, тому Webpack переклав відповідальність на автора додатку або пакета.

Крок 1: Визначте, хто імпортує fs

Почніть з першого корисного рядка у виводі помилок Webpack. Зазвичай він вказує на файл, де сталася помилка розв’язання, наприклад:

ERROR in ./src/utils/fileHelper.js 1:0-20
Module not found: Error: Can't resolve 'fs'
Ілюстрація терміналу, згенерована ШІ, що показує помилку Webpack під час розв’язання модуля fs Node у збірці для браузера
Ілюстрація, згенерована ШІ, що показує невдалу збірку Webpack через імпорт fs. Це не вивід реального проєкту; імена файлів і номери рядків є ілюстративними.

Якщо файл, що спричинив помилку, належить вам, шукайте в ньому будь-яку з цих форм:

const fs = require('fs')

// або
import fs from 'node:fs'

// або
import { readFile } from 'node:fs/promises'

У офіційній документації Node щодо файлової системи підтверджується, що node:fs та node:fs/promises є API Node для операцій з файловою системою. Звичайний браузерний бандл не отримує доступу до диска сервера лише тому, що Webpack може розібрати імпорт.

Якщо файл, що спричинив помилку, знаходиться в node_modules, не редагуйте цей пакет безпосередньо. Спочатку визначте, яка залежність верхнього рівня додала його до вашого браузерного бандла. Корисне питання не лише «Який пакет імпортує fs?», а й «Чому цей шлях коду, орієнтований на Node, досяжний з точки входу мого клієнта?»

Використовуйте цю діагностику, коли: помилка з’являється після оновлення Webpack, додавання залежності, імпорту утиліти, яка раніше була лише серверною, у фронтенд-код або переміщення спільного коду в клієнтський бандл.

Практична перевірка: тимчасово видаліть імпорт, що веде до модуля, який спричиняє помилку, і перебудуйте проєкт. Якщо помилка fs зникне, ви підтвердите шлях залежності перед зміною конфігурації Webpack.

Крок 2: Якщо коду дійсно потрібен доступ до файлової системи, перенесіть його в код Node/сервера

Це найкраще виправлення, коли код повинен читати конфігураційні файли, шаблони, локальні документи, приватні ключі, згенеровані ресурси, логи сервера або будь-що інше з файлової системи машини.

Наприклад, це доречно в Node:

import { readFile } from 'node:fs/promises'

export async function loadTemplate() {
  return readFile('./templates/email.html', 'utf8')
}

Але це не слід включати в точку входу браузера. Натомість надайте результат через серверний шар вашого додатку. Спрощений розподіл може виглядати так:

// серверний код
import { readFile } from 'node:fs/promises'

app.get('/api/template', async (req, res) => {
  const text = await readFile('./templates/email.html', 'utf8')
  res.type('text/plain').send(text)
})
// браузерний код
export async function loadTemplate() {
  const response = await fetch('/api/template')
  if (!response.ok) throw new Error('Failed to load template')
  return response.text()
}
Ілюстрація редактора коду, згенерована ШІ, що показує перенесення логіки файлової системи з браузерного коду на межу сервера/API
Ілюстрація, згенерована ШІ, що показує розділення роботи з файловою системою Node від браузерного коду. Це приклад концептуальної архітектури, а не скріншот конкретного фреймворку.

Компроміс тут архітектурний: ви додаєте серверний ендпоінт або іншу серверну межу, але зберігаєте семантику fs. Браузер запитує дані; сервер читає файлову систему.

Це рішення доречне, коли: операція з файловою системою є реальною та необхідною.

Це рішення не потрібне, коли: імпорт існує лише всередині необов’язкового шляху коду Node, який браузер ніколи не виконує. У такому випадку точка входу, специфічна для браузера, або ігнорований резервний варіант можуть бути чистішими.

Крок 3: Використовуйте resolve.fallback: { fs: false } лише коли поведінка файлової системи є необов’язковою

У офіційному посібнику з міграції з Webpack 4 на 5 зазначено, що конфігурації, які використовували старий шаблон node.fs: 'empty', слід змінити на:

module.exports = {
  // ...
  resolve: {
    fallback: {
      fs: false
    }
  }
}

Див. офіційний посібник з міграції на Webpack 5.

Ілюстрація webpack.config.js, згенерована ШІ, що показує резервний варіант resolve з fs, встановленим у false
Ілюстрація, згенерована ШІ, що показує resolve.fallback: { fs: false }. Використовуйте це лише коли браузеру не потрібна поведінка файлової системи залежності.

Встановлення резервного варіанту в false повідомляє Webpack не включати реалізацію для цього нерозв’язаного модуля. Це може бути саме те, що потрібно для пакета, який містить захищену гілку, доступну лише в Node, наприклад код, який використовує fs лише під час серверного рендерингу або виконання CLI.

Це також може приховати помилку збірки, залишивши вас із помилкою проєктування під час виконання. Розгляньте цю залежність:

const fs = require('fs')

export function loadUserConfig(path) {
  return fs.readFileSync(path, 'utf8')
}

Якщо ваш браузер дійсно викликає loadUserConfig(), заміна fs на «ніщо» не створює функціональної файлової системи браузера. Збірка може завершитися успішно, але функція все одно не зможе виконати заплановану операцію Node.

Використовуйте fs: false, коли: ви перевірили, що гілка, специфічна для файлової системи, не використовується в цільовому середовищі веб.

Не використовуйте це, коли: ваша браузерна функція залежить від readFileSync, обходу каталогів, серверних шляхів або іншої реальної поведінки файлової системи Node.

Чому «просто встановіть поліфіл fs» зазвичай є неправильною першою відповіддю

У поточній документації Webpack щодо resolve.fallback наведено приклади ручних поліфілів для кількох основних модулів Node, таких як path, buffer, stream та crypto. Примітно, що його список сумісності не пропонує загальної заміни для fs, еквівалентної файловій системі Node.

Ця відмінність важлива. Утиліти JavaScript часто можна відтворити в браузері. Довільний доступ до файлової системи хоста/сервера — це можливість середовища виконання, а не просто відсутня допоміжна функція.

Якщо вам насправді потрібен робочий процес у браузері, оберіть нативний для браузера дизайн для конкретного завдання — наприклад, завантажте ресурс із URL, дозвольте користувачу обрати файл або зберігайте дані додатку, використовуючи відповідний механізм зберігання браузера. Не оцінюйте успіх лише за тим, чи перестав Webpack показувати помилку.

Варіант 4: Віддайте перевагу залежності або експорту пакета, сумісному з браузером

Якщо помилка походить від пакета третьої сторони, перевірте, чи офіційно підтримує цей пакет браузери. У поточному посібнику Webpack щодо exports пакета пояснюється, що пакети можуть надавати умовні експорти для таких середовищ, як browser та node. У рекомендаціях щодо випуску Webpack також радиться авторам пакетів надавати альтернативи, сумісні з фронтендом, коли реалізації, доступні лише в Node, не підходять для браузерів.

Наприклад, пакет може концептуально надавати:

{
  "exports": {
    ".": {
      "browser": "./dist/browser.js",
      "node": "./dist/node.js",
      "default": "./dist/browser.js"
    }
  }
}

Якщо оновлена версія пакета надає належну точку входу для браузера, а ваша стара версія — ні, оновлення може бути безпечнішим, ніж налаштування fs: false. Так само заміна пакета, орієнтованого на Node, на той, що явно розроблений для використання в браузері, може зменшити кількість хаков сумісності та складність бандлу.

Оберіть цей шлях, коли: залежність повинна працювати в браузерах, але встановлена версія обирає або надає реалізацію, доступну лише в Node.

Компроміс: оновлення або заміна пакета може внести зміни в API, тому запускайте звичайні тести вашого додатку, а не вважайте успішну компіляцію достатньою.

Варіант 5: Якщо вихідний код є бандлом Node, встановіть цільову платформу Node

Іноді Webpack взагалі не створює браузерний код. Ви можете збирати CLI, фоновий воркер, інструмент збірки, сервер SSR або сервіс Node. У такому випадку спроба придушити fs є зворотною: середовище виконання насправді надає його.

У офіційній документації Webpack щодо цілей (Targets) зазначено, що:

module.exports = {
  target: 'node'
}

компілює для середовища, подібного до Node.js, і залишає вбудовані модулі, такі як fs та path, для надання Node під час виконання.

У більш детальній довідці з конфігурації цілі (target) Webpack також розрізняє web, node, цілі Electron, веб-воркери та інші середовища.

Використовуйте target: 'node', коли: отриманий JavaScript виконуватиметься під Node.

Не використовуйте це, щоб «виправити» звичайний браузерний SPA: зміна цілі не змушує браузер раптово надавати API файлової системи Node. Це змінює середовище, яке Webpack вважає виконуваним для бандлу.

Розширені збірки Node: externals можуть залишати вбудовані модулі під час виконання

Для серверних бандлів Webpack також надає поведінку externals, орієнтовану на Node. У його офіційній документації щодо Externals зазначено, що externalsPresets.node може розглядати вбудовані модулі Node, такі як fs, path та vm, як зовнішні та завантажувати їх за допомогою require() середовища виконання Node.

Типова конфігурація, орієнтована на Node, може виглядати так:

module.exports = {
  target: 'node',
  externalsPresets: {
    node: true
  }
}

Це питання розширеної серверної збірки, а не обхідний шлях для браузера.

Крок 4: Перебудуйте, а потім протестуйте функцію, яка спричинила імпорт

Після внесення архітектурної або конфігураційної зміни перебудуйте проєкт:

npm run build
Ілюстрація терміналу, згенерована ШІ, що показує успішну продакшн-збірку Webpack після вирішення проблеми з імпортом fs
Ілюстрація, згенерована ШІ, що показує успішну перебудову Webpack. Номери версій, розміри ресурсів і час збірки є вигаданими прикладами.

Чиста компіляція доводить лише те, що розв’язання модулів пройшло успішно. Це не доводить, що постраждала функція працює правильно. Тестуйте відповідно до обраного виправлення:

  • Якщо ви перенесли доступ до файлів на сервер, викличте браузерну функцію та перевірте, чи серверний ендпоінт повертає очікувані дані.
  • Якщо ви встановили fs: false, використовуйте залежність у браузері та підтвердьте, що вона ніколи не заходить у гілку, залежну від файлової системи.
  • Якщо ви перейшли на браузерну збірку пакета, запустіть реальний користувацький робочий процес пакета.
  • Якщо ви змінили ціль на Node, виконайте зібраний вихідний код під підтримуваною версією Node.

Порівняння поширених виправлень

ВиправленняБезпечне для браузера?Зберігає реальний доступ до файлової системи Node?Коли віддати перевагу
Перенести роботу з fs на сервер/APIТакТак, на серверіВаш додаток дійсно потребує даних файлової системи сервера
resolve.fallback.fs = falseЛише якщо гілка fs не використовуєтьсяНіНеобов’язковий шлях залежності, доступний лише в Node
Пакет/експорт, специфічний для браузераТак, якщо пакет це підтримуєНі; натомість надає поведінку, специфічну для браузераЗалежність призначена для підтримки обох середовищ виконання
target: 'node'НіТакБандл фактично виконується в Node
Загальний «поліфіл fs»Залежить від бібліотеки та семантикиНе еквівалентний довільному доступу до файлової системи NodeЛише після перевірки точної поведінки браузера, яка вам потрібна

Особливий випадок: спільний код, імпортований як браузерними, так і серверними бандлами

Частим джерелом цієї помилки є модуль утиліт, який містить як чисті функції, так і допоміжні функції, доступні лише в Node:

// shared-utils.js
import fs from 'node:fs'

export function formatDate(date) {
  return new Intl.DateTimeFormat('en-US').format(date)
}

export function readConfig(path) {
  return fs.readFileSync(path, 'utf8')
}

Навіть якщо ваш браузер імпортує лише formatDate, імпорт fs на верхньому рівні може змусити Webpack розв’язати fs. Чистішим дизайном є розділення модулів:

// shared/formatDate.js
export function formatDate(date) {
  return new Intl.DateTimeFormat('en-US').format(date)
}

// server/readConfig.js
import fs from 'node:fs'

export function readConfig(path) {
  return fs.readFileSync(path, 'utf8')
}

Це робить межу середовища виконання видимою в графі модулів, замість залежності від tree-shaking або резервного варіанту для видалення несумісного імпорту.

Особливий випадок: помилка з’явилася після оновлення з Webpack 4

Це один із класичних симптомів міграції на Webpack 5. Webpack 4 автоматично надавав сумісні шими для багатьох основних модулів Node. Webpack 5 навмисно припинив це робити. Якщо ваш код «працював до оновлення», запитайте, чи дійсно він потребував функції Node у браузері, чи старий бандлер мовчки впроваджував код сумісності.

У офіційному посібнику з міграції Webpack рекомендується читати рекомендації щодо зламаних змін у помилці збірки та замінювати стару конфігурацію сумісності node.* на новіший підхід до розв’язувача, де це доречно.

Не припускайте, що відтворення кожного поліфіла Webpack 4 є найкращою міграцією. У власних примітках до випуску Webpack рекомендується використовувати модулі, сумісні з фронтендом, де це можливо.

Фінальна самоперевірка

Перед закриттям питання перевірте ці пункти:

  1. Знайдіть точний вихідний файл або залежність, яка імпортує fs.
  2. Підтвердьте, чи постраждалий бандл виконується в браузері, чи в Node.
  3. Якщо це браузерний бандл, перевірте, чи функція дійсно потребує поведінки файлової системи.
  4. Якщо так, перенесіть операцію з файловою системою за серверну межу.
  5. Якщо використання fs у залежності є необов’язковим і ніколи не виконується в браузері, розгляньте resolve.fallback: { fs: false }.
  6. Якщо пакет офіційно надає браузерний експорт, віддайте перевагу цьому, а не придушенню необхідної поведінки.
  7. Якщо бандл виконується в Node, використовуйте ціль Node замість веб-цілі.
  8. Перебудуйте та підтвердьте, що помилка розв’язання модулів зникла.
  9. Запустіть фактичну функцію, яка раніше підтягувала fs; не зупиняйтеся на «успішно скомпільовано».

Тривалим виправленням є узгодження коду з його середовищем виконання. fs належить до середовища файлової системи Node. Webpack 5 робить цю межу більш видимою, більше не впроваджуючи автоматично поліфіли основних модулів Node. Щойно ви вирішите, чи робота з файловою системою належить серверу, є необов’язковою в браузері, чи є частиною бандлу, орієнтованого на Node, правильну конфігурацію буде набагато легше обрати.

Залишити коментар

Як виправити помилку “Prisma Client Has Not Been Generated Yet”

Як виправити помилку “Prisma Client Has Not Been Generated Yet”

Виправте помилку незгенерованого Prisma Client, перевіривши генератор, схему, шлях виводу, імпорти, версії, налаштування монорепозиторію та кроки збірки під час розгортання.

Як виправити помилку SSL-сертифіката: не вдалося отримати локальний сертифікат емітента в Git

Як виправити помилку SSL-сертифіката: не вдалося отримати локальний сертифікат емітента в Git

Виправте помилку Git «не вдалося отримати локальний сертифікат емітента», визначивши механізм довіри, встановивши правильний ланцюжок ЦС та зберігаючи перевірку SSL увімкненою.

Як виправити помилку таймауту мережі MongoDB у з'єднанні Mongoose

Як виправити помилку таймауту мережі MongoDB у з'єднанні Mongoose

Виправте помилки таймауту мережі MongoDB у Mongoose, визначивши тип таймауту, перевіривши доступність Atlas або TCP, виправивши URI та налаштувавши таймаути лише за необхідності.

Як виправити помилку «Execution Policy Restricted» у Windows PowerShell

Як виправити помилку «Execution Policy Restricted» у Windows PowerShell

Виправте помилку обмеженої політики виконання PowerShell, перевіривши область дії та групову політику, а потім обравши RemoteSigned, Unblock-File або тимчасовий параметр сесії.

Як виправити помилку npm ERR! code ERESOLVE: конфлікт залежностей-партнерів

Як виправити помилку npm ERR! code ERESOLVE: конфлікт залежностей-партнерів

Виправте конфлікти залежностей-партнерів npm ERESOLVE, визначивши несумісний діапазон пакетів, узгодивши версії, використовуючи npm explain та npm ls, а також розглядаючи legacy-peer-deps або force лише як контрольовані резервні варіанти.

Як виправити помилку підключення Redis до 127.0.0.1:6379

Як виправити помилку підключення Redis до 127.0.0.1:6379

Виправте помилки відмови у підключенні Redis на 127.0.0.1:6379, перевіривши сервер, порт, мережу Docker, redis.conf, автентифікацію та TLS.

Як виправити внутрішню помилку 500 у серверних компонентах Next.js

Як виправити внутрішню помилку 500 у серверних компонентах Next.js

Виправте помилки 500 у серверних компонентах Next.js, аналізуючи логи сервера, перевіряючи запити даних та змінні середовища, обробляючи помилки та перевіряючи збірку для продакшену.

Як виправити помилку CrashLoopBackOff у Kubernetes у локальному Minikube

Як виправити помилку CrashLoopBackOff у Kubernetes у локальному Minikube

Діагностуйте та виправляйте помилку CrashLoopBackOff у Kubernetes у локальному Minikube, перевіряючи стан пода, попередні логи, причини завершення роботи, проби, конфігурацію, ліміти пам’яті та стан кластера.

Як виправити помилку «Docker Desktop Engine Stopped» у Windows 11

Як виправити помилку «Docker Desktop Engine Stopped» у Windows 11

Виправте помилку «Docker Desktop Engine Stopped» у Windows 11, перевіривши статус Docker, оновивши та перезавантаживши WSL 2, підтвердивши віртуалізацію та використавши діагностику перед скиданням налаштувань.

Як виправити помилку Uncaught ReferenceError: process is not defined у Vite

Як виправити помилку Uncaught ReferenceError: process is not defined у Vite

Виправте помилку 'process is not defined' у Vite, замінивши використання process.env у стилі Node.js, правильно налаштувавши змінні VITE_ та перевіривши залежності.