Skip to content

Commit 155e17e

Browse files
committed
refactor: switch to esbuild, reduce extension file size
1 parent befe510 commit 155e17e

File tree

6 files changed

+156
-65
lines changed

6 files changed

+156
-65
lines changed

assets/icon.png

-1.16 KB
Loading

bun.lock

Lines changed: 54 additions & 34 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@
3636
"vscode": "^1.94.0"
3737
},
3838
"scripts": {
39-
"compile": "rimraf build && ncc build src/extension.ts -o build -m",
39+
"compile": "rimraf build && esbuild ./src/extension.ts --bundle --outfile=build/index.js --external:vscode --format=cjs --platform=node --minify",
4040
"lint": "tsc --noEmit && eslint .",
4141
"package": "vsce package --no-dependencies",
4242
"release:dry-run": "bun --env-file=.env semantic-release --dry-run"
4343
},
44-
"dependencies": {
45-
"preferred-pm": "^4.1.1"
46-
},
4744
"devDependencies": {
4845
"@eslint/js": "^9.21.0",
4946
"@semantic-release/changelog": "^6.0.3",
@@ -53,6 +50,7 @@
5350
"@vercel/ncc": "^0.38.3",
5451
"@vscode/vsce": "^3.2.2",
5552
"conventional-changelog-conventionalcommits": "^8.0.0",
53+
"esbuild": "^0.25.0",
5654
"eslint": "^9.21.0",
5755
"eslint-config-prettier": "^10.0.1",
5856
"eslint-plugin-prettier": "^5.2.3",

src/detectPackageManager.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* The original form of this code comes from the https://github.com/egoist/detect-package-manager package.
3+
* It has been adjusted for VS Code usage, and support for non-binary Bun lock has been added.
4+
*/
5+
import execa from 'execa';
6+
import { resolve } from 'node:path';
7+
import { workspace, Uri } from 'vscode';
8+
9+
export type PM = 'npm' | 'yarn' | 'pnpm' | 'bun';
10+
11+
async function pathExists(path: string) {
12+
try {
13+
await workspace.fs.stat(Uri.file(path));
14+
return true;
15+
} catch {
16+
return false;
17+
}
18+
}
19+
20+
async function hasGlobalInstallation(pm: PM): Promise<boolean> {
21+
return execa(pm, ['--version'])
22+
.then((res) => {
23+
return /^\d+.\d+.\d+$/.test(res.stdout);
24+
})
25+
.then((value) => {
26+
return value;
27+
})
28+
.catch(() => false);
29+
}
30+
31+
async function getTypeofLockFile(cwd = '.'): Promise<PM | null> {
32+
return Promise.all([
33+
pathExists(resolve(cwd, 'yarn.lock')),
34+
pathExists(resolve(cwd, 'pnpm-lock.yaml')),
35+
pathExists(resolve(cwd, 'bun.lock')),
36+
pathExists(resolve(cwd, 'bun.lockb'))
37+
]).then(([isYarn, isPnpm, isBun, isBunBinary]) => {
38+
if (isYarn) {
39+
return 'yarn';
40+
} else if (isPnpm) {
41+
return 'pnpm';
42+
} else if (isBun || isBunBinary) {
43+
return 'bun';
44+
}
45+
46+
return 'npm';
47+
});
48+
}
49+
50+
export async function detectPackageManager({ cwd }: { cwd?: string } = {}): Promise<PM> {
51+
const type = await getTypeofLockFile(cwd);
52+
53+
if (type) {
54+
return type;
55+
}
56+
const [hasYarn, hasPnpm, hasBun] = await Promise.all([
57+
hasGlobalInstallation('yarn'),
58+
hasGlobalInstallation('pnpm'),
59+
hasGlobalInstallation('bun')
60+
]);
61+
if (hasYarn) {
62+
return 'yarn';
63+
}
64+
if (hasPnpm) {
65+
return 'pnpm';
66+
}
67+
if (hasBun) {
68+
return 'bun';
69+
}
70+
return 'npm';
71+
}

src/extension.ts

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { exec } from 'node:child_process';
2-
import * as vscode from 'vscode';
3-
import { QuickPickItemKind } from 'vscode';
4-
import preferredPM from 'preferred-pm';
2+
import { workspace, commands, window, type ExtensionContext, QuickPickItemKind, env, Uri } from 'vscode';
3+
4+
import { detectPackageManager } from './detectPackageManager';
55
import { DirectoryEntry } from './types';
66
import {
77
ENTRY_OPTION,
@@ -14,15 +14,17 @@ import {
1414
ValidKeyword
1515
} from './utils';
1616

17-
export async function activate(context: vscode.ExtensionContext) {
18-
const workspacePath = vscode.workspace.workspaceFolders?.[0].uri.fsPath ?? vscode.workspace.rootPath;
19-
const manager = vscode.workspace.getConfiguration('npm').get<string>('packageManager', 'npm');
17+
export async function activate(context: ExtensionContext) {
18+
const workspacePath = workspace.workspaceFolders?.[0].uri.fsPath ?? workspace.rootPath;
19+
const manager = workspace.getConfiguration('npm').get<string>('packageManager', 'npm');
2020

2121
const shouldCheckPreferred = workspacePath && (!manager || manager === 'auto');
22-
const preferredManager = shouldCheckPreferred ? ((await preferredPM(workspacePath))?.name ?? 'npm') : manager;
22+
const preferredManager = shouldCheckPreferred
23+
? ((await detectPackageManager({ cwd: workspacePath })) ?? 'npm')
24+
: manager;
2325

24-
const disposable = vscode.commands.registerCommand('extension.showQuickPick', async () => {
25-
const packagesPick = vscode.window.createQuickPick<DirectoryEntry>();
26+
const disposable = commands.registerCommand('extension.showQuickPick', async () => {
27+
const packagesPick = window.createQuickPick<DirectoryEntry>();
2628

2729
packagesPick.placeholder = STRINGS.PLACEHOLDER_BUSY;
2830
packagesPick.title = STRINGS.DEFAULT_TITLE;
@@ -112,7 +114,7 @@ export async function activate(context: vscode.ExtensionContext) {
112114
{ label: ENTRY_OPTION.GO_BACK }
113115
].filter((option) => !!option && typeof option === 'object');
114116

115-
const optionPick = vscode.window.createQuickPick();
117+
const optionPick = window.createQuickPick();
116118
optionPick.title = `Actions for "${selectedEntry.label}"`;
117119
optionPick.placeholder = 'Select an action';
118120
optionPick.items = possibleActions;
@@ -125,51 +127,51 @@ export async function activate(context: vscode.ExtensionContext) {
125127
case ENTRY_OPTION.INSTALL: {
126128
exec(getCommandToRun(selectedEntry, preferredManager), { cwd: workspacePath }, (error, stout) => {
127129
if (error) {
128-
vscode.window.showErrorMessage(
130+
window.showErrorMessage(
129131
`An error occurred while trying to install the \`${selectedEntry.npmPkg}\` package: ${error.message}`
130132
);
131133
return;
132134
}
133-
vscode.window.showInformationMessage(
135+
window.showInformationMessage(
134136
`\`${selectedEntry.npmPkg}\` package has been installed${selectedEntry.dev ? ' as `devDependency`' : ''} in current workspace using \`${preferredManager}\`: ${stout}`
135137
);
136138
optionPick.hide();
137139
});
138140
break;
139141
}
140142
case ENTRY_OPTION.VISIT_HOMEPAGE: {
141-
vscode.env.openExternal(vscode.Uri.parse(selectedEntry.github.urls.homepage!));
143+
env.openExternal(Uri.parse(selectedEntry.github.urls.homepage!));
142144
break;
143145
}
144146
case ENTRY_OPTION.VISIT_REPO: {
145-
vscode.env.openExternal(vscode.Uri.parse(selectedEntry.githubUrl));
147+
env.openExternal(Uri.parse(selectedEntry.githubUrl));
146148
break;
147149
}
148150
case ENTRY_OPTION.VISIT_NPM: {
149-
vscode.env.openExternal(vscode.Uri.parse(`https://www.npmjs.com/package/${selectedEntry.npmPkg}`));
151+
env.openExternal(Uri.parse(`https://www.npmjs.com/package/${selectedEntry.npmPkg}`));
150152
break;
151153
}
152154
case ENTRY_OPTION.VIEW_BUNDLEPHOBIA: {
153-
vscode.env.openExternal(vscode.Uri.parse(`https://bundlephobia.com/package/${selectedEntry.npmPkg}`));
155+
env.openExternal(Uri.parse(`https://bundlephobia.com/package/${selectedEntry.npmPkg}`));
154156
break;
155157
}
156158
case ENTRY_OPTION.VIEW_LICENSE: {
157-
vscode.env.openExternal(vscode.Uri.parse(selectedEntry.github.license.url));
159+
env.openExternal(Uri.parse(selectedEntry.github.license.url));
158160
break;
159161
}
160162
case ENTRY_OPTION.COPY_NAME: {
161-
vscode.env.clipboard.writeText(selectedEntry.npmPkg);
162-
vscode.window.showInformationMessage('Package name copied to clipboard');
163+
env.clipboard.writeText(selectedEntry.npmPkg);
164+
window.showInformationMessage('Package name copied to clipboard');
163165
break;
164166
}
165167
case ENTRY_OPTION.COPY_REPO_URL: {
166-
vscode.env.clipboard.writeText(selectedEntry.githubUrl);
167-
vscode.window.showInformationMessage('Repository URL copied to clipboard');
168+
env.clipboard.writeText(selectedEntry.githubUrl);
169+
window.showInformationMessage('Repository URL copied to clipboard');
168170
break;
169171
}
170172
case ENTRY_OPTION.COPY_NPM_URL: {
171-
vscode.env.clipboard.writeText(`https://www.npmjs.com/package/${selectedEntry.npmPkg}`);
172-
vscode.window.showInformationMessage('npm registry URL copied to clipboard');
173+
env.clipboard.writeText(`https://www.npmjs.com/package/${selectedEntry.npmPkg}`);
174+
window.showInformationMessage('npm registry URL copied to clipboard');
173175
break;
174176
}
175177
case ENTRY_OPTION.GO_BACK: {

src/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as vscode from 'vscode';
1+
import { window } from 'vscode';
22

33
import { DirectoryEntry, PackageData } from './types';
44

@@ -113,14 +113,14 @@ export async function fetchData(query?: string, keywords?: ValidKeyword[]): Prom
113113
...item
114114
}));
115115
}
116-
vscode.window.showErrorMessage(`Invalid React Native Directory API response content`);
116+
window.showErrorMessage(`Invalid React Native Directory API response content`);
117117
return [];
118118
}
119-
vscode.window.showErrorMessage(`Invalid React Native Directory API response: ${response.status}`);
119+
window.showErrorMessage(`Invalid React Native Directory API response: ${response.status}`);
120120
return [];
121121
} catch (error) {
122122
console.error(error);
123-
vscode.window.showErrorMessage('Failed to fetch data from React Native Directory API');
123+
window.showErrorMessage('Failed to fetch data from React Native Directory API');
124124
return [];
125125
}
126126
}

0 commit comments

Comments
 (0)