Notes/apps/desktop/electron-forge/forge.config.ts

270 lines
10 KiB
TypeScript
Raw Normal View History

2025-06-19 15:38:35 +03:00
import path from "path";
import fs from "fs-extra";
import { LOCALES } from "@triliumnext/commons";
import { PRODUCT_NAME } from "../src/app-info.js";
2025-06-21 10:46:12 +03:00
import type { ForgeConfig } from "@electron-forge/shared-types";
2024-08-05 18:47:57 +02:00
2025-04-26 09:56:23 +03:00
const ELECTRON_FORGE_DIR = __dirname;
2025-04-26 01:09:28 +03:00
const EXECUTABLE_NAME = "trilium"; // keep in sync with server's package.json -> packagerConfig.executableName
2025-04-26 09:56:23 +03:00
const APP_ICON_PATH = path.join(ELECTRON_FORGE_DIR, "app-icon");
const extraResourcesForPlatform = getExtraResourcesForPlatform();
const baseLinuxMakerConfigOptions = {
name: EXECUTABLE_NAME,
bin: EXECUTABLE_NAME,
productName: PRODUCT_NAME,
2025-04-26 09:56:23 +03:00
icon: path.join(APP_ICON_PATH, "png/128x128.png"),
desktopTemplate: path.resolve(path.join(ELECTRON_FORGE_DIR, "desktop.ejs")),
categories: ["Office", "Utility"]
};
const windowsSignConfiguration = process.env.WINDOWS_SIGN_EXECUTABLE ? {
hookModulePath: path.join(ELECTRON_FORGE_DIR, "sign-windows.cjs")
} : undefined;
const macosSignConfiguration = process.env.APPLE_ID ? {
osxSign: {},
osxNotarize: {
2025-06-21 10:46:12 +03:00
appleId: process.env.APPLE_ID!,
appleIdPassword: process.env.APPLE_ID_PASSWORD!,
teamId: process.env.APPLE_TEAM_ID!
}
} : undefined;
2025-06-21 10:46:12 +03:00
const config: ForgeConfig = {
outDir: "out",
// Documentation of `packagerConfig` options: https://electron.github.io/packager/main/interfaces/Options.html
2025-01-09 18:07:02 +02:00
packagerConfig: {
executableName: EXECUTABLE_NAME,
name: PRODUCT_NAME,
2025-01-09 18:07:02 +02:00
overwrite: true,
asar: true,
2025-04-26 09:56:23 +03:00
icon: path.join(APP_ICON_PATH, "icon"),
...macosSignConfiguration,
windowsSign: windowsSignConfiguration,
2025-01-09 18:07:02 +02:00
extraResource: [
// All resources should stay in Resources directory for macOS
2025-04-26 01:09:28 +03:00
...(process.platform === "darwin" ? [] : extraResourcesForPlatform)
2025-01-09 18:07:02 +02:00
],
prune: false,
2025-01-09 18:07:02 +02:00
afterComplete: [
(buildPath, _electronVersion, platform, _arch, callback) => {
// Only move resources on non-macOS platforms
if (platform !== "darwin") {
for (const resource of extraResourcesForPlatform) {
const baseName = path.basename(resource);
const sourcePath = path.join(buildPath, "resources", baseName);
// prettier-ignore
const destPath = (baseName !== "256x256.png")
? path.join(buildPath, baseName)
: path.join(buildPath, "icon.png");
2024-08-05 18:47:57 +02:00
fs.move(sourcePath, destPath)
.then(() => callback())
.catch((err) => callback(err));
}
} else {
callback();
2025-01-09 18:07:02 +02:00
}
}
]
2024-08-05 18:47:57 +02:00
},
2025-01-09 18:07:02 +02:00
rebuildConfig: {
force: true,
extraModules: [ "better-sqlite3" ]
2024-08-05 18:47:57 +02:00
},
2025-01-09 18:07:02 +02:00
makers: [
{
name: "@electron-forge/maker-deb",
config: {
options: baseLinuxMakerConfigOptions
2025-01-09 18:07:02 +02:00
}
},
2025-02-03 23:21:27 +01:00
{
name: "@electron-forge/maker-flatpak",
config: {
options: {
...baseLinuxMakerConfigOptions,
2025-02-07 18:17:06 +02:00
id: "com.triliumnext.notes",
runtimeVersion: "24.08",
base: "org.electronjs.Electron2.BaseApp",
baseVersion: "24.08",
baseFlatpakref: "https://flathub.org/repo/flathub.flatpakrepo",
modules: [
{
name: "zypak",
sources: {
type: "git",
url: "https://github.com/refi64/zypak",
tag: "v2024.01.17"
}
}
]
2025-02-03 23:21:27 +01:00
},
}
},
2025-02-02 23:00:22 +01:00
{
name: "@electron-forge/maker-rpm",
config: {
options: baseLinuxMakerConfigOptions
2025-02-02 23:00:22 +01:00
}
},
2025-01-09 18:07:02 +02:00
{
name: "@electron-forge/maker-squirrel",
config: {
name: EXECUTABLE_NAME,
productName: PRODUCT_NAME,
2025-01-09 18:07:02 +02:00
iconUrl: "https://raw.githubusercontent.com/TriliumNext/Notes/develop/images/app-icons/icon.ico",
2025-04-26 01:09:28 +03:00
setupIcon: path.join(ELECTRON_FORGE_DIR, "setup-icon/setup.ico"),
loadingGif: path.join(ELECTRON_FORGE_DIR, "setup-icon/setup-banner.gif"),
windowsSign: windowsSignConfiguration
2025-01-09 18:07:02 +02:00
}
},
{
name: "@electron-forge/maker-dmg",
config: {
2025-04-26 09:56:23 +03:00
icon: path.join(APP_ICON_PATH, "icon.icns")
2025-01-09 18:07:02 +02:00
}
},
{
name: "@electron-forge/maker-zip",
config: {
options: {
iconUrl: "https://raw.githubusercontent.com/TriliumNext/Notes/develop/images/app-icons/icon.ico",
2025-04-26 09:56:23 +03:00
icon: path.join(APP_ICON_PATH, "icon.ico")
2025-01-09 18:07:02 +02:00
}
}
2024-08-05 18:47:57 +02:00
}
2025-01-09 18:07:02 +02:00
],
plugins: [
{
name: "@electron-forge/plugin-auto-unpack-natives",
config: {}
}
],
hooks: {
// Remove unused locales from the packaged app to save some space.
2025-06-21 10:46:12 +03:00
async postPackage(_, packageResult) {
const isMac = (process.platform === "darwin");
let localesToKeep = LOCALES
.filter(locale => !locale.contentOnly)
2025-06-19 15:38:35 +03:00
.map(locale => locale.electronLocale) as string[];
if (!isMac) {
localesToKeep = localesToKeep.map(locale => locale.replace("_", "-"))
}
const keptLocales = new Set();
2025-06-19 15:38:35 +03:00
const removedLocales: string[] = [];
const extension = (isMac ? ".lproj" : ".pak");
for (const outputPath of packageResult.outputPaths) {
const localeDirs = isMac
? [
path.join(outputPath, "TriliumNext Notes.app/Contents/Resources"),
path.join(outputPath, "TriliumNext Notes.app/Contents/Frameworks/Electron Framework.framework/Resources")
]
: [ path.join(outputPath, 'locales') ];
for (const localeDir of localeDirs) {
if (!fs.existsSync(localeDir)) {
console.log(`No locales directory found in '${localeDir}'.`);
process.exit(2);
}
2025-06-19 15:38:35 +03:00
const files = fs.readdirSync(localeDir);
2025-06-19 15:38:35 +03:00
for (const file of files) {
if (!file.endsWith(extension)) {
continue;
}
2025-06-19 15:38:35 +03:00
let localeName = path.basename(file, extension);
2025-06-15 21:16:02 +03:00
if (localeName === "en-US" && !isMac) {
// If the locale is "en-US" on Windows, we treat it as "en".
// This is because the Windows version of Electron uses "en-US.pak" instead of "en.pak".
localeName = "en";
}
2025-06-19 15:38:35 +03:00
if (localesToKeep.includes(localeName)) {
keptLocales.add(localeName);
continue;
}
2025-06-19 15:38:35 +03:00
const filePath = path.join(localeDir, file);
if (isMac) {
fs.rm(filePath, { recursive: true });
} else {
fs.unlinkSync(filePath);
}
2025-06-19 15:38:35 +03:00
removedLocales.push(file);
}
}
}
2025-06-19 15:38:35 +03:00
console.log(`Removed unused locale files: ${removedLocales.join(", ")}`);
// Ensure all locales that should be kept are actually present.
for (const locale of localesToKeep) {
if (!keptLocales.has(locale)) {
console.error(`Locale ${locale} was not found in the packaged app.`);
process.exit(1);
}
}
// Wait for a while to ensure the file system operations are completed.
await new Promise(resolve => setTimeout(resolve, 3000));
},
2025-06-11 21:08:02 +03:00
// Gather all the artifacts produced by the makers and copy them to a common upload directory.
2025-06-21 10:46:12 +03:00
async postMake(_, makeResults) {
for (const makeResult of makeResults) {
const outputDir = path.join(__dirname, "..", "upload", makeResult.arch);
fs.mkdirpSync(outputDir);
for (const artifactPath of makeResult.artifacts) {
2025-03-24 19:04:38 +02:00
// Ignore certain artifacts.
2025-03-24 19:10:29 +02:00
let fileName = path.basename(artifactPath);
const extension = path.extname(fileName);
if (fileName === "RELEASES" || extension === ".nupkg") {
2025-03-24 19:04:38 +02:00
continue;
}
2025-03-24 19:10:29 +02:00
// Override the extension for the CI.
const { TRILIUM_ARTIFACT_NAME_HINT } = process.env;
if (TRILIUM_ARTIFACT_NAME_HINT) {
fileName = TRILIUM_ARTIFACT_NAME_HINT.replaceAll("/", "-") + extension;
2025-03-24 19:10:29 +02:00
}
2025-06-19 15:38:35 +03:00
2025-03-24 19:04:38 +02:00
const outputPath = path.join(outputDir, fileName);
console.log(`[Artifact] ${artifactPath} -> ${outputPath}`);
2025-03-30 17:34:45 +03:00
fs.copyFileSync(artifactPath, outputPath);
}
}
}
}
};
2024-08-05 18:47:57 +02:00
function getExtraResourcesForPlatform() {
2025-06-19 15:38:35 +03:00
const resources: string[] = [];
2025-04-26 11:58:35 +03:00
const getScriptResources = () => {
const scripts = ["trilium-portable", "trilium-safe-mode", "trilium-no-cert-check"];
const scriptExt = (process.platform === "win32") ? "bat" : "sh";
return scripts.map(script => `electron-forge/${script}.${scriptExt}`);
}
2025-01-09 18:07:02 +02:00
switch (process.platform) {
case "win32":
2025-04-26 11:58:35 +03:00
resources.push(...getScriptResources())
2025-01-09 18:07:02 +02:00
break;
case "linux":
2025-04-26 11:58:35 +03:00
resources.push(...getScriptResources(), path.join(APP_ICON_PATH, "png/256x256.png"));
2025-01-09 18:07:02 +02:00
break;
default:
break;
}
2024-08-05 18:47:57 +02:00
2025-01-09 18:07:02 +02:00
return resources;
}
2025-06-21 10:46:12 +03:00
export default config;