Added assets hashing after build, added favicon
This commit is contained in:
parent
59e54fc1f5
commit
b842466b3a
|
@ -22,6 +22,7 @@ return [
|
|||
\Engelsystem\Http\ResponseServiceProvider::class,
|
||||
\Engelsystem\Http\Psr7ServiceProvider::class,
|
||||
\Engelsystem\Helpers\AuthenticatorServiceProvider::class,
|
||||
\Engelsystem\Helpers\AssetsServiceProvider::class,
|
||||
\Engelsystem\Renderer\TwigServiceProvider::class,
|
||||
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
||||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||
|
@ -33,7 +34,7 @@ return [
|
|||
\Engelsystem\Helpers\VersionServiceProvider::class,
|
||||
\Engelsystem\Mail\MailerServiceProvider::class,
|
||||
\Engelsystem\Http\HttpClientServiceProvider::class,
|
||||
\Engelsystem\Helpers\DumpServerServiceProvider::class
|
||||
\Engelsystem\Helpers\DumpServerServiceProvider::class,
|
||||
],
|
||||
|
||||
// Application middleware
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
"style-loader": "^3.3.1",
|
||||
"terser-webpack-plugin": "^5.1.2",
|
||||
"webpack": "^5.37.1",
|
||||
"webpack-cli": "^4.7.0"
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-manifest-plugin": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
<link rel="icon" href="{{ asset('assets/angel.svg') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('assets/theme' ~ themeId ~ '.css') }}"/>
|
||||
<script type="text/javascript" src="{{ asset('assets/vendor.js') }}"></script>
|
||||
|
||||
|
|
|
@ -109,7 +109,9 @@ class Application extends Container
|
|||
$this->instance('path', $appPath);
|
||||
$this->instance('path.config', $appPath . DIRECTORY_SEPARATOR . 'config');
|
||||
$this->instance('path.resources', $appPath . DIRECTORY_SEPARATOR . 'resources');
|
||||
$this->instance('path.public', $appPath . DIRECTORY_SEPARATOR . 'public');
|
||||
$this->instance('path.assets', $this->get('path.resources') . DIRECTORY_SEPARATOR . 'assets');
|
||||
$this->instance('path.assets.public', $this->get('path.public') . DIRECTORY_SEPARATOR . 'assets');
|
||||
$this->instance('path.lang', $this->get('path.resources') . DIRECTORY_SEPARATOR . 'lang');
|
||||
$this->instance('path.views', $this->get('path.resources') . DIRECTORY_SEPARATOR . 'views');
|
||||
$this->instance('path.storage', $appPath . DIRECTORY_SEPARATOR . 'storage');
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Helpers;
|
||||
|
||||
class Assets
|
||||
{
|
||||
/** @var string */
|
||||
protected string $assetsPath;
|
||||
|
||||
/** @var string */
|
||||
protected string $manifestFile = 'manifest.json';
|
||||
|
||||
/**
|
||||
* @param string $assetsPath Directory containing assets
|
||||
*/
|
||||
public function __construct(string $assetsPath)
|
||||
{
|
||||
$this->assetsPath = $assetsPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $asset
|
||||
* @return string
|
||||
*/
|
||||
public function getAssetPath(string $asset): string
|
||||
{
|
||||
$manifest = $this->assetsPath . DIRECTORY_SEPARATOR . $this->manifestFile;
|
||||
if (is_readable($manifest)) {
|
||||
$manifest = json_decode(file_get_contents($manifest), true);
|
||||
|
||||
if (isset($manifest[$asset])) {
|
||||
$asset = $manifest[$asset];
|
||||
}
|
||||
}
|
||||
|
||||
return $asset;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Helpers;
|
||||
|
||||
use Engelsystem\Container\ServiceProvider;
|
||||
|
||||
class AssetsServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
$this->app->when(Assets::class)
|
||||
->needs('$assetsPath')
|
||||
->give($this->app->get('path.assets.public'));
|
||||
}
|
||||
}
|
|
@ -2,20 +2,27 @@
|
|||
|
||||
namespace Engelsystem\Renderer\Twig\Extensions;
|
||||
|
||||
use Engelsystem\Helpers\Assets as AssetsProvider;
|
||||
use Engelsystem\Http\UrlGeneratorInterface;
|
||||
use Illuminate\Support\Str;
|
||||
use Twig\Extension\AbstractExtension as TwigExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class Assets extends TwigExtension
|
||||
{
|
||||
/** @var AssetsProvider */
|
||||
protected $assets;
|
||||
|
||||
/** @var UrlGeneratorInterface */
|
||||
protected $urlGenerator;
|
||||
|
||||
/**
|
||||
* @param AssetsProvider $assets
|
||||
* @param UrlGeneratorInterface $urlGenerator
|
||||
*/
|
||||
public function __construct(UrlGeneratorInterface $urlGenerator)
|
||||
public function __construct(AssetsProvider $assets, UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
$this->assets = $assets;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
}
|
||||
|
||||
|
@ -36,6 +43,10 @@ class Assets extends TwigExtension
|
|||
public function getAsset(string $path): string
|
||||
{
|
||||
$path = ltrim($path, '/');
|
||||
if (Str::startsWith($path, 'assets/')) {
|
||||
$asset = Str::replaceFirst('assets/', '', $path);
|
||||
$path = 'assets/' . $this->assets->getAssetPath($asset);
|
||||
}
|
||||
|
||||
return $this->urlGenerator->to('/' . $path);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ class ApplicationTest extends TestCase
|
|||
$this->assertTrue($app->has('path.cache'));
|
||||
$this->assertTrue($app->has('path.cache.routes'));
|
||||
$this->assertTrue($app->has('path.cache.views'));
|
||||
$this->assertTrue($app->has('path.public'));
|
||||
$this->assertTrue($app->has('path.assets.public'));
|
||||
|
||||
$this->assertEquals(realpath('.'), $app->path());
|
||||
$this->assertEquals(realpath('.') . '/config', $app->get('path.config'));
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers;
|
||||
|
||||
use Engelsystem\Application;
|
||||
use Engelsystem\Helpers\Assets;
|
||||
use Engelsystem\Helpers\AssetsServiceProvider;
|
||||
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||
|
||||
class AssetsServiceProviderTest extends ServiceProviderTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\AssetsServiceProvider::register
|
||||
*/
|
||||
public function testRegister()
|
||||
{
|
||||
$app = new Application();
|
||||
$app->instance('path.assets.public', '/tmp');
|
||||
|
||||
$serviceProvider = new AssetsServiceProvider($app);
|
||||
$serviceProvider->register();
|
||||
|
||||
$this->assertArrayHasKey(Assets::class, $app->contextual);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Helpers;
|
||||
|
||||
use Engelsystem\Helpers\Assets;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class AssetsTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Assets::__construct
|
||||
* @covers \Engelsystem\Helpers\Assets::getAssetPath
|
||||
*/
|
||||
public function testGetAssetPath()
|
||||
{
|
||||
$assets = new Assets('/foo/bar');
|
||||
$this->assertEquals('lorem.bar', $assets->getAssetPath('lorem.bar'));
|
||||
|
||||
$assets = new Assets(__DIR__ . '/Stub/files');
|
||||
$this->assertEquals('something.xyz', $assets->getAssetPath('something.xyz'));
|
||||
$this->assertEquals('lorem-hashed.ipsum', $assets->getAssetPath('foo.bar'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"foo.bar": "lorem-hashed.ipsum"
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Engelsystem\Test\Unit\Renderer\Twig\Extensions;
|
||||
|
||||
use Engelsystem\Helpers\Assets as AssetsProvider;
|
||||
use Engelsystem\Http\UrlGenerator;
|
||||
use Engelsystem\Renderer\Twig\Extensions\Assets;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
@ -14,10 +15,12 @@ class AssetsTest extends ExtensionTest
|
|||
*/
|
||||
public function testGetFunctions()
|
||||
{
|
||||
/** @var UrlGenerator|MockObject $urlGenerator */
|
||||
/** @var UrlGenerator&MockObject $urlGenerator */
|
||||
$urlGenerator = $this->createMock(UrlGenerator::class);
|
||||
/** @var AssetsProvider&MockObject $assets */
|
||||
$assets = $this->createMock(AssetsProvider::class);
|
||||
|
||||
$extension = new Assets($urlGenerator);
|
||||
$extension = new Assets($assets, $urlGenerator);
|
||||
$functions = $extension->getFunctions();
|
||||
|
||||
$this->assertExtensionExists('asset', [$extension, 'getAsset'], $functions);
|
||||
|
@ -28,20 +31,35 @@ class AssetsTest extends ExtensionTest
|
|||
*/
|
||||
public function testGetAsset()
|
||||
{
|
||||
/** @var UrlGenerator|MockObject $urlGenerator */
|
||||
/** @var UrlGenerator&MockObject $urlGenerator */
|
||||
$urlGenerator = $this->createMock(UrlGenerator::class);
|
||||
/** @var AssetsProvider&MockObject $assets */
|
||||
$assets = $this->createMock(AssetsProvider::class);
|
||||
|
||||
$urlGenerator->expects($this->exactly(2))
|
||||
$urlGenerator->expects($this->exactly(4))
|
||||
->method('to')
|
||||
->with('/assets/foo.css')
|
||||
->willReturn('https://foo.bar/project/assets/foo.css');
|
||||
->withConsecutive(['/test.png'], ['/assets/foo.css'], ['/assets/bar.css'], ['/assets/lorem-hashed.js'])
|
||||
->willReturnCallback(function ($path) {
|
||||
return 'https://foo.bar/project' . $path;
|
||||
});
|
||||
|
||||
$extension = new Assets($urlGenerator);
|
||||
$assets->expects($this->exactly(3))
|
||||
->method('getAssetPath')
|
||||
->withConsecutive(['foo.css'], ['bar.css'], ['lorem.js'])
|
||||
->willReturnOnConsecutiveCalls('foo.css', 'bar.css', 'lorem-hashed.js');
|
||||
|
||||
$extension = new Assets($assets, $urlGenerator);
|
||||
|
||||
$return = $extension->getAsset('test.png');
|
||||
$this->assertEquals('https://foo.bar/project/test.png', $return);
|
||||
|
||||
$return = $extension->getAsset('assets/foo.css');
|
||||
$this->assertEquals('https://foo.bar/project/assets/foo.css', $return);
|
||||
|
||||
$return = $extension->getAsset('/assets/foo.css');
|
||||
$this->assertEquals('https://foo.bar/project/assets/foo.css', $return);
|
||||
$return = $extension->getAsset('/assets/bar.css');
|
||||
$this->assertEquals('https://foo.bar/project/assets/bar.css', $return);
|
||||
|
||||
$return = $extension->getAsset('assets/lorem.js');
|
||||
$this->assertEquals('https://foo.bar/project/assets/lorem-hashed.js', $return);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
|||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
const nodeEnv = (process.env.NODE_ENV || 'development').trim();
|
||||
const {WebpackManifestPlugin} = require('webpack-manifest-plugin');
|
||||
const fs = require('fs');
|
||||
|
||||
// eslint-disable-next-line
|
||||
|
@ -18,9 +19,10 @@ const plugins = [
|
|||
},
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id]-[hash].css',
|
||||
filename: '[name]-[contenthash].css',
|
||||
chunkFilename: '[id]-[contenthash].css',
|
||||
}),
|
||||
new WebpackManifestPlugin({}),
|
||||
];
|
||||
|
||||
let themeFileNameRegex = /theme\d+/;
|
||||
|
@ -50,7 +52,7 @@ module.exports = {
|
|||
},
|
||||
output: {
|
||||
path: path.resolve('public/assets'),
|
||||
filename: '[name].js',
|
||||
filename: '[name]-[contenthash].js',
|
||||
publicPath: '',
|
||||
clean: true,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue