Featured image of post Strauss:Mozart 的繼承者,WordPress 外掛依賴隔離的更好選擇

Strauss:Mozart 的繼承者,WordPress 外掛依賴隔離的更好選擇

Strauss 是從 Mozart fork 出來的 Composer 依賴前綴工具,解決了 Mozart 幾個已知問題:支援 files autoloader、常數前綴、license 合規、零設定開箱即用。WordPress 外掛開發的現代選擇。

如果你看過 Mozart 的介紹,知道它在解決什麼問題:WordPress 外掛共用同一個 PHP process,不同外掛用同一個 library 的不同版本會炸,Mozart 把你的 vendor 依賴加上 namespace 前綴來隔離。

Strauss 從 Mozart fork 出來,解決了幾個 Mozart 的已知限制,現在是社群更推薦的選擇。

Strauss 改了什麼

問題MozartStrauss
files autoloader 支援有限完整支援
常數前綴(define()不支援支援
函式前綴不支援v0.21.0 起支援
License 合規可能有問題修改 header,保留 license 檔案
預設行為可能刪原始檔案非破壞性預設
零設定需要設定可以完全不設定
測試覆蓋率有限完整 PHPUnit 測試

安裝

推薦:PHAR 方式

1
mkdir bin && touch bin/.gitkeep

.gitignore 加上:

1
bin/strauss.phar

composer.json 加上 scripts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "scripts": {
    "prefix-namespaces": [
      "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/latest/download/strauss.phar'",
      "@php bin/strauss.phar",
      "@composer dump-autoload"
    ],
    "post-install-cmd": ["@prefix-namespaces"],
    "post-update-cmd": ["@prefix-namespaces"]
  }
}

第一次執行時自動下載 PHAR,之後直接用快取的。

或者 require 進專案

1
composer require --dev brianhenryie/strauss

設定

Strauss 可以完全不設定(零設定),它會從你的 composer.json 自動推斷 namespace 前綴和目標目錄。

需要自訂時,加在 extra.strauss

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "extra": {
    "strauss": {
      "target_directory": "vendor-prefixed",
      "namespace_prefix": "MyPlugin\\Vendor\\",
      "classmap_prefix": "MyPlugin_",
      "constant_prefix": "MYPLUGIN_",
      "packages": [
        "guzzlehttp/guzzle"
      ],
      "exclude_from_copy": {
        "packages": ["psr/container"],
        "namespaces": ["Psr\\Log\\"],
        "file_patterns": ["\\.md$"]
      },
      "exclude_from_prefix": {
        "namespaces": ["Psr\\"]
      }
    }
  }
}
選項說明
target_directory處理後的檔案放哪(預設 vendor-prefixed
namespace_prefix加在 namespace 前面的前綴
classmap_prefix沒有 namespace 的 class 前綴
constant_prefixdefine() 常數的前綴
exclude_from_copy不要複製的套件、namespace、檔案
exclude_from_prefix複製但不加前綴(例如 PSR 標準介面)

執行

1
composer prefix-namespaces

或者直接:

1
php bin/strauss.phar

乾跑預覽(不實際修改檔案):

1
php bin/strauss.phar --dry-run

常數前綴

Mozart 不支援 define() 的前綴,Strauss 支援:

1
2
3
4
5
// 你的依賴裡有
define('GUZZLE_VERSION', '7.0');

// Strauss 改成
define('MYPLUGIN_GUZZLE_VERSION', '7.0');

常數也是全域的,跟 class 一樣會衝突,這個功能對某些套件很重要。

files autoloader 支援

有些套件用 files autoloader(不是 PSR-4,直接 require 檔案),Mozart 對這種支援有限,Strauss 完整處理:

1
2
3
4
// 套件的 composer.json
"autoload": {
    "files": ["src/functions.php"]
}

Strauss 會複製並前綴化這些檔案,確保不漏掉。

在外掛裡載入

1
2
3
4
5
6
// plugin.php
require_once __DIR__ . '/vendor-prefixed/autoload.php';

use MyPlugin\Vendor\GuzzleHttp\Client;

$client = new Client();

或者讓 Strauss 把 autoloader 注入進 vendor/autoload.php

1
php bin/strauss.phar include-autoloader

這樣只需要 require vendor/autoload.php,不需要另外 require vendor-prefixed/autoload.php

License 合規

Strauss 在修改的每個檔案 header 加上注記,並保留原始 license 檔案。Mozart 這一塊有疑慮,開源 license 通常要求保留原始聲明,Strauss 直接處理這個問題。

跟 Mozart 設定相容

如果你原本用 Mozart,Strauss 可以直接讀 Mozart 的 extra.mozart 設定,不需要馬上改:

1
2
3
4
5
6
7
{
  "extra": {
    "mozart": {
      "dep_namespace": "MyPlugin\\Dependencies\\"
    }
  }
}

Strauss 會自動識別並套用。

應該選 Mozart 還是 Strauss?

如果是新專案,直接用 Strauss。

如果已經在用 Mozart,遇到以下情況可以考慮遷移:

  • 你的依賴用了 files autoloader
  • 需要 define() 常數前綴
  • 對 license 合規有要求
  • 需要函式前綴(v0.21.0+)

遷移成本不高,Strauss 讀得懂 Mozart 設定,改幾行 scripts 就切換過去了。

小結

Strauss 跟 Mozart 解決同一個問題:WordPress 外掛的依賴衝突。差別在細節:更完整的 autoloader 支援、常數前綴、license 合規、更保守的預設值。

新外掛直接選 Strauss,舊外掛有痛點再考慮遷移。

參考資源