I wanted a tiny desktop wrapper for TiddlyWiki so I could carry my notes everywhere without a browser tab. I fired up Electron, wrote twenty-odd lines of code, and boom DevTools spat the dreaded:
Uncaught TypeError: Cannot read property 'length' of undefined
Below is the full story, the exact cause, the two quick fixes, and the cleaner starter app I’m using now.
The One Window Experiment That Crashed
// main.js
const { app, BrowserWindow } = require('electron');
const url = require('url');
let win;
function createWindow () {
win = new BrowserWindow({ width: 800, height: 600 });
// Load the public TiddlyWiki site
win.loadURL(
url.format({
pathname : 'tiddlywiki.com', // → http://tiddlywiki.com
protocol : 'http:',
slashes : true
})
);
}
app.whenReady().then(createWindow);
I launched the app and immediately saw:
Uncaught TypeError: Cannot read property 'length' of undefined
at Object.$tw.boot.startup (tiddlywiki.com/:27506)
Why the Error Appear
Step | What Really Happens |
---|---|
1 | TiddlyWiki looks for process . If it finds one, it assumes Node is present and reads process.argv . |
2 | Electron always exposes process . Even with Node features hidden, the global object is still there. |
3 | With nodeIntegration:false Electron strips most Node data. process.argv is removed for security, so it becomes undefined . |
4 | TiddlyWiki calls process.argv.length . No argv means instant crash. |
Fixes The Code
Give Tiddly Wiki the Full Node Context
= new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true, // `argv` is back
contextIsolation: false
}
});
Perfect for local, trusted HTML. Do not enable this for random sites you’d hand them full access to the user’s machine.
Keep Node Integration Off, but Hide process
// preload.js
delete global.process; // remove the Node hint
= new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration : false,
contextIsolation: true,
preload : path.join(__dirname, 'preload.js')
}
});
Now TiddlyWiki runs in pure-browser mode and stays happy.
My Cleaner Starter App
I decided to polish the prototype, add a menu, and let myself open any single-file wiki.
// main.js
const { app, BrowserWindow, Menu, dialog } = require('electron');
const path = require('path');
const fs = require('fs');
const isMac = process.platform === 'darwin';
let win;
function createWindow () {
win = new BrowserWindow({
width: 1000,
height: 700,
webPreferences: {
nodeIntegration : true, // swap to the preload trick if you prefer
contextIsolation: false
}
});
// Prefer a local wiki if one sits beside the app
const localWiki = path.join(__dirname, 'my-wiki.html');
const startURL = fs.existsSync(localWiki)
? `file://${localWiki}`
: 'https://tiddlywiki.com/';
win.loadURL(startURL);
// Press F12 to toggle DevTools
win.webContents.on('before-input-event', (e, input) => {
if (input.key === 'F12') win.webContents.openDevTools();
});
}
/* --------- Simple native menu --------- */
const menuTemplate = [
...(isMac ? [{ role: 'appMenu' }] : []),
{
label: 'File',
submenu: [
{
label: 'Open HTML…',
accelerator: 'CmdOrCtrl+O',
click: async () => {
const { canceled, filePaths } = await dialog.showOpenDialog({
filters : [{ name: 'HTML', extensions: ['html'] }],
properties : ['openFile']
});
if (!canceled) win.loadFile(filePaths[0]);
}
},
{ type: 'separator' },
{ role: 'quit' }
]
},
{ role: 'viewMenu' } // reload/zoom built-ins
];
app.whenReady().then(() => {
createWindow();
Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate));
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', () => {
if (!isMac) app.quit();
});
Explain it
Feature | Skill You Pick Up |
---|---|
Custom menu | Native menus and keyboard shortcuts |
Open dialog | Loading local HTML files |
file:// vs https:// | Path rules & Content Security |
DevTools toggle | Listening for key events |
Practice Ideas
- Remember window size – store
win.getBounds()
on close, restore on launch. - Auto-save the wiki – listen for TiddlyWiki’s
save-wiki
hook and write the updated HTML back to disk. - Tray icon – minimise to tray with quick “Open / Save-as / Quit” actions.
- Update checker – fetch the latest TiddlyWiki release JSON, prompt when a new version is out.
- Package the app – ship installers with
electron-builder
for Windows, macOS, and Linux.
Final Thoughts
I started with a 20-line script and hit a wall because a single property (process.argv
) went missing. Digging into why the crash happened taught me more about Electron’s security layers than any tutorial could. If you’re wrapping a complex web app, always check what Node objects the page expects, and decide whether to expose them or mask them.