From d56ede02fee7274088436263cca144ff724bcf1f Mon Sep 17 00:00:00 2001 From: bat Date: Fri, 21 Apr 2023 06:50:45 +0000 Subject: [PATCH] use web component to show build progress; use Promise.all so errors are shown --- app.js | 122 +++++++++++++++++++++++++++++++++++++++++++----------- style.css | 17 -------- 2 files changed, 97 insertions(+), 42 deletions(-) diff --git a/app.js b/app.js index 657d764..35d8c60 100644 --- a/app.js +++ b/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}`) + } } } diff --git a/style.css b/style.css index 36da046..4dc37e3 100644 --- a/style.css +++ b/style.css @@ -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; } \ No newline at end of file