Merge pull request 'Download files' (#1) from download-files into pages
Reviewed-on: https://codeberg.org/macchiato/editor-lib-codemirror/pulls/1pages
commit
4d4be5c98e
@ -0,0 +1,143 @@
|
||||
function log(message, cls = 'cyan') {
|
||||
const el = document.createElement('pre')
|
||||
el.classList.add(cls)
|
||||
el.innerText = message
|
||||
document.body.append(el)
|
||||
}
|
||||
|
||||
class App {
|
||||
jApiBaseUrl = 'https://data.jsdelivr.com/v1/'
|
||||
jCdnBaseUrl = 'https://cdn.jsdelivr.net/npm/'
|
||||
|
||||
scripts = {
|
||||
'@rollup/browser': {
|
||||
version: '3.20.4',
|
||||
path: 'dist/rollup.browser.js',
|
||||
sha: 'sha256-GgOznxZmgghx1a7CH09B+VmDKtziPO5tAnC5gC+/5Kw=',
|
||||
},
|
||||
}
|
||||
|
||||
topLevelDeps = [
|
||||
"@codemirror/autocomplete",
|
||||
"@codemirror/commands",
|
||||
"@codemirror/language",
|
||||
"@codemirror/lint",
|
||||
"@codemirror/search",
|
||||
"@codemirror/state",
|
||||
"@codemirror/view",
|
||||
"@codemirror/lang-javascript",
|
||||
]
|
||||
|
||||
constructor() {
|
||||
this.downloads = []
|
||||
this.run().catch(e => {
|
||||
log(`${e}`)
|
||||
})
|
||||
}
|
||||
|
||||
checkOk(resp) {
|
||||
if (!resp.ok) {
|
||||
throw new Error(`HTTP request failed: ${resp.status}`)
|
||||
}
|
||||
}
|
||||
|
||||
async loadDep(dep) {
|
||||
this.scripts[dep] = {}
|
||||
const dataResp = await fetch(
|
||||
this.jApiBaseUrl +
|
||||
`packages/npm/${dep}/resolved`,
|
||||
{
|
||||
headers: {
|
||||
'User-Agent':
|
||||
'https://codeberg.org/macchiato',
|
||||
},
|
||||
},
|
||||
)
|
||||
this.checkOk(dataResp)
|
||||
const {version} = await dataResp.json()
|
||||
this.scripts[dep].version = version
|
||||
const pkgResp = await fetch(
|
||||
this.jCdnBaseUrl +
|
||||
`${dep}@${version}/package.json`
|
||||
)
|
||||
this.checkOk(pkgResp)
|
||||
log(dep)
|
||||
const pkg = await pkgResp.json()
|
||||
this.scripts[dep].path = (
|
||||
pkg.module ?? pkg.main
|
||||
)
|
||||
this.downloads.push(this.getScript(dep))
|
||||
const deps = Object.keys(
|
||||
pkg.dependencies || {}
|
||||
).filter(dep => !(dep in this.scripts))
|
||||
await Promise.allSettled(deps.map(dep => (
|
||||
this.loadDep(dep)
|
||||
)))
|
||||
}
|
||||
|
||||
async checkIntegrity(resp, name, script) {
|
||||
const blob = await resp.blob()
|
||||
const ab = await blob.arrayBuffer()
|
||||
const hash = await crypto.subtle.digest(
|
||||
"SHA-256", ab
|
||||
)
|
||||
const checkValue = 'sha256-' + btoa(
|
||||
String.fromCharCode(
|
||||
...new Uint8Array(hash)
|
||||
)
|
||||
)
|
||||
if (checkValue !== script.sha) {
|
||||
throw new Error(
|
||||
'failed integrity check: ' +
|
||||
`${checkValue} !== ${script.sha}`
|
||||
)
|
||||
}
|
||||
return ab
|
||||
}
|
||||
|
||||
async getScript(name) {
|
||||
log('[downloading] ' + name, 'green')
|
||||
const script = this.scripts[name]
|
||||
if (script.text) {
|
||||
return script.text
|
||||
}
|
||||
const url = (
|
||||
this.jCdnBaseUrl +
|
||||
`${name}@${script.version}/${script.path}`
|
||||
)
|
||||
const resp = await fetch(url)
|
||||
this.checkOk(resp)
|
||||
if (script.sha) {
|
||||
const ab = await this.checkIntegrity(
|
||||
resp, name, script
|
||||
)
|
||||
script.text = new TextDecoder().decode(ab)
|
||||
} else {
|
||||
script.text = await resp.text
|
||||
script.sha = resp.integrity
|
||||
}
|
||||
log('[downloaded] ' + url, 'green')
|
||||
return script.text
|
||||
}
|
||||
|
||||
async loadScript(name) {
|
||||
const text = await this.getScript(name)
|
||||
const s = document.createElement('script')
|
||||
s.text = text
|
||||
document.head.append(s)
|
||||
}
|
||||
|
||||
async run() {
|
||||
await Promise.allSettled(
|
||||
this.topLevelDeps.map(dep => (
|
||||
this.loadDep(dep)
|
||||
))
|
||||
)
|
||||
await Promise.allSettled(this.downloads)
|
||||
//await this.loadScript('@rollup/browser')
|
||||
//const { rollup } = window.rollup
|
||||
//output.value = `${typeof rollup}`
|
||||
}
|
||||
}
|
||||
|
||||
new App()
|
||||
@ -0,0 +1,29 @@
|
||||
html, body {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: navy;
|
||||
margin: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
pre.cyan {
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
pre.green {
|
||||
background: lightgreen;
|
||||
}
|
||||
Loading…
Reference in New Issue