This boilerplate demonstrates a turborepo setup combining Next.js with Electron, allowing you to use the same codebase with SSR (Server-Side Rendering)/ React Server Components(RSC) for Electron applications.
Next.js App - next.config.mjs
/** @type {import('next').NextConfig} */
module.exports = {
transpilePackages: ["@nextelectron/ui"],
+ output: "standalone",
};
Electron App - package.json
build
configuration in package.json
:
"build": {
"asar": true,
"executableName": "NextJSElectron",
"appId": "com.saybackend.nextjs-electron",
"asarUnpack": [
"node_modules/next",
"node_modules/@img",
"node_modules/sharp",
"**\\*.{node,dll}"
],
"files": [
"build",
{
"from": ".next/standalone",
"to": "app",
"filter": [
"!**/.env",
"!**/package.json"
]
},
{
"from": ".next/static",
"to": "app/.next/static"
},
{
"from": "public",
"to": "app/public"
}
],
"win": {
"target": [
"nsis"
]
},
"linux": {
"target": [
"deb"
],
"category": "Development"
}
}
Main Electron file (main.ts
):
import { is } from "@electron-toolkit/utils";
import { app, BrowserWindow, ipcMain } from "electron";
import { getPort } from "get-port-please";
import { startServer } from "next/dist/server/lib/start-server";
import { join } from "path";
const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 900,
height: 670,
webPreferences: {
preload: join(__dirname, "preload.js"),
nodeIntegration: true,
},
});
mainWindow.on("ready-to-show", () => mainWindow.show());
const loadURL = async () => {
if (is.dev) {
mainWindow.loadURL("http://localhost:3000");
} else {
try {
const port = await startNextJSServer();
console.log("Next.js server started on port:", port);
mainWindow.loadURL(`http://localhost:${port}`);
} catch (error) {
console.error("Error starting Next.js server:", error);
}
}
};
loadURL();
return mainWindow;
};
const startNextJSServer = async () => {
try {
const nextJSPort = await getPort({ portRange: [30_011, 50_000] });
const webDir = join(app.getAppPath(), "app");
await startServer({
dir: webDir,
isDev: false,
hostname: "localhost",
port: nextJSPort,
customServer: true,
allowRetry: false,
keepAliveTimeout: 5000,
minimalMode: true,
});
return nextJSPort;
} catch (error) {
console.error("Error starting Next.js server:", error);
throw error;
}
};
app.whenReady().then(() => {
createWindow();
ipcMain.on("ping", () => console.log("pong"));
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
index.html
is loaded, this setup runs the Next.js app on a different port and loads it, enabling SSR in Electron.get-port-please
is used to get a free port, starting the Next.js server on that port. This allows the same codebase to be used for both web and Electron.To run the application, use the following commands:
make next_dev
make electron_dev
To build the Electron app:
make electron_dist
Note: Electron expects the Next.js app's production output to be present and copied to the Electron app. Ensure you have built the Next.js app before running the Electron app.
Development Server: Starts the development server for Next.js.
make next_dev
Build: Builds the Next.js project for production.
make next_build
Start: Starts the Next.js project.
make next_start
Lint: Lints the Next.js project.
make next_lint
dprint
.
make format
Postinstall: Installs app dependencies for Electron.
make postinstall
Build for Distribution: Builds Electron for distribution in directory mode.
make electron_dist
Build for Debian Distribution: Builds Electron for Debian distribution.
make electron_dist_deb
Build Using tsup: Builds Electron using tsup
.
make electron_build
Watch Mode: Watch mode for Electron with tsup
.
make electron_build_watch
Development Mode: Starts development mode for Electron.
make electron_dev
Build All: Builds both Next.js and Electron projects.
make build
Distribute All: Distributes both Next.js and Electron projects.
make dist
Development Mode for All: Starts development mode for both Electron and Next.js.
make dev
To use any of the tasks, simply run the corresponding make
command in your terminal. For example, to start the development server for Next.js, you would run:
make next_dev
For a list of all available tasks, you can run:
make help
This will display a summary of all tasks and their descriptions.
pnpm
before running the tasks.Makefile
for ease of use and to maintain consistency across development and build processes.