caseyamcl / easyasset
Requires
- php: >=5.5
- skyzyx/mimetypes: ~1.1
Requires (Dev)
- kriswallsmith/assetic: ~1.2
- leafo/scssphp: ~0.1
- mockery/mockery: ~0.9
- oyejorge/less.php: ~1.7
- patchwork/jsqueeze: ~2.0
- phpunit/phpunit: ~4.0
- silex/silex: ~1.2
- symfony/console: ~2.3
- symfony/http-kernel: ~2.3
- twig/twig: ~1.16
This package is auto-updated.
Last update: 2020-08-21 14:07:23 UTC
README
一个库,可让您在使用应用程序中的资产(CSS、JS等)时更加方便。
主要功能
- 编译LESS、SASS/SCSS、JS或任何Assetic资产(或资产集合)
- 递归编译(合并)目录中的资产文件
- 包括Silex提供程序,但将与任何框架、路由器或HTTP库一起工作
- 包括'强制编译'选项,允许您在每次页面加载时编译资产
- 单元测试,完全符合PSR-4/PSR-2规范
为什么?
大多数人将在开发期间使用外部工具编译LESS、SASS和JS,例如IDE或GUI/CLI工具。然而,有时您可能希望应用程序本身能够以透明的方式编译这些资源。这样,资产编译在任何环境中都保持一致。EasyAsset就是这样做的。
我建立这个不是要取代功能齐全的Asset库,如Assetic,而是通过添加一个常见用例的API来补充它。但是,EasyAsset也可以作为一个独立工具使用。
安装
此包需要PHP >= 5.4
请将以下内容包含在您的composer.json
文件中
require {
...
"caseyamcl/easyasset": "@stable"
...
}
使用
EasyAsset库可以做一些不同的事情
- 通过HTTP从多个路径提供资产,发送正确的MIME类型和HTTP头。这使得您(可选)将资产保留在Web文档根目录之外。
- 即时编译LESS、SASS、JS或任何Assetic资产。
- 将编译后的资产写入输出文件。
使用AssetLoader
EasyAsset的核心是EasyAsset\AssetContentLoader
类。此类流式传输静态(非编译)和/或编译后的资产。您应该传递资产所在位置(或将被编译到的)的文件路径
$loader = new AssetContentLoader(['/path/to/assets']);
此基本用法允许您加载静态资产,但不能编译任何资产。例如,如果您有一个位于/path/to/assets/img.jpg
的图像,您可以加载内容
// Returns TRUE if the file exists, otherwise false
$loader->exists('img.jpg');
// Get a callable function (closure) that will echo the output of the 'img.jpg' file:
$output = $loader->load('img.jpg');
// And invoke the output to send the content to php://output
$output->__invoke();
如果您希望它搜索多个路径,可以向构造函数传递多个资产路径
$loader = new AssetContentLoader(['/path/to/assets', '/another/path']);
// Will search both paths, in the order they are specified, until a match is found
$loader->exists('img.jpg');
如果资产不存在,将抛出\EasyAsset\Exception\AssetNotExistsException
异常,您可以在框架中捕获它并将其转换为404错误,或进行其他处理。
// Throws an AssetNotExistsException
$loader->load('does-not-exist.jpg');
使用编译后的资产(LESS、SASS、JS、Assetic..)与AssetLoader
如果静态版本已存在或您指定它应该每次都编译,无论是否存在静态文件,AssetContentLoader还将编译您想要的任何资产。
编译后的资产应指定输出文件名(例如style.css
或js/scripts.js
),并指示提供原始内容的类。此类必须是\EasyAsset\CompiledAssetInterface
的实例。
首先,创建一个 EasyAsset\CompiledAssetsCollection
类
$compiledAssets = new CompiledAssetsCollection();
然后,添加编译后的资源
$compiledAssets->add('styles.css', new EasyAsset\CompiledAsset\LessCompiledAsset('/path/to/less'));
$compiledAssets->add('script.js', new EasyAsset\CompiledAsset\JsCompiledAsset('/path/to/js-source'));
如果您想使用编译后的资源,在实例化 AssetContentLoader
类时必须传递 CompiledAssetsCollection
$loader = new AssetContentLoader(['/path/to/assets'], $compiledAssets);
现在,当 AssetContentLoader
被指示查找 styles.css
时,它将首先检查是否有名为该名的文件存在于某个路径中,如果没有,它将使用 CompiledAsset
类构建内容。
// If the 'styles.css' exists in any specified asset path, use that; otherwise will compile
$output = $loader->load('styles.css');
// prints the raw CSS content
$output->__invoke();
您也可以通过将 true
作为 AssetContentLoader::load
的第三个参数传递给 Loader 来强制其编译资源,即使存在文件也是如此。这在进行开发/设计时非常有用。
$output = $loader->load('styles.css', null, true):
内置编译后的资源
EasyAsset 包含四个内置编译器
EasyAsset\CompiledAsset\LessCompiledAsset
- 使用 oyejorge/less.php 库编译 LESSEasyAsset\CompiledAsset\JsCompiledAsset
- 使用 patchwork/jsqueeze 库编译和压缩 JSEasyAsset\CompiledAsset\SassCompiledAsset
- 使用 leafo/scssphp 库编译和压缩 SASS/SCSSEasyAsset\CompiledAsset\AsseticAsset
- 包装任何Assetic\Asset\AssetInterface
实例,以便您可以使用 EasyAsset
此外,LESS、JS 和 SASS/SCSS 编译器将递归地合并和压缩您指定的路径中所有相应的文件类型。
例如,假设您有以下 JS 文件
/asset_source/js
/01-jquery
/01-jquery.js
/02-jquery-ui.min.js
/02-vendor
/01-chosen.js
/02-mappify.js
/03-local
/scripts.js
如果您将 /asset_source/js
路径传递给 JsCompiledAsset
类,它将按字母顺序按完整路径名合并所有文件并压缩它们。这使得组织和最小化资源 HTTP 请求变得非常容易。
您也可以将单个文件名传递给编译器的构造函数,例如
$lessCompiler = new EasyAsset\CompiledAsset\LessCompiledAsset('/path/to/less/01-main.less');
Assetic Asset 类允许您使用任何 Assetic Asset 作为编译后的资源。例如
$compiledAssets->add('image.png', new Assetic\Asset\FileAsset('asset_src/image.png', [new AsseticPngFilter()]);
创建自己的编译后资源类型
如果内置的编译后资源类型都不符合您的需求,您可以通过实现 EasyAsset\CompiledAssetInterface
来创建自己的。
如果您的资源能够递归地合并文件,您可以使用 EasyAsset\RecursiveDirParserTrait
。例如
class MyCompiledAsset implements CompiledAssetInterface
{
// .. code here..
use RecursiveDirParserTrait;
public function compile($outStream)
{
// ..code here..
// getCombinedFiles comes from the trait
$combinedFiles = $this->getCombinedFiles($this->pathToSource);
// ..or you can use getFileIterator(), which accepts a directory or file path
// and returns an iterator with all files listed in alphabetical order by path
$allAssetSourceFiles = $this->getFileIterator($this->pathToSource);
// ..code here..
}
}
通过 HTTP 提供资源
EasyAsset 包含一个抽象控制器类,用于通过 PHP HTTP 框架提供资源:EasyAsset\AssetController
。如果您正在使用使用 Symfony HttpKernel 组件的框架,您可以使用包含的 EasyAsset\Provider\Symfony\AssetController
控制器。如果不使用,您可以在自己的类中扩展 EasyAsset\AssetController
。例如
/**
* A simple Asset Controller that uses PHP-built in functions to deliver a response
*/
class MyAssetController extends EasyAsset\AssetController
{
/**
* This method prints out the response directly.. Alternatively, your
* controller could return some kind of response object, which would be handled
* by your framework.
*/
protected function sendContentResponse(\Closure $contentCallback, $mimeType)
{
header("HTTP/1.0 200 OK");
header("Content-Type: " . $mimeType);
$contentCallback->__invoke(); // prints the raw asset content
}
/**
* {@inheritdoc}
*/
protected function sendNotFoundResponse($path)
{
header("HTTP/1.0 404 Not Found");
header("Content-Type: text/plain");
echo "Asset at path: {$path} not found";
}
}
使用您的类很容易
$assetController = new MyAssetController($assetLoader);
// You'll probably be using a more sophisticated router than this...
$route = $_SERVER['REQUEST_URI']
if (substr($route, 0, strlen('asset')) == 'asset') {
// Get the asset path from the URI; again, this is crude for example purposes..
$assetPath = ltrim(substr($route, strlen('asset')), '/');
// Your implementation of the AssetController class may return a value or simply echo output,
// like this example does
$assetController->loadAction($assetPath);
exit();
}
如果您可以使用内置的 Symfony 控制器,那么使用起来甚至更简单。例如,在 Silex 中(注意:详细的 Silex 集成文档如下)
$controller = new EasyAsset\Provider\Symfony\AssetController($loader);
$app->get('assets/{path}', [$controller, 'loadAction']);
将资源写入输出文件
EasyAsset 包含一个类,用于将编译后的资源写入您选择的路径。这可能在构建过程中、部署过程中、按需发生,或者您可以配置您的应用程序在每次编译时都写入它们。
$writer = new AssetFileWriter('/path/to/assets');
// Write the whole collection of assets
$writer->writeAssetCollection($compiledAssets);
// Write a single asset
$writer->write('style.css', $lessCompiledAsset);
如果您的项目使用 Symfony Console 组件,您可以利用内置的命令来写入资源
use EasyAsset\Provider\AssetWriterCommand;
$mySymfonyConsoleApp->add(new AssetWriterCommand($compiledAssets, $writer));
然后,在命令行中
# Write assets
$ app/console assets:compile
# Or, override the default directory to write to:
$ app/console assets:compile /some/other/asset/path
与 Silex 一起使用
如果您使用Silex,可以使用EasyAsset\Provider\Silex\AssetServiceProvider
参数
assets.paths
- 必填 - 一个数组,包含常规资产(图片等)的实际系统路径以及应该编译到的地方。您可以传递任意数量的路径;在检索资产时,将按顺序搜索这些路径。assets.compiled
- 资产编译器关联数组。键是编译后资产输出文件位置的相对URL;值是编译器类。下面是示例。assets.force_compile
- 真值/假值;如果您想在每次加载资产时都让EasyAsset编译它们,请将其设置为TRUE
。
默认值为$app['debug']
的值。assets.write_path
- 如果您的应用程序将写入资产,请指定文件应写入的路径。默认值为assets.paths
中的第一个值。assets.write_on_compile
- 真值/假值;如果您指定了assets.write_path
,您可以配置Silex在每次编译资产时将它们输出到文件。默认值为false
。
服务
assets.loader
- 资产加载类;您通常不需要直接使用此功能assets.controller
- 资产控制器。期望URI参数{path}
。例如:/assets/{path}
assets.writer
- 资产写入器。将编译后的资产写入文件系统assets.command
- 资产写入器控制台命令。提供了一个Symfony控制台命令,用于将资产写入文件系统
示例Bootstrap代码
use EasyAsset\Provider\Silex\AssetServiceProvider;
use EasyAsset\CompiledAsset;
$app->register(new AssetServiceProvider(), array(
'assets.paths' => ['/path/to/assets', '/another/asset/path'],
'assets.write_path' => '/path/to/assets' // you can omit this if you want to use the first value from 'assets.path'
'assets.force_compile' => false, // you may want to use TRUE for development
'assets.write_on_compile' => true, // defaults to FALSE
'assets.compilers => [
'style.css', new CompiledAsset\LessCompiledAsset('/path/to/less'),
'script.js', new CompiledAsset\JsCompiledAsset('/path/to/js'),
'fancypng.png, new CompiledAsset\AsseticAsset($someAsseticAsset)
];
));
示例控制器代码
$app->get('/asset/{path}, [$app['assets.controller'], 'loadAction']);
如果您在应用程序中使用UrlGenerator
和Twig
,您可以在模板中轻松创建资产URL,通过将路由绑定到名称
$app->get('/asset/{path}, [$app['assets.controller'], 'loadAction'])->bind('asset');
然后,在您的模板中,使用url()
函数创建资产URL。如果资产是编译后的资产,且输出文件不存在,应用程序将透明地编译它。
<head>
{# ... #}
<link rel='stylesheet' href="{{ url('asset', {'path': 'style.css'}); }}" />
<script src="{{ url('asset', {'path': 'script.js'}); }}"></script>
{# ... #}
</head>
贡献
欢迎贡献!我特别感兴趣的是包含除了Symfony/Silex之外提供者的拉取请求。
有关详细信息,请参阅<CONTRIBUTING.md>
文件。
许可证
MIT许可证(MIT)。请参阅许可证文件获取更多信息。