Packaging
npm run lepton packagelepton package builds a release and lays it out under src-lepton/bundle/<name>-<version>-<os>-<arch>/ (on Linux with a desktop entry), then writes each format listed in bundle.targets. The default is tar.gz on Linux and zip on Windows; the Linux packages are refused on Windows before anything is built.
{ "bundle": { "targets": ["tar.gz", "deb", "arch"], "maintainer": "Your Name <you@example.com>" }}| Format | |
|---|---|
tar.gz |
An AppDir 0.1.9-beta.3, runnable from wherever it is unpacked: ./AppRun starts the app, and the AppImage layout is kept (<identifier>.desktop, its icon and .DirIcon at the top, the app under usr/). ./install.sh installs it for you into ~/.local, or for everyone with --system into /usr/local (run with sudo); the desktop entry then names the installed program by its full path. ./uninstall.sh (with the same flag) removes exactly the files and directories the install wrote and leaves your app’s data, ~/.local/share/<identifier>. |
appimage |
0.1.9-beta.3 The same AppDir as one file, <name>-<version>-x86_64.AppImage: AppImage’s own runtime in front of the app’s file system (squashfs, gzip), run as ./<file>.AppImage with nothing to unpack. The runtime is AppImage/type2-runtime 20251108, unchanged, from a dev dependency: npm install -D @lepton-desk/appimage-runtime-linux-x64; lepton package checks its SHA-256. It is statically linked, so the machine that runs the AppImage needs no libfuse; to mount the file system it looks for a setuid-root fusermount or fusermount3 on PATH (its runtime.c), and without one ./<file>.AppImage --appimage-extract-and-run still runs it. WPE WebKit comes from that machine too, as for every Lepton package. x86-64 only for now. |
arch |
An Arch Linux package (.pkg.tar.zst). Dependencies come from the binary’s linked libraries. |
deb |
A Debian package. Needs bundle.maintainer, and bundle.copyright and bundle.license 0.1.9-beta.3 for the copyright file Debian policy requires. Dependency names come from dpkg-query, or from bundle.deb.depends on a machine without it — never guessed. |
zip |
Windows 0.1.9-beta.0: portable 0.1.9-beta.3, the program at the top as <name>.exe with its icon as <name>.ico, its pages in share\ beside it and a README.txt that says how to run it, where it keeps its data and that the .msi installs it. Unpack it anywhere and run the program. |
msi |
Windows 0.1.9-beta.0: a Windows Installer package written by Lepton itself, without WiX. It installs per user (%LOCALAPPDATA%\Programs\<product>) without admin rights, adds a Start menu shortcut, upgrades an older version, replaces another build of the same version 0.1.9-beta.2 (Windows Installer compares only major.minor.build, so 1.0.0-beta.1 → 1.0.0-beta.2 is the same version to it), refuses a downgrade, and uninstalls cleanly. bundle.icon (an .ico) is its shortcut and Apps icon. It passes the Windows SDK’s ICE validation with no errors. |
What the packages say about the app 0.1.9-beta.3. Six optional fields in bundle:
{ "bundle": { "description": "Take notes, offline", "longDescription": "Notes keeps your notes on your machine.\n\nNo account, no sync.", "license": "MIT", "homepage": "https://example.com/notes", "copyright": "© 2026 Example", "category": "Office" }}description (one line) is the desktop entry’s Comment, the Arch pkgdesc and the .deb synopsis; without it, productName. longDescription is the .deb’s extended description. license (an SPDX expression) and homepage reach the Arch package (license, url) and the .deb (Homepage). With copyright and license, Linux packages carry share/doc/<package>/copyright in Debian’s machine-readable format. category is the desktop entry’s main category (AudioVideo, Audio, Video, Development, Education, Game, Graphics, Network, Office, Science, Settings, System or Utility); without it, Development. Every Linux package also carries share/metainfo/<identifier>.metainfo.xml 0.1.9-beta.3, what GNOME Software, KDE Discover and Flathub show before the app is installed: the name, description as its summary, longDescription as its paragraphs, license, homepage, the developer (bundle.maintainer’s name under your identifier’s owner), the program, and the version dated by SOURCE_DATE_EPOCH, else bundle.releaseDate (YYYY-MM-DD); with neither there is no release, since AppStream refuses an undated one, and lepton package warns. The age rating is bundle.contentRating, your answers to OARS 1.1 (for example { "social-chat": "intense" }); without it the rating is empty, which software centres read as no age restrictions. The file’s own licence is bundle.metadataLicense, CC0-1.0 without it. lepton package warns when the description’s first paragraph is under 80 characters, which software centres show poorly. It passes appstreamcli validate (measured with AppStream 1.2.1, with and without a date).
Icon. lepton new puts Lepton’s mark in src-lepton/icon.svg 0.1.9-beta.2; replace it with your own. On Linux the package installs it as share/icons/hicolor/scalable/apps/<identifier>.svg and the desktop entry names it (Icon=<identifier>); lepton dev and run install it beside the entry they write. bundle.icon names your own: one path or a list, an .ico for Windows (the program, the MSI) and an .svg for Linux, for example "icon": ["assets/app.ico", "assets/app.svg"]; the .svg there wins over src-lepton/icon.svg. Linux icons are scalable, so a .png is refused rather than installed at one size. Without one, each system gets Lepton’s mark. Linux packages also carry PNGs from 16 to 512 px under hicolor/<n>x<n>/apps 0.1.9-beta.3, for desktops and stores that read no SVG: the ones lepton icon wrote into src-lepton/icons/, else drawn from the SVG while packaging. Its icon.ico is the Windows program’s and the MSI’s when bundle.icon names none.
Packages are reproducible: sorted entries, root:root, and SOURCE_DATE_EPOCH. Each archive gets a .sha256 file. A format that can’t be built is an error, never a silent skip.
The application does not carry a browser: a React app from lepton new packaged to a 176,601-byte .tar.gz here (0.1.9-beta.1, 2026-10-20), depending on the system’s wpewebkit.
--verify
Section titled “--verify”npm run lepton package -- --verifyUnpacks every package into an empty directory, starts the app from there, measures its memory, closes it, and fails if it does not start or leaves a process behind. On Windows the app and every process it starts are held in a job object and closed as a user would close the window.
What an app costs in memory 0.1.9-beta.3
Section titled “What an app costs in memory 0.1.9-beta.3”--verify prints it, three seconds after the start: on Windows the private working set of the app and every process it started, the figure Task Manager’s Memory column shows (on Linux the tree’s PSS). Measured on Windows Server 2025 in Lepton’s CI, the same vanilla-ts template built both ways:
| App | Processes | Memory |
|---|---|---|
| Web view (WebView2) | 7 | 69.4 MB |
| Native, GPU (Direct3D 11) | 1 | 6.9 MB |
Native, CPU (LEPTON_GPU=cpu) |
1 | 5.9 MB |
The web view’s figure is WebView2’s processes as much as your page’s: two earlier runs gave 70.6 and 72.9 MB. The CI machine has no GPU, so Direct3D 11 there runs on Microsoft’s software renderer (WARP, loaded in the process); a machine with a graphics card was not measured yet, nor Linux.