laravel 应用程序的主题系统
Theme system for laravel application
我正在为小众游戏服务器开发控制面板。我想要我的应用程序的基本主题系统,目标是将主题资产 (js/css/images) 与视图保持在一起。我不希望资源目录中的视图和 public 目录中的资产分开。
考虑到这一点;这是我想出的。
这样组织的主题(视图和资产)- 即删除了默认 views
目录:
新config/site.php
<?php
return [
'theme' => 'default',
];
修改config/views.php
<?php
return [
'paths' => [
resource_path('themes/' . config('site.theme')),
],
...
新路线routes/web.php
Route::get('theme/{file?}', 'ThemeController@serve')
->where('file', '[a-zA-Z0-9\.\-\/]+');
新控制器app/Http/Controllers/ThemeController.php
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Support\Facades\File;
class ThemeController extends Controller
{
/**
* @param $file
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function serve($file)
{
$siteConfig = config('site');
$filePath = resource_path("themes/{$siteConfig['theme']}/{$file}");
if (!file_exists($filePath)) {
header("HTTP/1.0 404 Not Found");
exit;
}
$fileLastModified = Carbon::createFromTimestamp(filemtime($filePath))->format('D, j M Y H:i:s');
$fileEtag = md5_file($filePath);
$requestFileEtag = request()->getETags()[0] ?? null;
if (!empty($requestFileEtag) && strcmp($fileEtag, $requestFileEtag) === 0) {
header("Last-Modified: {$fileLastModified}");
header("Etag: {$fileEtag}");
header("HTTP/1.1 304 Not Modified");
exit;
}
return response()->file($filePath, [
'Cache-Control' => 'public, max-age=' . ($siteConfig['themeFilesCacheForMinutes'] * 60),
'Etag' => $fileEtag,
'Last-Modified' => $fileLastModified,
'Content-Type' => $this->guessMimeType($filePath)
]);
}
/**
* @param $filePath
* @return false|string
*/
private function guessMimeType($filePath) {
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
switch ($ext) {
case 'css':
return 'text/css; charset=UTF-8';
case 'js':
return 'text/javascript; charset=UTF-8';
default:
return File::mimeType($filePath);
}
}
}
有了那个设置;如果我想从我的主题中包含一个资产,例如css/sb-admin-2.min.css
在我 <head>...</head>
的主布局中,我是这样做的:
<link href="{{ url('theme/css/sb-admin-2.min.css') }}" rel="stylesheet">
因此,使用这种技术我可以将视图和资产放在一起,php 以提供具有缓存功能的静态资产(通过 headers + etag)。
我已经在本地测试过它并且它有效,初始加载大约需要 900 毫秒,一旦缓存预热,它加载页面的时间不到 500 毫秒。
我的问题;这是一个坏方法吗?即使用 php 提供静态文件?有更好的方法吗?
如果您想将刀片服务器和静态资产打包为单独的可替换主题,只需使用依赖注入为每个主题和 select 所需主题创建一个包。在每个主题的 ServiceProvider 中将您的资产发布到 public 目录。
我正在为小众游戏服务器开发控制面板。我想要我的应用程序的基本主题系统,目标是将主题资产 (js/css/images) 与视图保持在一起。我不希望资源目录中的视图和 public 目录中的资产分开。
考虑到这一点;这是我想出的。
这样组织的主题(视图和资产)- 即删除了默认 views
目录:
新config/site.php
<?php
return [
'theme' => 'default',
];
修改config/views.php
<?php
return [
'paths' => [
resource_path('themes/' . config('site.theme')),
],
...
新路线routes/web.php
Route::get('theme/{file?}', 'ThemeController@serve')
->where('file', '[a-zA-Z0-9\.\-\/]+');
新控制器app/Http/Controllers/ThemeController.php
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Support\Facades\File;
class ThemeController extends Controller
{
/**
* @param $file
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function serve($file)
{
$siteConfig = config('site');
$filePath = resource_path("themes/{$siteConfig['theme']}/{$file}");
if (!file_exists($filePath)) {
header("HTTP/1.0 404 Not Found");
exit;
}
$fileLastModified = Carbon::createFromTimestamp(filemtime($filePath))->format('D, j M Y H:i:s');
$fileEtag = md5_file($filePath);
$requestFileEtag = request()->getETags()[0] ?? null;
if (!empty($requestFileEtag) && strcmp($fileEtag, $requestFileEtag) === 0) {
header("Last-Modified: {$fileLastModified}");
header("Etag: {$fileEtag}");
header("HTTP/1.1 304 Not Modified");
exit;
}
return response()->file($filePath, [
'Cache-Control' => 'public, max-age=' . ($siteConfig['themeFilesCacheForMinutes'] * 60),
'Etag' => $fileEtag,
'Last-Modified' => $fileLastModified,
'Content-Type' => $this->guessMimeType($filePath)
]);
}
/**
* @param $filePath
* @return false|string
*/
private function guessMimeType($filePath) {
$ext = pathinfo($filePath, PATHINFO_EXTENSION);
switch ($ext) {
case 'css':
return 'text/css; charset=UTF-8';
case 'js':
return 'text/javascript; charset=UTF-8';
default:
return File::mimeType($filePath);
}
}
}
有了那个设置;如果我想从我的主题中包含一个资产,例如css/sb-admin-2.min.css
在我 <head>...</head>
的主布局中,我是这样做的:
<link href="{{ url('theme/css/sb-admin-2.min.css') }}" rel="stylesheet">
因此,使用这种技术我可以将视图和资产放在一起,php 以提供具有缓存功能的静态资产(通过 headers + etag)。
我已经在本地测试过它并且它有效,初始加载大约需要 900 毫秒,一旦缓存预热,它加载页面的时间不到 500 毫秒。
我的问题;这是一个坏方法吗?即使用 php 提供静态文件?有更好的方法吗?
如果您想将刀片服务器和静态资产打包为单独的可替换主题,只需使用依赖注入为每个主题和 select 所需主题创建一个包。在每个主题的 ServiceProvider 中将您的资产发布到 public 目录。