Skip to content

Commit ec38ca9

Browse files
perf: decrease initial loading time (#458)
1 parent 5f74295 commit ec38ca9

File tree

2 files changed

+81
-29
lines changed

2 files changed

+81
-29
lines changed

lib/index.js

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55

66
"use strict";
77

8-
const fs = require("graceful-fs");
9-
const CachedInputFileSystem = require("./CachedInputFileSystem");
10-
const ResolverFactory = require("./ResolverFactory");
8+
const memoize = require("./util/memoize");
119

1210
/** @typedef {import("./CachedInputFileSystem").BaseFileSystem} BaseFileSystem */
1311
/** @typedef {import("./PnpPlugin").PnpApiImpl} PnpApi */
@@ -36,17 +34,28 @@ const ResolverFactory = require("./ResolverFactory");
3634
* }} ResolveFunction
3735
*/
3836

39-
const nodeFileSystem = new CachedInputFileSystem(fs, 4000);
37+
const getCachedFileSystem = memoize(() => require("./CachedInputFileSystem"));
4038

41-
const nodeContext = {
42-
environments: ["node+es3+es5+process+native"],
43-
};
39+
const getNodeFileSystem = memoize(() => {
40+
const fs = require("graceful-fs");
41+
42+
const CachedInputFileSystem = getCachedFileSystem();
4443

45-
const asyncResolver = ResolverFactory.createResolver({
46-
conditionNames: ["node"],
47-
extensions: [".js", ".json", ".node"],
48-
fileSystem: nodeFileSystem,
44+
return new CachedInputFileSystem(fs, 4000);
4945
});
46+
const getNodeContext = memoize(() => ({
47+
environments: ["node+es3+es5+process+native"],
48+
}));
49+
50+
const getResolverFactory = memoize(() => require("./ResolverFactory"));
51+
52+
const getAsyncResolver = memoize(() =>
53+
getResolverFactory().createResolver({
54+
conditionNames: ["node"],
55+
extensions: [".js", ".json", ".node"],
56+
fileSystem: getNodeFileSystem(),
57+
}),
58+
);
5059

5160
/**
5261
* @type {ResolveFunctionAsync}
@@ -65,12 +74,12 @@ const resolve =
6574
resolveContext = /** @type {ResolveContext} */ (request);
6675
request = path;
6776
path = context;
68-
context = nodeContext;
77+
context = getNodeContext();
6978
}
7079
if (typeof callback !== "function") {
7180
callback = /** @type {ResolveCallback} */ (resolveContext);
7281
}
73-
asyncResolver.resolve(
82+
getAsyncResolver().resolve(
7483
context,
7584
path,
7685
/** @type {string} */ (request),
@@ -79,12 +88,14 @@ const resolve =
7988
);
8089
};
8190

82-
const syncResolver = ResolverFactory.createResolver({
83-
conditionNames: ["node"],
84-
extensions: [".js", ".json", ".node"],
85-
useSyncFileSystemCalls: true,
86-
fileSystem: nodeFileSystem,
87-
});
91+
const getSyncResolver = memoize(() =>
92+
getResolverFactory().createResolver({
93+
conditionNames: ["node"],
94+
extensions: [".js", ".json", ".node"],
95+
useSyncFileSystemCalls: true,
96+
fileSystem: getNodeFileSystem(),
97+
}),
98+
);
8899

89100
/**
90101
* @type {ResolveFunction}
@@ -100,9 +111,9 @@ const resolveSync =
100111
if (typeof context === "string") {
101112
request = path;
102113
path = context;
103-
context = nodeContext;
114+
context = getNodeContext();
104115
}
105-
return syncResolver.resolveSync(
116+
return getSyncResolver().resolveSync(
106117
context,
107118
path,
108119
/** @type {string} */ (request),
@@ -116,8 +127,8 @@ const resolveSync =
116127
* @returns {ResolveFunctionAsync} Resolver function
117128
*/
118129
function create(options) {
119-
const resolver = ResolverFactory.createResolver({
120-
fileSystem: nodeFileSystem,
130+
const resolver = getResolverFactory().createResolver({
131+
fileSystem: getNodeFileSystem(),
121132
...options,
122133
});
123134
/**
@@ -133,7 +144,7 @@ function create(options) {
133144
resolveContext = /** @type {ResolveContext} */ (request);
134145
request = path;
135146
path = context;
136-
context = nodeContext;
147+
context = getNodeContext();
137148
}
138149
if (typeof callback !== "function") {
139150
callback = /** @type {ResolveCallback} */ (resolveContext);
@@ -153,9 +164,9 @@ function create(options) {
153164
* @returns {ResolveFunction} Resolver function
154165
*/
155166
function createSync(options) {
156-
const resolver = ResolverFactory.createResolver({
167+
const resolver = getResolverFactory().createResolver({
157168
useSyncFileSystemCalls: true,
158-
fileSystem: nodeFileSystem,
169+
fileSystem: getNodeFileSystem(),
159170
...options,
160171
});
161172
/**
@@ -168,7 +179,7 @@ function createSync(options) {
168179
if (typeof context === "string") {
169180
request = path;
170181
path = context;
171-
context = nodeContext;
182+
context = getNodeContext();
172183
}
173184
return resolver.resolveSync(context, path, /** @type {string} */ (request));
174185
};
@@ -196,8 +207,12 @@ module.exports = mergeExports(resolve, {
196207
return createSync;
197208
},
198209
}),
199-
ResolverFactory,
200-
CachedInputFileSystem,
210+
get ResolverFactory() {
211+
return getResolverFactory();
212+
},
213+
get CachedInputFileSystem() {
214+
return getCachedFileSystem();
215+
},
201216
get CloneBasenamePlugin() {
202217
return require("./CloneBasenamePlugin");
203218
},

lib/util/memoize.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
6+
"use strict";
7+
8+
/**
9+
* @template T
10+
* @typedef {() => T} FunctionReturning
11+
*/
12+
13+
/**
14+
* @template T
15+
* @param {FunctionReturning<T>} fn memorized function
16+
* @returns {FunctionReturning<T>} new function
17+
*/
18+
const memoize = (fn) => {
19+
let cache = false;
20+
/** @type {T | undefined} */
21+
let result;
22+
return () => {
23+
if (cache) {
24+
return /** @type {T} */ (result);
25+
}
26+
27+
result = fn();
28+
cache = true;
29+
// Allow to clean up memory for fn
30+
// and all dependent resources
31+
/** @type {FunctionReturning<T> | undefined} */
32+
(fn) = undefined;
33+
return /** @type {T} */ (result);
34+
};
35+
};
36+
37+
module.exports = memoize;

0 commit comments

Comments
 (0)