分享几个实用的 npm 包

0 阅读3分钟

joycon

JoyCon 是一个轻量级的配置文件查找和加载库,常用于 CLI 工具、构建工具和需要配置管理的应用中。

const JoyCon = require('joycon')
const joycon = new JoyCon()

// 查找配置文件
joycon.load(['package.json'])
  .then(result => {
    if (result.path) {
      console.log('文件路径:', result.path)
      console.log('文件内容:', result.data)
    } else {
      console.log('未找到文件')
    }
  })

cac

CAC 全称是 Command And Control,中文含义是命令行工具,是一个流行的 Node.js 命令行应用框架。

一个简单的示例:

// cli.js
const cac = require('cac')

const cli = cac('myapp') // 工具名

// 定义一个命令
cli.command('greet <name>', '向某人问好')
  .option('--time <time>', '指定时间', { default: '早晨' })
  .action((name, options) => {
    console.log(`你好 ${name}${options.time}好!`)
  })

// 显示帮助信息
cli.help()
// 处理命令行参数
cli.parse()

然后在终端运行:

node cli.js greet 小明 --time 晚上
# 输出:你好 小明,晚上好!

也可以添加 --help 参数查看帮助:

node cli.js greet 小明 --help
# 输出:
myapp

Usage:
  $ myapp greet <name>

Options:
  --time <time>  指定时间 (default: 早晨)
  -h, --help     Display this message

etag/fresh

协商缓存中的 Last-ModifiedETag 想必大家都不陌生,那么如何获取最后修改时间和 Etag 呢?其实很简单。

const etag = require("etag");
const fresh = require("fresh");

// fs.stat 用于获取文件或目录的元数据信息,如最后修改时间
fs.stat(filePath, function (err, stat) {
    const lastModified = stat.mtime.toUTCString(); // 最后修改时间
    const fileEtag = etag(stat);
    res.setHeader("Cache-Control", "public, max-age=0");
    res.setHeader("Last-Modified", lastModified);
    res.setHeader("ETag", fileEtag);

    // 根据请求头判断缓存是否是最新的
    isFresh = fresh(req.headers, {
        etag: fileEtag,
        "last-modified": lastModified,
    });
})

import-html-entry

import-html-entry 是一个用于动态加载和解析 HTML 文件的 JavaScript 库。它最初由 qiankun(乾坤)微前端框架 创造,用于解决微前端场景下的子应用加载问题。

举个简单的例子,假设有以下 html:

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
  <link href="/src/main.css" rel="stylesheet">
  <style>
    .local { color: red; }
  </style>
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
  <script>
    console.log('inline script');
  </script>
</body>
</html>

调用 import-html-entry 可返回以下内容:

  1. template: 处理后的 HTML 模板
<!DOCTYPE html>
<html>
<head>
  <style>/* http://127.0.0.1:5173/src/main.css */import { createHotContext as __vite__createHotContext } from "/@vite/client";import.meta.hot = __vite__createHotContext("/src/main.css");import { updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle } from "/@vite/client"
const __vite__id = "/Documents/projects/vue-demo/src/main.css"
const __vite__css = "div {\n    color: red;\n}"
__vite__updateStyle(__vite__id, __vite__css)
import.meta.hot.accept()
import.meta.hot.prune(() => __vite__removeStyle(__vite__id))</style>
  <style>
    .local { color: red; }
  </style>
</head>
<body>
  <div id="app"></div>
  <!--   script http://127.0.0.1:5173/src/main.js?t=1769919841809 replaced by import-html-entry -->
  <!-- inline scripts replaced by import-html-entry -->
</body>
</html>
  1. getExternalScripts: 获取所有外部脚本的函数
[
    {
        "src": "http://127.0.0.1:5173/src/main.js?t=1769920162957",
        "value": "import { createApp } from \"/node_modules/.vite/deps/vue.js?v=e7ce54e7\"\nimport App from \"/src/App.vue?t=1769920162957\"\n\ncreateApp(App).mount('#app')\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3JlYXRlQXBwIH0gZnJvbSBcIi9ub2RlX21vZHVsZXMvLnZpdGUvZGVwcy92dWUuanM/dj1lN2NlNTRlN1wiXG5pbXBvcnQgQXBwIGZyb20gXCIvc3JjL0FwcC52dWU/dD0xNzY5OTIwMTYyOTU3XCJcblxuY3JlYXRlQXBwKEFwcCkubW91bnQoJyNhcHAnKVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUTtBQUNyRSxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGFBQWE7O0FBRTdDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQzsifQ=="
    },
    {
        "src": "<script>\n    console.log('inline script');\n  </script>",
        "value": "\n    console.log('inline script');\n  "
    }
]
  1. getExternalStyleSheets: 获取所有外部样式表的函数
[
    {
        "src": "http://127.0.0.1:5173/src/main.css",
        "value": "import { createHotContext as __vite__createHotContext } from \"/@vite/client\";import.meta.hot = __vite__createHotContext(\"/src/main.css\");import { updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle } from \"/@vite/client\"\nconst __vite__id = \"/Documents/projects/vue-demo/src/main.css\"\nconst __vite__css = \"div {\\n    color: red;\\n}\"\n__vite__updateStyle(__vite__id, __vite__css)\nimport.meta.hot.accept()\nimport.meta.hot.prune(() => __vite__removeStyle(__vite__id))"
    }
]

react-helmet

react-helmet 在功能上类似于 ahooks 中的 useTitle。两者区别如下:

  • useTitle:轻量级解决方案,适合只需要修改标题的简单场景
  • React Helmet:功能完整的解决方案,适合需要全面 SEO 优化的复杂场景
import { Helmet } from 'react-helmet';

function MyPage() {
  return (
    <div>
      <Helmet>
        <title>我的页面标题</title>
        <meta name="description" content="页面描述" />
        <meta name="keywords" content="关键词1,关键词2" />
      </Helmet>
      
      <h1>页面内容</h1>
    </div>
  );
}