Организуем библиотеки и патчи в drupal-проекте

Дубовской Александр
Team lead

Работа с патчами.

Если у вас более-менее стабильный набор патчей под проекты, имеет смысл выделить их в отдельный файл. Делается это довольно элементарно: с помощью https://github.com/cweagans/composer-patches .

Достаточно сделать: composer require cweagans/composer-patches, а потом добавить в свой composer.json:

"extra": {
        "patches-file": "composer.patches.json",
        "enable-patching": true
...

И создать файл composer.patches.json, в котором указать требуемые патчи, например:

{
  "patches": {
    "drupal/core": {
        "Fix images link problem": "https://www.drupal.org/files/issues/2018-09-11/edit_drupalimage-86x-2855521-27.patch"
    },
    "drupal/features": {
      "Fix features-import-all bug": "https://www.drupal.org/files/issues/2018-04-16/fix-features-import-all-2961007.patch",
      "Fix unicode error": "https://www.drupal.org/files/issues/2018-08-15/2992790-drupal-component-namespace-case.patch"
    },
    "drupal/colorbutton": {
      "issue:#2919123#comment-12393742": "https://www.drupal.org/files/issues/2919123.patch"
    },
    "drupal/ckeditor_font": {
      "issue#2900789#comment-12501946": "https://www.drupal.org/files/issues/ckeditor_font_8_1_0_libraries_integration_01.patch"
    }
  }  
}

Вуаля, при следующем composer update/install патчи будут применяться, а мы в git истории будем легко отслеживать именно правку файла с патчами.

 

Работа с библиотеками

Мы хотим складывать все js-зависимости (слайдеры, colorbox, и т.п.) в отдельную папку libraries и хранить это в composer-файле. Сделать это очень просто: сначала убедимся что стоит composer/installers. Для этого сделаем composer require composer/installers .

После чего в разделе "installer-paths" вашего composer.json укажите путь куда складывать библиотеки:

"installer-paths": {
            "core": ["type:drupal-core"],
            "modules/contrib/{$name}": ["type:drupal-module"],
            "modules/custom/{$name}": ["type:drupal-custom-module"],
            "modules/features/{$name}": ["type:drupal-custom-feature"],
            "profiles/contrib/{$name}": ["type:drupal-profile"],
            "themes/contrib/{$name}": ["type:drupal-theme"],
            "drush/contrib/{$name}": ["type:drupal-drush"],
            "themes/repository/{$name}": ["type:drupal-custom-theme"],
            "libraries/{$name}": ["type:drupal-library"]
        }

А именно: добавить строчку "libraries/{$name}": ["type:drupal-library"] .

Далее, т.к. библиотек много, нам бы хотелось хранить пути к ним в отдельном файле, для этого нам нужно убедиться что он стоит (вообще должен, для composer-based drupal-инсталляции он уже включен. Честно говоря не помню как было с ранними версиями 8.x ядра, но в новых уже есть): composer require wikimedia/composer-merge-plugin . Т.е. установить плагин https://github.com/wikimedia/composer-merge-plugin, он позволяет разделить composer.json файл на несколько составляющих (в т.ч. сделать файл с отдельным списком репозиториев). После чего, в composer.json нужно добавить:

        "merge-plugin": {
            "include": [
                "core/composer.json",
                "composer.libraries.json"
            ],
            "recurse": false,
            "replace": false,
            "merge-extra": false
        },

А именно, мы добавили "composer.libraries.json", в котором нужно указать все наши библиотеки. Пример нашего типового (да, он довольно большой, но может кому пригодится, т.к. там чаще всего используемый UI-контриб).

{
  "repositories": [{
      "type": "package",
      "package": {
        "name": "ckeditor/colorbutton",
        "type": "drupal-library",
        "version": "4.10.0",
        "dist": {
          "url": "https://download.ckeditor.com/colorbutton/releases/colorbutton_4.10.0.zip",
          "type": "zip"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/panelbutton",
        "type": "drupal-library",
        "version": "4.10.0",
        "dist": {
          "url": "https://download.ckeditor.com/panelbutton/releases/panelbutton_4.10.0.zip",
          "type": "zip"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/font",
        "type": "drupal-library",
        "version": "4.10.0",
        "dist": {
          "url": "https://download.ckeditor.com/font/releases/font_4.10.0.zip",
          "type": "zip"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "kenwheeler/slick",
        "type": "drupal-library",
        "version": "1.8.0",
        "dist": {
          "url": "https://github.com/kenwheeler/slick/archive/1.8.0.zip",
          "type": "zip"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "bgrins/spectrum",
        "type": "drupal-library",
        "version": "1.8.0",
        "dist": {
          "url": "https://github.com/bgrins/spectrum/archive/1.8.0.zip",
          "type": "zip"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "recurser/jquery-simple-color",
        "type": "drupal-library",
        "version": "1.2.2",
        "dist": {
          "url": "https://github.com/recurser/jquery-simple-color/archive/v1.2.2.zip",
          "type": "zip"
        }
      }
    },

    {
      "type": "package",
      "package": {
        "name": "algolia/places",
        "version": "1.9.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "algolia.places"
        },
        "dist": {
          "url": "https://registry.npmjs.org/places.js/-/places.js-1.9.0.tgz",
          "type": "tar"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/autogrow",
        "version": "4.10.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "ckeditor.autogrow"
        },
        "dist": {
          "url": "https://download.ckeditor.com/autogrow/releases/autogrow_4.10.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/codemirror",
        "version": "v1.17.5",
        "type": "drupal-library",
        "extra": {
          "installer-name": "ckeditor.codemirror"
        },
        "dist": {
          "url": "https://github.com/w8tcha/CKEditor-CodeMirror-Plugin/releases/download/v1.17.5/CKEditor-CodeMirror-Plugin.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/fakeobjects",
        "version": "4.10.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "ckeditor.fakeobjects"
        },
        "dist": {
          "url": "https://download.ckeditor.com/fakeobjects/releases/fakeobjects_4.10.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/image",
        "version": "4.10.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "ckeditor.image"
        },
        "dist": {
          "url": "https://download.ckeditor.com/image/releases/image_4.10.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "ckeditor/link",
        "version": "4.10.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "ckeditor.link"
        },
        "dist": {
          "url": "https://download.ckeditor.com/link/releases/link_4.10.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "codemirror/codemirror",
        "version": "5.39.2",
        "type": "drupal-library",
        "extra": {
          "installer-name": "codemirror"
        },
        "dist": {
          "url": "https://github.com/components/codemirror/archive/5.39.2.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/geocomplete",
        "version": "1.7.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.geocomplete"
        },
        "dist": {
          "url": "https://github.com/ubilabs/geocomplete/archive/1.7.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/icheck",
        "version": "1.0.2 ",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.icheck"
        },
        "dist": {
          "url": "https://github.com/fronteed/icheck/archive/1.0.2.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/inputmask",
        "version": "4.0.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.inputmask"
        },
        "dist": {
          "url": "https://github.com/RobinHerbots/jquery.inputmask/archive/4.0.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/intl-tel-input",
        "version": "13.0.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.intl-tel-input"
        },
        "dist": {
          "url": "https://github.com/jackocnr/intl-tel-input/archive/v13.0.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/rateit",
        "version": "1.1.1",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.rateit"
        },
        "dist": {
          "url": "https://github.com/gjunge/rateit.js/archive/1.1.1.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/select2",
        "version": "4.0.5",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.select2"
        },
        "dist": {
          "url": "https://github.com/select2/select2/archive/4.0.5.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/textcounter",
        "version": "0.8.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.textcounter"
        },
        "dist": {
          "url": "https://github.com/ractoon/jQuery-Text-Counter/archive/0.8.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jquery/timepicker",
        "version": "1.11.13",
        "type": "drupal-library",
        "extra": {
          "installer-name": "jquery.timepicker"
        },
        "dist": {
          "url": "https://github.com/jonthornton/jquery-timepicker/archive/1.11.13.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "progress-tracker/progress-tracker",
        "version": "1.4.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "progress-tracker"
        },
        "dist": {
          "url": "https://github.com/NigelOToole/progress-tracker/archive/v1.4.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "signature_pad/signature_pad",
        "version": "2.3.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "signature_pad"
        },
        "dist": {
          "url": "https://github.com/szimek/signature_pad/archive/v2.3.0.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    },
    {
      "type": "package",
      "package": {
        "name": "jackmoore/colorbox",
        "version": "2.3.0",
        "type": "drupal-library",
        "extra": {
          "installer-name": "colorbox"
        },
        "dist": {
          "url": "https://github.com/jackmoore/colorbox/archive/master.zip",
          "type": "zip"
        },
        "require": {
          "composer/installers": "~1.0"
        }
      }
    }
  ]
}

 

Обратите внимание, в некоторых указан параметр "extra": {  "installer-name": "algolia.places"  }, он сообщает, что нужно директорию в libraries назвать определенным образом. Т.е. у нас будет /libraries/algolia.places/ каталог, т.к. именно такой путь указан в drupal-модуле который требует эту библиотеку и именно в данный путь мы ее будем разворачивать. 

После чего нам достаточно указать все эти библиотеки как зависимости (установить т.е), набрав composer require ckeditor/colorbutton ckeditor/panelbutton (и все остальные).