/* Copyright 2020 Bruno Windels Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ import cheerio from "cheerio"; import fsRoot from "fs"; const fs = fsRoot.promises; import path from "path"; import rollup from 'rollup'; import postcss from "postcss"; import postcssImport from "postcss-import"; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const projectDir = path.join(__dirname, "../"); const targetDir = path.join(projectDir, "target"); const debug = false; const offline = true; async function build() { // get version number const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version; // clear target dir await removeDirIfExists(targetDir); await fs.mkdir(targetDir); await buildHtml(version); await buildJs(); await buildCss(); if (offline) { await buildOffline(version); } console.log(`built brawl ${version} successfully`); } async function buildHtml(version) { // 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("script#main").replaceWith( `` + ``); removeOrEnableScript(doc("script#phone-debug-pre"), debug); removeOrEnableScript(doc("script#phone-debug-post"), debug); removeOrEnableScript(doc("script#service-worker"), offline); const versionScript = doc("script#version"); versionScript.attr("type", "text/javascript"); let vSource = versionScript.contents().text(); vSource = vSource.replace(`"%%VERSION%%"`, `"${version}"`); versionScript.text(vSource); if (offline) { 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', output: { file: path.join(targetDir, "brawl.js"), format: 'iife', name: 'main' } }; 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: "fullscreen", 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"); } function removeOrEnableScript(scriptNode, enable) { if (enable) { scriptNode.attr("type", "text/javascript"); } else { scriptNode.remove(); } } async function removeDirIfExists(targetDir) { try { const files = await fs.readdir(targetDir); await Promise.all(files.map(filename => fs.unlink(path.join(targetDir, filename)))); await fs.rmdir(targetDir); } catch (err) { if (err.code !== "ENOENT") { throw err; } } } build().catch(err => console.error(err));