feat: dist building
This commit is contained in:
20
README.md
20
README.md
@@ -120,10 +120,26 @@ npm run test:coverage
|
||||
# Generates drizzle artifacts, builds main process and renderer
|
||||
npm run build
|
||||
|
||||
# Package distributables
|
||||
npx electron-builder
|
||||
# Package app directory only (no installer)
|
||||
npm run package
|
||||
|
||||
# Package distributables for all supported systems
|
||||
npm run dist
|
||||
|
||||
# Package by target platform
|
||||
npm run dist:mac
|
||||
npm run dist:win
|
||||
npm run dist:linux
|
||||
```
|
||||
|
||||
### Distribution Notes
|
||||
|
||||
- Custom protocol `bds://` is declared in electron-builder metadata for packaged apps.
|
||||
- macOS signing/notarization is scaffolded via `scripts/notarize.mjs` and runs when these env vars are set:
|
||||
- `APPLE_ID`
|
||||
- `APPLE_APP_SPECIFIC_PASSWORD`
|
||||
- `APPLE_TEAM_ID`
|
||||
|
||||
### Database Utilities
|
||||
|
||||
```bash
|
||||
|
||||
108
package-lock.json
generated
108
package-lock.json
generated
@@ -45,11 +45,13 @@
|
||||
"simple-git": "^3.31.1",
|
||||
"snowball-stemmers": "^0.6.0",
|
||||
"turndown": "^7.2.2",
|
||||
"uuid": "^13.0.0",
|
||||
"vanilla-calendar-pro": "^3.1.0",
|
||||
"zod": "^4.3.6",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron/notarize": "^3.1.0",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
@@ -75,7 +77,6 @@
|
||||
"memfs": "^4.6.0",
|
||||
"tsx": "^4.6.0",
|
||||
"typescript": "^5.3.0",
|
||||
"uuid": "^13.0.0",
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^4.0.18",
|
||||
"wait-on": "^9.0.3"
|
||||
@@ -1134,57 +1135,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz",
|
||||
"integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-3.1.1.tgz",
|
||||
"integrity": "sha512-uQQSlOiJnqRkTL1wlEBAxe90nVN/Fc/hEmk0bqpKk8nKjV1if/tXLHKUPePtv9Xsx90PtZU8aidx5lAiOpjkQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"debug": "^4.4.0",
|
||||
"promise-retry": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize/node_modules/jsonfile": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/notarize/node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
"node": ">= 22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/osx-sign": {
|
||||
@@ -6350,6 +6311,60 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz",
|
||||
"integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"promise-retry": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/fs-extra": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
|
||||
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/jsonfile": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
|
||||
"integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/@electron/notarize/node_modules/universalify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
|
||||
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/app-builder-lib/node_modules/ci-info": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz",
|
||||
@@ -14913,7 +14928,6 @@
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
|
||||
45
package.json
45
package.json
@@ -12,6 +12,11 @@
|
||||
"start": "concurrently --kill-others \"npm run dev:renderer\" \"npm run start:electron\"",
|
||||
"start:electron": "wait-on http://localhost:5173 && cross-env NODE_ENV=development node ./node_modules/electron/cli.js .",
|
||||
"build": "npm run lint && npm run db:generate && npm run build:main && npm run build:renderer",
|
||||
"package": "npm run build && electron-builder --dir",
|
||||
"dist": "npm run build && electron-builder",
|
||||
"dist:mac": "npm run build && electron-builder --mac",
|
||||
"dist:win": "npm run build && electron-builder --win",
|
||||
"dist:linux": "npm run build && electron-builder --linux",
|
||||
"build:main": "node ./node_modules/typescript/bin/tsc -p tsconfig.main.json",
|
||||
"build:renderer": "node ./node_modules/vite/bin/vite.js build",
|
||||
"start:prod": "node ./node_modules/electron/cli.js .",
|
||||
@@ -29,6 +34,7 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@electron/notarize": "^3.1.0",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
@@ -54,7 +60,6 @@
|
||||
"memfs": "^4.6.0",
|
||||
"tsx": "^4.6.0",
|
||||
"typescript": "^5.3.0",
|
||||
"uuid": "^13.0.0",
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^4.0.18",
|
||||
"wait-on": "^9.0.3"
|
||||
@@ -96,6 +101,7 @@
|
||||
"simple-git": "^3.31.1",
|
||||
"snowball-stemmers": "^0.6.0",
|
||||
"turndown": "^7.2.2",
|
||||
"uuid": "^13.0.0",
|
||||
"vanilla-calendar-pro": "^3.1.0",
|
||||
"zod": "^4.3.6",
|
||||
"zustand": "^5.0.11"
|
||||
@@ -108,6 +114,8 @@
|
||||
"build": {
|
||||
"appId": "com.bds.blogging-desktop-server",
|
||||
"productName": "Blogging Desktop Server",
|
||||
"asar": true,
|
||||
"afterSign": "scripts/notarize.mjs",
|
||||
"directories": {
|
||||
"output": "release"
|
||||
},
|
||||
@@ -122,14 +130,43 @@
|
||||
"to": "drizzle"
|
||||
}
|
||||
],
|
||||
"protocols": [
|
||||
{
|
||||
"name": "bDS Blogmark Links",
|
||||
"schemes": [
|
||||
"bds"
|
||||
]
|
||||
}
|
||||
],
|
||||
"win": {
|
||||
"target": "nsis"
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"target": "dmg"
|
||||
"target": [
|
||||
"dmg",
|
||||
"zip"
|
||||
],
|
||||
"category": "public.app-category.productivity",
|
||||
"hardenedRuntime": true,
|
||||
"gatekeeperAssess": false,
|
||||
"entitlements": "build/entitlements.mac.plist",
|
||||
"entitlementsInherit": "build/entitlements.mac.inherit.plist"
|
||||
},
|
||||
"linux": {
|
||||
"target": "AppImage"
|
||||
"target": [
|
||||
"AppImage",
|
||||
"deb",
|
||||
"rpm"
|
||||
],
|
||||
"category": "Utility"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
scripts/notarize.mjs
Normal file
30
scripts/notarize.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
import { notarize } from '@electron/notarize';
|
||||
|
||||
export default async function notarizeIfConfigured(context) {
|
||||
const { electronPlatformName, appOutDir, packager } = context;
|
||||
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return;
|
||||
}
|
||||
|
||||
const appleId = process.env.APPLE_ID;
|
||||
const appleIdPassword = process.env.APPLE_APP_SPECIFIC_PASSWORD;
|
||||
const teamId = process.env.APPLE_TEAM_ID;
|
||||
|
||||
if (!appleId || !appleIdPassword || !teamId) {
|
||||
console.log('[notarize] Skipped: APPLE_ID / APPLE_APP_SPECIFIC_PASSWORD / APPLE_TEAM_ID not set');
|
||||
return;
|
||||
}
|
||||
|
||||
const appName = packager.appInfo.productFilename;
|
||||
const appPath = `${appOutDir}/${appName}.app`;
|
||||
|
||||
console.log(`[notarize] Submitting ${appPath}`);
|
||||
await notarize({
|
||||
appPath,
|
||||
appleId,
|
||||
appleIdPassword,
|
||||
teamId,
|
||||
});
|
||||
console.log('[notarize] Completed');
|
||||
}
|
||||
45
tests/engine/PackagingConfig.test.ts
Normal file
45
tests/engine/PackagingConfig.test.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
describe('package.json packaging configuration', () => {
|
||||
const packageJsonPath = path.resolve(process.cwd(), 'package.json');
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as Record<string, any>;
|
||||
|
||||
it('defines cross-platform distribution scripts', () => {
|
||||
const scripts = packageJson.scripts as Record<string, string>;
|
||||
|
||||
expect(scripts['dist']).toBeTypeOf('string');
|
||||
expect(scripts['dist:mac']).toBeTypeOf('string');
|
||||
expect(scripts['dist:win']).toBeTypeOf('string');
|
||||
expect(scripts['dist:linux']).toBeTypeOf('string');
|
||||
});
|
||||
|
||||
it('registers bds protocol for packaged apps', () => {
|
||||
const build = packageJson.build as Record<string, any>;
|
||||
const protocols = build.protocols as Array<{ name: string; schemes: string[] }>;
|
||||
|
||||
expect(Array.isArray(protocols)).toBe(true);
|
||||
expect(protocols.some((entry) => Array.isArray(entry.schemes) && entry.schemes.includes('bds'))).toBe(true);
|
||||
});
|
||||
|
||||
it('configures macOS, Windows, and Linux targets', () => {
|
||||
const build = packageJson.build as Record<string, any>;
|
||||
|
||||
expect(build.mac).toBeTruthy();
|
||||
expect(build.win).toBeTruthy();
|
||||
expect(build.linux).toBeTruthy();
|
||||
|
||||
expect(build.mac.target).toBeTruthy();
|
||||
expect(build.win.target).toBeTruthy();
|
||||
expect(build.linux.target).toBeTruthy();
|
||||
});
|
||||
|
||||
it('keeps runtime modules in dependencies (not devDependencies)', () => {
|
||||
const dependencies = packageJson.dependencies as Record<string, string>;
|
||||
const devDependencies = packageJson.devDependencies as Record<string, string>;
|
||||
|
||||
expect(dependencies.uuid).toBeTypeOf('string');
|
||||
expect(devDependencies.uuid).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user