node.js - Hur hanterar man node-moduler i webbläsaren?
Min titel är lite vag, här är vad jag försöker göra:
- Jag har ett TypeScript npm-paket
- Jag vill att det ska kunna användas både på Node och i webbläsare.
- Jag bygger det med ett enkelt
tsc-kommando (ingen paketering), för att få korrekta typer - Min modul har 1 ingångspunkt, en
index.ts-fil, som exponerar (återexporterar) allt.
Vissa funktioner i denna modul är avsedda att användas endast på node, så det finns node-importer i vissa filer, som:
import { fileURLToPath } from 'url'
import { readFile } from 'fs/promises'
import { resolve } from 'path'
// ...
Jag skulle vilja hitta ett sätt att:
- Låt inte bundlers snava över detta
- Tvinga inte användare av detta paket att lägga till "hacks" i deras bundler-konfiguration, som nämnts här: Node kan inte hitta modulen "fs" när man använder webpack
- Kasta vettiga
Errorom de försöker använda funktioner som endast finns i Node - Använd korrekta typer inuti min modul, med
@types/nodei min kod
Mitt huvudproblem är att oavsett vad, måste jag import eller require de moduler som endast finns för Node, vilket bryter mot krav 1 (stör bundlers, eller tvingar användaren att lägga till någon polyfill).
Det enda sättet jag har hittat som fungerar är det som isomorfa paket använder, vilket är att ha två olika ingångspunkter och markera det i min package.json på följande sätt:
{
// The entry point for node modules
"main": "lib/index.node.js",
// The entry point for bundlers
"browser": "lib/index.browser.js",
// Common typings
"typings": "lib/index.browser.d.ts"
}
Detta är dock mycket opraktiskt och tvingar mig att göra mycket upprepning, eftersom jag inte har två olika versioner av paketet, bara lite kod som borde orsaka fel i webbläsaren när den används.
Finns det ett sätt att få något sådant att fungera?
// create safe-fs.ts locally and use it instead of the real "fs" module
import * as fs from 'fs'
function createModuleProxy(moduleName: string): any {
return new Proxy(
{},
{
get(target, property) {
return () => {
throw new Error(`Function "${String(property)}" from module "${moduleName}" should only be used on node.js`)
}
},
},
)
}
const isNode = typeof window === undefined && typeof process === 'object'
const safeFs: typeof fs = isNode ? fs : createModuleProxy('fs')
export default safeFs
Som det står, får detta bundlers att snubbla, eftersom jag fortfarande importerar fs.