移除 Composer 中不需要的 Polyfill

預設在安裝 Laravel(或其他框架 / Library)時,常常或多或少會一併安裝許多的「Polyfill」。這些 Polyfill 往往是不必要的。本文說明了如何檢視目前已安裝的 Polyfill,以及如何在專案中移除這些 Polyfill。

Polyfill?

什麼是 Polyfill 呢?Polyfill 是一段用來讓程式能使用還未實作或在為安裝特定套件時使用特定功能的一段程式碼。

舉例來說,Symfony 維護了針對各個 PHP 版本中新增函式的 Polyfill。symfony/polyfill-php81 中,提供了 array_is_list 方法,讓我們不需要安裝 PHP 8.1 也能通過 require 這個 Package 來使用該方法。

使用 composer info 來看看我們安裝了哪些 Polyfill

我們可以使用 composer info 來檢視目前安裝了哪些 Package。搭配 grep 篩選出名稱/說明中有 polyfill 的 Package:

$ composer info | grep polyfill

ralouphie/getallheaders            3.0.3              A polyfill for getallheaders.
symfony/polyfill-ctype             v1.25.0            Symfony polyfill for ctype functions
symfony/polyfill-iconv             v1.25.0            Symfony polyfill for the Iconv extension
symfony/polyfill-intl-grapheme     v1.25.0            Symfony polyfill for intl's grapheme_* functions
symfony/polyfill-intl-idn          v1.25.0            Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions
symfony/polyfill-intl-normalizer   v1.25.0            Symfony polyfill for intl's Normalizer class and related functions
symfony/polyfill-mbstring          v1.25.0            Symfony polyfill for the Mbstring extension
symfony/polyfill-php72             v1.25.0            Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions
symfony/polyfill-php73             v1.25.0            Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions
symfony/polyfill-php80             v1.25.0            Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions
symfony/polyfill-php81             v1.25.0            Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions

筆者目前已經是使用 PHP 8.1 了,但可以看到,預設情況下安裝的 Laravel 還是包含了許多的 Polyfill。
所以,我們其實不需要這些 PHP 7.2 ~ PHP 8.1 的 Polyfill。而且,如果有安裝正確的 Extension 的話,其實也不需要安裝這些 Iconv、intl……等 Extension 的 Polyfill。

使用 replace 來避免安裝這些 Polyfill

在前一步驟,我們已經取得了這些 Polyfill 的列表。那麼,有沒有什麼辦法可以避免安裝這些 Polyfill 呢?
打開 Composer 的說明文件,可以找到 composer.json 中有個欄位叫 replace
replace 的功能是用來指示 Composer,目前這個 Package(即,這個 composer.json 所屬的 Package)可用來取代特定版本的 Package。
Laravel 框架中也使用了這個功能來避免使用者重複安裝了 illuminate/* 的 Package。

我們可以使用這個功能來讓 Composer 不要安裝這些不需要的 Polyfill,像這樣:

// composer.json

{
    // ...
    "replace": {
        "ralouphie/getallheaders": "*",
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-intl-grapheme": "*",
        "symfony/polyfill-intl-idn": "*",
        "symfony/polyfill-intl-normalizer": "*",
        "symfony/polyfill-mbstring": "*",
        "symfony/polyfill-php72": "*",
        "symfony/polyfill-php80": "*",
        "symfony/polyfill-php81": "*"
    },
    // ...
}

更新好 composer.json 後,執行 composer update nothing,就會移除這些 Polyfill:

$ composer update nothing
Loading composer repositories with package information
Updating dependencies
Lock file operations: 0 installs, 0 updates, 10 removals
  - Removing ralouphie/getallheaders (3.0.3)
  - Removing symfony/polyfill-ctype (v1.25.0)
  - Removing symfony/polyfill-iconv (v1.25.0)
  - Removing symfony/polyfill-intl-grapheme (v1.25.0)
  - Removing symfony/polyfill-intl-idn (v1.25.0)
  - Removing symfony/polyfill-intl-normalizer (v1.25.0)
  - Removing symfony/polyfill-mbstring (v1.25.0)
  - Removing symfony/polyfill-php72 (v1.25.0)
  - Removing symfony/polyfill-php80 (v1.25.0)
  - Removing symfony/polyfill-php81 (v1.25.0)