mirror of
https://github.com/LD-Reborn/Berufsschule_HAM.git
synced 2026-05-06 11:32:19 +00:00
Merge pull request #334 from LD-Reborn/331-bug-image-elements-do-not-have-explicit-width-and-height-lighthouse-warning
331 bug image elements do not have explicit width and height lighthouse warning
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
-1
@@ -6,6 +6,7 @@ using Berufsschule_HAM.Services;
|
||||
using Berufsschule_HAM.Models;
|
||||
using Berufsschule_HAM.HealthChecks;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Bind options
|
||||
@@ -50,11 +51,14 @@ builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationSc
|
||||
builder.Services.AddResponseCompression(options =>
|
||||
{
|
||||
options.EnableForHttps = true;
|
||||
options.Providers.Add<GzipCompressionProvider>();
|
||||
options.Providers.Add<BrotliCompressionProvider>();
|
||||
options.MimeTypes =
|
||||
[
|
||||
"text/plain",
|
||||
"text/css",
|
||||
"application/javascript",
|
||||
"text/javascript",
|
||||
"text/html",
|
||||
"application/xml",
|
||||
"text/xml",
|
||||
@@ -91,6 +95,7 @@ if (app.Environment.IsDevelopment())
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseResponseCompression();
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
OnPrepareResponse = ctx =>
|
||||
@@ -118,7 +123,6 @@ app.UseStaticFiles(new StaticFileOptions
|
||||
app.UseRouting();
|
||||
app.UseAuthorization();
|
||||
app.UseResponseCaching();
|
||||
app.UseResponseCompression();
|
||||
|
||||
string[] supportedCultures = ["de", "en"];
|
||||
var localizationOptions = new RequestLocalizationOptions()
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
}
|
||||
|
||||
<form id="updateSettings" style="margin-bottom: 4rem !important" method="post" asp-controller="Settings" asp-action="Admin">
|
||||
<div class="row g-3">
|
||||
<h4 class="fw-bold">@T["General settings"]</h4>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label" for="updateHashAlgorithm">@T["Default hash algorithm"]</label>
|
||||
<select type="text" name="DefaultHashAlgorithm" id="updateHashAlgorithm" class="form-control">
|
||||
|
||||
@@ -12,14 +12,26 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Berufsschule_HAM</title>
|
||||
<script type="importmap"></script>
|
||||
@* <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-append-version="true"/> *@
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||
crossorigin="anonymous">
|
||||
<style>
|
||||
@if (Context.Request.Path.Value is not null)
|
||||
{
|
||||
string path = System.IO.Path.Combine("CriticalCSS", Context.Request.Path.Value.Trim('/').Replace("/", ".") + ".css");
|
||||
if (File.Exists(path))
|
||||
{
|
||||
@Html.Raw(File.ReadAllText(path));
|
||||
}
|
||||
} else {
|
||||
@Html.Raw(File.ReadAllText("CriticalCSS/_Layout.css"));
|
||||
}
|
||||
</style>
|
||||
<link rel="preload" href="~/lib/bootstrap/dist/css/bootstrap.min.css" as="style"/>
|
||||
<link rel="stylesheet" fetchpriority="high"
|
||||
href="~/lib/bootstrap/dist/css/bootstrap.min.css"
|
||||
media="print"
|
||||
onload="this.media='all'">
|
||||
@* <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" /> *@
|
||||
<link rel="preload" href="~/css/site.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
||||
<noscript><link rel="stylesheet" href="~/css/site.css"></noscript>
|
||||
<link rel="stylesheet" href="~/Berufsschule_HAM.styles.css" asp-append-version="true" />
|
||||
<noscript><link fetchpriority="high" rel="stylesheet" href="~/css/site.css"></noscript>
|
||||
<script>
|
||||
window.appTranslations = {
|
||||
selectLocation: '@T["Select location"]',
|
||||
@@ -38,9 +50,9 @@
|
||||
</script>
|
||||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar bg border-bottom box-shadow mb-3">
|
||||
<a href="#main-content" class="skip-link btn btn-primary">@T["Jump to content"]</a>
|
||||
<a href="#main-content" class="skip-link btn btn-primary" style="position: fixed; left: -10000px; z-index: 1000;">@T["Jump to content"]</a>
|
||||
<div class="container-fluid">
|
||||
<a class="" asp-area="" asp-controller="Home" asp-action="Index"><img fetchpriority="high" src="/HAM_Banner_xs.png" alt="Logo" style="max-height: 40px; width: 123px;"></a>
|
||||
<a class="" asp-area="" asp-controller="Home" asp-action="Index"><img fetchpriority="high" src="/HAM_Banner_xs.png" alt="Logo" width="123" height="40" style="width: 123px; height: 40px;"></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
|
||||
@@ -46,14 +46,3 @@ button.accept-policy {
|
||||
white-space: nowrap;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
left: -10000px;
|
||||
z-index: 1000;
|
||||
}
|
||||
.skip-link:focus {
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
import { generate } from 'critical';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
const browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
// Login
|
||||
await page.goto('http://localhost:5275/Home/Login');
|
||||
await page.type('#username', 'admin');
|
||||
await page.type('#password', 'Test1234.');
|
||||
await page.click('button[type=submit]');
|
||||
await page.waitForNavigation();
|
||||
|
||||
// Extract cookies
|
||||
const cookies = await page.cookies();
|
||||
await browser.close();
|
||||
|
||||
async function generateCriticalCSSForViews() {
|
||||
const viewsDir = 'Views';
|
||||
|
||||
// Helper function to get all .cshtml files recursively
|
||||
function getAllCshtmlFiles(dir) {
|
||||
let results = [];
|
||||
const list = fs.readdirSync(dir);
|
||||
|
||||
list.forEach(file => {
|
||||
const filePath = path.join(dir, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat && stat.isDirectory()) {
|
||||
// Recursively get files from subdirectories
|
||||
results = results.concat(getAllCshtmlFiles(filePath));
|
||||
} else if (file.endsWith('.cshtml')) {
|
||||
results.push(filePath);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Helper function to convert file path to URL path
|
||||
function filePathToUrlPath(filePath) {
|
||||
// Remove 'Views/' prefix
|
||||
let relativePath = filePath.replace(/^Views[\/\\]/, '');
|
||||
|
||||
// Remove .cshtml extension
|
||||
relativePath = relativePath.replace(/\.cshtml$/, '');
|
||||
|
||||
// Convert to URL format (replace \ with / and capitalize first letter)
|
||||
const urlPath = relativePath
|
||||
.split(/[\/\\]/)
|
||||
.map((segment, index) =>
|
||||
index === 0 ? segment : segment.charAt(0).toUpperCase() + segment.slice(1)
|
||||
)
|
||||
.join('/');
|
||||
|
||||
// Handle the case where we have a single file (like Index.cshtml)
|
||||
if (relativePath.includes('/')) {
|
||||
// Convert to URL path format: Views/Home/Index.cshtml -> /Home/Index
|
||||
return '/' + relativePath.replace(/\\/g, '/').replace(/\.cshtml$/, '');
|
||||
} else {
|
||||
// For files directly in Views folder (like Views/Index.cshtml)
|
||||
return '/' + relativePath.replace(/\.cshtml$/, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Get all .cshtml files
|
||||
const cshtmlFiles = getAllCshtmlFiles(viewsDir);
|
||||
|
||||
// Create CriticalCSS directory if it doesn't exist
|
||||
const criticalCssDir = 'CriticalCSS';
|
||||
if (!fs.existsSync(criticalCssDir)) {
|
||||
fs.mkdirSync(criticalCssDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Process each file
|
||||
for (const file of cshtmlFiles) {
|
||||
try {
|
||||
const urlPath = filePathToUrlPath(file);
|
||||
|
||||
// Generate critical CSS
|
||||
await generate({
|
||||
src: `http://localhost:5275${urlPath}`,
|
||||
inline: false,
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
penthouse: {
|
||||
customHeaders: {
|
||||
cookie: cookies.map(c => `${c.name}=${c.value}`).join('; ')
|
||||
},
|
||||
forceInclude: [
|
||||
'[data-bs-theme="dark"]',
|
||||
'.navbar',
|
||||
'.dropdown-menu',
|
||||
'.me-2',
|
||||
'.align-items-center',
|
||||
'.d-flex',
|
||||
'.position-fixed', // print batch
|
||||
'.bottom-0',
|
||||
'.start-0',
|
||||
'.m-4',
|
||||
'.row', // elements
|
||||
'.row>*',
|
||||
'.g-3',
|
||||
'.col-md-3',
|
||||
'.text-center',
|
||||
'.mb-3',
|
||||
'.mb-4',
|
||||
'.mt-3',
|
||||
'.py-4',
|
||||
'.text-center',
|
||||
'h2',
|
||||
'.form-control',
|
||||
'.form-control-sm',
|
||||
'.modal',
|
||||
'.btn',
|
||||
'.btn-sm',
|
||||
'.btn-secondary',
|
||||
'.btn-warning',
|
||||
'.btn-danger',
|
||||
'.rounded-circle', // user icon
|
||||
'table', // table elements (users)
|
||||
'.table>thead',
|
||||
'.user-row > td',
|
||||
'thead',
|
||||
'tbody',
|
||||
'th',
|
||||
'tr',
|
||||
'td',
|
||||
'.table>:not(caption)>*>*',
|
||||
'.table-striped>tbody>tr:nth-of-type(odd)>*',
|
||||
'.gap-2',
|
||||
'.table',
|
||||
'.table-responsive',
|
||||
'.align-middle'
|
||||
]
|
||||
},
|
||||
target: {
|
||||
css: path.join(criticalCssDir, urlPath.replace(/\//g, '.').replace(/^\./, '') + '.css')
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Critical CSS generated for: ${urlPath}`);
|
||||
} catch (err) {
|
||||
console.error(`Error processing ${file}:`, err);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('All critical CSS files generated!');
|
||||
}
|
||||
|
||||
// Run the function
|
||||
generateCriticalCSSForViews().catch(console.error);
|
||||
|
||||
|
||||
// How to run this:
|
||||
// install dependencies:
|
||||
// npm i -D critical
|
||||
// npm install puppeteer
|
||||
// run:
|
||||
// node critical.js
|
||||
@@ -72,3 +72,13 @@ h3.modal-title {
|
||||
h4.fw-bold, h4.card-title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.table button {
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
outline: none;
|
||||
}
|
||||
Reference in New Issue
Block a user