use web component to show build progress; use Promise.all so errors are shown

pages
bat 3 years ago
parent ba18185138
commit d56ede02fe

122
app.js

@ -40,15 +40,7 @@ import {lintKeymap} from '@codemirror/lint'
])
])()`
function log(message, cls = 'cyan') {
const el = document.createElement('pre')
el.classList.add(cls)
el.innerText = message
document.body.append(el)
;(el.scrollIntoViewIfNeeded ?? el.scrollIntoView).call(el)
}
class App {
class Builder {
jApiBaseUrl = 'https://data.jsdelivr.com/v1/'
jCdnBaseUrl = 'https://cdn.jsdelivr.net/npm/'
@ -73,9 +65,6 @@ class App {
constructor() {
this.downloads = []
this.run().catch(e => {
log(`${e}`)
})
}
checkOk(resp) {
@ -104,7 +93,7 @@ class App {
`${dep}@${version}/package.json`
)
this.checkOk(pkgResp)
log(dep)
this.log(dep)
const pkg = await pkgResp.json()
this.scripts[dep].path = (
pkg.module ?? pkg.main
@ -118,18 +107,22 @@ class App {
)))
}
async checkIntegrity(resp, name, script) {
const blob = await resp.blob()
const ab = await blob.arrayBuffer()
async sha(ab) {
const hash = await crypto.subtle.digest(
"SHA-256", ab
)
const checkValue = 'sha256-' + btoa(
return 'sha256-' + btoa(
String.fromCharCode(
...new Uint8Array(hash)
)
)
if (checkValue !== script.sha) {
}
async checkIntegrity(resp, name, script) {
const blob = await resp.blob()
const ab = await blob.arrayBuffer()
const sha = await this.sha(ab)
if (sha !== script.sha) {
throw new Error(
'failed integrity check: ' +
`${checkValue} !== ${script.sha}`
@ -139,7 +132,7 @@ class App {
}
async getScript(name) {
log('[downloading] ' + name, 'green')
this.log('[downloading] ' + name, 'green')
const script = this.scripts[name]
if (script.text) {
return script.text
@ -159,7 +152,10 @@ class App {
script.text = await resp.text()
script.sha = resp.integrity
}
log('[downloaded] ' + url + ` [${script.text.length}]`, 'green')
this.log(
'[downloaded] ' + url + ` [${script.text.length}]`,
'green'
)
return script.text
}
@ -180,29 +176,105 @@ class App {
},
load: async id => {
if (id === 'editor.js') {
this.log(`[found] editor.js`)
return editorSrc
} else if (id in this.scripts) {
log(`[found] ${id}`)
this.log(`[found] ${id}`)
return this.scripts[id].text
}
},
}
}
async run() {
await Promise.allSettled(
async build() {
const result = await Promise.all(
this.topLevelDeps.map(dep => (
this.loadDep(dep)
))
)
await Promise.allSettled(this.downloads)
await Promise.all(this.downloads)
await this.loadScript('@rollup/browser')
const { rollup } = window.rollup
const input = 'editor.js'
const plugins = [this.loaderPlugin]
const bundle = await rollup({input, plugins})
const {output} = await bundle.generate({format: 'es'})
log(output[0].code)
this.code = output[0].code
this.sha = await this.sha(
new TextEncoder().encode(this.code)
)
this.log(`built ${this.sha}`)
}
}
class BuildView extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.shadowRoot.adoptedStyleSheets = [
this.constructor.styleSheet
]
}
log(message, cls = 'cyan') {
const el = document.createElement('pre')
el.classList.add(cls)
el.innerText = message
this.shadowRoot.append(el)
;(el.scrollIntoViewIfNeeded ?? el.scrollIntoView).call(el)
}
static get styleSheet() {
if (this._styleSheet === undefined) {
this._styleSheet = new CSSStyleSheet()
this._styleSheet.replaceSync(this.css)
}
return this._styleSheet
}
static css = `
:host {
display: flex;
flex-direction: column;
align-items: stretch;
margin: 10px;
gap: 10px;
}
pre {
padding: 8px;
border-radius: 5px;
margin: 0;
overflow-x: auto;
}
pre.cyan {
background: cyan;
}
pre.green {
background: lightgreen;
}
`
}
customElements.define('m-build-view', BuildView)
class App {
constructor() {
this.builder = new Builder()
this.buildView = document.createElement('m-build-view')
document.body.append(this.buildView)
this.builder.log = this.buildView.log.bind(this.buildView)
this.build()
}
async build() {
try {
await this.builder.build()
} catch (e) {
this.buildView.log(`${e}`)
}
}
}

@ -9,21 +9,4 @@ body {
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…
Cancel
Save