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

ql-publish

v0.0.10

Published

一个面向前端项目的自动化发布工具,封装了 SSH/SFTP 上传、阿里云 CDN 刷新、OSS 上传与远程旧文件清理等常见发布动作。

Readme

ql-publish

一个面向前端项目的自动化发布工具,封装了 SSH/SFTP 上传、阿里云 CDN 刷新、OSS 上传与远程旧文件清理等常见发布动作。

如何发布本项目到 npm

面向本仓库维护者:发布新版本到 npm registry 的标准流程。

  1. 登录 npm 账号(首次或登录过期时执行)

    npm login
    # 按提示输入用户名、密码、邮箱、OTP
    # 验证当前登录身份:
    npm whoami
  2. 确认 registry 指向官方源(如果用过淘宝镜像需切回)

    npm config get registry
    # 不是 https://registry.npmjs.org/ 时执行:
    npm config set registry https://registry.npmjs.org/
  3. 更新版本号:修改 package.json 里的 version,或使用:

    npm version patch   # 0.0.9 -> 0.0.10
    npm version minor   # 0.0.9 -> 0.1.0
    npm version major   # 0.0.9 -> 1.0.0
  4. 同步更新文档:在本 README 「更新日志」追加新版本变更说明。

  5. 本地自检:发布前先看看会被打包进 npm 的文件有哪些。

    npm pack --dry-run
  6. 正式发布

    npm publish
    # 如果包名带 scope(如 @xxx/ql-publish)且需要公开:
    # npm publish --access public
  7. 验证发布结果

    npm view ql-publish version

注意:npm 已发布的版本号不可覆盖,发错了只能 npm unpublish(24 小时内)或发布更高版本号修复。

安装

npm i ql-publish
# or
yarn add ql-publish
# or
pnpm add ql-publish

导出的 API

| 方法 | 用途 | | --- | --- | | initConfig(config, coreConfig) | 注入业务配置与凭证配置,所有后续方法必须先调用一次 | | upload() | 把本地构建产物通过 SFTP 上传到远程服务器,并写入 fileMap.json 作为发布基线 | | clear() | 根据远程 fileMap.jsonmtime 基线,递归清理「修改时间不晚于基线」的旧文件,支持白名单 | | refresh() | 刷新阿里云 CDN(按 config[NODE_ENV].cdn 列表) | | reset() | 回滚到上一次发布的备份版本(依赖 backUp: true) |

配置结构

调用方需要构造两个对象:业务配置 config、凭证配置 coreConfig,分别通过 initConfig 传入。

config(业务配置)

module.exports = {
  test: {
    localPath: '本地构建产物目录(绝对路径)',
    path: '远程服务器部署路径',
    backUpSeconds: 60 * 60 * 24 * 30, // 备份保留时长(秒)
    backUp: false,                    // 是否开启备份
    clearExcludes: ['dist.tar.gz'],   // 清理白名单,详见下文
  },
  pro: {
    localPath: '...',
    path: '...',
    backUpSeconds: 60 * 60 * 24 * 7,
    backUp: true,
    clearExcludes: ['dist.tar.gz'],
    cdn: [
      { type: 'File', url: 'https://example.com/your-app/' },
      { type: 'File', url: 'https://example.com/your-app/index.html' },
    ],
  },
  oss: {
    localDir: '本地构建产物目录(绝对路径)',
    targetDir: 'oss 上的目标前缀',
    backUpSeconds: 60 * 60 * 24 * 30,
    cdn: [/* 同上 */],
  },
};

coreConfig(凭证配置)

const fs = require('fs');

module.exports = {
  cdn: {
    accessKeyId: process.env.cdn_accessKeyId,
    accessKeySecret: process.env.cdn_accessKeySecret,
    endpoint: 'cdn.aliyuncs.com',
  },
  test: {
    host: '服务器 IP',
    port: 22,
    username: 'root',
    privateKey: fs.readFileSync(process.env.id_ed25519),
  },
  pro: {
    host: '...',
    port: 22,
    username: 'root',
    privateKey: fs.readFileSync(process.env.ali_rsa),
  },
  oss: {
    accessKeyId: process.env.oss_accessKeyId,
    accessKeySecret: process.env.oss_accessKeySecret,
    region: 'oss-cn-shenzhen',
    bucket: process.env.oss_bucket,
  },
};

使用示例

最佳实践是把 4 个动作各自拆成独立脚本,再用 package.jsonscripts 串联 cross-env NODE_ENV=test|pro

// upload.js
const config = require('./config');
const coreConfig = require('./core/core');
const { initConfig, upload } = require('ql-publish');

initConfig(config, coreConfig);
upload();
// clear.js
const config = require('./config');
const coreConfig = require('./core/core');
const { initConfig, clear } = require('ql-publish');

initConfig(config, coreConfig);
clear();
// refresh.js
const config = require('./config');
const coreConfig = require('./core/core');
const { initConfig, refresh } = require('ql-publish');

initConfig(config, coreConfig);
refresh();
// reset.js
const config = require('./config');
const coreConfig = require('./core/core');
const { initConfig, reset } = require('ql-publish');

initConfig(config, coreConfig);
reset();
// package.json 片段
{
  "scripts": {
    "upload:test": "cross-env NODE_ENV=test node ./upload/index.js",
    "upload:pro":  "cross-env NODE_ENV=pro  node ./upload/index.js",
    "clear:test":  "cross-env NODE_ENV=test node ./upload/clear.js",
    "clear:pro":   "cross-env NODE_ENV=pro  node ./upload/clear.js",
    "refresh:cdn": "cross-env NODE_ENV=pro  node ./upload/refresh.js",
    "reset:test":  "cross-env NODE_ENV=test node ./upload/reset.js",
    "reset:pro":   "cross-env NODE_ENV=pro  node ./upload/reset.js"
  }
}

clearExcludes 清理白名单(v0.0.9+)

clear() 默认会把远程目录下「mtime 不晚于发布基线」的旧文件全部删除。若你的发布流程在服务器上保留了与版本无关的常驻文件(例如压缩包归档、人工上传的资源),可以通过 clearExcludes 让它们免删。

配置位置

// config.js
module.exports = {
  test: {
    // ...其它字段
    clearExcludes: ['dist.tar.gz'],
  },
  pro: {
    // ...其它字段
    clearExcludes: ['dist.tar.gz'],
  },
};

三类匹配规则

| 规则形态 | 匹配方式 | 大小写 | 示例 | | --- | --- | --- | --- | | 以 . 开头 | 扩展名后缀匹配(endsWith),支持多段后缀 | 不区分 | .tar.gz.zip | | 含 * 字符 | 子串匹配(去掉所有 * 后用 includes) | 区分 | *keep*backup-* | | 其它 | 文件名精确匹配(===) | 区分 | dist.tar.gzfileMap.json |

任一规则命中即跳过删除。

配置示例

// 1) 只想保留某个具体文件
clearExcludes: ['dist.tar.gz']

// 2) 想保留全部压缩包归档
clearExcludes: ['.tar.gz', '.zip']

// 3) 想保留所有名字里带 keep 的文件,且排除所有 .zip
clearExcludes: ['*keep*', '.zip']

行为说明

  • 白名单只作用于文件层级:目录始终会被递归进入,以便清理其子文件。
  • 命中白名单时控制台会打印 ⏭ 已保留文件: <远程路径>,便于核对。
  • 启动时若 clearExcludes 非空,会先打印 🛡 本次清理将保留以下规则命中的文件: [...],供发布者在二次确认之前可视化检查规则。
  • 未配置 / 配置为空数组 / 非数组类型 → 退化为无白名单,行为与 0.0.8 完全一致,可零成本升级。

更新日志

0.0.10

  • upload() 服务器解压完成后不再自动删除远程的 dist.tar.gz,方便后续归档/手动回滚。
  • 若不希望该压缩包在后续 clear() 时被当作旧文件删除,请在 config 中配置 clearExcludes: ['dist.tar.gz']

0.0.9

  • 新增 clearExcludes 配置,支持「精确文件名 / 扩展名后缀 / 子串」三类规则跳过清理。
  • 旧版本零破坏性升级:未配置该字段时行为与 0.0.8 完全一致。