Så åtgärdar du "Module Not Found: Can’t Resolve fs" i Webpack
Senast verifierad: 11 september 2026. Felet “Module not found: Error: Can’t resolve 'fs'” betyder vanligtvis att Webpack bygger kod för en webbläsare, men att din källkod – eller en av dess beroenden – importerar Node.js filsystemmodul. Node dokumenterar node:fs som API:t för interaktion med filsystemet, medan Webpacks aktuella dokumentation anger att Webpack 5 inte längre automatiskt polyfillar Node.js kärnmoduler för webbläsarbyggen.
Det viktiga är att välja den lösning som matchar vad koden faktiskt försöker göra. Det finns ingen enda inställning som är korrekt för alla projekt. Om din applikation verkligen behöver läsa filer från serverns disk, flytta det arbetet till Node/serverkod. Om ett beroende importerar fs endast för en valfri Node-specifik funktion som din webbläsarbunt aldrig använder, kan resolve.fallback: { fs: false } vara lämpligt. Om paketet har en webbläsarkompatibel bygge, använd den istället. Och om bunten är avsedd att köras i Node, rikta in dig på Node istället för att låtsas att det är en webbunt.
Snabb beslutsstabell
Situation
Bästa första åtgärd
Huvudfördel
Huvudsaklig kompromiss
Din egen webbläsarkod importerar fs
Ta bort den från webbläsarsökvägen eller flytta operationen till en server/API
Matchar den faktiska körningen
Kräver en arkitektonisk gräns mellan klient och server
Ett beroende importerar fs, men den funktionen används aldrig i webbläsaren
Överväg resolve.fallback: { fs: false }
Liten, enkel byggfix
Kommer att misslyckas logiskt om paketet senare kör filsystemberoende kod
Ett beroende erbjuder både webbläsar- och Node-byggen
Använd eller uppgradera till den webbläsarkompatibla ingången
Bevarar avsedd webbläsarbeteende
Kan kräva ändringar av paket/version
Utdata körs i Node, inte i en webbläsare
Använd target: "node"
Håller Node inbyggda moduler tillgängliga vid körning
Utdata är inte längre en webbläsarbunt
Du försöker “polyfilla fs” i webbläsaren
Ompröva kravet
Undviker ett vilseledande kompatibilitetsskikt
Du kan behöva en annan webbläsarbaserad lagrings/fil-workflow
Webpacks officiella dokumentation för resolve.fallback anger att Webpack 5 inte längre polyfillar Node kärnmoduler automatiskt. Dess Webpack 5 release notes förklarar anledningen: automatiska polyfills kunde lägga till stor, onödig kompatibilitetskod i frontend-buntar, så Webpack flyttade ansvaret till applikationen eller paketförfattaren.
Steg 1: Ta reda på vem som importerar fs
Börja med den första användbara raden i Webpacks felutdata. Den pekar normalt på filen där upplösningen misslyckades, till exempel:
ERROR in ./src/utils/fileHelper.js 1:0-20
Module not found: Error: Can't resolve 'fs'
AI-genererad illustration av ett Webpack-bygge som misslyckas på ett fs-import. Det är inte utdata från ett riktigt projekt; filnamn och radnummer är illustrativa.
Om den misslyckade filen är din, sök i den efter någon av formerna:
const fs = require('fs')
// eller
import fs from 'node:fs'
// eller
import { readFile } from 'node:fs/promises'
Nodes officiella dokumentation för File System bekräftar att node:fs och node:fs/promises är Node-API:er för filsystemoperationer. En vanlig webbläsarbunt får inte tillgång till serverns disk bara för att Webpack kan tolka importen.
Om den misslyckade filen finns under node_modules, redigera inte det paketet på plats direkt. Identifiera först vilket toppnivåberoende som förde in det i din webbläsarbunt. Den användbara frågan är inte bara “Vilket paket importerar fs?” utan “Varför är den Node-orienterade kodsökvägen nåbar från min klientingång?”
Använd denna diagnos när: felet dyker upp efter att du uppgraderat Webpack, lagt till ett beroende, importerat ett tidigare server-endast-verktyg i frontend-kod, eller flyttat delad kod till en klientbunt.
Praktisk kontroll: ta tillfälligt bort importen som leder till den misslyckade modulen och bygg om. Om fs-felet försvinner har du bekräftat beroendesökvägen innan du ändrar Webpack-konfigurationen.
Steg 2: Om koden verkligen behöver filsystemåtkomst, flytta den till Node/serverkod
Detta är den bästa lösningen när koden behöver läsa konfigurationsfiler, mallar, lokala dokument, privata nycklar, genererade tillgångar, serverloggar eller något annat från maskinens filsystem.
Till exempel är detta lämpligt i Node:
import { readFile } from 'node:fs/promises'
export async function loadTemplate() {
return readFile('./templates/email.html', 'utf8')
}
Men det bör inte dras in i en webbläsaringång. Exponera istället resultatet genom din applikations serverlager. En förenklad uppdelning kan se ut så här:
// browser-side code
export async function loadTemplate() {
const response = await fetch('/api/template')
if (!response.ok) throw new Error('Failed to load template')
return response.text()
}
AI-genererad illustration av att separera Node filsystemarbete från webbläsarkod. Det är ett konceptuellt arkitektur exempel, inte en skärmdump av ett specifikt ramverk.
Kompromissen är arkitektonisk: du lägger till en serverendpoint eller en annan serversidig gräns, men du bevarar semantiken för fs. Webbläsaren begär data; servern läser filsystemet.
Denna lösning är lämplig när: filsystemoperationen är verklig och nödvändig.
Denna lösning är inte nödvändig när: importen endast finns inuti en valfri Node-kodsökväg som webbläsaren aldrig kör. I det fallet kan en webbläsarspecifik paketingång eller en ignorerad fallback vara renare.
Steg 3: Använd resolve.fallback: { fs: false } endast när filsystembeteendet är valfritt
Webpacks officiella migrationsguide från Webpack 4 till 5 säger specifikt att konfigurationer som använder det gamla mönstret node.fs: 'empty' bör flytta till:
AI-genererad illustration av resolve.fallback: { fs: false }. Använd detta endast när webbläsaren inte behöver beroendets filsystembeteende.
Att ställa in en fallback till false säger till Webpack att inte inkludera en implementation för den upplösta modulen. Detta kan vara exakt rätt för ett paket som innehåller en skyddad Node-endast-gren, som kod som använder fs endast under serverrendering eller CLI-körning.
Det kan också dölja byggfelet medan du lämnas med ett designfel vid körning. Överväg detta beroende:
Om din webbläsare faktiskt anropar loadUserConfig(), skapar inte att ersätta fs med “ingenting” ett fungerande webbläsarfilsystem. Bygget kan fortsätta, men funktionen kan fortfarande inte utföra den avsedda Node-operationen.
Använd fs: false när: du har verifierat att den filsystemspecifika grenen inte används i webbmålet.
Använd det inte när: din webbläsarfunktion är beroende av readFileSync, kataloggenomgång, serversökvägar eller annat verkligt Node filsystembeteende.
Varför “bara installera en fs-polyfill” oftast är fel första svar
Webpacks aktuella dokumentation för resolve.fallback ger exempel på manuella polyfills för flera Node kärnmoduler som path, buffer, stream och crypto. Noterbart är att dess kompatibilitetslista inte tillhandahåller en allmän fs-ersättning motsvarande Node filsystemet.
Den skillnaden är viktig. JavaScript-verktyg kan ofta reproduceras i en webbläsare. Godtycklig åtkomst till värd-/serverfilsystemet är en körningskapacitet, inte bara en saknad hjälpfunktion.
Om det du verkligen behöver är en webbläsar-workflow, välj en webbläsarnativ design för den specifika uppgiften – till exempel, hämta en tillgång från en URL, låt användaren välja en fil, eller lagra applikationsdata med en lämplig webbläsarlagringsmekanism. Bedöm inte framgång enbart efter om Webpack slutar visa felet.
Alternativ 4: Föredra ett webbläsarkompatibelt beroende eller paketexport
Om felet kommer från ett tredjepartspaket, inspektera om det paketet officiellt stöder webbläsare. Webpacks aktuella guide för paket exports förklarar att paket kan tillhandahålla villkorliga exporter för miljöer som browser och node. Webpacks releasevägledning rekommenderar också att paketförfattare tillhandahåller frontend-kompatibla alternativ när Node-endast-implementationer är olämpliga för webbläsare.
Om en uppgraderad paketversion tillhandahåller en korrekt webbläsaringång medan din äldre version inte gör det, kan uppgradering vara säkrare än att konfigurera fs: false. På samma sätt kan att ersätta ett Node-orienterat paket med ett som uttryckligen är designat för webbläsaranvändning minska kompatibilitetshacks och buntkomplexitet.
Välj denna väg när: beroendet förväntas fungera i webbläsare, men den installerade versionen väljer eller exponerar en Node-endast-implementation.
Kompromiss: att uppgradera eller ersätta ett paket kan introducera API-ändringar, så kör dina normala applikationstester istället för att behandla en lyckad kompilering som tillräcklig.
Alternativ 5: Om utdata är en Node-bunt, sätt målet till Node
Ibland producerar Webpack inte alls webbläsarkod. Du kan bunta en CLI, bakgrundsarbetare, byggverktyg, SSR-server eller Node-tjänst. I det fallet är det bakvänt att försöka undertrycka fs: körningen tillhandahåller det faktiskt.
kompilerar för en Node.js-liknande miljö och lämnar inbyggda moduler som fs och path för Node att tillhandahålla vid körning.
Webpacks mer detaljerade referens för target-konfiguration skiljer också på web, node, Electron-mål, webbarbetare och andra miljöer.
Använd target: 'node' när: den resulterande JavaScript-koden kommer att köras under Node.
Använd det inte för att “fixa” en vanlig webbläsar-SPA: att ändra målet gör inte att en webbläsare plötsligt tillhandahåller Nodes filsystem-API:er. Det ändrar vilken miljö Webpack antar kommer att köra bunten.
Avancerade Node-byggen: externals kan hålla inbyggda moduler vid körning
För serverbuntar tillhandahåller Webpack också Node-orienterat externals-beteende. Dess officiella dokumentation för Externals anger att externalsPresets.node kan behandla Node inbyggda moduler som fs, path och vm som externa och ladda dem med Nodes körnings require().
En typisk Node-orienterad konfiguration kan därför se ut så här:
Detta är en avancerad serverbuntfråga, inte en webbläsarworkaround.
Steg 4: Bygg om, testa sedan funktionen som orsakade importen
Efter att ha gjort den arkitektoniska eller konfigurationsmässiga ändringen, bygg om:
npm run build
AI-genererad illustration av en lyckad Webpack ombyggnad. Versionsnummer, tillgångsstorlekar och byggtider är fiktiva exempel.
En ren kompilering bevisar bara att modulpplösningen lyckades. Det bevisar inte att den påverkade funktionen beter sig korrekt. Testa enligt den lösning du valde:
Om du flyttade filåtkomst till servern, anropa webbläsarfunktionen och verifiera att serverendpointen returnerar förväntad data.
Om du ställde in fs: false, utöva beroendet i webbläsaren och bekräfta att det aldrig går in i den filsystemberoende grenen.
Om du bytte till ett webbläsarbygge av ett paket, kör paketets verkliga användarriktade workflow.
Om du ändrade målet till Node, kör den byggda utdata under den Node-version du stöder.
Vanliga lösningar jämförda
Lösning
Webbläsarsäker?
Bevarar verklig Node filsystemåtkomst?
När att föredra den
Flytta fs-arbete till server/API
Ja
Ja, på servern
Din applikation behöver verkligen server filsystemdata
resolve.fallback.fs = false
Endast om fs-grenen inte används
Nej
Valfri Node-endast beroendesökväg
Webbläsarspecifikt paket/export
Ja, om paketet stöder det
Nej; tillhandahåller webbläsarspecifikt beteende istället
Ett beroende är avsett att stödja båda körningarna
target: 'node'
Nej
Ja
Bunten körs faktiskt i Node
Generisk “fs polyfill”
Beroende på bibliotek och semantik
Inte motsvarande godtycklig Node filsystemåtkomst
Endast efter att ha verifierat det exakta webbläsarbeteendet du behöver
Specialfall: delad kod importerad av både webbläsar- och serverbuntar
En vanlig källa till detta fel är ett verktygsmodul som innehåller både rena funktioner och Node-endast-hjälpare:
// 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')
}
Även om din webbläsare bara importerar formatDate, kan den toppnivå fs-importen tvinga Webpack att upplösa fs. En renare design är att dela upp modulerna:
// 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')
}
Detta gör körningsgränsen synlig i modulgrafet istället för att förlita sig på tree-shaking eller en fallback för att ta bort en inkompatibel import.
Specialfall: felet dök upp efter uppgradering från Webpack 4
Detta är ett av de klassiska Webpack 5 migrationssymptomen. Webpack 4 tillhandahöll automatiskt kompatibilitetsshimmar för många Node kärnmoduler. Webpack 5 slutade avsiktligt göra det. Om din kod “funkade före uppgraderingen”, fråga dig om den verkligen behövde Node-funktionen i webbläsaren eller om den gamla bundlern tyst injicerade kompatibilitetskod.
Den officiella Webpack migrationsguiden rekommenderar att läsa byggfelets vägledning för brytande ändringar och ersätta gammal node.* kompatibilitetskonfiguration med den nyare resolvermetoden där det är lämpligt.
Anta inte att återskapa varje Webpack 4 polyfill är den bästa migrationen. Webpacks egna release notes rekommenderar frontend-kompatibla moduler där det är möjligt.
Slutlig självkontroll
Innan du stänger ärendet, verifiera dessa punkter:
Hitta den exakta källfilen eller beroendet som importerar fs.
Bekräfta om den påverkade bunten körs i en webbläsare eller i Node.
Om det är en webbläsarbunt, verifiera om funktionen verkligen behöver filsystembeteende.
Om den gör det, flytta filsystemoperationen bakom en servergräns.
Om beroendets fs-användning är valfri och aldrig körs i webbläsaren, överväg resolve.fallback: { fs: false }.
Om paketet officiellt tillhandahåller en webbläsarexport, föredra den framför att undertrycka nödvändigt beteende.
Om bunten körs i Node, använd ett Node-mål istället för ett webbmål.
Bygg om och bekräfta att modulpplösningsfelet är borta.
Kör den faktiska funktionen som tidigare drog in fs; sluta inte vid “lyckad kompilering”.
Den hållbara lösningen är att anpassa koden till dess körning. fs tillhör Nodes filsystemmiljö. Webpack 5 gör den gränsen mer synlig genom att inte längre injicera Node kärnpolyfills automatiskt. När du väl bestämt om filsystemarbetet hör hemma på servern, är valfritt i webbläsaren, eller är en del av en Node-riktad bunt, blir den korrekta konfigurationen mycket lättare att välja.