From 99606ea4dfe66e6a26925cc6cc48311ab8255d98 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 21 Feb 2024 14:01:45 +0100 Subject: [PATCH] perf(resolver): stat absolute paths once in fast path (#229) * test: add test for links * add test for non js modules * perf(resolver): stat absolute paths once in fast path --- src/resolve.ts | 26 ++++++++++++++++---------- test.mjs | 1 + test/fixture/hello.link.mjs | 1 + test/fixture/test.link.txt | 1 + test/fixture/test.txt | 1 + test/resolve.test.ts | 12 ++++++++++++ 6 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 test.mjs create mode 120000 test/fixture/hello.link.mjs create mode 120000 test/fixture/test.link.txt create mode 100644 test/fixture/test.txt diff --git a/src/resolve.ts b/src/resolve.ts index df18f56..24bcdac 100644 --- a/src/resolve.ts +++ b/src/resolve.ts @@ -1,4 +1,4 @@ -import { existsSync, realpathSync } from "node:fs"; +import { statSync } from "node:fs"; import { pathToFileURL } from "node:url"; import { joinURL } from "ufo"; import { isAbsolute, normalize } from "pathe"; @@ -27,7 +27,7 @@ function _tryModuleResolve( id: string, url: URL, conditions: any, -): any | undefined { +): URL | undefined { try { return moduleResolve(id, url, conditions); } catch (error) { @@ -49,10 +49,17 @@ function _resolve(id: string, options: ResolveOptions = {}): string { } // Skip resolve for absolute paths - if (isAbsolute(id) && existsSync(id)) { - // Resolve realPath and normalize slash - const realPath = realpathSync(fileURLToPath(id)); - return pathToFileURL(realPath).toString(); + if (isAbsolute(id)) { + try { + const stat = statSync(id); + if (stat.isFile()) { + return pathToFileURL(id).toString(); + } + } catch (error) { + if (error.code !== "ENOENT") { + throw error; + } + } } // Condition set @@ -82,7 +89,7 @@ function _resolve(id: string, options: ResolveOptions = {}): string { } } - let resolved; + let resolved: URL | undefined; for (const url of urls) { // Try simple resolve resolved = _tryModuleResolve(id, url, conditionsSet); @@ -120,9 +127,8 @@ function _resolve(id: string, options: ResolveOptions = {}): string { throw error; } - // Resolve realPath and normalize slash - const realPath = realpathSync(fileURLToPath(resolved)); - return pathToFileURL(realPath).toString(); + // Normalize (TODO: simplify) + return pathToFileURL(fileURLToPath(resolved)).toString(); } export function resolveSync(id: string, options?: ResolveOptions): string { diff --git a/test.mjs b/test.mjs new file mode 100644 index 0000000..11f474e --- /dev/null +++ b/test.mjs @@ -0,0 +1 @@ +console.log(import.meta.resolve.toString()) diff --git a/test/fixture/hello.link.mjs b/test/fixture/hello.link.mjs new file mode 120000 index 0000000..5d12f6b --- /dev/null +++ b/test/fixture/hello.link.mjs @@ -0,0 +1 @@ +hello.mjs \ No newline at end of file diff --git a/test/fixture/test.link.txt b/test/fixture/test.link.txt new file mode 120000 index 0000000..541cb64 --- /dev/null +++ b/test/fixture/test.link.txt @@ -0,0 +1 @@ +test.txt \ No newline at end of file diff --git a/test/fixture/test.txt b/test/fixture/test.txt new file mode 100644 index 0000000..524acff --- /dev/null +++ b/test/fixture/test.txt @@ -0,0 +1 @@ +Test file diff --git a/test/resolve.test.ts b/test/resolve.test.ts index 75e5a02..c1a2d50 100644 --- a/test/resolve.test.ts +++ b/test/resolve.test.ts @@ -36,6 +36,18 @@ describe("resolveSync", () => { } }); } + + it("follows symlinks", () => { + const resolved = resolveSync("./fixture/hello.link", { + url: import.meta.url, + }); + expect(fileURLToPath(resolved)).match(/fixture\/hello\.mjs$/); + + const resolved2 = resolveSync("./fixture/test.link.txt", { + url: import.meta.url, + }); + expect(fileURLToPath(resolved2)).match(/fixture\/test.txt$/); + }); }); describe("resolvePathSync", () => {