Skip to content

Commit 705f8c6

Browse files
authored
feat: add yarn_pnp logic to FileSystem (#589)
Running fs operations through yarn pnp incurs significant performance cost, caused by running `VPath::from(path)` on every path. Feature gate this through a runtime flag, because a bundler can enable `yarn_pnp` feature but run the resolver without presence of `yarn`.
1 parent b4e88b3 commit 705f8c6

File tree

5 files changed

+70
-42
lines changed

5 files changed

+70
-42
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
- uses: ./.github/actions/pnpm
4545
- run: cargo check --all-features --locked
4646
- run: cargo test --doc
47+
- run: cargo test # without features
4748
- run: cargo test --all-features
4849
- run: pnpm run build:debug && pnpm run test
4950
if: ${{ matrix.os != 'windows-latest' }}

justfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ check:
5454

5555
# Run all the tests
5656
test:
57+
cargo test
5758
cargo test --all-features
5859
node --run build
5960
node --run test

src/file_system.rs

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ use pnp::fs::{LruZipCache, VPath, VPathInfo, ZipCache};
99

1010
/// File System abstraction used for `ResolverGeneric`
1111
pub trait FileSystem: Send + Sync {
12+
#[cfg(feature = "yarn_pnp")]
13+
fn new(yarn_pnp: bool) -> Self;
14+
15+
#[cfg(not(feature = "yarn_pnp"))]
16+
fn new() -> Self;
17+
1218
/// See [std::fs::read_to_string]
1319
///
1420
/// # Errors
@@ -95,25 +101,13 @@ impl From<fs::Metadata> for FileMetadata {
95101
}
96102
}
97103

98-
/// Operating System
99-
#[cfg(feature = "yarn_pnp")]
100-
pub struct FileSystemOs {
101-
pnp_lru: LruZipCache<Vec<u8>>,
102-
}
103-
104104
#[cfg(not(feature = "yarn_pnp"))]
105105
pub struct FileSystemOs;
106106

107-
impl Default for FileSystemOs {
108-
fn default() -> Self {
109-
cfg_if! {
110-
if #[cfg(feature = "yarn_pnp")] {
111-
Self { pnp_lru: LruZipCache::new(50, pnp::fs::open_zip_via_read_p) }
112-
} else {
113-
Self
114-
}
115-
}
116-
}
107+
#[cfg(feature = "yarn_pnp")]
108+
pub struct FileSystemOs {
109+
pnp_lru: LruZipCache<Vec<u8>>,
110+
yarn_pnp: bool,
117111
}
118112

119113
impl FileSystemOs {
@@ -171,38 +165,51 @@ impl FileSystemOs {
171165
}
172166

173167
impl FileSystem for FileSystemOs {
168+
#[cfg(feature = "yarn_pnp")]
169+
fn new(yarn_pnp: bool) -> Self {
170+
Self { pnp_lru: LruZipCache::new(50, pnp::fs::open_zip_via_read_p), yarn_pnp }
171+
}
172+
173+
#[cfg(not(feature = "yarn_pnp"))]
174+
fn new() -> Self {
175+
Self
176+
}
177+
174178
fn read_to_string(&self, path: &Path) -> io::Result<String> {
175179
cfg_if! {
176180
if #[cfg(feature = "yarn_pnp")] {
177-
match VPath::from(path)? {
178-
VPath::Zip(info) => {
179-
self.pnp_lru.read_to_string(info.physical_base_path(), info.zip_path)
181+
if self.yarn_pnp {
182+
return match VPath::from(path)? {
183+
VPath::Zip(info) => {
184+
self.pnp_lru.read_to_string(info.physical_base_path(), info.zip_path)
185+
}
186+
VPath::Virtual(info) => Self::read_to_string(&info.physical_base_path()),
187+
VPath::Native(path) => Self::read_to_string(&path),
180188
}
181-
VPath::Virtual(info) => Self::read_to_string(&info.physical_base_path()),
182-
VPath::Native(path) => Self::read_to_string(&path),
183189
}
184-
} else {
185-
Self::read_to_string(path)
186190
}
187191
}
192+
Self::read_to_string(path)
188193
}
189194

190195
fn metadata(&self, path: &Path) -> io::Result<FileMetadata> {
191196
cfg_if! {
192197
if #[cfg(feature = "yarn_pnp")] {
193-
match VPath::from(path)? {
194-
VPath::Zip(info) => self
195-
.pnp_lru
196-
.file_type(info.physical_base_path(), info.zip_path)
197-
.map(FileMetadata::from),
198-
VPath::Virtual(info) => {
199-
Self::metadata(&info.physical_base_path())
198+
if self.yarn_pnp {
199+
return match VPath::from(path)? {
200+
VPath::Zip(info) => self
201+
.pnp_lru
202+
.file_type(info.physical_base_path(), info.zip_path)
203+
.map(FileMetadata::from),
204+
VPath::Virtual(info) => {
205+
Self::metadata(&info.physical_base_path())
206+
}
207+
VPath::Native(path) => Self::metadata(&path),
200208
}
201-
VPath::Native(path) => Self::metadata(&path),
202209
}
203-
} else {
204-
Self::metadata(path)}
210+
}
205211
}
212+
Self::metadata(path)
206213
}
207214

208215
fn symlink_metadata(&self, path: &Path) -> io::Result<FileMetadata> {
@@ -212,15 +219,16 @@ impl FileSystem for FileSystemOs {
212219
fn read_link(&self, path: &Path) -> io::Result<PathBuf> {
213220
cfg_if! {
214221
if #[cfg(feature = "yarn_pnp")] {
215-
match VPath::from(path)? {
216-
VPath::Zip(info) => Self::read_link(&info.physical_base_path().join(info.zip_path)),
217-
VPath::Virtual(info) => Self::read_link(&info.physical_base_path()),
218-
VPath::Native(path) => Self::read_link(&path),
222+
if self.yarn_pnp {
223+
return match VPath::from(path)? {
224+
VPath::Zip(info) => Self::read_link(&info.physical_base_path().join(info.zip_path)),
225+
VPath::Virtual(info) => Self::read_link(&info.physical_base_path()),
226+
VPath::Native(path) => Self::read_link(&path),
227+
}
219228
}
220-
} else {
221-
Self::read_link(path)
222229
}
223230
}
231+
Self::read_link(path)
224232
}
225233
}
226234

src/lib.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,24 @@ impl<Fs> fmt::Debug for ResolverGeneric<Fs> {
125125
}
126126
}
127127

128-
impl<Fs: FileSystem + Default> Default for ResolverGeneric<Fs> {
128+
impl<Fs: FileSystem> Default for ResolverGeneric<Fs> {
129129
fn default() -> Self {
130130
Self::new(ResolveOptions::default())
131131
}
132132
}
133133

134-
impl<Fs: FileSystem + Default> ResolverGeneric<Fs> {
134+
impl<Fs: FileSystem> ResolverGeneric<Fs> {
135135
#[must_use]
136136
pub fn new(options: ResolveOptions) -> Self {
137-
Self { options: options.sanitize(), cache: Arc::new(Cache::new(Fs::default())) }
137+
cfg_if::cfg_if! {
138+
if #[cfg(feature = "yarn_pnp")] {
139+
let fs = Fs::new(options.yarn_pnp);
140+
} else {
141+
let fs = Fs::new();
142+
}
143+
}
144+
let cache = Arc::new(Cache::new(fs));
145+
Self { options: options.sanitize(), cache }
138146
}
139147
}
140148

src/tests/memory_fs.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ impl MemoryFS {
4242
}
4343

4444
impl FileSystem for MemoryFS {
45+
#[cfg(not(feature = "yarn_pnp"))]
46+
fn new() -> Self {
47+
Self::default()
48+
}
49+
50+
#[cfg(feature = "yarn_pnp")]
51+
fn new(_yarn_pnp: bool) -> Self {
52+
Self::default()
53+
}
54+
4555
fn read_to_string(&self, path: &Path) -> io::Result<String> {
4656
use vfs::FileSystem;
4757
let mut file = self

0 commit comments

Comments
 (0)