civicrm / composer-compile-lib
Small library of compilation helpers
Installs: 278 155
Dependents: 4
Suggesters: 0
Security: 0
Stars: 3
Watchers: 18
Forks: 3
Open Issues: 0
Requires
- civicrm/composer-compile-plugin: ~0.19 || ~1.0
- padaliyajay/php-autoprefixer: ~1.2
- scssphp/scssphp: ^1.8.1
- symfony/filesystem: ~2.8 || ~3.4 || ~4.0 || ~5.0 || ~6.0 || ~7.0
- tubalmartin/cssmin: ^4.1
README
This package provides a handful of small tasks and helpers for use with composer-compile-plugin.
Design guidelines for this package:
- To ensure easy operation in a new/unbooted system:
- Use basic functions and static methods
- Use primitive data sources (such as static JSON files)
- To ensure that compilation steps report errors:
- Every task/function must throw an exception if it doesn't work.
- To allow pithy tasks:
- If a task is outputting to a folder, and if the folder doesn't exist, then it should auto-create the folder.
The primary purpose here is demonstrative - to provide examples. Consequently, it is fairly minimal / lightweight / loosely-coupled. There is no dependency on CiviCRM. Conversely, CiviCRM packages may define other tasks which are not in this library.
Require the library
All the examples below require the civicrm/composer-compile-lib
package. Load via CLI:
composer require civicrm/composer-compile-lib:'~0.2'
Or via composer.json
:
"require": { "civicrm/composer-compile-lib": "~0.2" }
Task: SCSS
In this example, we generate a file dist/sandwich.css
by reading scss/sandwich.scss
. The file may @import
mixins and
variables from the ./scss/
folder.
{ "extra": { "compile": [ { "title": "Prepare CSS (<comment>sandwich.css</comment>, <comment>salad.css</comment>)", "run": "@php-method \\CCL\\Tasks::scss", "watch-files": ["scss"], "scss-files": { "dist/sandwich.css": "scss/sandwich.scss", "dist/salad.css": "scss/salad.scss" }, "scss-imports": ["scss"] "scss-import-prefixes": {"LOGICAL_PREFIX/": "physical/folder/"} } ] } }
Note that a "task" simply calls a static PHP method (@php-method \\CCL\\Tasks::scss
) with the JSON data as input. You
can also call the method in a PHP script. For example, we could define a task based on a script:
{ "extra": { "compile": [ { "title": "Prepare CSS (<comment>sandwich.css</comment>, <comment>salad.css</comment>)", "run": "@php-script bin/compile-scss" } ] } }
The following script generalizes the example from before -- it maps any SCSS files (scss/*.scss
) to
corresponding CSS files (dist/#1.css
). This file-list is passed into \CCL\Tasks::scss
for processing:
\CCL::assertTask(); $files = \CCL::globMap('scss/*.scss', 'dist/#1.css', 1); \CCL\Tasks::scss([ 'scss-files' => $files, 'scss-imports' => ['scss'] 'scss-import-prefixes' => ['LOGICAL_PREFIX/' => 'physical/folder/'] ]);
Note that this implementation of \CCL\Tasks::scss()
is fairly opinionated - it combines scssphp
with
php-autoprefixer
. The output is written as two files, a larger files (*.css
) and a smaller file (*.min.css
).
Task: PHP Template
In this example, we use a PHP template to generate another PHP file. Specifically, we create Sandwich.php
using
the specification from Sandwich.json
and EntityTemplate.php
:
{ "extra": { "compile": [ { "title": "Sandwich (<comment>src/Sandwich.php</comment>)", "run": "@php-method \\CCL\\Tasks::template", "watch-files": ["src/Entity"], "tpl-items": [ "src/Entity/Sandwich.php": "src/Entity/Sandwich.json", "src/Entity/Salad.php": "src/Entity/Salad.json" ], "tpl-file": "src/Entity/EntityTemplate.php" } ] } }
As in the previous example, the task is simply a PHP method (@php-method \\CCL\\Tasks::template
), so it can be used
from a PHP script. The following script would extend the pattern, mapping any JSON files (src/Entity/*.json
) to
corresponding PHP files (src/Entity/#1.php
):
$files = \CCL::globMap('src/Entity/*.json', 'src/Entity/#1.php', 1); \CCL\Tasks::template([ "tpl-file" => "src/Entity/EntityTemplate.php", "tpl-items" => $files, ]);
Functions
PHP's standard library has a lot of functions that would work for basic file manipulation (copy()
, rename()
, chdir()
, etc). The
problem is error-signaling -- you have to explicitly check error-output, and this grows cumbersome for improvised glue code. It's more
convenient to have a default stop-on-error behavior, e.g. throwing exceptions.
symfony/filesystem provides wrappers which throw exceptions.
But it puts them into a class Filesystem
which, which requires more boilerplate.
For the most part, CCL
simply mirrors symfony/filesystem
using static methods in the CCL
class. Compare:
// PHP Standard Library if (!copy('old', 'new')) { throw new \Exception("..."); } // Symfony Filesystem $fs = new \Symfony\Component\Filesystem\Filesystem(); $fs->copy('old', 'new'); // Composer Compile Library \CCL::copy('old', 'new');
This is more convenient for scripting one-liners. For example, the following tasks do simple file operations. If anything goes wrong, they raise an exception and stop the compilation process.
{ "extra": { "compile": [ { "title": "Smorgasboard of random helpers", "run": [ // Create files and folders "@php-eval \\CCL::dumpFile('dist/timestamp.txt', date('Y-m-d H:i:s'));", "@php-eval \\CCL::mkdir('some/other/place');", // Concatenate a few files "@php-eval \\CCL::dumpFile('dist/bundle.js', \\CCL::cat(glob('js/*.js'));", "@php-eval \\CCL::chdir('css'); \\CCL::dumpFile('all.css', ['colors.css', 'layouts.css']);", // If you need reference material from another package... "@export TWBS={{pkg:twbs/bootstrap}}", "@php-eval \\CCL::copy(getenv('TWBS') .'/dist/bootstrap.css', 'web/main.css')" ] } ] } }
The full function list:
// CCL wrapper functions function chdir(string $dir); function glob($pat, $flags = null); // CCL distinct functions function cat($files); function mapkv($array, $func); function globMap($globPat, $mapPat, $flip = false); // Symfony wrapper functions function appendToFile($filename, $content); function dumpFile($filename, $content); function mkdir($dirs, $mode = 511); function touch($files, $time = null, $atime = null); function copy($originFile, $targetFile, $overwriteNewerFiles = true); function mirror($originDir, $targetDir, $iterator = null, $options = []); function remove($files); function rename($origin, $target, $overwrite = false); function chgrp($files, $group, $recursive = false); function chmod($files, $mode, $umask = 0, $recursive = false); function chown($files, $user, $recursive = false); function hardlink($originFile, $targetFiles); function readlink($path, $canonicalize = false); function symlink($originDir, $targetDir, $copyOnWindows = false); function exists($files); function tempnam($dir, $prefix);
For more details about each function, see CCL\Functions
and
symfony/filesystem.