diff --git a/.github/workflows/publish-jsr.yml b/.github/workflows/publish-jsr.yml index dcd199f..9e13eec 100644 --- a/.github/workflows/publish-jsr.yml +++ b/.github/workflows/publish-jsr.yml @@ -2,8 +2,8 @@ name: Publish to jsr on: push: - branches: - - main + tags: + - 'v*' jobs: publish: diff --git a/RELEASE.md b/RELEASE.md index a7b9d10..f489114 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -24,25 +24,25 @@ No setup required. JSR authentication happens via browser during first publish. ## Pre-Release Checklist -1. Ensure all tests pass +- [ ] Ensure all tests pass - ```bash - pnpm test:run - ``` +```bash +pnpm test:run +``` -2. Type check all packages +- [ ] Type check all packages - ```bash - pnpm typecheck - ``` +```bash +pnpm typecheck +``` -3. Build all packages +- [ ] Build all packages - ```bash - pnpm build - ``` +```bash +pnpm build +``` -4. Review changelog and update version numbers +- [ ] Update version numbers ## Publishing voltx.js @@ -51,6 +51,8 @@ The core package is published as: - **npm**: `voltx.js` (unscoped) - **JSR**: `@voltx.js/core` (scoped, JSR requires scopes) +Publishing is **fully automated** via GitHub Actions when you push a tag. + ### 1. Update Version Update version in both files: @@ -64,78 +66,121 @@ Use semantic versioning (semver): - Minor: new features, backward compatible (0.1.0 → 0.2.0) - Major: breaking changes (0.1.0 → 1.0.0) -### 2. Build Package +### 2. Build and Test Locally ```bash cd lib pnpm build +pnpm test:run ``` Verify build outputs: -- `dist/volt.js` - Main framework bundle -- `dist/volt.css` - CSS framework -- `dist/index.d.ts` - TypeScript declarations +- [ ] `dist/voltx.js` - Unminified ES module +- [ ] `dist/voltx.min.js` - Minified ES module +- [ ] `dist/voltx.min.js.gz` - Gzipped minified version (for size verification) +- [ ] `dist/voltx.d.ts` - Main TypeScript declarations +- [ ] `dist/debug.js` - Debug module (unminified) +- [ ] `dist/debug.min.js` - Debug module (minified) +- [ ] `dist/debug.d.ts` - Debug TypeScript declarations +- [ ] `dist/voltx.css` - Unminified CSS framework +- [ ] `dist/voltx.min.css` - Minified CSS framework + +Ensure no unwanted files: + +- [ ] No chunks (code splitting disabled) +- [ ] No asset files (vite.svg, etc.) -### 3. Publish to npm +### 3. Commit Version Bump ```bash -cd lib -npm publish --provenance +git add lib/package.json lib/jsr.json +git commit -m "chore: bump version to vX.Y.Z" +git push origin main ``` -The `--provenance` flag adds supply chain security metadata when publishing from GitHub Actions. - -### 4. Publish to JSR +### 4. Create and Push Tag ```bash -cd lib -npx jsr publish +git tag vX.Y.Z +git push origin vX.Y.Z ``` -First time: Browser window opens for authentication -Subsequent publishes: Uses cached credentials +**This triggers automated publishing:** + +- `.github/workflows/publish-npm.yml` - Publishes to npm with provenance +- `.github/workflows/publish-jsr.yml` - Publishes to JSR + +### 5. Monitor GitHub Actions + +- [ ] Check workflow runs: +- [ ] Verify npm publish workflow succeeded +- [ ] Verify JSR publish workflow succeeded -### 5. Verify Publication +### 6. Verify Publication -npm: +- [ ] Verify npm publication ```bash npm view voltx.js ``` -JSR: +Visit: + +- [ ] Verify JSR publication ```bash npx jsr info @voltx.js/core ``` -Or visit: +Visit: + +- [ ] Verify unpkg.com distribution structure +Visit: `https://unpkg.com/voltx.js@VERSION/` (replace VERSION) -- npm: -- JSR: +You should see: + - dist/ directory with all build outputs + - LICENSE + - README.md + - package.json ## Post-Release -1. Create Git tag +- [ ] Create GitHub release with changelog + - Go to + - Click "Draft a new release" + - Select the tag (vX.Y.Z) that was just pushed + - Add release notes and changelog +- [ ] Update documentation if needed +- [ ] Announce release (if significant update) - ```bash - git tag v0.1.0 - git push origin v0.1.0 - ``` +## Manual Publishing (Fallback) -2. Create GitHub release with changelog +If GitHub Actions fail or you need to publish manually: -3. Update documentation if needed +### npm -## To-Do +```bash +cd lib +npm publish --provenance +``` + +Requires: + +- npm login (`npm whoami` to verify) +- npm publish rights to voltx.js package -Consider setting up GitHub Actions workflow to automate: +### JSR + +```bash +cd lib +npx jsr publish +``` -- Publishing to npm -- Version bumping -- Building -- Git tagging -- GitHub release creation +First time: Browser window opens for authentication +Subsequent publishes: Uses cached credentials + +## To-Do -Consider using `bumpp` or `changeset` for automated version management across the monorepo. +- Consider using `bumpp` or `changeset` for automated version management across the monorepo. +- Write a changelog diff --git a/lib/README.md b/lib/README.md index 3fa82ab..fbbdbe5 100644 --- a/lib/README.md +++ b/lib/README.md @@ -61,7 +61,7 @@ import 'voltx.js/css'; Or include via CDN: ```html - + ``` ## Documentation diff --git a/lib/package.json b/lib/package.json index 189e2e1..d964c6b 100644 --- a/lib/package.json +++ b/lib/package.json @@ -9,20 +9,24 @@ "keywords": ["reactive", "signals", "framework", "ui", "declarative", "html", "dom", "frontend"], "main": "./dist/voltx.js", "module": "./dist/voltx.js", - "types": "./dist/index.d.ts", + "types": "./dist/voltx.d.ts", "exports": { - ".": { "types": "./dist/index.d.ts", "import": "./dist/voltx.js" }, + ".": { "types": "./dist/voltx.d.ts", "import": "./dist/voltx.js" }, "./debug": { "types": "./dist/debug.d.ts", "import": "./dist/debug.js" }, - "./css": "./dist/volt.css", + "./css": "./dist/voltx.css", "./package.json": "./package.json" }, - "files": ["dist", "src", "README.md"], + "files": ["dist", "LICENSE", "README.md"], "scripts": { "dev": "vite", - "build": "pnpm build:lib && pnpm build:css", - "build:lib": "tsc -p tsconfig.build.json && vite build --mode lib", + "build": "pnpm build:clean && pnpm build:types && pnpm build:lib && pnpm build:lib:min && pnpm build:css && pnpm build:css:min && pnpm build:finalize", + "build:clean": "rm -rf dist", + "build:types": "tsc -p tsconfig.build.json", + "build:lib": "vite build --mode lib", + "build:lib:min": "vite build --mode lib:min", "build:css": "postcss src/styles/index.css -o dist/voltx.css", "build:css:min": "postcss src/styles/index.css -o dist/voltx.min.css --env production", + "build:finalize": "node scripts/build-finalize.js", "preview": "vite preview", "test": "vitest", "test:run": "vitest run", diff --git a/lib/scripts/build-finalize.js b/lib/scripts/build-finalize.js new file mode 100644 index 0000000..9c1532f --- /dev/null +++ b/lib/scripts/build-finalize.js @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +/** + * Post-build script to finalize the distribution package: + * 1. Copy index.d.ts to voltx.d.ts for cleaner imports + * 2. Compress voltx.min.js to voltx.min.js.gz + * 3. Clean up unwanted files (chunks, assets) + */ +import { copyFileSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { createGzip } from "node:zlib"; + +// TODO: move to dev cli +function main() { + const __dirname = path.dirname(fileURLToPath(import.meta.url)); + const distDir = path.resolve(__dirname, "../dist"); + + console.log("Finalizing build...\n"); + + try { + const indexDts = path.join(distDir, "index.d.ts"); + const voltxDts = path.join(distDir, "voltx.d.ts"); + copyFileSync(indexDts, voltxDts); + console.log("✓ Copied index.d.ts → voltx.d.ts"); + } catch (error) { + console.error("✗ Failed to copy type definitions:", error.message); + process.exit(1); + } + + try { + const minJsPath = path.join(distDir, "voltx.min.js"); + const gzPath = path.join(distDir, "voltx.min.js.gz"); + + const input = readFileSync(minJsPath); + const gzip = createGzip({ level: 9 }); + const output = []; + + gzip.on("data", (chunk) => output.push(chunk)); + gzip.on("end", () => { + writeFileSync(gzPath, Buffer.concat(output)); + const originalSize = (input.length / 1024).toFixed(2); + const compressedSize = (Buffer.concat(output).length / 1024).toFixed(2); + console.log(`✓ Compressed voltx.min.js: ${originalSize}KB → ${compressedSize}KB (gzip)`); + }); + + gzip.write(input); + gzip.end(); + } catch (error) { + console.error("✗ Failed to compress voltx.min.js:", error.message); + process.exit(1); + } + + try { + const files = readdirSync(distDir); + // Any files not named voltx* or debug* or images + const unwantedPatterns = [/^(?!voltx|debug).*\.js$/, /\.svg$/, /\.png$/, /\.jpg$/]; + + let cleanedCount = 0; + for (const file of files) { + const shouldDelete = unwantedPatterns.some((pattern) => pattern.test(file)); + if (shouldDelete) { + unlinkSync(path.join(distDir, file)); + console.log(`✓ Removed unwanted file: ${file}`); + cleanedCount++; + } + } + + if (cleanedCount === 0) { + console.log("✓ No unwanted files to clean"); + } + } catch (error) { + console.error("✗ Failed to clean unwanted files:", error.message); + process.exit(1); + } + + console.log("\n✨ Build finalization complete!"); + process.exit(0); +} + +main(); diff --git a/lib/tsconfig.json b/lib/tsconfig.json index c4d48cf..093121a 100644 --- a/lib/tsconfig.json +++ b/lib/tsconfig.json @@ -29,5 +29,5 @@ "$volt": ["./src/index.ts"] } }, - "include": ["src", "test", "eslint.config.js", "vite.config.ts", "postcss.config.js"] + "include": ["src", "test", "eslint.config.js", "vite.config.ts", "postcss.config.js", "scripts"] } diff --git a/lib/vite.config.ts b/lib/vite.config.ts index 9b1661f..ab14671 100644 --- a/lib/vite.config.ts +++ b/lib/vite.config.ts @@ -21,19 +21,34 @@ const test: ViteUserConfig["test"] = { }, }; -const buildOptions = (mode: string): BuildEnvironmentOptions => ({ - minify: mode === "lib" ? "oxc" : true, - ...(mode === "lib" - ? { - lib: { - entry: { voltx: path.resolve(__dirname, "src/index.ts"), debug: path.resolve(__dirname, "src/debug.ts") }, - name: "VoltX", - formats: ["es"], - }, - rolldownOptions: { output: { assetFileNames: "voltx.[ext]", minify: true } }, - } - : {}), -}); +const buildOptions = (mode: string): BuildEnvironmentOptions => { + const isLibBuild = mode === "lib" || mode === "lib:min"; + const shouldMinify = mode === "lib:min"; + + return { + minify: shouldMinify ? "oxc" : false, + ...(isLibBuild + ? { + lib: { + entry: { voltx: path.resolve(__dirname, "src/index.ts"), debug: path.resolve(__dirname, "src/debug.ts") }, + name: "VoltX", + formats: ["es"], + fileName: (format, entryName) => { + const suffix = shouldMinify ? ".min.js" : ".js"; + return `${entryName}${suffix}`; + }, + }, + rolldownOptions: { + output: { assetFileNames: "voltx.[ext]", manualChunks: undefined, preserveModules: false }, + onwarn(warning, warn) { + if (warning.code === "UNUSED_EXTERNAL_IMPORT") return; + warn(warning); + }, + }, + } + : {}), + }; +}; export default defineConfig(({ mode }) => ({ resolve: { @@ -46,7 +61,10 @@ export default defineConfig(({ mode }) => ({ "$vebug": path.resolve(__dirname, "./src/debug.ts"), }, }, - build: buildOptions(mode), + build: { + ...buildOptions(mode), + emptyOutDir: false, // Don't clear dist/ to preserve TypeScript declarations + }, test, plugins: [], }));