a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals

build: update build process to gzip & minify assets

+2 -2
.github/workflows/publish-jsr.yml
··· 2 2 3 3 on: 4 4 push: 5 - branches: 6 - - main 5 + tags: 6 + - 'v*' 7 7 8 8 jobs: 9 9 publish:
+93 -48
RELEASE.md
··· 24 24 25 25 ## Pre-Release Checklist 26 26 27 - 1. Ensure all tests pass 27 + - [ ] Ensure all tests pass 28 28 29 - ```bash 30 - pnpm test:run 31 - ``` 29 + ```bash 30 + pnpm test:run 31 + ``` 32 32 33 - 2. Type check all packages 33 + - [ ] Type check all packages 34 34 35 - ```bash 36 - pnpm typecheck 37 - ``` 35 + ```bash 36 + pnpm typecheck 37 + ``` 38 38 39 - 3. Build all packages 39 + - [ ] Build all packages 40 40 41 - ```bash 42 - pnpm build 43 - ``` 41 + ```bash 42 + pnpm build 43 + ``` 44 44 45 - 4. Review changelog and update version numbers 45 + - [ ] Update version numbers 46 46 47 47 ## Publishing voltx.js 48 48 ··· 51 51 - **npm**: `voltx.js` (unscoped) 52 52 - **JSR**: `@voltx.js/core` (scoped, JSR requires scopes) 53 53 54 + Publishing is **fully automated** via GitHub Actions when you push a tag. 55 + 54 56 ### 1. Update Version 55 57 56 58 Update version in both files: ··· 64 66 - Minor: new features, backward compatible (0.1.0 → 0.2.0) 65 67 - Major: breaking changes (0.1.0 → 1.0.0) 66 68 67 - ### 2. Build Package 69 + ### 2. Build and Test Locally 68 70 69 71 ```bash 70 72 cd lib 71 73 pnpm build 74 + pnpm test:run 72 75 ``` 73 76 74 77 Verify build outputs: 75 78 76 - - `dist/volt.js` - Main framework bundle 77 - - `dist/volt.css` - CSS framework 78 - - `dist/index.d.ts` - TypeScript declarations 79 + - [ ] `dist/voltx.js` - Unminified ES module 80 + - [ ] `dist/voltx.min.js` - Minified ES module 81 + - [ ] `dist/voltx.min.js.gz` - Gzipped minified version (for size verification) 82 + - [ ] `dist/voltx.d.ts` - Main TypeScript declarations 83 + - [ ] `dist/debug.js` - Debug module (unminified) 84 + - [ ] `dist/debug.min.js` - Debug module (minified) 85 + - [ ] `dist/debug.d.ts` - Debug TypeScript declarations 86 + - [ ] `dist/voltx.css` - Unminified CSS framework 87 + - [ ] `dist/voltx.min.css` - Minified CSS framework 79 88 80 - ### 3. Publish to npm 89 + Ensure no unwanted files: 90 + 91 + - [ ] No chunks (code splitting disabled) 92 + - [ ] No asset files (vite.svg, etc.) 93 + 94 + ### 3. Commit Version Bump 81 95 82 96 ```bash 83 - cd lib 84 - npm publish --provenance 97 + git add lib/package.json lib/jsr.json 98 + git commit -m "chore: bump version to vX.Y.Z" 99 + git push origin main 85 100 ``` 86 101 87 - The `--provenance` flag adds supply chain security metadata when publishing from GitHub Actions. 88 - 89 - ### 4. Publish to JSR 102 + ### 4. Create and Push Tag 90 103 91 104 ```bash 92 - cd lib 93 - npx jsr publish 105 + git tag vX.Y.Z 106 + git push origin vX.Y.Z 94 107 ``` 95 108 96 - First time: Browser window opens for authentication 97 - Subsequent publishes: Uses cached credentials 109 + **This triggers automated publishing:** 110 + 111 + - `.github/workflows/publish-npm.yml` - Publishes to npm with provenance 112 + - `.github/workflows/publish-jsr.yml` - Publishes to JSR 113 + 114 + ### 5. Monitor GitHub Actions 115 + 116 + - [ ] Check workflow runs: <https://github.com/stormlightlabs/volt/actions> 117 + - [ ] Verify npm publish workflow succeeded 118 + - [ ] Verify JSR publish workflow succeeded 98 119 99 - ### 5. Verify Publication 120 + ### 6. Verify Publication 100 121 101 - npm: 122 + - [ ] Verify npm publication 102 123 103 124 ```bash 104 125 npm view voltx.js 105 126 ``` 106 127 107 - JSR: 128 + Visit: <https://www.npmjs.com/package/voltx.js> 129 + 130 + - [ ] Verify JSR publication 108 131 109 132 ```bash 110 133 npx jsr info @voltx.js/core 111 134 ``` 112 135 113 - Or visit: 136 + Visit: <https://jsr.io/@voltx.js/core> 137 + 138 + - [ ] Verify unpkg.com distribution structure 139 + Visit: `https://unpkg.com/voltx.js@VERSION/` (replace VERSION) 114 140 115 - - npm: <https://www.npmjs.com/package/voltx.js> 116 - - JSR: <https://jsr.io/@voltx.js/core> 141 + You should see: 142 + - dist/ directory with all build outputs 143 + - LICENSE 144 + - README.md 145 + - package.json 117 146 118 147 ## Post-Release 119 148 120 - 1. Create Git tag 149 + - [ ] Create GitHub release with changelog 150 + - Go to <https://github.com/stormlightlabs/volt/releases> 151 + - Click "Draft a new release" 152 + - Select the tag (vX.Y.Z) that was just pushed 153 + - Add release notes and changelog 154 + - [ ] Update documentation if needed 155 + - [ ] Announce release (if significant update) 121 156 122 - ```bash 123 - git tag v0.1.0 124 - git push origin v0.1.0 125 - ``` 157 + ## Manual Publishing (Fallback) 158 + 159 + If GitHub Actions fail or you need to publish manually: 126 160 127 - 2. Create GitHub release with changelog 161 + ### npm 128 162 129 - 3. Update documentation if needed 163 + ```bash 164 + cd lib 165 + npm publish --provenance 166 + ``` 167 + 168 + Requires: 169 + 170 + - npm login (`npm whoami` to verify) 171 + - npm publish rights to voltx.js package 172 + 173 + ### JSR 130 174 131 - ## To-Do 175 + ```bash 176 + cd lib 177 + npx jsr publish 178 + ``` 132 179 133 - Consider setting up GitHub Actions workflow to automate: 180 + First time: Browser window opens for authentication 181 + Subsequent publishes: Uses cached credentials 134 182 135 - - Publishing to npm 136 - - Version bumping 137 - - Building 138 - - Git tagging 139 - - GitHub release creation 183 + ## To-Do 140 184 141 - Consider using `bumpp` or `changeset` for automated version management across the monorepo. 185 + - Consider using `bumpp` or `changeset` for automated version management across the monorepo. 186 + - Write a changelog
+1 -1
lib/README.md
··· 61 61 Or include via CDN: 62 62 63 63 ```html 64 - <link rel="stylesheet" href="https://unpkg.com/voltx.js/dist/volt.css"> 64 + <link rel="stylesheet" href="https://unpkg.com/voltx.js/dist/voltx.css"> 65 65 ``` 66 66 67 67 ## Documentation
+10 -6
lib/package.json
··· 9 9 "keywords": ["reactive", "signals", "framework", "ui", "declarative", "html", "dom", "frontend"], 10 10 "main": "./dist/voltx.js", 11 11 "module": "./dist/voltx.js", 12 - "types": "./dist/index.d.ts", 12 + "types": "./dist/voltx.d.ts", 13 13 "exports": { 14 - ".": { "types": "./dist/index.d.ts", "import": "./dist/voltx.js" }, 14 + ".": { "types": "./dist/voltx.d.ts", "import": "./dist/voltx.js" }, 15 15 "./debug": { "types": "./dist/debug.d.ts", "import": "./dist/debug.js" }, 16 - "./css": "./dist/volt.css", 16 + "./css": "./dist/voltx.css", 17 17 "./package.json": "./package.json" 18 18 }, 19 - "files": ["dist", "src", "README.md"], 19 + "files": ["dist", "LICENSE", "README.md"], 20 20 "scripts": { 21 21 "dev": "vite", 22 - "build": "pnpm build:lib && pnpm build:css", 23 - "build:lib": "tsc -p tsconfig.build.json && vite build --mode lib", 22 + "build": "pnpm build:clean && pnpm build:types && pnpm build:lib && pnpm build:lib:min && pnpm build:css && pnpm build:css:min && pnpm build:finalize", 23 + "build:clean": "rm -rf dist", 24 + "build:types": "tsc -p tsconfig.build.json", 25 + "build:lib": "vite build --mode lib", 26 + "build:lib:min": "vite build --mode lib:min", 24 27 "build:css": "postcss src/styles/index.css -o dist/voltx.css", 25 28 "build:css:min": "postcss src/styles/index.css -o dist/voltx.min.css --env production", 29 + "build:finalize": "node scripts/build-finalize.js", 26 30 "preview": "vite preview", 27 31 "test": "vitest", 28 32 "test:run": "vitest run",
+81
lib/scripts/build-finalize.js
··· 1 + #!/usr/bin/env node 2 + 3 + /** 4 + * Post-build script to finalize the distribution package: 5 + * 1. Copy index.d.ts to voltx.d.ts for cleaner imports 6 + * 2. Compress voltx.min.js to voltx.min.js.gz 7 + * 3. Clean up unwanted files (chunks, assets) 8 + */ 9 + import { copyFileSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; 10 + import path from "node:path"; 11 + import { fileURLToPath } from "node:url"; 12 + import { createGzip } from "node:zlib"; 13 + 14 + // TODO: move to dev cli 15 + function main() { 16 + const __dirname = path.dirname(fileURLToPath(import.meta.url)); 17 + const distDir = path.resolve(__dirname, "../dist"); 18 + 19 + console.log("Finalizing build...\n"); 20 + 21 + try { 22 + const indexDts = path.join(distDir, "index.d.ts"); 23 + const voltxDts = path.join(distDir, "voltx.d.ts"); 24 + copyFileSync(indexDts, voltxDts); 25 + console.log("✓ Copied index.d.ts → voltx.d.ts"); 26 + } catch (error) { 27 + console.error("✗ Failed to copy type definitions:", error.message); 28 + process.exit(1); 29 + } 30 + 31 + try { 32 + const minJsPath = path.join(distDir, "voltx.min.js"); 33 + const gzPath = path.join(distDir, "voltx.min.js.gz"); 34 + 35 + const input = readFileSync(minJsPath); 36 + const gzip = createGzip({ level: 9 }); 37 + const output = []; 38 + 39 + gzip.on("data", (chunk) => output.push(chunk)); 40 + gzip.on("end", () => { 41 + writeFileSync(gzPath, Buffer.concat(output)); 42 + const originalSize = (input.length / 1024).toFixed(2); 43 + const compressedSize = (Buffer.concat(output).length / 1024).toFixed(2); 44 + console.log(`✓ Compressed voltx.min.js: ${originalSize}KB → ${compressedSize}KB (gzip)`); 45 + }); 46 + 47 + gzip.write(input); 48 + gzip.end(); 49 + } catch (error) { 50 + console.error("✗ Failed to compress voltx.min.js:", error.message); 51 + process.exit(1); 52 + } 53 + 54 + try { 55 + const files = readdirSync(distDir); 56 + // Any files not named voltx* or debug* or images 57 + const unwantedPatterns = [/^(?!voltx|debug).*\.js$/, /\.svg$/, /\.png$/, /\.jpg$/]; 58 + 59 + let cleanedCount = 0; 60 + for (const file of files) { 61 + const shouldDelete = unwantedPatterns.some((pattern) => pattern.test(file)); 62 + if (shouldDelete) { 63 + unlinkSync(path.join(distDir, file)); 64 + console.log(`✓ Removed unwanted file: ${file}`); 65 + cleanedCount++; 66 + } 67 + } 68 + 69 + if (cleanedCount === 0) { 70 + console.log("✓ No unwanted files to clean"); 71 + } 72 + } catch (error) { 73 + console.error("✗ Failed to clean unwanted files:", error.message); 74 + process.exit(1); 75 + } 76 + 77 + console.log("\n✨ Build finalization complete!"); 78 + process.exit(0); 79 + } 80 + 81 + main();
+1 -1
lib/tsconfig.json
··· 29 29 "$volt": ["./src/index.ts"] 30 30 } 31 31 }, 32 - "include": ["src", "test", "eslint.config.js", "vite.config.ts", "postcss.config.js"] 32 + "include": ["src", "test", "eslint.config.js", "vite.config.ts", "postcss.config.js", "scripts"] 33 33 }
+32 -14
lib/vite.config.ts
··· 21 21 }, 22 22 }; 23 23 24 - const buildOptions = (mode: string): BuildEnvironmentOptions => ({ 25 - minify: mode === "lib" ? "oxc" : true, 26 - ...(mode === "lib" 27 - ? { 28 - lib: { 29 - entry: { voltx: path.resolve(__dirname, "src/index.ts"), debug: path.resolve(__dirname, "src/debug.ts") }, 30 - name: "VoltX", 31 - formats: ["es"], 32 - }, 33 - rolldownOptions: { output: { assetFileNames: "voltx.[ext]", minify: true } }, 34 - } 35 - : {}), 36 - }); 24 + const buildOptions = (mode: string): BuildEnvironmentOptions => { 25 + const isLibBuild = mode === "lib" || mode === "lib:min"; 26 + const shouldMinify = mode === "lib:min"; 27 + 28 + return { 29 + minify: shouldMinify ? "oxc" : false, 30 + ...(isLibBuild 31 + ? { 32 + lib: { 33 + entry: { voltx: path.resolve(__dirname, "src/index.ts"), debug: path.resolve(__dirname, "src/debug.ts") }, 34 + name: "VoltX", 35 + formats: ["es"], 36 + fileName: (format, entryName) => { 37 + const suffix = shouldMinify ? ".min.js" : ".js"; 38 + return `${entryName}${suffix}`; 39 + }, 40 + }, 41 + rolldownOptions: { 42 + output: { assetFileNames: "voltx.[ext]", manualChunks: undefined, preserveModules: false }, 43 + onwarn(warning, warn) { 44 + if (warning.code === "UNUSED_EXTERNAL_IMPORT") return; 45 + warn(warning); 46 + }, 47 + }, 48 + } 49 + : {}), 50 + }; 51 + }; 37 52 38 53 export default defineConfig(({ mode }) => ({ 39 54 resolve: { ··· 46 61 "$vebug": path.resolve(__dirname, "./src/debug.ts"), 47 62 }, 48 63 }, 49 - build: buildOptions(mode), 64 + build: { 65 + ...buildOptions(mode), 66 + emptyOutDir: false, // Don't clear dist/ to preserve TypeScript declarations 67 + }, 50 68 test, 51 69 plugins: [], 52 70 }));