跳至主要內容

Exec 協定

exec: 協定會在取得時於暫存目錄中執行 Node.js 指令碼,並使用預先設定的執行時間環境。然後,此指令碼預期會填入環境中定義的特殊目錄,並在產生完成後結束。

yarn add my-pkg@exec:./package-builder.js

您為何需要

典型的 Yarn 取得器會從網際網路下載套件 - 如果您想使用的專案事先已打包,這樣做會很順利,但只要您需要自行打包,就會失敗。Yarn 的內建機制允許您在相容的 git 儲存庫上執行 prepare 指令碼,並將結果用作最終套件,但即使這樣也不總是足夠 - 您可能需要複製特定分支、進入特定目錄、執行特定建置指令碼 ... 所有這些事情都讓我們難以支援每一個使用案例。

exec: 協定表示一種方法,讓您自行定義如何取得指定的套件。在某種意義上,它可以被視為 Yarn 提供的 取得器 API 的更高級版本。

產生器指令碼和 require

由於產生器會在非常特殊的環境中被呼叫(在任何套件已安裝在磁碟上之前),它將無法呼叫 require 函式(即使使用相對路徑)。如果您需要非常複雜的產生器,只需使用 Webpack 或 Rollup 等工具將它們事先打包在單一指令碼中。

由於此限制,且產生器幾乎總是需要使用 Node 內建模組,因此這些模組會在全域範圍內提供 - 與 Node REPL 已執行的操作方式非常類似。因此,無需手動要求 fs 模組:它可透過全域 fs 變數取得!

執行時間環境

為了讓腳本了解產生程序中涉及的各種預定義資料夾,Yarn 將注入一個腳本可用的特殊 execEnv 全域變數。此物件的 介面 定義如下

屬性類型說明
tempDir字串腳本可自由使用的空暫存目錄的絕對路徑。在呼叫腳本之前自動建立。
buildDir字串腳本預期會產生封裝檔案的空目錄的絕對路徑。在呼叫腳本之前自動建立。
locator字串識別產生器封裝的字串化 定位器

您可以在 execEnv.tempDir 中執行任何您想做的事,但在執行結束時,Yarn 會預期 execEnv.buildDir 包含可壓縮成封存檔並儲存在快取中的檔案。

範例

產生 hello world 封裝

fs.writeFileSync(path.join(execEnv.buildDir, 'package.json'), JSON.stringify({
name: 'hello-world',
version: '1.0.0',
}));

fs.writeFileSync(path.join(execEnv.buildDir, 'index.js'), `
module.exports = 'hello world!';
`);

複製單一儲存庫並建置特定封裝

const pathToRepo = path.join(execEnv.tempDir, 'repo');
const pathToArchive = path.join(execEnv.tempDir, 'archive.tgz');
const pathToSubpackage = path.join(pathToRepo, 'packages/foobar');

// Clone the repository
child_process.execFileSync(`git`, [`clone`, `git@github.com:foo/bar`, pathToRepo]);

// Install the dependencies
child_process.execFileSync(`yarn`, [`install`], {cwd: pathToRepo});

// Pack a specific workspace
child_process.execFileSync(`yarn`, [`pack`, `--out`, pathToArchive], {cwd: pathToSubpackage});

// Send the package content into the build directory
child_process.execFileSync(`tar`, [`-x`, `-z`, `--strip-components=1`, `-f`, pathToArchive, `-C`, execEnv.buildDir]);