npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

blink-installer

v0.3.0

Published

Build Windows installers with an HTML/CSS/JS user interface.

Downloads

123

Readme

blink-installer

应用打磨了半年,用户第一眼看到的,是一个 1998 年的灰色向导。

用 HTML、CSS、JavaScript 写 Windows 安装包界面。

npm license platform size

English

全屏入场动画收敛为安装卡片

🤖 不想自己写? 复制一段提示语给 AI agent,它读懂你的项目后会生成配套的动画、对话框和安装流程。


受够了吧

  • 想挪一个按钮,得在 nsDialogs 里手算像素坐标,改一次编译一次
  • 想加个入场动画——没有这个东西,NSIS 的界面模型里压根不存在
  • 全世界的 Inno Setup 安装包长得一模一样,你的产品也一样
  • 弹个「确定要退出吗」,出来的是 Windows 95 同款灰底方框
  • 改一行文案,要先学一门只有写安装包才用得上的 DSL
  • 前端同事想帮忙?帮不上,这里没有 CSS

而你已经会写网页了。

<button class="primary" id="install">开始安装</button>
import { installer, fs } from 'blink-installer-ui';

document.querySelector('#install').onclick = () => installer.begin();
installer.on('progress', ({ percent }) => bar.style.width = percent + '%');

就这样。圆角、渐变、投影、transition、全屏动画、你自己的字体——都是你平时怎么写就怎么写

npm i -D blink-installer
npx blink-installer init
npx blink-installer build

凭什么能做到

压缩、解压、快捷方式、卸载注册这些脏活由 NSIS 干,界面交给 miniblink 渲染(一个 Blink 内核,单文件 DLL,Win7 也能跑)。

关键在于窗口是透明分层窗口:所以你能有圆角、投影,以及直接画在桌面上、四周全透明的全屏动画——这些普通 Win32 安装程序做不到。

而且动画和安装界面是同一个窗口。它从全屏收缩成卡片,不是切到第二个进程,所以画面不跳、不闪、不重载。


它做什么

它不打包你的应用,只把已经打好包的目录套成安装程序:

已打包目录(electron-builder 的 win-unpacked / electron-packager 输出 / 一个 exe 加若干 dll)
        +  你的 HTML 界面
        +  一份配置
        ─────────────────────────▶  MyApp-Setup-1.2.3.exe

快速开始

// blink-installer.config.mjs
import { defineConfig } from 'blink-installer-core';

export default defineConfig({
  appId: 'com.example.myapp',
  productName: '我的应用',
  version: '1.2.3',
  publisher: '某某公司',

  source: 'dist/win-unpacked',   // 已打包好的目录
  exe: 'myapp.exe',

  ui: './installer-ui',          // 省略则用自带模板
  splash: { enabled: true },     // 全屏入场动画

  install: {
    folderName: 'MyApp',         // 安装目录名;标题、快捷方式照旧用中文显示名
    defaultDir: '$LOCALAPPDATA\\Programs\\MyApp',
    elevate: false,              // 每用户安装,免 UAC
    shortcuts: { desktop: true, startMenu: true },
  },
});

npx blink-installer init --eject-ui 会把自带模板拷到你项目里,直接改。

两种构建模式

压缩载荷占掉了绝大部分构建时间,而调界面时这部分工作跟你无关。所以分两条命令:

"installer:dev":     "blink-installer build --ui-only --compression zlib --out dist/preview.exe",
"installer:release": "blink-installer build --compression lzma"

--ui-only 把应用换成占位文件,其余全是真的(真 NSIS 脚本、真页面、真进度、真卸载器),能跑完整流程。它还会自动隔离:装到独立目录、独立注册表键、关掉快捷方式,所以预览包不可能覆盖你已装的正式版。

实测(1.1 GB 的 Electron 应用):

| | 耗时 | 体积 | |---|---|---| | --ui-only --compression zlib | 3 秒 | 13 MB | | --compression zlib | 79 秒 | 496 MB | | --compression lzma | 450 秒 | 401 MB |

发布用 lzma——electron-builder 自带的 NSIS 也是这个,选别的就是你俩体积差异的来源。


让 AI agent 帮你集成

把下面整段复制到 Claude Code / Cursor / Codex 之类的编码 agent 里,它会读懂你的项目,然后生成配套的动画、对话框和安装流程。

提示语里带了这个渲染引擎的全部硬约束。少了它们,agent 会写出在普通浏览器里好好的、到安装包里却空白或塌掉的界面。

请为本项目集成 blink-installer,做一个用 HTML/CSS/JS 写界面的 Windows 安装包。

## 第一步:先读懂这个项目
在动手之前,先看 README、package.json、主进程入口和产品文案,弄清楚:
这个产品是做什么的、卖点是什么、面向谁、有没有品牌色和图标、名字与版本号从哪里取。
安装界面和动画必须由这些**具体内容**长出来,不要套通用模板。

## 第二步:装并初始化
npm i -D blink-installer
npx blink-installer init --eject-ui

## 第三步:写配置 blink-installer.config.mjs
- version 和 productName 从 package.json 现算,不要写死(写死必然漂)
- source 指向已打包目录(electron-builder 是 dist/<out>/win-unpacked)
- exe 是该目录下的主程序文件名
- productName 是中文就一定要配 install.folderName(英文字母数字),否则安装目录会是
  `C:\Program Files\中文名`——路径里的中文谁都不想敲;不配会直接构建失败并提示
- 装 $LOCALAPPDATA 就设 elevate: false(免 UAC,体验好得多);装 $PROGRAMFILES 才需要 true
- output 若要替换现有安装包,就对齐原来的产物命名规则

## 第四步:设计界面(重点)
在 installer-ui/ 下做三样东西,都要贴合这个产品:

1. **入场动画**(splash.js / splash.css)
   全屏、透明、画在桌面上。用产品自己的意象,别用无意义的粒子。
   例如协作类产品可以让多个节点汇聚成一个中心;工具类可以让零件组装成形。
   时长 2~3 秒,结束后调 win.setBounds 把窗口收成安装卡片。

2. **安装流程界面**(index.html / main.js / style.css)
   欢迎页讲清楚这个产品是什么、装完能干什么;
   带安装路径选择与磁盘空间校验;安装中显示进度并轮播产品能力;完成页给下一步动作。

3. **对话框**
   用 ui.messageBox,它是页内绘制的,通过 --bk-dialog-* 变量调成产品配色。
   退出确认、覆盖安装确认、卸载原因询问都走它。

## 渲染引擎的硬约束(务必遵守,否则静默失效)
渲染器是 Chromium 57~60 时代的 Blink:
- CSS 不能用:inset(改 top/right/bottom/left)、flex 的 gap(改 margin)、
  accent-color、aspect-ratio、:is()/:where()、flex 子项上的 position: sticky
- JS 语法会被 Babel 自动降级,可以正常写;但 Object.entries 和 String.padStart
  是运行时缺失、编译不掉,绝对不要用
- **U+FFFF 以上的字符渲染为空白**。绝大多数彩色 emoji 在此列(🕑 U+1F551、
  💬 U+1F4AC 都是空白),只能用基本多文种平面内的符号(✋ U+270B、✉ U+2709 可以),
  或者内联 SVG
- 呈现帧率硬上限约 33fps。动画要用大幅度、慢速、带缓动的运动,避免细碎快速位移
- 尺寸一律写**逻辑像素**,原生层会按系统缩放自动放大并缩放页面,不要自己做 DPI 补偿
- 透明窗口下 window.innerWidth 返回 0,要屏幕尺寸就调 sys.screen()

## 第五步:验证
package.json 加两条命令:
  "installer:dev":     "blink-installer build --ui-only --compression zlib --out dist/preview.exe"
  "installer:release": "blink-installer build --compression lzma"
跑 installer:dev(几秒出包),实际运行产物,把整个流程点一遍再交付。

写界面

页面就是普通网页,通过一套带类型的 API 和安装程序对话:

import { installer, config, fs, proc, win, ui } from 'blink-installer-ui';

const dir = await fs.pickDirectory({ title: '选择安装位置' });
config.set('installDir', dir);

installer.on('progress', ({ percent }) => bar.style.width = percent + '%');
installer.on('log', ({ message }) => detail.textContent = message);

document.querySelector('#install').onclick = () => installer.begin();

对话框

ui.messageBox 画在页面里,不走 Win32,所以确认框和界面其余部分是一套东西:

const answer = await ui.messageBox({
  title: '退出安装?',
  message: '安装正在进行中,此时退出会留下不完整的安装。',
  buttons: 'yesNo',
  icon: 'warning',
});
if (answer === 'yes') win.close(true);

三层控制:默认样式直接能用(按钮文案跟随系统语言)→ 覆盖 --bk-dialog-surface--bk-dialog-accent 等变量调色 → 重写 .bk-dialog* 类,或用 ui.setDialogRenderer(fn) 整个接管。

ui.messageBoxNative 保留了原生弹窗,用于页面还没法绘制的早期失败。

屏幕缩放

配置和 CSS 里写的都是逻辑像素。安装程序启动时读一次系统缩放,据此定窗口大小并缩放页面,所以 width: 880font-size: 14px 在 150% 的笔记本和 100% 的台式机上观感一致,不需要媒体查询,也不要自己补偿。

sys.screen() 返回的同样是逻辑像素,win.setBounds / win.resize 收的也是,所以拿屏幕矩形和 CSS 尺寸一起做运算不会错位。真需要设备像素时用 sys.screen().scale

入场动画

splash: { enabled: true } 让窗口先铺满工作区、带逐像素透明地播一段动画,没画到的地方就是透明的,桌面透出来;播完同一个窗口收成安装卡片。

帧率:miniblink 的呈现被硬限制在约 33fps,而 requestAnimationFrame 以 59Hz 触发——页面算出的帧约有一半从未上屏。这个调不动:五个 miniblink 版本(2017~2021)、各种窗口尺寸、开不开逐像素透明、改 drawMinInterval,结果都一样。native/test/FINDINGS.md 有测量数据。

按这个来设计:大幅、慢速、带拖尾和辉光的运动在 33fps 下很好看;细碎的快速位移会顿。把动画循环跑得更快只是烧 CPU。

引擎老,这点很重要

miniblink 报的是 Chrome/60,但 JS 解析器比这更旧。实测没有解构、默认参数、对象展开、async/await、类字段、?.??**、可选 catch 绑定;类、生成器、箭头函数、let、模板字符串、PromiseMap/Setfor...of

你不用管:构建链先 esbuild 再 Babel,上面这些全部降级,正常写现代 JavaScript 即可。只有两个是运行时缺失、编译不掉——别用 Object.entriesString.padStart

CSS 不做转译,避开 flex 子项上的 position: sticky,2017 年之后的特性用前先确认。

内容上还有一个坑:U+FFFF 以上的字符画不出来。绝大多数彩色 emoji 在那个区间,🕑(U+1F551)、💬(U+1F4AC) 是空白,而 (U+270B)、(U+2709) 正常。图标非要用字符就限制在基本多文种平面内,否则用内联 SVG。


配置

| 字段 | 含义 | | --- | --- | | appId | 反向域名标识,用于卸载注册表项 | | productName / version / publisher | 界面与文件属性里显示 | | source | 要安装的已打包目录 | | exe | 主程序,相对 source | | output | 安装包路径,默认 dist/<product>-Setup-<version>.exe | | ui | 含 index.html 的目录,省略则用自带模板 | | icon | setup.exe 与「程序和功能」里的 .ico | | window | widthheighttransparent | | splash | enabledtimeoutMs(动画卡住时的兜底) | | install.defaultDir | 可用 $PROGRAMFILES$LOCALAPPDATA 等 NSIS 变量,以及 ${FOLDER_NAME} | | install.folderName | 安装目录叶子名(C:\Program Files\MyApp 里的 MyApp),只收英文字母数字与空格 . _ -。默认取 productNameproductName 不是合法目录名(例如中文)时必须配 | | install.elevate | true 需管理员、装全机(HKLM);false 为每用户(HKCU) | | install.shortcuts | desktopstartMenustartMenuFolder | | install.uninstallEntry | 生成卸载程序并注册 | | install.legacyFolderPicker | 强制用 XP 时代的目录树选择框,见下 | | uninstall.ui | 卸载程序也用你的 HTML 界面(默认 true) | | compression | lzma(最小)、bzip2zlib(最快) | | sign | 代码签名,省略则不签 | | nsis.include | 注入生成脚本的 .nsh,逃生舱 |

关于 install.legacyFolderPicker

选目录默认用资源管理器那个对话框(IFileOpenDialog):有地址栏、有收藏夹、能直接粘路径。打开这个开关会换成 XP 时代那个 400 像素宽的目录树框(SHBrowseForFolder)。

这是逃生舱,不是风格选项。 现代对话框由 shell 托管,也就等于把进程暴露给这台机器上加载的一切 shell 扩展——遇到某个第三方扩展让它卡住或打不开的时候,老的树框反而还能用,因为它对 shell 的要求少得多。手上有确切复现再打开它,不要因为"想要复古"。

页面也可以单次覆盖,不用改构建:

await fs.pickDirectory({ title: '选择安装位置', legacy: true });

两条路径的取消行为一致:取消就结束,不会再弹第二个对话框。

代码签名

不签名的安装包每次下载都会触发 SmartScreen 警告,直到足够多人点过「仍要运行」。

如果你已经在用 electron-builder,多半已经有一个签名钩子,而这里的形状和它的 win.signtoolOptions.sign 完全一致——直接指过去:

sign: { hook: './electron/sign-win.cjs' }

签名这套东西会沉淀很多踩出来的细节(云证书没有可导出的私钥、会话中途过期、无人值守构建答不了的弹窗要靠超时兜住)。复用同一个钩子,就不会有两份实现慢慢走岔。

没有现成钩子就直接驱动 signtool。按指纹从证书store里取(云/HSM 证书唯一可行的方式):

sign: { thumbprint: 'C3C1…91ED', timestamp: 'http://time.certum.pl' }

或者用证书文件,密码走环境变量而不是写进配置:

sign: { certificateFile: './cert.pfx' }   // BLINK_SIGN_PASSWORD=…

默认签不上就大声警告、照常出不签名的包,这样会话过期也还有东西可测。正式发版设 sign.required: true,让它直接失败。

卸载程序不签名:NSIS 是在用户机器上安装时才写出它的,构建期不存在这个文件。要签得做两遍构建;而 SmartScreen 判定的是用户下载的那个安装包。

卸载程序

默认和安装程序一套待遇:你的 HTML、确认页、进度、完成页。代价是安装目录里要常驻一份渲染器(约 17 MB)供卸载时用。uninstall: { ui: false } 关掉,退回 NSIS 自带对话框,磁盘上不留额外东西。

静默安装

/S 跳过所有界面,/D=路径 指定安装目录(必须是最后一个参数,且不加引号):

MyApp-Setup.exe /S /D=C:\Tools\MyApp

集成方式

Electron Forge

makers: [{ name: 'blink-installer-maker', config: { /* 同上面的配置 */ } }]

electron-builder:先 electron-builder --dirwin-unpacked,再让 blink-installer build 接手。

传统 Win32source 指向你放 exe 和 dll 的目录即可。

从源码构建

npm install
npm run build              # TypeScript 各包
npm run native:configure   # CMake,x86
npm run native:build       # 产出 blinkkit.dll
npm test

需要 Visual Studio(含 C++ 桌面开发工作负载)与 CMake。运行时二进制已随仓库提交,所以克隆下来离线也能构建。

许可

本项目 MIT。分发的第三方二进制按各自许可:miniblink 为 Apache-2.0,NSIS 为 zlib/libpng(其 LZMA 模块为 CPL-1.0)。详见 THIRD-PARTY-NOTICES.md