diff --git a/README.md b/README.md new file mode 100644 index 0000000..808a8e6 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# Twig asset() + +A simple asset function for Twig, which appends the file modification time of the referenced asset file to ensure the browser reloads the resource when it changes. (cache invalidation) + +This repository holds the extension for PHP and JS. + + +## Installation + +### PHP + +1. Add the package to your project. + ```sh + $ composer require netzstrategen/twig-asset + ``` + +2. Add the extension and configuration to your Twig environment. + ```php + addGlobal('asset_path_document_root', ''); + $twig->addExtension(new TwigAsset()); + ``` + +### JS + +1. Add the package to your project. + ```sh + $ npm install @netzstrategen/twig-asset --save + ``` + +2. Load the extension with your configuration in your project. + ```js + const TwigAsset = require('@netzstrategen/twig-asset')({ + asset_path_document_root: __dirname, + }); + +3. Register the function in your Twig environment: + ```js + for (const name in TwigAsset) { + twig.extendFunction(name, TwigAsset[name]); + } + ``` + +### Third-party integrations + +#### [Fractal](https://fractal.build) + +```js +const twigAdapter = require('@netzstrategen/twig-drupal-fractal-adapter'); +const instance = fractal.components.engine(twigAdapter); +instance.twig.extendFunction('asset', TwigAsset.asset); +``` + + +## Configuration + +- `asset_path_document_root` (string, required): Path to the document root. + + Acts as a base path. The path passed to the asset() function will be appended + to this base path in order to retrieve the file's modification time. + +## Usage + +```twig + +``` +yields: +```html + +``` + +### Parameters + +- `add_version` (bool, optional): Whether to append the file modification time. Defaults to `true`. + + Example: + ```twig + + ``` + yields: + ```html + + ``` + + +## Alternatives to this package + +See Symfony for a more sophisticated solution (PHP only): +- [Symfony Asset Component](https://symfony.com/doc/current/components/asset.html) +- [Symfony Encore](https://symfony.com/doc/current/frontend/encore/versioning.html) diff --git a/composer.json b/composer.json index efa7420..f188cd2 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "cue/twig_extensions", - "description": "Fractal integration for Drupal.", + "name": "netzstrategen/twig-asset", + "description": "asset() function for Twig.", "license": "GPL-2.0+", "authors": [ { @@ -14,7 +14,7 @@ ], "autoload": { "psr-4": { - "Cue\\twig_extensions\\": "src/" + "Netzstrategen\\TwigAsset\\": "php/" } } } diff --git a/js/functions.js b/js/functions.js new file mode 100644 index 0000000..93b3972 --- /dev/null +++ b/js/functions.js @@ -0,0 +1,31 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const querystring = require('querystring'); + +module.exports = (config = {}) => { + + config = Object.assign({ + add_version: true, + }, config); + + return { + asset: (asset_path) => { + if (!config.asset_path_document_root) { + return asset_path; + } + const absolute_path = path.join(config.asset_path_document_root, asset_path); + if (config.add_version && fs.existsSync(absolute_path)) { + const stats = fs.statSync(absolute_path); + const filemtime = Math.floor(stats.mtimeMs / 1000); + const query_string = querystring.stringify({ + v: filemtime, + }); + asset_path += `?${query_string}`; + } + return asset_path; + } + } + +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1c74d9a --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "@netzstrategen/twig-asset", + "version": "1.0.0", + "description": "asset() function for Twig.", + "main": "js/functions.js", + "files": ["js/*"], + "repository": { + "type": "git", + "url": "git+https://github.com/netzstrategen/twig-asset.git" + }, + "author": "Fabian Marz ", + "contributors": [ + "Daniel Kudwien " + ], + "license": "GPL-2.0+", + "bugs": { + "url": "https://github.com/netzstrategen/twig-asset/issues" + }, + "homepage": "https://github.com/netzstrategen/twig-asset#readme" +} diff --git a/php/TwigExtension.php b/php/TwigExtension.php new file mode 100644 index 0000000..2eecfcf --- /dev/null +++ b/php/TwigExtension.php @@ -0,0 +1,53 @@ + TRUE, + ]), + ]; + } + + /** + * Appends the modification time to the given asset file path. + * + * @param Twig_Environment $env + * The current Twig environment. + * @param string $path + * The path to the asset file relative to the Twig environment. + * @param bool $add_version + * Whether to append the file modification time. Defaults to TRUE. + * + * @return string + */ + public static function getAssetPath(Twig_Environment $env, string $path, bool $add_version = TRUE): string { + $globals = $env->getGlobals(); + if (!empty($globals['asset_path_document_root'])) { + $asset_root = realpath($globals['asset_path_document_root']); + $absolute_path = $asset_root . '/' . $path; + + if ($add_version && file_exists($absolute_path)) { + $query_string = http_build_query([ + 'v' => filemtime($absolute_path), + ]); + $path .= '?' . $query_string; + } + } + return $path; + } + +} diff --git a/src/TwigExtensions.php b/src/TwigExtensions.php deleted file mode 100644 index f595f73..0000000 --- a/src/TwigExtensions.php +++ /dev/null @@ -1,57 +0,0 @@ - TRUE, - ]), - ]; - } - - /** - * Appends the filemtime to the given asset path to ensure cache invalidation. - * - * @param Twig_Environment $env - * The current Twig environment. - * @param $asset_path - * The given path to the asset. - * @param bool $is_versioned - * If the asset should be versioned by appending the filemtime. - * - * @return string - */ - public static function getAssetPath(Twig_Environment $env, $asset_path, $is_versioned = TRUE): string { - $globals = $env->getGlobals(); - $context_publication = $globals['contextPublication']; - $template_path = realpath($context_publication['templateDir']); - $asset_abspath = $template_path . '/' . $asset_path; - - if (is_dir($template_path) && is_file($asset_abspath) && $is_versioned) { - $query_string = http_build_query([ - 'v' => filemtime($asset_abspath), - ]); - $asset_path = $asset_path . '?' . $query_string; - } - - return $asset_path; - } - -}