Build & Tag (CDN Ready) #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build & Tag (CDN Ready) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version (e.g. 1.0.0)" | |
| required: true | |
| permissions: | |
| contents: write | |
| jobs: | |
| tag: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout main | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - name: Install dependencies | |
| run: npm install terser clean-css | |
| - name: Build files | |
| run: | | |
| node <<'EOF' | |
| import fs from "fs"; | |
| import { minify } from "terser"; | |
| import CleanCSS from "clean-css"; | |
| const VERSION = process.env.VERSION; | |
| const repo = process.env.GITHUB_REPOSITORY; | |
| const [owner, name] = repo.split("/"); | |
| const BASE_URL = `https://${owner}.github.io/${name}/`; | |
| const files = fs.readdirSync(".").filter(f => { | |
| if (fs.statSync(f).isDirectory()) return false; | |
| if (f.startsWith(".")) return false; | |
| return true; | |
| }); | |
| // detect main file (framework or component) | |
| const mainFile = | |
| files.find(f => f === "ccm.js") || | |
| files.find(f => /^ccm\.[a-z0-9_]+\.mjs$/.test(f)); | |
| for (const file of files) { | |
| const ext = file.split(".").pop(); | |
| if (!["js", "mjs", "css"].includes(ext)) continue; | |
| let content = fs.readFileSync(file, "utf-8"); | |
| // replace local paths | |
| content = content.replaceAll("././", BASE_URL); | |
| let outputName = file; | |
| // rename main file with version | |
| if (file === mainFile) { | |
| if (file.endsWith(".mjs")) { | |
| outputName = file.replace(".mjs", `-${VERSION}.mjs`); | |
| } else { | |
| outputName = file.replace(".js", `-${VERSION}.js`); | |
| } | |
| } | |
| // JS / MJS minify + source map | |
| if (ext === "js" || ext === "mjs") { | |
| const result = await minify(content, { | |
| sourceMap: { | |
| filename: outputName, | |
| url: outputName + ".map" | |
| } | |
| }); | |
| const minName = outputName.replace(ext, `min.${ext}`); | |
| fs.writeFileSync(minName, result.code); | |
| fs.writeFileSync(outputName + ".map", result.map); | |
| } | |
| // CSS minify | |
| if (ext === "css") { | |
| const minified = new CleanCSS().minify(content).styles; | |
| const minName = file.replace(".css", ".min.css"); | |
| fs.writeFileSync(minName, minified); | |
| } | |
| } | |
| // 🔥 CLEANUP: keep ONLY .min.* and .map, preserve .git | |
| const all = fs.readdirSync("."); | |
| for (const file of all) { | |
| // never delete git directory | |
| if (file === ".git") continue; | |
| // remove other hidden files (.github, .gitignore, etc.) | |
| if (file.startsWith(".")) { | |
| fs.rmSync(file, { recursive: true, force: true }); | |
| continue; | |
| } | |
| const ext = file.split(".").pop(); | |
| const isMin = file.includes(".min."); | |
| const isMap = ext === "map"; | |
| if (!isMin && !isMap) { | |
| fs.rmSync(file, { recursive: true, force: true }); | |
| } | |
| } | |
| EOF | |
| env: | |
| VERSION: ${{ github.event.inputs.version }} | |
| - name: Commit build | |
| run: | | |
| git config user.name "github-actions" | |
| git config user.email "github-actions@github.com" | |
| git add . | |
| git commit -m "build v${{ github.event.inputs.version }}" | |
| - name: Create and push tag | |
| run: | | |
| git tag -f v${{ github.event.inputs.version }} | |
| git push origin v${{ github.event.inputs.version }} --force |