diff --git a/icon.png b/icon.png new file mode 100644 index 00000000..39f1ae92 Binary files /dev/null and b/icon.png differ diff --git a/index.html b/index.html index ef553722..dfb259cf 100644 --- a/index.html +++ b/index.html @@ -4,12 +4,45 @@ + + + + - + + + diff --git a/scripts/build.mjs b/scripts/build.mjs index 90d13b07..f5ed5abc 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -14,30 +14,7 @@ const __dirname = dirname(__filename); const projectDir = path.join(__dirname, "../"); const targetDir = path.join(projectDir, "target"); -const jsPostfix = ` -window.DEBUG = true; -let buf = ""; -console.error = (...params) => { - const lastLines = "...\\n" + buf.split("\\n").slice(-10).join("\\n"); - // buf = buf + "ERR " + params.join(" ") + "\\n"; - // const location = new Error().stack.split("\\n")[2]; - alert(params.join(" ") +"\\n...\\n" + lastLines); -}; -console.log = console.info = console.warn = (...params) => { - buf = buf + params.join(" ") + "\\n"; -}; -`; - -const jsSuffix = ` -setTimeout(() => { - const showlogs = document.getElementById("showlogs"); - showlogs.addEventListener("click", () => { - const lastLines = "...\\n" + buf.split("\\n").slice(-20).join("\\n"); - alert(lastLines); - }, true); - showlogs.innerText = "Show last 20 log lines"; -}, 10000); -`; +const debug = true; async function build() { // get version number @@ -45,15 +22,32 @@ async function build() { // clear target dir await removeDirIfExists(targetDir); await fs.mkdir(targetDir); + + await buildHtml(); + await buildJs(); + await buildCss(); + await buildOffline(version); + + console.log(`built brawl ${version} successfully`); +} + +async function buildHtml() { // transform html file const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8"); const doc = cheerio.load(devHtml); doc("link[rel=stylesheet]").attr("href", "brawl.css"); - // doc("html").attr("manifest", "manifest.appcache"); - doc("script").replaceWith( + doc("script#main").replaceWith( `` + - ``); + ``); + removeOrEnableScript(doc("script#phone-debug-pre"), debug); + removeOrEnableScript(doc("script#phone-debug-post"), debug); + removeOrEnableScript(doc("script#service-worker"), false); + doc("html").attr("manifest", "manifest.appcache"); + doc("head").append(``); await fs.writeFile(path.join(targetDir, "index.html"), doc.html(), "utf8"); +} + +async function buildJs() { // create js bundle const rollupConfig = { input: 'src/main.js', @@ -65,23 +59,58 @@ async function build() { }; const bundle = await rollup.rollup(rollupConfig); await bundle.write(rollupConfig); +} + +async function buildOffline(version) { + // write offline availability + const offlineFiles = ["brawl.js", "brawl.css", "index.html", "icon-192.png"]; + + // write appcache manifest + const manifestLines = [ + `CACHE MANIFEST`, + `# v${version}`, + `NETWORK`, + `"*"`, + `CACHE`, + ]; + manifestLines.push(...offlineFiles); + const manifest = manifestLines.join("\n") + "\n"; + await fs.writeFile(path.join(targetDir, "manifest.appcache"), manifest, "utf8"); + // write service worker + let swSource = await fs.readFile(path.join(projectDir, "src/service-worker.template.js"), "utf8"); + swSource = swSource.replace(`"%%VERSION%%"`, `"${version}"`); + swSource = swSource.replace(`"%%FILES%%"`, JSON.stringify(offlineFiles)); + await fs.writeFile(path.join(targetDir, "sw.js"), swSource, "utf8"); + // write web manifest + const webManifest = { + name: "Brawl Chat", + short_name: "Brawl", + display: "standalone", + start_url: "index.html", + icons: [{"src": "icon-192.png", "sizes": "192x192", "type": "image/png"}], + }; + await fs.writeFile(path.join(targetDir, "manifest.json"), JSON.stringify(webManifest), "utf8"); + // copy icon + let icon = await fs.readFile(path.join(projectDir, "icon.png")); + await fs.writeFile(path.join(targetDir, "icon-192.png"), icon); +} + +async function buildCss() { // create css bundle const cssMainFile = path.join(projectDir, "src/ui/web/css/main.css"); const preCss = await fs.readFile(cssMainFile, "utf8"); const cssBundler = postcss([postcssImport]); const postCss = await cssBundler.process(preCss, {from: cssMainFile}); await fs.writeFile(path.join(targetDir, "brawl.css"), postCss, "utf8"); - // write appcache manifest - const manifestLines = [ - `CACHE MANIFEST`, - `# v${version}`, - "brawl.js", - "brawl.css", - "index.html", - "" - ]; - await fs.writeFile(path.join(targetDir, "manifest.appcache"), manifestLines.join("\n"), "utf8"); - console.log(`built brawl ${version} successfully`); +} + + +function removeOrEnableScript(scriptNode, enable) { + if (enable) { + scriptNode.attr("type", "text/javascript"); + } else { + scriptNode.remove(); + } } async function removeDirIfExists(targetDir) { diff --git a/src/service-worker.template.js b/src/service-worker.template.js new file mode 100644 index 00000000..ee9c54e0 --- /dev/null +++ b/src/service-worker.template.js @@ -0,0 +1,31 @@ +const VERSION = "%%VERSION%%"; +const FILES = "%%FILES%%"; +const cacheName = `brawl-${VERSION}`; + +self.addEventListener('install', function(e) { + e.waitUntil( + caches.open(cacheName).then(function(cache) { + return cache.addAll(FILES); + }) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((keyList) => { + return Promise.all(keyList.map((key) => { + if (key !== cacheName) { + return caches.delete(key); + } + })); + }) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.open(cacheName) + .then(cache => cache.match(event.request)) + .then((response) => response || fetch(event.request)) + ); +});