Skip to content

Commit 8f9ac17

Browse files
committed
feat: make dependencies download script cross-platform using Node.js
1 parent a91db2b commit 8f9ac17

File tree

1 file changed

+52
-18
lines changed

1 file changed

+52
-18
lines changed

app/components/Package/DownloadButton.vue

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -153,36 +153,70 @@ async function downloadPackage() {
153153
function downloadDependenciesScript() {
154154
if (!props.dependencies?.length) return
155155
156-
const lines = [
157-
'#!/bin/bash',
158-
`# Download dependencies for ${props.packageName}@${props.version.version}`,
159-
'mkdir -p node_modules',
160-
'',
161-
]
156+
const tarballs: { name: string; version: string; url: string }[] = []
162157
163-
// Add root package
164158
const rootTarball = props.version.dist.tarball
165159
if (rootTarball) {
166-
lines.push(`# ${props.packageName}@${props.version.version}`)
167-
lines.push(
168-
`curl -L "${rootTarball}" -o "${props.packageName.replace(/\//g, '__')}-${props.version.version}.tgz"`,
169-
)
160+
tarballs.push({ name: props.packageName, version: props.version.version, url: rootTarball })
170161
}
171162
172-
// Add dependencies
173163
props.dependencies.forEach(dep => {
174164
if (!dep.tarballUrl) return
175-
lines.push(`# ${dep.name}@${dep.version}`)
176-
lines.push(
177-
`curl -L "${dep.tarballUrl}" -o "${dep.name.replace(/\//g, '__')}-${dep.version}.tgz"`,
178-
)
165+
tarballs.push({ name: dep.name, version: dep.version, url: dep.tarballUrl })
179166
})
180167
181-
const blob = new Blob([lines.join('\n')], { type: 'text/x-shellscript' })
168+
const sanitize = (name: string) => name.replace(/\//g, '__')
169+
170+
// Node.js script — works on all platforms
171+
const lines = [
172+
'#!/usr/bin/env node',
173+
`// Download dependencies for ${props.packageName}@${props.version.version}`,
174+
'// Run: node <filename>',
175+
'',
176+
"const { mkdirSync, createWriteStream } = require('fs');",
177+
"const https = require('https');",
178+
"const http = require('http');",
179+
"const { basename } = require('path');",
180+
'',
181+
"const dir = 'tarballs';",
182+
'mkdirSync(dir, { recursive: true });',
183+
'',
184+
'const tarballs = [',
185+
...tarballs.map(t => ` { name: '${t.name}', version: '${t.version}', url: '${t.url}' },`),
186+
'];',
187+
'',
188+
'function download(url, dest) {',
189+
' return new Promise((resolve, reject) => {',
190+
" const client = url.startsWith('https') ? https : http;",
191+
' client.get(url, (res) => {',
192+
' if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {',
193+
' return download(res.headers.location, dest).then(resolve, reject);',
194+
' }',
195+
' if (res.statusCode !== 200) {',
196+
' return reject(new Error(`HTTP ${res.statusCode} for ${url}`));',
197+
' }',
198+
' const file = createWriteStream(dest);',
199+
" res.pipe(file).on('finish', () => file.close(resolve));",
200+
' }).on("error", reject);',
201+
' });',
202+
'}',
203+
'',
204+
'(async () => {',
205+
' for (const t of tarballs) {',
206+
" const filename = `${t.name.replace(/\\//g, '__')}-${t.version}.tgz`;",
207+
' const dest = `${dir}/${filename}`;',
208+
' console.log(`Downloading ${t.name}@${t.version}...`);',
209+
' await download(t.url, dest);',
210+
' }',
211+
' console.log(`Done! ${tarballs.length} tarball(s) saved to ${dir}/`);',
212+
'})();',
213+
]
214+
215+
const blob = new Blob([lines.join('\n')], { type: 'application/javascript' })
182216
const url = URL.createObjectURL(blob)
183217
const link = document.createElement('a')
184218
link.href = url
185-
link.download = `download-${props.packageName.replace(/\//g, '__')}-deps.sh`
219+
link.download = `download-${sanitize(props.packageName)}-deps.js`
186220
document.body.appendChild(link)
187221
link.click()
188222
document.body.removeChild(link)

0 commit comments

Comments
 (0)