Skip to content

Commit 994b810

Browse files
authored
Cache browsers locally instead of globally (#106)
1 parent 55863eb commit 994b810

5 files changed

Lines changed: 42 additions & 46 deletions

File tree

.changeset/stupid-kids-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'pleasantest': minor
3+
---
4+
5+
Cache browser instances locally instead of globally

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
dist
2-
node_modules
2+
node_modules
3+
.browser-cache.json

package-lock.json

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"ansi-regex": "6.0.0",
2626
"aria-query": "*",
2727
"babel-plugin-un-cjs": "2.5.0",
28-
"env-paths": "2.2.1",
2928
"errorstacks": "2.3.2",
3029
"esbuild": "0.12.8",
3130
"esbuild-jest": "0.5.0",

src/connect-to-browser.ts

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
import * as childProcess from 'child_process';
22
import * as path from 'path';
33
import { promises as fs } from 'fs';
4-
import envPaths from 'env-paths';
54
import * as puppeteer from 'puppeteer';
65
// @ts-expect-error the bundle: syntax is from a plugin in the rollup config and TS does not know about it
76
import startDisownedBrowserPath from 'bundle:./start-disowned-browser';
7+
import { fileURLToPath } from 'url';
88

9-
const readConfig = async (configPath: string) => {
9+
const readCache = async (cachePath: string) => {
1010
try {
11-
const config = await fs.readFile(configPath, 'utf8').catch(() => '');
12-
const parsed = JSON.parse(config);
11+
const cache = await fs.readFile(cachePath, 'utf8').catch(() => '');
12+
const parsed = JSON.parse(cache);
1313
if (typeof parsed === 'object') return parsed;
1414
} catch {}
1515

1616
return {};
1717
};
1818

19-
const updateConfig = async (
20-
configPath: string,
19+
const updateCacheFile = async (
20+
cachePath: string,
2121
browser: 'chromium',
2222
headless: boolean,
2323
value: string | undefined,
2424
previousValue: string | undefined,
2525
) => {
26-
await fs.mkdir(path.dirname(configPath), { recursive: true });
27-
const oldConfig = await readConfig(configPath);
26+
await fs.mkdir(path.dirname(cachePath), { recursive: true });
27+
const oldCache = await readCache(cachePath);
2828
const headlessStr = headless ? 'headless' : 'headed';
29-
const browserObj = oldConfig[browser] || (oldConfig[browser] = {});
29+
const browserObj = oldCache[browser] || (oldCache[browser] = {});
3030
if (
3131
previousValue !== undefined &&
3232
previousValue !== browserObj[headlessStr]
@@ -35,17 +35,17 @@ const updateConfig = async (
3535
}
3636

3737
browserObj[headlessStr] = value;
38-
await fs.writeFile(configPath, JSON.stringify(oldConfig, null, 2));
38+
await fs.writeFile(cachePath, JSON.stringify(oldCache, null, 2));
3939
};
4040

4141
const connectToCachedBrowser = async (
42-
configPath: string,
42+
cachePath: string,
4343
browser: 'chromium',
4444
headless: boolean,
4545
timeLimit = 5000,
4646
) => {
47-
const config = await readConfig(configPath);
48-
const cachedWSEndpoint = config[browser]?.[headless ? 'headless' : 'headed'];
47+
const cache = await readCache(cachePath);
48+
const cachedWSEndpoint = cache[browser]?.[headless ? 'headless' : 'headed'];
4949
// In case another process is currently starting a browser, wait for that process
5050
// rather than starting a whole new one
5151
if (cachedWSEndpoint === 'starting' && timeLimit > 0) {
@@ -56,7 +56,7 @@ const connectToCachedBrowser = async (
5656
setTimeout(
5757
() =>
5858
connectToCachedBrowser(
59-
configPath,
59+
cachePath,
6060
browser,
6161
headless,
6262
timeLimit - 50,
@@ -87,28 +87,35 @@ export const connectToBrowser = async (
8787
) => {
8888
// I acknowledge that this code is gross and should be refactored
8989
// Constraints:
90-
// - If there is no browser in the config, multiple concurrent processes should only start 1 new browser
91-
// - If there is a killed browser in the config, multiple concurrent processes should only start 1 new browser
92-
// - If there "starting" in the config but nothing is really starting, multiple concurrent processes should only start 1 new browser
90+
// - If there is no browser in the cache, multiple concurrent processes should only start 1 new browser
91+
// - If there is a killed browser in the cache, multiple concurrent processes should only start 1 new browser
92+
// - If there "starting" in the cache but nothing is really starting, multiple concurrent processes should only start 1 new browser
9393
// TODO: Idea: use a state machine!!!
94-
const dataPath = envPaths('pleasantest').data;
95-
const configPath = path.join(dataPath, 'config.json');
94+
// This is the folder that Pleasantest is installed in (e.g. <something>/node_modules/pleasantest)
95+
const installFolder = path.dirname(
96+
path.dirname(path.dirname(fileURLToPath(import.meta.url))),
97+
);
98+
// Something like <something>/node_modules/pleasantest/.browser-cache.json
99+
const cachePath = path.join(installFolder, '.browser-cache.json');
96100
const cachedBrowser = await connectToCachedBrowser(
97-
configPath,
101+
cachePath,
98102
browser,
99103
headless,
100104
);
101-
if (isBrowser(cachedBrowser)) return cachedBrowser;
102-
let valueWrittenInMeantime = await updateConfig(
103-
configPath,
105+
if (isBrowser(cachedBrowser)) {
106+
return cachedBrowser;
107+
}
108+
109+
let valueWrittenInMeantime = await updateCacheFile(
110+
cachePath,
104111
browser,
105112
headless,
106113
'starting',
107114
cachedBrowser.previousValue,
108115
);
109116
if (valueWrittenInMeantime) {
110117
const connectedBrowser = await connectToCachedBrowser(
111-
configPath,
118+
cachePath,
112119
browser,
113120
headless,
114121
);
@@ -131,17 +138,17 @@ export const connectToBrowser = async (
131138
});
132139
}).catch(async (error) => {
133140
subprocess.kill();
134-
valueWrittenInMeantime = await updateConfig(
135-
configPath,
141+
valueWrittenInMeantime = await updateCacheFile(
142+
cachePath,
136143
browser,
137144
headless,
138145
'',
139146
'starting',
140147
);
141148
throw error;
142149
});
143-
valueWrittenInMeantime = await updateConfig(
144-
configPath,
150+
valueWrittenInMeantime = await updateCacheFile(
151+
cachePath,
145152
browser,
146153
headless,
147154
wsEndpoint,

0 commit comments

Comments
 (0)