package-npm-nix

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<objective> Create Nix packages for npm-based CLI tools, covering both pre-built packages from npm registry and source builds with proper dependency management. This skill provides patterns for fetching, building, and packaging JavaScript/TypeScript/Bun tools in Nix environments. </objective>
<quick_start> <pre_built_from_npm> For tools already built and published to npm (fastest approach):
nix
{
  lib,
  stdenv,
  fetchzip,
  nodejs,
}:

stdenv.mkDerivation rec {
  pname = "tool-name";
  version = "1.0.0";

  src = fetchzip {
    url = "https://registry.npmjs.org/${pname}/-/${pname}-${version}.tgz";
    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };

  nativeBuildInputs = [ nodejs ];

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin
    cp $src/dist/cli.js $out/bin/tool-name
    chmod +x $out/bin/tool-name

    # Fix shebang
    substituteInPlace $out/bin/tool-name \
      --replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"

    runHook postInstall
  '';

  meta = with lib; {
    description = "Tool description";
    homepage = "https://github.com/org/repo";
    license = licenses.mit;
    sourceProvenance = with lib.sourceTypes; [ binaryBytecode ];
    maintainers = with maintainers; [ ];
    mainProgram = "tool-name";
    platforms = platforms.all;
  };
}
Get the hash:
bash
nix-prefetch-url --unpack https://registry.npmjs.org/tool-name/-/tool-name-1.0.0.tgz
<objective> 为基于npm的CLI工具创建Nix包,涵盖来自npm注册表的预构建包以及具备完善依赖管理的源码构建。本技能提供了在Nix环境中获取、构建和打包JavaScript/TypeScript/Bun工具的实现模式。 </objective>
<quick_start> <pre_built_from_npm> 针对已构建并发布到npm的工具(最快方式):
nix
{
  lib,
  stdenv,
  fetchzip,
  nodejs,
}:

stdenv.mkDerivation rec {
  pname = "tool-name";
  version = "1.0.0";

  src = fetchzip {
    url = "https://registry.npmjs.org/${pname}/-/${pname}-${version}.tgz";
    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };

  nativeBuildInputs = [ nodejs ];

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin
    cp $src/dist/cli.js $out/bin/tool-name
    chmod +x $out/bin/tool-name

    # Fix shebang
    substituteInPlace $out/bin/tool-name \
      --replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"

    runHook postInstall
  '';

  meta = with lib; {
    description = "Tool description";
    homepage = "https://github.com/org/repo";
    license = licenses.mit;
    sourceProvenance = with lib.sourceTypes; [ binaryBytecode ];
    maintainers = with maintainers; [ ];
    mainProgram = "tool-name";
    platforms = platforms.all;
  };
}
获取哈希值:
bash
nix-prefetch-url --unpack https://registry.npmjs.org/tool-name/-/tool-name-1.0.0.tgz

Convert to SRI format:

转换为SRI格式:

nix hash convert --to sri --hash-algo sha256 <hash-output>
</pre_built_from_npm>

<source_build_with_bun>
For tools that need to be built from source using Bun:

```nix
{
  lib,
  stdenv,
  stdenvNoCC,
  fetchFromGitHub,
  bun,
  makeBinaryWrapper,
  nodejs,
  autoPatchelfHook,
}:

let
  fetchBunDeps =
    { src, hash, ... }@args:
    stdenvNoCC.mkDerivation {
      pname = args.pname or "${src.name or "source"}-bun-deps";
      version = args.version or src.version or "unknown";
      inherit src;

      nativeBuildInputs = [ bun ];

      buildPhase = ''
        export HOME=$TMPDIR
        export npm_config_ignore_scripts=true
        bun install --no-progress --frozen-lockfile --ignore-scripts
      '';

      installPhase = ''
        mkdir -p $out
        cp -R ./node_modules $out
        cp ./bun.lock $out/
      '';

      dontFixup = true;
      outputHash = hash;
      outputHashAlgo = "sha256";
      outputHashMode = "recursive";
    };

  version = "1.0.0";
  src = fetchFromGitHub {
    owner = "org";
    repo = "repo";
    rev = "v${version}";
    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };

  node_modules = fetchBunDeps {
    pname = "tool-name-bun-deps";
    inherit version src;
    hash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
  };
in
stdenv.mkDerivation rec {
  pname = "tool-name";
  inherit version src;

  nativeBuildInputs = [
    bun
    nodejs
    makeBinaryWrapper
    autoPatchelfHook
  ];

  buildInputs = [
    stdenv.cc.cc.lib
  ];

  buildPhase = ''
    # Verify lockfile match
    diff -q ./bun.lock ${node_modules}/bun.lock || exit 1

    # Copy and patch node_modules
    cp -R ${node_modules}/node_modules .
    chmod -R u+w node_modules
    patchShebangs node_modules
    autoPatchelf node_modules

    export HOME=$TMPDIR
    export npm_config_ignore_scripts=true
    bun run build
  '';

  installPhase = ''
    mkdir -p $out/bin
    cp dist/tool-name $out/bin/tool-name
    chmod +x $out/bin/tool-name
  '';

  dontStrip = true;

  meta = with lib; {
    description = "Tool description";
    homepage = "https://github.com/org/repo";
    license = licenses.mit;
    sourceProvenance = with lib.sourceTypes; [ fromSource ];
    maintainers = with maintainers; [ ];
    mainProgram = "tool-name";
    platforms = [ "x86_64-linux" ];
  };
}
</source_build_with_bun> </quick_start>
<workflow> <step_1_identify_package_type> **Determine build approach**:
Check the npm package:
bash
undefined
nix hash convert --to sri --hash-algo sha256 <hash-output>
</pre_built_from_npm>

<source_build_with_bun>
针对需要使用Bun从源码构建的工具:

```nix
{
  lib,
  stdenv,
  stdenvNoCC,
  fetchFromGitHub,
  bun,
  makeBinaryWrapper,
  nodejs,
  autoPatchelfHook,
}:

let
  fetchBunDeps =
    { src, hash, ... }@args:
    stdenvNoCC.mkDerivation {
      pname = args.pname or "${src.name or "source"}-bun-deps";
      version = args.version or src.version or "unknown";
      inherit src;

      nativeBuildInputs = [ bun ];

      buildPhase = ''
        export HOME=$TMPDIR
        export npm_config_ignore_scripts=true
        bun install --no-progress --frozen-lockfile --ignore-scripts
      '';

      installPhase = ''
        mkdir -p $out
        cp -R ./node_modules $out
        cp ./bun.lock $out/
      '';

      dontFixup = true;
      outputHash = hash;
      outputHashAlgo = "sha256";
      outputHashMode = "recursive";
    };

  version = "1.0.0";
  src = fetchFromGitHub {
    owner = "org";
    repo = "repo";
    rev = "v${version}";
    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };

  node_modules = fetchBunDeps {
    pname = "tool-name-bun-deps";
    inherit version src;
    hash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
  };
in
stdenv.mkDerivation rec {
  pname = "tool-name";
  inherit version src;

  nativeBuildInputs = [
    bun
    nodejs
    makeBinaryWrapper
    autoPatchelfHook
  ];

  buildInputs = [
    stdenv.cc.cc.lib
  ];

  buildPhase = ''
    # Verify lockfile match
    diff -q ./bun.lock ${node_modules}/bun.lock || exit 1

    # Copy and patch node_modules
    cp -R ${node_modules}/node_modules .
    chmod -R u+w node_modules
    patchShebangs node_modules
    autoPatchelf node_modules

    export HOME=$TMPDIR
    export npm_config_ignore_scripts=true
    bun run build
  '';

  installPhase = ''
    mkdir -p $out/bin
    cp dist/tool-name $out/bin/tool-name
    chmod +x $out/bin/tool-name
  '';

  dontStrip = true;

  meta = with lib; {
    description = "Tool description";
    homepage = "https://github.com/org/repo";
    license = licenses.mit;
    sourceProvenance = with lib.sourceTypes; [ fromSource ];
    maintainers = with maintainers; [ ];
    mainProgram = "tool-name";
    platforms = [ "x86_64-linux" ];
  };
}
</source_build_with_bun> </quick_start>
<workflow> <step_1_identify_package_type> **确定构建方式**:
检查npm包:
bash
undefined

Download and inspect

下载并检查

nix-prefetch-url --unpack https://registry.npmjs.org/package/-/package-1.0.0.tgz ls -la /nix/store/<hash>-package-1.0.0.tgz/

If `dist/` directory exists with built files:
→ Use pre-built approach (simpler, faster)

If only `src/` exists or package.json has build scripts:
→ Use source build approach

Check package.json for:
- `"bin"` field: Shows what executables are provided
- `"type": "module"`: ES modules (common in modern packages)
- `"scripts"`: Build commands (indicates source build needed)
- Runtime: Look for bun, node, or specific version requirements
</step_1_identify_package_type>

<step_2_fetch_hashes>
**Get source and dependency hashes**:

For pre-built packages:
```bash
nix-prefetch-url --unpack https://registry.npmjs.org/package/-/package-1.0.0.tgz ls -la /nix/store/<hash>-package-1.0.0.tgz/

如果存在包含构建后文件的`dist/`目录:
→ 使用预构建方式(更简单、快速)

如果仅存在`src/`目录或package.json包含构建脚本:
→ 使用源码构建方式

检查package.json中的以下字段:
- `"bin"`字段:显示工具提供的可执行文件
- `"type": "module"`:ES模块(现代包中常见)
- `"scripts"`:构建命令(表明需要源码构建)
- 运行时:查看是否依赖bun、node或特定版本要求
</step_1_identify_package_type>

<step_2_fetch_hashes>
**获取源码和依赖哈希值**:

针对预构建包:
```bash

Fetch npm tarball

获取npm压缩包

Output: 1abc... (base32 format)

输出:1abc...(base32格式)

Convert to SRI format

转换为SRI格式

nix hash convert --to sri --hash-algo sha256 1abc...
nix hash convert --to sri --hash-algo sha256 1abc...

Output: sha256-xyz...

输出:sha256-xyz...


For source builds:
```bash

针对源码构建:
```bash

Get GitHub source hash

获取GitHub源码哈希

Get dependencies hash (requires iteration):

获取依赖哈希(需要迭代操作):

1. Use lib.fakeHash in fetchBunDeps

1. 在fetchBunDeps中使用lib.fakeHash

2. Try to build

2. 尝试构建

3. Nix will show expected hash in error

3. Nix会在错误信息中显示期望的哈希值

4. Update hash and rebuild

4. 更新哈希值并重新构建

</step_2_fetch_hashes>

<step_3_create_package_files>
**Create package structure**:

```bash
mkdir -p packages/tool-name
Create
packages/tool-name/package.nix
with full derivation (see quick_start).
Create
packages/tool-name/default.nix
:
nix
{ pkgs }: pkgs.callPackage ./package.nix { }
This two-file pattern allows the package to be used standalone or integrated into a flake. </step_3_create_package_files>
<step_4_handle_special_cases> Common additional requirements:
WASM files or other assets:
nix
installPhase = ''
  mkdir -p $out/bin
  cp $src/dist/cli.js $out/bin/tool
  cp $src/dist/*.wasm $out/bin/  # Copy WASM alongside
  chmod +x $out/bin/tool

  substituteInPlace $out/bin/tool \
    --replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"
'';
Multiple executables:
nix
undefined
</step_2_fetch_hashes>

<step_3_create_package_files>
**创建包结构**:

```bash
mkdir -p packages/tool-name
创建
packages/tool-name/package.nix
文件并写入完整的派生包定义(参考快速开始部分)。
创建
packages/tool-name/default.nix
nix
{ pkgs }: pkgs.callPackage ./package.nix { }
这种双文件模式允许包独立使用或集成到flake中。 </step_3_create_package_files>
<step_4_handle_special_cases> 常见额外需求:
WASM文件或其他资源:
nix
installPhase = ''
  mkdir -p $out/bin
  cp $src/dist/cli.js $out/bin/tool
  cp $src/dist/*.wasm $out/bin/  # Copy WASM alongside
  chmod +x $out/bin/tool

  substituteInPlace $out/bin/tool \
    --replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"
'';
多个可执行文件:
nix
undefined

package.json might have:

package.json中可能包含:

"bin": {

"bin": {

"tool": "dist/cli.js",

"tool": "dist/cli.js",

"tool-admin": "dist/admin.js"

"tool-admin": "dist/admin.js"

}

}

installPhase = '' mkdir -p $out/bin for exe in tool tool-admin; do cp $src/dist/$exe.js $out/bin/$exe chmod +x $out/bin/$exe substituteInPlace $out/bin/$exe
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node" done '';
meta.mainProgram = "tool"; # Primary command

**Platform-specific binaries**:
```nix
meta = {
  platforms = [ "x86_64-linux" ];  # Bun-compiled binaries often Linux-only
  # or
  platforms = platforms.all;  # Pure JS works everywhere
};
</step_4_handle_special_cases>
<step_5_test_build> Build and test:
bash
undefined
installPhase = '' mkdir -p $out/bin for exe in tool tool-admin; do cp $src/dist/$exe.js $out/bin/$exe chmod +x $out/bin/$exe substituteInPlace $out/bin/$exe
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node" done '';
meta.mainProgram = "tool"; # 主命令

**特定平台二进制文件**:
```nix
meta = {
  platforms = [ "x86_64-linux" ];  # Bun编译的二进制文件通常仅支持Linux
  # 或
  platforms = platforms.all;  # 纯JS包支持所有平台
};
</step_4_handle_special_cases>
<step_5_test_build> 构建并测试:
bash
undefined

Build

构建

nix build .#tool-name
nix build .#tool-name

Test the binary

测试二进制文件

./result/bin/tool-name --version ./result/bin/tool-name --help
./result/bin/tool-name --version ./result/bin/tool-name --help

Check dependencies (Linux)

检查依赖(Linux)

ldd ./result/bin/tool-name # Should show all deps resolved
ldd ./result/bin/tool-name # 应显示所有依赖已解析

Format

格式化

nix fmt
nix fmt

Run flake checks

运行flake检查

nix flake check
</step_5_test_build>
</workflow>

<metadata_requirements>
<essential_fields>
Every package must have complete metadata:

```nix
meta = with lib; {
  description = "Clear, concise description";
  homepage = "https://project-homepage.com";
  changelog = "https://github.com/org/repo/releases";  # Optional but nice
  license = licenses.mit;  # or licenses.unfree for proprietary
  sourceProvenance = with lib.sourceTypes; [
    fromSource          # Built from source
    # or
    binaryBytecode      # Pre-built JS/TS (npm dist/)
    # or
    binaryNativeCode    # Compiled binaries
  ];
  maintainers = with maintainers; [ ];  # Empty OK for community packages
  mainProgram = "binary-name";
  platforms = platforms.all;  # or specific: [ "x86_64-linux" ]
};
</essential_fields>
<source_provenance_guide> Choose based on what you're packaging:
  • fromSource
    : Built from TypeScript/source during derivation
  • binaryBytecode
    : Pre-compiled JS from npm registry
  • binaryNativeCode
    : Native binaries (Rust, Go, Bun-compiled)
This affects security auditing and reproducibility expectations. </source_provenance_guide> </metadata_requirements>
<common_patterns> <shebang_replacement> Always replace shebangs for reproducibility:
nix
undefined
nix flake check
</step_5_test_build>
</workflow>

<metadata_requirements>
<essential_fields>
每个包必须包含完整的元数据:

```nix
meta = with lib; {
  description = "Clear, concise description";
  homepage = "https://project-homepage.com";
  changelog = "https://github.com/org/repo/releases";  # 可选但推荐
  license = licenses.mit;  # 专有包使用licenses.unfree
  sourceProvenance = with lib.sourceTypes; [
    fromSource          # 从源码构建
    # 或
    binaryBytecode      # 预编译JS/TS(npm dist/目录)
    # 或
    binaryNativeCode    # 编译后的原生二进制文件
  ];
  maintainers = with maintainers; [ ];  # 社区包可留空
  mainProgram = "binary-name";
  platforms = platforms.all;  # 或指定平台:[ "x86_64-linux" ]
};
</essential_fields>
<source_provenance_guide> 根据打包内容选择:
  • fromSource
    : 构建过程中从TypeScript/源码编译
  • binaryBytecode
    : 从npm注册表获取的预编译JS
  • binaryNativeCode
    : 原生二进制文件(Rust、Go、Bun编译)
这会影响安全审计和可复现性要求。 </source_provenance_guide> </metadata_requirements>
<common_patterns> <shebang_replacement> 为了可复现性,务必替换shebang:
nix
undefined

Single file

单个文件

substituteInPlace $out/bin/tool
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"
substituteInPlace $out/bin/tool
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"

Multiple files

多个文件

find $out/bin -type f -exec substituteInPlace {}
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node" ;

The `--replace-quiet` flag suppresses warnings if pattern not found.
</shebang_replacement>

<native_dependencies>
**Handle native modules** (like sqlite, sharp):

```nix
nativeBuildInputs = [
  bun
  nodejs
  makeBinaryWrapper
  autoPatchelfHook  # Linux: patches ELF binaries
];

buildInputs = [
  stdenv.cc.cc.lib  # Provides libgcc_s.so.1, libstdc++.so.6
];

autoPatchelfIgnoreMissingDeps = [
  "libc.musl-x86_64.so.1"  # Ignore musl if not available
];
autoPatchelf
runs automatically on Linux, fixing RPATH for .so files. </native_dependencies>
<bun_compiled_binaries> Don't strip Bun-compiled executables:
nix
undefined
find $out/bin -type f -exec substituteInPlace {}
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node" ;

`--replace-quiet`参数会在未找到匹配模式时抑制警告。
</shebang_replacement>

<native_dependencies>
**处理原生模块**(如sqlite、sharp):

```nix
nativeBuildInputs = [
  bun
  nodejs
  makeBinaryWrapper
  autoPatchelfHook  # Linux:修补ELF二进制文件
];

buildInputs = [
  stdenv.cc.cc.lib  # 提供libgcc_s.so.1、libstdc++.so.6
];

autoPatchelfIgnoreMissingDeps = [
  "libc.musl-x86_64.so.1"  # 忽略不可用的musl库
];
autoPatchelf
会在Linux上自动运行,修复.so文件的RPATH。 </native_dependencies>
<bun_compiled_binaries> 不要剥离Bun编译的二进制文件:
nix
undefined

Bun embeds JavaScript in the binary

Bun会将JavaScript嵌入到二进制文件中

dontStrip = true;

Stripping would remove the embedded JS, breaking the program.
</bun_compiled_binaries>

<checking_tarball_contents>
**Inspect npm package structure**:

```bash
dontStrip = true;

剥离操作会移除嵌入的JS代码,导致程序无法运行。
</bun_compiled_binaries>

<checking_tarball_contents>
**检查npm包结构**:

```bash

After nix-prefetch-url

在nix-prefetch-url之后

ls -la /nix/store/*-pkg-1.0.0.tgz/
ls -la /nix/store/*-pkg-1.0.0.tgz/

Common layouts:

常见布局:

dist/cli.js → Pre-built, use directly

dist/cli.js → 预构建包,可直接使用

dist/index.js → Main entry, check package.json "bin"

dist/index.js → 主入口,需检查package.json的"bin"字段

src/index.ts → Source only, need to build

src/index.ts → 仅源码,需要构建

lib/ → Built CommonJS

lib/ → 已构建的CommonJS模块

esm/ → Built ES modules

esm/ → 已构建的ES模块


Check package.json to find the correct entry point.
</checking_tarball_contents>
</common_patterns>

<anti_patterns>
<avoid_these>
**Don't do this**:

❌ Hardcode node paths:
```nix

查看package.json以找到正确的入口点。
</checking_tarball_contents>
</common_patterns>

<anti_patterns>
<avoid_these>
**请勿执行以下操作**:

❌ 硬编码node路径:
```nix

Bad

错误

"#!/usr/bin/node" # Won't work on NixOS

✅ Use substituteInPlace:
```nix
"#!/usr/bin/node" # 在NixOS上无法工作

✅ 使用substituteInPlace:
```nix

Good

正确

substituteInPlace $out/bin/tool
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"

❌ Skip hash verification:
```nix
substituteInPlace $out/bin/tool
--replace-quiet "#!/usr/bin/env node" "#!${nodejs}/bin/node"

❌ 跳过哈希验证:
```nix

Bad - insecure

错误 - 不安全

hash = lib.fakeHash;

✅ Get real hash:
```nix
hash = lib.fakeHash;

✅ 使用真实哈希值:
```nix

Good - reproducible and secure

正确 - 可复现且安全

hash = "sha256-actual-hash-here";

❌ Forget to make executable:
```nix
hash = "sha256-actual-hash-here";

❌ 忘记设置可执行权限:
```nix

Bad - won't run

错误 - 无法运行

cp $src/dist/cli.js $out/bin/tool

✅ Set executable bit:
```nix
cp $src/dist/cli.js $out/bin/tool

✅ 设置可执行位:
```nix

Good

正确

cp $src/dist/cli.js $out/bin/tool chmod +x $out/bin/tool

❌ Strip Bun binaries:
```nix
cp $src/dist/cli.js $out/bin/tool chmod +x $out/bin/tool

❌ 剥离Bun二进制文件:
```nix

Bad - breaks Bun-compiled executables

错误 - 破坏Bun编译的可执行文件

(default behavior strips binaries)

(默认行为会剥离二进制文件)


✅ Disable stripping:
```nix

✅ 禁用剥离:
```nix

Good

正确

dontStrip = true;
</avoid_these>
</anti_patterns>

<troubleshooting>
<hash_mismatch>
**Error: "hash mismatch in fixed-output derivation"**

The hash you provided doesn't match what Nix fetched.

Solution:
1. Nix error shows "got: sha256-XYZ..."
2. Copy that hash into your derivation
3. Rebuild

For `fetchBunDeps`, this is expected the first time—use the error output to get the correct hash.
</hash_mismatch>

<missing_executable>
**Error: Binary not found after build**

Check:
```bash
dontStrip = true;
</avoid_these>
</anti_patterns>

<troubleshooting>
<hash_mismatch>
**错误:"hash mismatch in fixed-output derivation"**

你提供的哈希值与Nix获取的内容不匹配。

解决方法:
1. Nix错误信息会显示"got: sha256-XYZ..."
2. 将该哈希值复制到你的派生包定义中
3. 重新构建

对于`fetchBunDeps`,首次构建时出现此错误是正常的——使用错误输出中的正确哈希值即可。
</hash_mismatch>

<missing_executable>
**错误:构建后未找到二进制文件**

检查以下内容:
```bash

List what was actually built

列出实际构建的内容

ls -R result/
ls -R result/

Check package.json "bin" field

检查package.json的"bin"字段

cat /nix/store/*-source/package.json | jq .bin
cat /nix/store/*-source/package.json | jq .bin

Check build output location

检查构建输出目录

cat /nix/store/*-source/package.json | jq .scripts.build

The build might output to a different directory than expected.
</missing_executable>

<elf_interpreter_error>
**Error: "No such file or directory" when running binary (Linux)**

The binary needs ELF patching for native dependencies.

Solution:
```nix
nativeBuildInputs = [
  autoPatchelfHook
];

buildInputs = [
  stdenv.cc.cc.lib
];
For node_modules with native addons:
nix
buildPhase = ''
  cp -R ${node_modules}/node_modules .
  chmod -R u+w node_modules
  autoPatchelf node_modules  # Patch .node files
'';
</elf_interpreter_error>
<bun_lock_mismatch> Error: "bun.lock mismatch"
The lockfile in your source doesn't match the cached dependencies.
This happens when:
  • Source version updated but dependency hash not updated
  • Source repo has uncommitted lockfile changes
Solution:
  1. Update source hash to match new version
  2. Set dependency hash to
    lib.fakeHash
  3. Build to get correct dependency hash
  4. Update dependency hash
  5. Rebuild </bun_lock_mismatch> </troubleshooting>
<validation> <build_checklist> Before considering the package done:
  • nix build .#package-name
    succeeds
  • ./result/bin/tool --version
    works
  • ./result/bin/tool --help
    works
  • nix flake check
    passes
  • meta.description
    is clear and concise
  • meta.homepage
    points to project site
  • meta.license
    is correct
  • meta.sourceProvenance
    matches what you packaged
  • meta.mainProgram
    is set
  • meta.platforms
    is appropriate for the tool
  • All hashes are real (no
    lib.fakeHash
    )
  • Shebangs use Nix store paths, not /usr/bin
  • File is formatted with
    nix fmt
    </build_checklist>
<testing_on_other_platforms> If you only have Linux but package claims
platforms.all
:
Consider asking maintainers with macOS/ARM to test, or:
  • Mark platforms conservatively based on what you can test
  • Note in package that other platforms are untested
  • Let CI or other contributors expand platform support </testing_on_other_platforms> </validation>
<success_criteria> A well-packaged npm tool has:
  • Clean build with no warnings or errors
  • Working executable in
    result/bin/
  • Complete and accurate metadata
  • Proper source provenance classification
  • All dependencies resolved (no missing libraries)
  • Reproducible builds (real hashes, no network access during build)
  • Follows Nix packaging conventions (shebang patching, proper phases) </success_criteria>
cat /nix/store/*-source/package.json | jq .scripts.build

构建产物可能输出到了预期之外的目录。
</missing_executable>

<elf_interpreter_error>
**错误:运行二进制文件时提示"No such file or directory"(Linux)**

该二进制文件需要对原生依赖进行ELF修补。

解决方法:
```nix
nativeBuildInputs = [
  autoPatchelfHook
];

buildInputs = [
  stdenv.cc.cc.lib
];
对于包含原生扩展的node_modules:
nix
buildPhase = ''
  cp -R ${node_modules}/node_modules .
  chmod -R u+w node_modules
  autoPatchelf node_modules  # 修补.node文件
'';
</elf_interpreter_error>
<bun_lock_mismatch> 错误:"bun.lock mismatch"
源码中的锁文件与缓存的依赖不匹配。
出现此问题的场景:
  • 源码版本更新但依赖哈希值未更新
  • 源码仓库存在未提交的锁文件变更
解决方法:
  1. 更新源码哈希值以匹配新版本
  2. 将依赖哈希值设置为
    lib.fakeHash
  3. 构建以获取正确的依赖哈希值
  4. 更新依赖哈希值
  5. 重新构建 </bun_lock_mismatch> </troubleshooting>
<validation> <build_checklist> 在确认包完成前,请检查以下项:
  • nix build .#package-name
    执行成功
  • ./result/bin/tool --version
    可正常运行
  • ./result/bin/tool --help
    可正常运行
  • nix flake check
    检查通过
  • meta.description
    清晰简洁
  • meta.homepage
    指向项目官网
  • meta.license
    设置正确
  • meta.sourceProvenance
    与打包内容匹配
  • meta.mainProgram
    已设置
  • meta.platforms
    与工具支持的平台相符
  • 所有哈希值均为真实值(无
    lib.fakeHash
  • Shebang使用Nix存储路径,而非/usr/bin
  • 文件已使用
    nix fmt
    格式化 </build_checklist>
<testing_on_other_platforms> 如果你仅使用Linux但包声明支持
platforms.all
:
可以联系使用macOS/ARM的维护者进行测试,或:
  • 根据你能测试的内容保守标记平台
  • 在包中注明其他平台未测试
  • 让CI或其他贡献者扩展平台支持 </testing_on_other_platforms> </validation>
<success_criteria> 一个良好打包的npm工具应具备以下特性:
  • 构建过程无警告或错误
  • result/bin/
    目录下存在可正常工作的可执行文件
  • 元数据完整且准确
  • 正确分类源码来源
  • 所有依赖已解析(无缺失库)
  • 构建可复现(使用真实哈希值,构建过程无网络访问)
  • 遵循Nix打包规范(Shebang修补、正确的构建阶段) </success_criteria>