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 🙏

© 2025 – Pkg Stats / Ryan Hefner

scaffold-wizard

v2.1.1

Published

图形界面版的 inquirer。由 rust + GNOME.GTK3 制作。

Downloads

10

Readme

scaffold-wizard

该模块是对Rust + GNOME.GTK3 图形界面版 inquirerFFI封装,使其能够在常规js代码内被轻易使用。

平台限制

鉴于Rust + GNOME.GTK3图形界面版inquirer动态链接库还仅只针对win32_x64操作系统提供了预编译二进制程序包,scaffold-wizard也在package.json中严格限制了安装平台的os类型与cpu架构分别为win32x64。所以,一般的64windows 7windows 10操作系统是能够正常地安装与运行此模块的。

今后,Rust + GNOME.GTK3图形界面版inquirer会陆续发布针对更多操作系统平台的预编译二进制程序包的。

可以将该模块作为optional dependencies依赖来安装。于是,在遇到非windows x64环境时,借助safe-require将其降级为命令行inquirer

工作原理

在如下两个时间点:

  • npm模块安装过程中
  • 每次该模块的js api被调用之前

程序都会尝试:

  1. 检查系统临时目录下是否存在npm-scaffold-wizard/basic2文件夹。其中,basic2Rust + GNOME.GTK3图形界面版inquirertag号。随着Rust + GNOME.GTK3图形界面版inquirer的升级,此tag号以后可能会发生改变。
  2. 检查两个dll文件(npm-scaffold-wizard/basic2/bin/scaffold_wizard.dllnpm-scaffold-wizard/basic2/bin/zlib1.dll)是否存在。

若上面两个检查项之一返回失败的结果,那么就从githubrelease频道(具体地讲,如https://github.com/stuartZhang/scaffold-wizard/releases/download/basic2/scaffold-wizard.setup-lib.zip)下载被预编译的二进制程序包至npm-scaffold-wizard/basic2文件夹。

若哪天不幸赶上github被墙,可以考虑设置http_proxyhttps_proxy环境变量,来“科学上网”下载【预编译的二进制程序】。

另外,该模块是对Rust + GNOME.GTK3图形界面版inquirer模块的·薄·封装。所有输入参数与返回结果都是经由node-ffi被透传的(甚至包括·回调函数·),未做加工处理。

安装与使用

package.json文件里,添加

{
    "optionalDependencies": {
        "scaffold-wizard": "^1.0.0"
    }
}

js业务代码里,

const inquirer = safeRequire('inquirer');
const guiInquirer = require('safe-require')('scaffold-wizard');
const config = {...}; // 问卷配置对象
let answers;
if (guiInquirer) { // 在 windows x64 环境,直接弹出 native gui。
    answers = guiInquirer.inquire(config);
} else { // 其它环境,降级至命令行交互。
    answers = inquirer.prompt(Object.values(config));
}

接口描述

Rust + GNOME.GTK3图形界面版inquirer经由FFI仅对外开放了两个接口

import inquirer from 'inquirer';
/**
 * 和原版 inquirer 的微小差别,这里的问题清单不是 Array<inquirer.DistinctQuestion<T>>,
 * 而是一个 Object<string, inquirer.DistinctQuestion<T>>。其中,键是一个问题
 * 的唯一标识符 identifier(等同于【问题配置对象】里的 name 属性);值就是该问题的配置对象。
 *
 * 另一方面,问题的提问次序与 Questions 配置对象内【键-值】对的词法次序一致。
 * @export
 * @interface Questions
 * @template T
 */
export interface Questions<T> {
    [key: string]: inquirer.DistinctQuestion<T>
}
/**
 * 在经由图形界面收集问卷答案时,阻塞 libuv 的事件循环。
 * @export
 * @param {Questions} questions
 * @returns {Promise<inquirer.Answers>}
 */
export function inquire(questions: Questions): Promise<inquirer.Answers>;
/**
 * 在经由图形界面收集问卷答案时,不阻塞 libuv 的事件循环。所以,node 还能接着响应
 * 来自其它事件源的请求。
 * @export
 * @param {Questions} questions
 * @returns {Promise<inquirer.Answers>}
 */
export function inquireAsync(questions: Questions): Promise<inquirer.Answers>;

所以,一个json格式问题清单的例子如下。这是一个典型的【vue前端-脚手架】图形界面安装向导的问卷配置数据结构。

{
    "subprojects": { // 这个问题唯一标识字符串。相当于主键 ID。
        "type": "checkbox",
        "message": "请选择 工程类型",
        "required": true,
        "choices": [{
            "name": "PC浏览器-管理界面",
            "value": "admin",
            "short": "中后台",
            "checked": false
        }, {
            "name": "本地 H5 插件",
            "value": "app",
            "short": "移动插件",
            "checked": false
        }, {
            "name": "组件/模块/微前端应用",
            "value": "component",
            "short": "组件/模块/微前端",
            "checked": false,
            "mutex": true
        }, {
            "name": "RUST 语言 WEB 字节码 NPM 模块",
            "value": "wasm",
            "short": "RUST + WASM + NPM",
            "checked": false,
            "mutex": true
        }, {
            "name": "RUST 语言原生 GUI 应用",
            "value": "rust_gui",
            "short": "RUST + GTK3 APP",
            "checked": false,
            "mutex": true
        }]
    },
    "adminPort": {
        "when": "subprojects.admin", // 条件表达式,当前问题是出现在交互流程中(true),还是被跳过(false)。
        "type": "input", // 文本输入框
        "subType": "port", // 端口数字输入框
        "message": "请输入【管理端】webpack dev server 监听端口号", // 题面
        "required": true, // 是否必填
        "default": 9000 // 默认值
    },
    "appPort": {
        "when": "subprojects.app",
        "type": "input",
        "subType": "port",
        "message": "请输入 移动端 webpack dev server 监听端口号",
        "required": true,
        "default": 9010
    },
    "componentPort": {
        "when": "subprojects.component",
        "type": "input",
        "subType": "port",
        "message": "请输入 组件/模块开发 webpack dev server 监听端口号",
        "required": true,
        "default": 9015
    },
    "adminUiLib": {
        "when": "subprojects.admin",
        "type": "list",
        "message": "请选择“管理端” UI 组件库",
        "choices": [{
            "name": "不使用UI组件库",
            "value": "none",
            "short": "无"
        }, {
            "name": "iView",
            "value": "iView",
            "short": "iView"
        }, {
            "name": "Element UI",
            "value": "elementUI",
            "short": "Element"
        }]
    },
    "appUiLib": {
        "when": "subprojects.app",
        "type": "list",
        "message": "请选择“移动端” UI 组件库",
        "choices": [{
            "name": "不使用UI组件库",
            "value": "none",
            "short": "无"
        }, {
            "name": "Vant",
            "value": "vant",
            "short": "vant"
        }]
    },
    "compWhichEnd": {
        "when": "subprojects.component",
        "type": "list",
        "message": "请选择“组件的目标”运行环境",
        "default": 0,
        "choices": [{
            "name": "桌面浏览器",
            "value": "pcBrowser",
            "short": "桌面"
        }, {
            "name": "移动 WebView",
            "value": "mobileBrowser",
            "short": "移动"
        }]
    },
    "compUiLib": {
        "when": "subprojects.component",
        "type": "list",
        "message": "请选择 基于哪款【UI 组件库】做二次开发实现组件",
        "choices": [{
            "name": "不使用UI组件库",
            "value": "none",
            "short": "无"
        }, {
            "when": "compWhichEnd == 'pcBrowser'",
            "name": "Element UI",
            "value": "elementUI",
            "short": "Element"
        }, {
            "when": "compWhichEnd == 'mobileBrowser'",
            "name": "Vant",
            "value": "vant",
            "short": "vant"
        }]
    },
    "favicon": {
        "when": "subprojects.admin || subprojects.app",
        "type": "confirm",
        "message": "针对【管理端】与【移动端】,是否自己管理网页的 favicon 图标?",
        "default": false
    },
    "adminMultiEntries": {
        "when": "subprojects.admin",
        "type": "list",
        "message": "【管理端】是几页应用程序?",
        "default": 0,
        "choices": [{
            "name": "单页",
            "value": 1,
            "short": "单"
        }, {
            "name": "双页",
            "value": 2,
            "short": "双"
        }]
    },
    "appMultiEntries": {
        "when": "subprojects.app",
        "type": "list",
        "message": "【移动端】是几页应用程序?",
        "default": 0,
        "choices": [{
            "name": "单页",
            "value": 1,
            "short": "单"
        }, {
            "name": "双页",
            "value": 2,
            "short": "双"
        }]
    },
    "flavor": {
        "when": "subprojects.wasm == false && subprojects.rust_gui == false",
        "type": "confirm",
        "message": "是否支持 Flavor 选择器?",
        "default": false
    },
    "adminAssetsSubDirectory": {
        "when": "subprojects.admin",
        "type": "list",
        "message": "请选择-管理端-资源文件目录名",
        "default": 0,
        "choices": [{
            "name": "bundle/admin",
            "value": "bundle/admin",
            "short": "bundle/admin"
        }, {
            "name": "static",
            "value": "static",
            "short": "static"
        }]
    },
    "appAssetsSubDirectory": {
        "when": "subprojects.app",
        "type": "list",
        "message": "请选择-移动端-资源文件目录名",
        "default": 0,
        "choices": [{
            "name": "bundle/app",
            "value": "bundle/app",
            "short": "bundle/app"
        }, {
            "name": "static",
            "value": "static",
            "short": "static"
        }]
    },
    "appWebWorker": {
        "when": "subprojects.app",
        "type": "confirm",
        "message": "是否预置线程化 web worker 加速?",
        "default": false
    },
    "adminI18n": {
        "when": "subprojects.admin",
        "type": "confirm",
        "message": "是否预置 Vue 国际化?",
        "default": false
    },
    "appI18n": {
        "when": "subprojects.app",
        "type": "confirm",
        "message": "是否预置 Vue 国际化?",
        "default": false
    },
    "imgCompress": {
        "when": "subprojects.wasm == false && subprojects.rust_gui == false",
        "type": "confirm",
        "message": "是否预压缩各类图片?",
        "default": false
    },
    "appPrerender": {
        "when": "subprojects.app",
        "type": "confirm",
        "message": "【是/否】启动首屏预渲染模式?",
        "default": false
    },
    "cssModules": {
        "when": "subprojects.admin || subprojects.app",
        "type": "confirm",
        "message": "【是/否】启用 CSS 模块?",
        "default": false
    },
    "adminType": {
        "when": "subprojects.admin",
        "type": "list",
        "message": "请选择 工程子类型",
        "default": 0,
        "choices": [{
            "name": "单体应用",
            "value": "standalone",
            "short": "常规"
        }, {
            "name": "微前端宿主",
            "value": "microFrontEnd",
            "short": "微前端"
        }]
    },
    "appType": {
        "when": "subprojects.app",
        "type": "list",
        "message": "请选择 工程子类型",
        "default": 0,
        "choices": [{
            "name": "单体应用",
            "value": "standalone",
            "short": "常规"
        }, {
            "name": "微前端宿主",
            "value": "microFrontEnd",
            "short": "微前端"
        }]
    },
    "compType": {
        "when": "subprojects.component",
        "type": "list",
        "message": "请选择 工程子类型",
        "default": 0,
        "choices": [{
            "name": "组件/模块",
            "value": "module",
            "short": "常规"
        }, {
            "name": "微前端应用",
            "value": "microFrontEnd",
            "short": "微前端"
        }]
    },
    "adminPx2remTactic": {
        "when": "subprojects.admin",
        "type": "list",
        "message": "px2rem 自适应布局策略",
        "default": 1,
        "choices": [{
            "name": "放弃(没有设计稿,凭感觉度量)",
            "value": "none",
            "short": "放弃"
        }, {
            "name": "采用且以·设计稿宽度·为基准(对齐设计稿,制作常规网页)",
            "value": "width",
            "short": "常规网页制作"
        }, {
            "name": "采用且以·设计稿对角线长度·为基准(对齐设计稿,制作·限高·iframe)",
            "value": "diagonal",
            "short": "限高iframe制作"
        }]
    },
    "installDepsImmediate": {
        "when": "!subprojects.rust_gui",
        "type": "confirm",
        "message": "【是/否】是否立即给工程原型安装依赖?",
        "default": true
    },
    "name": {
        "type": "string",
        "subType": "packageName",
        "message": "工程名",
        "required": true,
        "default": "project_name"
    },
    "author": {
        "type": "string",
        "message": "作者名",
        "required": true,
        "default": "author_name"
    }
}

inquirer的细微差别

  1. 问卷配置对象是Object<inquirer.KeyUnion<T>, inquirer.DistinctQuestion<T>>,而不是Array<inquirer.DistinctQuestion<T>>
    1. 这一点没有顺从于·原著·是为了更容易地与公司现成的【前端-脚手架】安装向导对接。所以,从核心层Rust + GNOME.GTK3 图形界面版 inquirer就这么处理的数据结构。
  2. 单个问题【配置对象】内暂时缺少【回调函数】支持 --- 这类·动态出现的·FFI接口,我还不会做。但作为补偿,我在如下几处添加了新配置属性:
    1. "type": "input"类型(即,文本输入框)添加了"subType": "port"子类。其专门收集【数字类型】,取值范围在1000 ~ 99999的端口号。样板配置如下:

      {
          "appPort": { // 这个问题唯一标识字符串。相当于主键 ID。
              "when": "subprojects.app", // 条件表达式,当前问题是出现在交互流程中(true),还是被跳过(false)。
              "type": "input", // 文本输入框
              "subType": "port", // 端口数字输入框
              "message": "请输入 移动端 webpack dev server 监听端口号", // 题面
              "required": true, // 是否必填
              "default": 9010 // 默认值
          },
      }
    2. "type": "list"类型(即,单选题)的每一个单选项添加了when(布尔)表达式。从而,根据上下文内容,动态地决定当前单选项是否被显示出来。样板配置如下:

      {
          "compUiLib": { // 这个问题唯一标识字符串。相当于主键 ID。
              "when": "subprojects.component", // 条件表达式,当前问题是出现在交互流程中(true),还是被跳过(false)。
              "type": "list", // 单选题
              "message": "请选择 基于哪款【UI 组件库】做二次开发实现组件", // 题面 - 标题
              "choices": [{ // 题面 - 单选项1
                  "name": "不使用UI组件库", // 【显示用】完整名
                  "short": "无", // 【显示用】简称名 - 暂时尚未使用
                  "value": "none" // 【程序引用】此选项的唯一标识字符串
              }, { // 题面 - 单选项2
                  "when": "compWhichEnd == 'pcBrowser'", // 决定此选项是否出现的`when`表达式
                  "name": "Element UI", // 【显示用】完整名
                  "short": "Element", // 【显示用】简称名 - 暂时尚未使用
                  "value": "elementUI" // 【程序引用】此选项的唯一标识字符串
              }, { // 题面 - 单选项3
                  "when": "compWhichEnd == 'mobileBrowser'", // 决定此选项是否出现的`when`表达式
                  "name": "Vant", // 【显示用】完整名
                  "short": "vant", // 【显示用】简称名 - 暂时尚未使用
                  "value": "vant" // 【程序引用】此选项的唯一标识字符串
              }]
          },
      }
    3. "type": "checkbox"类型(即,多选题)的每一个多选项添加了mutex: boolean属性。"mutex": true表示该选项具有排它性。若其被选中,则该选项只能被单选。样板配置如下:

      {
          "subprojects": { // 这个问题唯一标识字符串。相当于主键 ID。
              "type": "checkbox", // 多选题
              "message": "请选择 工程类型", // 题面 - 标题
              "required": true, // 是否必填
              "choices": [{ // 题面 - 多选项1
                  "name": "PC浏览器-管理界面", // 【显示用】完整名
                  "short": "中后台", // 【显示用】简称名 - 暂时尚未使用
                  "value": "admin", // 【程序引用】此选项的唯一标识字符串。比如,subprojects.admin
                  "checked": false // 初始选中状态
              }, { // 题面 - 多选项2
                  "name": "本地 H5 插件", // 【显示用】完整名
                  "short": "移动插件", // 【显示用】简称名 - 暂时尚未使用
                  "value": "app", // 【程序引用】此选项的唯一标识字符串。比如,subprojects.app
                  "checked": false // 初始选中状态
              }, { // 题面 - 多选项3
                  "name": "组件/模块/微前端应用", // 【显示用】完整名
                  "short": "组件/模块/微前端", // 【显示用】简称名 - 暂时尚未使用
                  "value": "component", // 【程序引用】此选项的唯一标识字符串。比如,subprojects.component
                  "checked": false, // 初始选中状态
                  "mutex": true // 是否为单选
              }, { // 题面 - 多选项3
                  "name": "RUST 语言 WEB 字节码 NPM 模块", // 【显示用】完整名
                  "short": "RUST + WASM + NPM", // 【显示用】简称名 - 暂时尚未使用
                  "value": "wasm", // 【程序引用】此选项的唯一标识字符串。比如,subprojects.wasm
                  "checked": false, // 初始选中状态
                  "mutex": true // 是否为单选
              }, { // 题面 - 多选项4
                  "name": "RUST 语言原生 GUI 应用", // 【显示用】完整名
                  "short": "RUST + GTK3 APP", // 【显示用】简称名 - 暂时尚未使用
                  "value": "rust_gui", // 【程序引用】此选项的唯一标识字符串。比如,subprojects.rust_gui
                  "checked": false, // 初始选中状态
                  "mutex": true // 是否为单选
              }]
          },
      }

关于核心模块更多内容也请阅读scaffold-wizard