插件教學
從 Yarn 2 開始,Yarn 現在支援插件。有關它們是什麼以及在何種情況下你會想要使用它們的更多資訊,請參閱專屬頁面。我們將在此討論撰寫插件所需的具體步驟。這真的很簡單!
插件是什麼樣子?
插件是在執行時期由 Yarn 載入的腳本,並且可以將新的行為注入其中。它們還可以要求 Yarn 本身提供的某些套件,例如 @yarnpkg/core
。這允許你使用與目前使用的 Yarn 二進位檔完全相同的核心 API,就像它是對等相依性一樣!
由於插件是在 Yarn 啟動之前載入(因此在你進行第一次安裝之前),強烈建議你以不依賴的方式撰寫插件。如果這變得困難,請知道我們提供了一個強大的工具(@yarnpkg/builder
),它可以將你的插件捆綁成一個單一的 Javascript 檔案,準備好發布。
撰寫我們的首個插件
在文字編輯器中開啟一個名為 plugin-hello-world.js
的新檔案,並輸入以下程式碼
module.exports = {
name: `plugin-hello-world`,
factory: require => ({
// What is this `require` function, you ask? It's a `require`
// implementation provided by Yarn core that allows you to
// access various packages (such as @yarnpkg/core) without
// having to list them in your own dependencies - hence
// lowering your plugin bundle size, and making sure that
// you'll use the exact same core modules as the rest of the
// application.
//
// Of course, the regular `require` implementation remains
// available, so feel free to use the `require` you need for
// your use case!
})
};
我們有我們的外掛程式,但現在我們需要註冊它,讓 Yarn 知道在哪裡可以找到它。為此,我們只需在儲存庫根目錄的 .yarnrc.yml
檔案中新增一個項目
plugins:
- ./plugin-hello-world.js
就是這樣!你有了你的第一個外掛程式,恭喜!當然它沒有做太多(或根本沒做任何事),但我們將看看如何擴充它以使其更強大。
多合一外掛程式建構器
正如我們所見,外掛程式應該是獨立的 JavaScript 原始檔。手動撰寫它們非常可行,特別是如果你只需要一個小的外掛程式,但一旦你開始新增多個指令,它可能會變得有點複雜。為了簡化這個過程,我們維護一個名為 @yarnpkg/builder
的套件。這個建構器對 Yarn 來說就像 Next.js 對網路開發一樣 - 它是一個旨在協助建立、建構和管理使用 TypeScript 編寫的複雜外掛程式的工具。
其文件可以在 專屬頁面 中找到,但請記住你不需要使用它。有時好的舊腳本就很好!
新增指令
外掛程式也可以註冊自己的指令。為此,我們只需使用 clipanion
函式庫撰寫它們 - 我們甚至不必將它新增到我們的相依性!讓我們看一個範例
module.exports = {
name: `plugin-hello-world`,
factory: require => {
const {BaseCommand} = require(`@yarnpkg/cli`);
class HelloWorldCommand extends BaseCommand {
static paths = [[`hello`]];
async execute() {
this.context.stdout.write(`This is my very own plugin 😎\n`);
}
}
return {
commands: [
HelloWorldCommand,
],
};
}
};
現在,嘗試執行 yarn hello
。你會看到你的訊息出現!請注意,你可以使用 clipanion 提供的完整功能集,包括短選項、長選項、可變引數清單,... 你甚至可以使用我們提供的 typanion
函式庫驗證你的選項。以下是我們只接受數字作為參數的範例
module.exports = {
name: `plugin-addition`,
factory: require => {
const {BaseCommand} = require(`@yarnpkg/cli`);
const {Command, Option} = require(`clipanion`);
const t = require(`typanion`);
class AdditionCommand extends BaseCommand {
static paths = [[`addition`]];
// Show descriptive usage for a --help argument passed to this command
static usage = Command.Usage({
description: `hello world!`,
details: `
This command will print a nice message.
`,
examples: [[
`Add two numbers together`,
`yarn addition 42 10`,
]],
});
a = Option.String({validator: t.isNumber()});
b = Option.String({validator: t.isNumber()});
async execute() {
this.context.stdout.write(`${this.a}+${this.b}=${this.a + this.b}\n`);
}
}
return {
commands: [
AdditionCommand,
],
};
},
};
使用掛鉤
外掛程式可以註冊到 Yarn 生命週期中的各種事件,並提供額外的資訊來改變它們的行為。為此,你只需在外掛程式中宣告一個新的 hooks
屬性,並為你想要偵聽的每個掛鉤新增成員
module.exports = {
name: `plugin-hello-world`,
factory: require => ({
hooks: {
setupScriptEnvironment(project, scriptEnv) {
scriptEnv.HELLO_WORLD = `my first plugin!`;
},
},
})
};
在此範例中,我們註冊到 setupScriptEnvironment
掛勾,並使用它將參數注入到環境中。現在,每次執行腳本時,你會看到你的環境會包含一個名為 HELLO_WORLD
的新值!
掛勾很多,而且我們仍在開發中。根據你的回饋,可能會新增、移除或變更某些掛勾。因此,如果你想執行掛勾尚未允許你執行的操作,請告訴我們!
使用 Yarn API
Yarn 的大多數掛勾會使用各種參數呼叫,這些參數會告訴你更多關於呼叫掛勾的背景資訊。每個掛勾的確切參數清單都不相同,但通常它們的類型在 @yarnpkg/core
函式庫中定義。
在此範例中,我們將整合 afterAllInstalled
掛勾,以便在每次安裝後列印一些關於依賴項樹的基本資訊。此掛勾會使用額外的參數呼叫,該參數是公開的 Project
實例,其中包含 Yarn 關於專案收集的大部分資訊:依賴項、套件清單、工作區資訊等。
const fs = require(`fs`);
const util = require(`util`);
module.exports = {
name: `plugin-project-info`,
factory: require => {
const {structUtils} = require(`@yarnpkg/core`);
return {
default: {
hooks: {
afterAllInstalled(project) {
let descriptorCount = 0;
for (const descriptor of project.storedDescriptors.values())
if (!structUtils.isVirtualDescriptor(descriptor))
descriptorCount += 1;
let packageCount = 0;
for (const pkg of project.storedPackages.values())
if (!structUtils.isVirtualLocator(pkg))
packageCount += 1;
console.log(`This project contains ${descriptorCount} different descriptors that resolve to ${packageCount} packages`);
}
}
}
};
}
};
這變得有趣了。如你所見,我們從專案實例中存取了 storedDescriptors
和 storedPackages
欄位,並反覆運算它們以取得非虛擬項目數目(虛擬套件在此處有更詳細的說明在此處)。這是一個非常簡單的用例,但我們可以執行更多操作:專案根目錄位於 cwd
屬性中,工作區公開為 workspaces
,描述符和套件之間的連結可透過 storedResolutions
執行,... 等等。
請注意,我們僅觸及了 Project
類別實例的表面!Yarn 核心提供許多其他類別(和掛勾),讓你能夠使用快取、下載套件、觸發 http 要求等,以及更多功能。下次你想要撰寫外掛程式時,請查看一下,幾乎可以肯定會有一個工具程式,讓你能夠避免重新實作輪子。
使用 YARN_PLUGINS
環境變數動態載入外掛程式
雖然外掛程式通常在 .yarnrc.yml
設定檔中宣告,但這些代表使用者導向的設定,第三方工具不應在未經使用者允許的情況下修改。
YARN_PLUGINS
環境變數是一個分號分隔的插件路徑清單,Yarn 在被呼叫時會動態載入這些路徑。路徑會根據 Yarn 被呼叫時的 startingCwd
進行解析。
套件可以使用此機制動態註冊插件,並使用命令查詢 Yarn API,而無需明確依賴 Yarn 套件並處理潛在的版本不匹配問題。
官方掛鉤
我們的全新網站尚不支援產生掛鉤清單;抱歉 :(