diff --git a/CHANGES.md b/CHANGES.md index edd1562..7572638 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,8 +8,13 @@ Version 0.4.2 To be released. - - The npm version of LogTape no more depends on `node:stream/web` module. - This should make it easier to use LogTape on edge functions. + - LogTape now works well on edge functions. [[#5]] + + - The npm version of LogTape no more depends on `node:stream/web` module. + - LogTape now works well with JavaScript runtimes that do not support + `node:fs` module. + +[#5]: https://github.com/dahlia/logtape/issues/5 Version 0.4.1 diff --git a/dnt.ts b/dnt.ts index 12fe26d..2b71189 100644 --- a/dnt.ts +++ b/dnt.ts @@ -31,6 +31,7 @@ await build({ mappings: { "./logtape/filesink.jsr.ts": "./logtape/filesink.node.ts", "./logtape/filesink.deno.ts": "./logtape/filesink.node.ts", + "./logtape/fs.ts": "./logtape/fs.js", }, shims: { deno: "dev", @@ -42,6 +43,8 @@ await build({ lib: ["ES2021", "DOM"], }, async postBuild() { + await Deno.copyFile("logtape/fs.mjs", "npm/esm/fs.js"); + await Deno.copyFile("logtape/fs.cjs", "npm/script/fs.js"); await Deno.copyFile("LICENSE", "npm/LICENSE"); await Deno.copyFile("README.md", "npm/README.md"); }, diff --git a/logtape/filesink.node.ts b/logtape/filesink.node.ts index f2e78a3..8cf65ae 100644 --- a/logtape/filesink.node.ts +++ b/logtape/filesink.node.ts @@ -1,4 +1,6 @@ -import fs from "node:fs"; +// @ts-ignore: a trick to avoid module resolution error on non-Node.js environ +import fsMod from "./fs.ts"; +import type fsType from "node:fs"; import { webDriver } from "./filesink.web.ts"; import { type FileSinkOptions, @@ -9,19 +11,24 @@ import { type Sink, } from "./sink.ts"; +// @ts-ignore: a trick to avoid module resolution error on non-Node.js environ +const fs = fsMod as (typeof fsType | null); + /** * A Node.js-specific file sink driver. */ -export const nodeDriver: RotatingFileSinkDriver = { - openSync(path: string) { - return fs.openSync(path, "a"); - }, - writeSync: fs.writeSync, - flushSync: fs.fsyncSync, - closeSync: fs.closeSync, - statSync: fs.statSync, - renameSync: fs.renameSync, -}; +export const nodeDriver: RotatingFileSinkDriver = fs == null + ? webDriver + : { + openSync(path: string) { + return fs.openSync(path, "a"); + }, + writeSync: fs.writeSync, + flushSync: fs.fsyncSync, + closeSync: fs.closeSync, + statSync: fs.statSync, + renameSync: fs.renameSync, + }; /** * Get a file sink. diff --git a/logtape/fs.cjs b/logtape/fs.cjs new file mode 100644 index 0000000..bcb0170 --- /dev/null +++ b/logtape/fs.cjs @@ -0,0 +1,16 @@ +let fs = null; +if ( + "process" in globalThis && "versions" in globalThis.process && + "node" in globalThis.process.versions && + typeof globalThis.caches === "undefined" && + typeof globalThis.addEventListener !== "function" || + "Bun" in globalThis +) { + try { + fs = require("node" + ":fs"); + } catch (_) { + fs = null; + } +} + +module.exports = fs; diff --git a/logtape/fs.js b/logtape/fs.js new file mode 100644 index 0000000..1c2b978 --- /dev/null +++ b/logtape/fs.js @@ -0,0 +1 @@ +export * from "node:fs"; diff --git a/logtape/fs.mjs b/logtape/fs.mjs new file mode 100644 index 0000000..3e9d1ed --- /dev/null +++ b/logtape/fs.mjs @@ -0,0 +1,20 @@ +let fs = null; +if ( + "process" in globalThis && "versions" in globalThis.process && + "node" in globalThis.process.versions && + typeof globalThis.caches === "undefined" && + typeof globalThis.addEventListener !== "function" || + "Bun" in globalThis +) { + try { + fs = await import("node" + ":fs"); + } catch (e) { + if (e instanceof TypeError) { + fs = null; + } else { + throw e; + } + } +} + +export default fs; diff --git a/logtape/fs.ts b/logtape/fs.ts new file mode 100644 index 0000000..29de881 --- /dev/null +++ b/logtape/fs.ts @@ -0,0 +1,22 @@ +let fs = null; +if ( + // @ts-ignore: process is a global variable + "process" in globalThis && "versions" in globalThis.process && + // @ts-ignore: process is a global variable + "node" in globalThis.process.versions && + typeof globalThis.caches === "undefined" && + typeof globalThis.addEventListener !== "function" || + "Bun" in globalThis +) { + try { + fs = await import("node" + ":fs"); + } catch (e) { + if (e instanceof TypeError) { + fs = null; + } else { + throw e; + } + } +} + +export default fs;