Skip to content

Instantly share code, notes, and snippets.

@ChenYFan
Last active February 20, 2024 02:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ChenYFan/8bb67aaced9949e2583492d2956a6f37 to your computer and use it in GitHub Desktop.
Save ChenYFan/8bb67aaced9949e2583492d2956a6f37 to your computer and use it in GitHub Desktop.
使用ServiceWorker,通过下载NPM registry中的tgz包,实现前端下载、UNGZIP、UNTar一条龙分发静态文件
import tarball from "./tarball.js"
import { ungzip } from "pako"
import CacheDb from "@chenyfan/cache-db"
const defaultResponse = `<a href="/?package_name=chenyfan-os&version=0.0.0-r26&path=img%20(4).png">Example</a>`
const genTarUrl = (package_name, version) => {
//const prefix = "https://registry.npmjs.org/"
//const prefix = "https://mirrors.cloud.tencent.com/npm/"
//const prefix = "https://registry.npmmirror.com/"
//const prefix = "https://mirrors.huaweicloud.com/repository/npm/" //CORS限制
const prefix = "https://npmreg.proxy.ustclug.org/"
return prefix + package_name + "/-/" + package_name + "-" + version + ".tgz"
}
const handleNPMRequest = async (request) => {
const url = new URL(request.url)
const npm_package = url.searchParams.get("package_name")
const npm_version = url.searchParams.get("version") || "latest"
const npm_path = url.searchParams.get("path") || "/"
if (!npm_package) return new Response(defaultResponse, { status: 400, headers: { "Content-Type": "text/html" } })
const PackageCache = new CacheDb("npmPackage")
const ProviderCache = new CacheDb(`npmProvider@${npm_package}@${npm_version}`)
let getProviderExist = await ProviderCache.read(`package.json`).then(res => res ? true : false)
if (!getProviderExist) {
let getPackage = await PackageCache.read(`${npm_package}@${npm_version}`)
if (!getPackage) {
getPackage = await fetch(genTarUrl(npm_package, npm_version)).then(res => res.arrayBuffer())
await PackageCache.write(`${npm_package}@${npm_version}`, getPackage)
}
const ungziped = ungzip(new Uint8Array(getPackage))
const ungzipedBlob = new Blob([ungziped], { type: "application/gzip" })
let tarReader = new tarball.TarReader()
const unTaredList = await tarReader.readFile(ungzipedBlob)
for (let file in unTaredList) {
await ProviderCache.write(unTaredList[file].name.replace("package/", ""), tarReader.getFileBinary(unTaredList[file].name))
}
}
return new Response(await ProviderCache.read(npm_path, { type: "arrayBuffer" }), {
status: 200, headers: {
"content-type": ((suffix) => {
switch (suffix) {
case "json":
return "application/json"
case "js":
return "application/javascript"
case "css":
return "text/css"
case "png":
return "image/png"
case "jpg":
return "image/jpeg"
case "html":
return "text/html"
default:
return "text/plain"
}
})(npm_path.split(".").pop().toLowerCase())
}
})
}
addEventListener("fetch", (event) => {
event.respondWith(handleNPMRequest(event.request))
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment