Javascript
مقدمه
این بخش شامل دستورالعملهایی درباره نحوه بستهبندی برنامههای JavaScript است.
ابزارهای مختلف موجود در tools-overview فهرست خواهند شد. سپس برخی از اصول عمومی برای بستهبندی ارائه میشود. در نهایت، دستورالعملهای خاص هر ابزار داده خواهد شد.
برطرف کردن بنبست / یافتن نمونههای کد
اگر احساس میکنید برای بستهبندی برنامههای JavaScript ایده یا الهام کافی ندارید، لینکهای زیر ممکن است مفید واقع شوند. جستجوی آنلاین برای کارهای قبلاً انجامشده میتواند در صورت مواجهه با مشکلاتی که پیشتر حل شدهاند، مفید باشد.
Github {'{'}#javascript-
- گاهی اوقات مخزن بالادستی فرض میکند که برخی وابستگیها باید به صورت سراسری نصب شوند. در این حالت، میتوانید آنها را به صورت دستی به
package.jsonبالادستی اضافه کنید (yarn add
yarn build:ui
yarn build:server
# OR
npm run build:ui
npm run build:server های صریح روی آن ایده خوبی است. در ادامه یک مثال آورده شده است:
Let's check spacing and sentence structure:
{
patchedPackageJSON = final.runCommand "package.json" { } ''
${jq}/bin/jq '.version = "0.4.0" |
.devDependencies."@jsdoc/cli" = "^0.2.5"
${sonar-src}/package.json > $out
'';
} همچنان لازم است نسخه تغییریافته فایلهای قفل (lock files) را کامیت کنید، اما حداقل بازنشانیها بهطور صریح برای همگان قابل مشاهده است.
استفاده مستقیم از node_modules
{
lib,
buildNpmPackage,
fetchFromGitHub,
}:
buildNpmPackage (finalAttrs: {
pname = "flood";
version = "4.7.0";
src = fetchFromGitHub {
owner = "jesec";
repo = "flood";
tag = "v${finalAttrs.version}";
hash = "sha256-BR+ZGkBBfd0dSQqAvujsbgsEPFYw/ThrylxUbOksYxM=";
};
npmDepsHash = "sha256-tuEfyePwlOy2/mOPdXbqJskO6IowvAP4DWg8xSZwbJw=";
# The prepack script runs the build script, which we'd rather do in the build phase.
npmPackFlags = [ "--ignore-scripts" ];
NODE_OPTIONS = "--openssl-legacy-provider";
meta = {
description = "Modern web UI for various torrent clients with a Node.js backend and React frontend";
homepage = "https://flood.js.org";
license = lib.licenses.gpl3Only;
maintainers = with lib.maintainers; [ winter ];
};
}) در فاز نصب (installPhase) پیشفرض که توسط buildNpmPackage تنظیم میشود، از npm pack --json --dry-run برای تصمیمگیری درباره فایلهای قابل نصب در $out/lib/node_modules/$name/ استفاده میشود، که در آن $name همان رشته name تعریفشده در package.json متعلق به بسته است.
علاوه بر این، کلیدهای bin و man در package.json کد منبع برای تصمیمگیری در مورد اینکه چه باینریها و صفحات راهنمایی (manpages) باید نصب شوند، استفاده میشوند.
اگر این موارد تعریف نشده باشند، ممکن است npm pack برخی از فایلها را ندیده بگیرد و هیچ باینری تولید نشود.
آرگومانها
npmDepsHash: هش خروجی وابستگیها برای این پروژه. میتواند از قبل باprefetch-npm-depsمحاسبه شود.makeCacheWritable: آیا کش پیش از نصب
$ ls
package.json package-lock.json index.js
$ prefetch-npm-deps package-lock.json
...
sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= fetchNpmDeps
fetchNpmDeps یک تابع Nix است که به آرگومانهای اجباری زیر نیاز دارد:
src: یک پوشه / تاربال دارای فایلpackage-lock.jsonhash: هش خروجی وابستگیهای node تعریفشده درpackage-lock.json.
این تابع یک derivation / اشتقاق ساخت را برمیگرداند که تمام وابستگیهای package-lock.json در $out/ آن بارگیری شدهاند و به عنوان کش npm قابل استفاده است.
importNpmLock
این تابع ارجاعات وابستگی npm را در package.json و package-lock.json با مسیرهایی به انبار نیکس (Nix store) جایگزین میکند.
نحوه دریافت هر وابستگی را میتوان با آرگومان fetcherOpts سفارشیسازی کرد.
این روش جایگزینی سادهتر و راحتتر برای fetchNpmDeps جهت مدیریت وابستگیهای npm در Nixpkgs است.
نیازی به تعیین یک hash نیست، زیرا کاملاً به هشهای یکپارچگی موجود در فایل package-lock.json متکی است.
ورودیها {'{'}#javascript-build
{ buildNpmPackage, importNpmLock }:
buildNpmPackage {
pname = "hello";
version = "0.1.0";
src = ./.;
npmDeps = importNpmLock { npmRoot = ./.; };
npmConfigHook = importNpmLock.npmConfigHook;
} مثال
نمونه استفاده از
pkgs.importNpmLockهمراه باfetcherOpts
importNpmLockاز دریافتکنندههای زیر استفاده میکند:
pkgs.fetchurlبرای وابستگیهایhttp(s)fetchGitبرای وابستگیهایgitدر صورت نیاز، امکان ارائه آرگومانهای اضافی به دریافتکنندههای فردی وجود دارد:
{ buildNpmPackage, importNpmLock }: buildNpmPackage { pname = "hello"; version = "0.1.0"; src = ./.; npmDeps = importNpmLock { npmRoot = ./.; fetcherOpts = { # Pass 'curlOptsList' to 'pkgs.fetchurl' while fetching 'axios' "node_modules/axios" = { curlOptsList = [ "--verbose" ]; }; }; }; npmConfigHook = importNpmLock.npmConfigHook; }
importNpmLock.buildNodeModules
تابع importNpmLock.buildNodeModules یک درایویشن شامل یک پوشه node_modules پیش
pkgs.mkShell {
packages = [
importNpmLock.hooks.linkNodeModulesHook
nodejs
];
npmDeps = importNpmLock.buildNodeModules {
npmRoot = ./.;
inherit nodejs;
};
} ، یک پوشه node_modules ساخته شده و بستهها به انبار نیکس (Nix store) پیوند نمادین (symlink) داده میشوند.
نکته
دستوراتی مانند
npm installوnpm addکه بستهها و فایلهای اجر
{ fetchPnpmDeps, nodejs, pnpm_11, pnpmConfigHook, stdenv, }: let # It is recommended to pin pnpm to a major version, due to regular breaking changes in the store format # The latest major version is always available under `pkgs.pnpm` # Optionally override pnpm to use a custom nodejs version # Make sure that the same nodejs version is referenced in nativeBuildInputs # pnpm = pnpm_11.override { nodejs = nodejs_24; }; pnpm = pnpm_11; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs # in case scripts are run outside of a pnpm call pnpmConfigHook pnpm # At least required by pnpmConfigHook, if not other (custom) phases ]; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; inherit pnpm; fetcherVersion = 4; hash = "..."; }; })شدیداً توصیه میشود برای افزایش بازتولیدپذیری در آینده، از یک نسخه ثابتشده از pnpm (یعنی
pnpm_9یاpnpm_10) استفاده کنید
{ fetchPnpmDeps, nodejs, - pnpm, + pnpm_10, pnpmConfigHook, stdenv, }: +let + # Optionally override pnpm to use a custom nodejs version + # Make sure that the same nodejs version is referenced in nativeBuildInputs + # pnpm = pnpm_10.override { nodejs-slim = nodejs-slim_22; }; +in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs # in case scripts are run outside of a pnpm call pnpmConfigHook - pnpm # At least required by pnpmConfigHook, if not other (custom) phases + pnpm_10 # At least required by pnpmConfigHook, if not other (custom) phases ]; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; + pnpm = pnpm_10; fetcherVersion = 4; hash = "..."; }; })در صورتی که در حال پچ کردن
package.jsonیاpnpm-lock.yamlهستید، حتماًfinalAttrs.patches
{ # ... pnpmDeps = fetchPnpmDeps { # ... inherit (finalAttrs) pnpmInstallFlags; }; pnpmInstallFlags = [ "--shamefully-hoist" ]; }در صورت نیاز، میتوان از
dontPnpmConfigure = true;برای غیرفعالسازی کاملpnpmConfigHookبدون حذف دستی آن از ورودیها استفاده کرد.. ├── frontend │ ├── ... │ ├── package.json │ └── pnpm-lock.yaml └── ...
{ # ... pnpmDeps = fetchPnpmDeps { # ... sourceRoot = "${finalAttrs.src.name}/frontend"; }; # by default the working directory is the extracted source pnpmRoot = "frontend"; }فضاهای کاری PNPM
اگر برای پروژه خود نیاز به استفاده از یک فضای کاری PNPM دارید، مقدار
pnpmWorkspaces = [ "<workspace project name 1>" "<workspace project name 2>" ]و غیره را در فراخوانیfetchPnpmDepsخود تنظیم کنید، که باعث میشود PNPM فقط وابستگیها را برای همان بستههای فضای کاری نصب کند.برای مثال:
{ # ... pnpmWorkspaces = [ "@astrojs/language-server" ]; pnpmDeps = fetchPnpmDeps { #... inherit (finalAttrs) pnpmWorkspaces; }; }
کار نخواهد کرد. یکbuildPhaseبر اساس نمونه زیر احتمالاً برای اکثر پروژههای فضای کاری مناسب خواهد بود:Wait, check
npmHooks.npmBuildHook
{ buildPhase = '' runHook preBuild pnpm --filter=@astrojs/language-server build runHook postBuild ''; }دستورات و تنظیمات اضافی PNPM
اگر به اعمال یک گزینه پیکربندی اضافی PNPM (مانند
dedupe-peer-dependentsیا موارد مشابه) نیاز دارید،prePnpmInstallرا روی دستورات مناسب جهت اجرا تنظیم کنید. برای مثال:
{ prePnpmInstall = '' pnpm config set dedupe-peer-dependents false ''; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) prePnpmInstall; # ... }; }در این مثال،
prePnpmInstallهم توسطpnpmConfigHookو هم توسط سازندهfetchPnpmDepsاجرا خواهد شد.pnpm
fetcherVersionاین نسخهٔ خروجی
fetchPnpmDepsاست. بستههای جدید باید از4استفاده کنند:
{ # ... pnpmDeps = fetchPnpmDeps { # ... fetcherVersion = 4; hash = "..."; # clear this hash and generate a new one }; }هنگام ارتقا به یک
fetcherVersionجدیدتر، باید هش را دوباره تولید کنید.این متغیر تضمین میکند که میتوانیم تغییراتی در خروجی
fetchPnpmDepsایجاد کنیم بدون اینکه هشهای موجود شکسته شوند. تغییرات میتوانند شامل راهکارهای مو
{ lib, stdenv, fetchFromGitHub, fetchYarnDeps, yarnConfigHook, yarnBuildHook, yarnInstallHook, nodejs, }: stdenv.mkDerivation (finalAttrs: { pname = "..."; version = "..."; src = fetchFromGitHub { owner = "..."; repo = "..."; tag = "v${finalAttrs.version}"; hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; }; yarnOfflineCache = fetchYarnDeps { yarnLock = finalAttrs.src + "/yarn.lock"; hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; }; nativeBuildInputs = [ yarnConfigHook yarnBuildHook yarnInstallHook # Needed for executing package.json scripts nodejs ]; meta = { # ... }; })پیش از نصب را غیرفعال میکند.
Section 4:
Yarn Berry v3/v4
Yarn Berry (v3 / v4) have similar formats, they start with blocks like these:
Yarn Berry
__metadata: version: 6 cacheKey: 8[cX]
__metadata: version: 8 cacheKey: 10[cX]برای این بستهها، برخی ابزارهای کمکی در زیر بستههای مربوطهٔ
yarn-berry_3وyarn-berry_4ارائه شدهاند:
{ stdenv, nodejs, yarn-berry_4, }: let yarn-berry = yarn-berry_4; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs yarn-berry.yarnBerryConfigHook ]; offlineCache = yarn-berry.fetchYarnBerryDeps { inherit (finalAttrs) src; hash = "..."; }; })
yarn-berry_X.fetchYarnBerryDeps
fetchYarnBerryDepsدستورyarn-berry-fetcher fetchرا در یک derivation با خروجی ثابت (fixed-output derivation) اجرا میکند. این یک دریافتکننده سفارشی است که برای بارگیری بازتولیدپذیر تمام فایلهای موجود در فایلyarn.lockو اعتبارسنجی هشهای آنها در طول این فرآیند طراحی شده است. برای وابستگیهای git، یک چکاوت (checkout) در مسیر${'{'}'{'{'}'{'}'}offlineCache{'{'}'{'}'}'{'}'}/checkouts/<40-character-commit-hash>ایجاد میکند (که برای توصیف محتوای چکاوت
$ yarn-berry-fetcher prefetch </path/to/yarn.lock> [/path/to/missing-hashes.json]این خروجی، هش را در stdout چاپ میکند و میتوان از آن در اسکریپتهای بهروزرسانی برای محاسبهی مجدد هش برای نسخه جدیدی از
yarn.lockاستفاده کرد.
yarn-berry_X.yarnBerryConfigHook
yarnBerryConfigHookاز مسیر انبار کهofflineCacheبه آن اشاره دارد برای اجرایyarn installدر طول ساخت استفاده میکند و یک پوشهnode_modulesقابل استفاده از وابستگیهای دانلودشده تولید مینماید.به صورت داخلی، این ابزار از نسخه پچشدهای از Yarn استفاده میکند تا مطمئن شود وابستگیهای git دوباره بستهبندی میشوند و هرگونه تلاش برای دانلود بلافاصله با شکست مواجه میشود.
پچ کردن فایلهای
package.jsonیاyarn.lockبالادستیدر صورتی که به پچ کردن
package.jsonیاyarn.lockبال
{ stdenv, nodejs, yarn-berry_4, }: let yarn-berry = yarn-berry_4; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs yarn-berry.yarnBerryConfigHook ]; missingHashes = ./missing-hashes.json; offlineCache = yarn-berry.fetchYarnBerryDeps { inherit (finalAttrs) src missingHashes; hash = "..."; }; })خارج از Nixpkgs
ابزارهای دیگری نیز در دسترس هستند که به زبان Nix نوشته شدهاند. این ابزارها نمیتوانند در داخل Nixpkgs استفاده شوند زیرا به Import From Derivation نیاز دارند، که در Nixpkgs مجاز نیست.
اگر در حال بستهبندی چیزی خارج از Nixpkgs هستید، موارد زیر را در نظر بگیرید:
npmlock2nix {'{'}#javascript-