lighthouse
Some checks failed
deploy to production / lighthouse-evaluation (push) Failing after 1s
deploy to production / deploy (push) Failing after 28s

This commit is contained in:
2023-12-26 12:45:24 +00:00
parent edfca1f007
commit 8184ffecf4
20 changed files with 613 additions and 125 deletions

View File

@@ -46,6 +46,22 @@ meta:
subFields:
- source: aktiv
- source: meta
subNavigation:
- name: modalForeign
defaultSort:
field: "path"
order: "ASC"
views:
- type: table
columns:
- path
defaultCallback:
eval: |
//js
(entry) => {
parent.selectEntry(entry)
}
//!js
imageFilter:
xs:

View File

@@ -0,0 +1,29 @@
name: lighthouseSubpath
meta:
label: Lighthouse Subpaths
muiIcon: web
views:
- type: table
columns:
- source: lighthouseSubpath
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
fields:
- type: string
name: lighthouseSubpath
meta:
label: PagespeedPaths

View File

@@ -0,0 +1,120 @@
name: lighthouse
meta:
label: Lighthouse
muiIcon: web
views:
- type: table
mediaQuery: "(min-width: 600px)"
columns:
- source: insertTime
filter: true
- source: perfomance
filter: true
- source: accessibility
filter: true
- source: bestPractices
filter: true
- source: seo
filter: true
- type: simpleList
mediaQuery: "(max-width: 599px)"
primaryText: insertTime
secondaryText: performance
tertiaryText: accessibility
permissions:
public:
methods:
get: false
post: false
put: false
delete: false
user:
methods:
get: true
post: true
put: true
delete: true
projections:
dashboard:
hooks:
post:
create:
type: javascript
file: hooks/lighthouse/post_create.js
fields:
- name: analyzedPaths
type: string[]
meta:
label: Analyzed Paths
- name: performance
type: number
meta:
label: Performance
- name: accessibility
type: number
meta:
label: Accessibility
- name: bestPractices
type: number
meta:
label: Best Practices
- name: seo
type: number
meta:
label: SEO
- name: lighthouseMetrics
type: object
meta:
label: Lighthouse Metrics
subFields:
- name: FCPS
type: number
meta:
label: First Contentful Paint Score
- name: FCPV
type: number
meta:
label: First Contentful Paint Value
- name: FMPV
type: number
meta:
label: First Meaningful Paint Value
- name: FMPS
type: number
meta:
label: First Meaningful Paint Score
- name: SIS
type: number
meta:
label: Speed Index Score
- name: SIV
type: number
meta:
label: Speed Index Value
- name: TTIS
type: number
meta:
label: Time to Interactive Score
- name: TTIV
type: number
meta:
label: Time to Interactive Value
- name: FPIDS
type: number
meta:
label: First Potential Input Delay Score
- name: FPIDV
type: number
meta:
label: First Potential Input Delay Value

View File

@@ -5,15 +5,250 @@ meta:
servers:
- url: https://tibi-admin-server.code.testversion.online/api/v1/_/demo
description: code-server
dashboard:
majorItems:
- collection: banner # Sammlung, aus der die Daten für das nächste Element stammen
type: reference # Art des Elements, hier ein Referenz-Element
style: # Stil des Elements
upper: rgba(3, 50, 59, 0.7) # Farbe des oberen Teils
lower: rgba(3, 50, 59) # Farbe des unteren Teils
- type: "sectionTitle"
title: { de: "Website Perfomance", en: "Website Perfomance" }
appendix:
collection: lighthouse
eval: |
(function(){
return " " + new Date($date).toLocaleDateString() + ""
})()
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: performance
yAxis: latestValue
graphName: { de: "Perfomance Score", en: "Perfomance Score" }
dateTimeField: insertTime
- collection: content # Wiederholung der vorherigen Elemente
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: accessibility
yAxis: latestValue
graphName: { de: "Accessibility Score", en: "Accessibility Score" }
dateTimeField: insertTime
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: bestPractices
yAxis: latestValue
graphName: { de: "Best Practices Score", en: "Best Practices Score" }
dateTimeField: insertTime
- type: graph
filter: false
graphType: radialBar
until: "lastYear"
value: total
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-6"
small: "col-12"
large: "col-3"
options:
{
property: plotOptions,
value:
{
radialBar:
{
hollow: { margin: 0, size: "70%" },
track: { dropShadow: { enabled: true, top: 2, left: 0, blur: 4, opacity: 0.15 } },
dataLabels:
{
name: { offsetY: -10, color: "#000", fontSize: "13px" },
value: { color: "#000", fontSize: "30px", show: true },
},
},
},
}
graphs:
- collection: lighthouse
field: seo
yAxis: latestValue
graphName: { de: "SEO Score", en: "SEO Score" }
dateTimeField: insertTime
- type: swiper # Art des Elements, hier ein Swiper
containerProps:
#optional class prop
layout:
breakBefore: false
breakAfter: false
size:
default: "col-12"
small: "col-12"
large: "col-6 row-2-4"
elements: # Liste der Elemente in diesem Swiper
- type: graph
title:
value: { de: "Ladezeit (Score)", en: "Loadtime (Score)" }
xAxis: manual
until: "lastYear"
filter: false #deaktiviert die Filter möglichkeit für den Nutzer beim diagramm, normalerweise aktiviert. Hierbei sind alle kombinationen x >= until möglich
columns:
- name: { de: '["Erstes sichtbares", "Element"]', en: '["First Contentful", "Paint"]' }
field: lighthouseMetrics.FCPS
- name: { de: '["Erstes bedeutsames", "Element"]', en: '["First Meaningful", "Paint"]' }
field: lighthouseMetrics.FMPS
- name:
{
de: '["Maximale potenzielle", "erste", "ingabeverzögerung"]',
en: '["Max Potential", "First Input", "Delay"]',
}
field: lighthouseMetrics.FPIDS
- name: { de: '["Zeit bis", "zur", "Interaktivität"]', en: '["Time to", "Interactive"]' }
field: lighthouseMetrics.TTIS
- name: { de: '["Geschwindigkeitsindex"]', en: '["Speed Index"]' }
field: lighthouseMetrics.SIS
graphType: "bar"
graphs:
- graphName: { de: "Lighthouse Metriken", en: "Lighthouse Metrics" }
yAxis: latestValue
collection: lighthouse
dateTimeField: insertTime
- type: graph
title:
value: { de: "Ladezeit (Sekunden)", en: "Loadtime (seconds)" }
xAxis: manual
until: "lastYear"
filter: false #deaktiviert die Filter möglichkeit für den Nutzer beim diagramm, normalerweise aktiviert. Hierbei sind alle kombinationen x >= until möglich
columns:
- name: { de: '["Erstes sichtbares", "Element"]', en: '["First Contentful", "Paint"]' }
field: lighthouseMetrics.FCPV
- name: { de: '["Erstes bedeutsames", "Element"]', en: '["First Meaningful", "Paint"]' }
field: lighthouseMetrics.FMPV
- name:
{
de: '["Maximale potenzielle", "erste", "ingabeverzögerung"]',
en: '["Max Potential", "First Input", "Delay"]',
}
field: lighthouseMetrics.FPIDV
- name: { de: '["Zeit bis", "zur", "Interaktivität"]', en: '["Time to", "Interactive"]' }
field: lighthouseMetrics.TTIV
- name: { de: '["Geschwindigkeitsindex"]', en: '["Speed Index"]' }
field: lighthouseMetrics.SIV
graphType: "bar"
graphs:
- graphName: { de: "Lighthouse Metriken", en: "Lighthouse Metrics" }
yAxis: latestValue
collection: lighthouse
dateTimeField: insertTime
- type: "sectionTitle"
title: { de: "Seiteninhalte", en: "Page content" }
- collection: content
type: reference
style:
upper: rgba(3, 50, 59, 0.7)
@@ -30,6 +265,26 @@ meta:
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
- type: "sectionTitle"
title: { de: "Aktionen", en: "Actions" }
- collection: lighthouse
type: action
action: "Lighthouse Durchlauf starten"
backgroundAction: true
modalText:
{
de: "Zur Analyse der Website werden einige Zeitintensive prozesse gestartet, daher wird dies im Hintergrund ausgeführt. Es kann einige Minuten dauern bis das Dashboard aktuallisiert wird, bitte haben Sie etwas Geduld.",
en: "To analyze the website, some time-intensive processes are started, so this is done in the background. It may take a few minutes for the dashboard to be updated, please be patient.",
}
properties:
url: https://allkids-erfurt.de
type: post
style:
upper: rgba(3, 50, 59, 0.7)
lower: rgba(3, 50, 59)
minorItems: []
collections:
@@ -39,8 +294,10 @@ collections:
- !include collections/forms.yml
- !include collections/backups.yml
- !include collections/ssr.yml
- !include collections/lighthouse.yml
- !include collections/lighthouse-subpaths.yml
jobs:
- cron: "0 * * * *"
- cron: "* * * * "
type: javascript
file: jobs/requestTemperature.js
file: jobs/lighthouse.js

View File

@@ -29,4 +29,5 @@ module.exports = {
return -1
},
ssrPublishCheckCollections: ["content"],
LIGHTHOUSE_TOKEN: "AIzaSyC0UxHp3-MpJiDL3ws7pEV6lj57bfIc7GQ",
}

View File

@@ -37,6 +37,7 @@ function obj2str(obj) {
if (obj) return obj
}
var { LIGHTHOUSE_TOKEN } = require("../config")
/**
* clear SSR cache
@@ -46,8 +47,103 @@ function clearSSRCache() {
context.response.header("X-SSR-Cleared", info.removed)
}
function calculateAverageDynamically(dbObjs) {
const sumObj = {}
let count = 0
dbObjs.forEach((obj) => {
accumulate(obj, sumObj)
count++
})
function accumulate(sourceObj, targetObj) {
for (const key in sourceObj) {
if (typeof sourceObj[key] === "number") {
targetObj[key] = (targetObj[key] || 0) + sourceObj[key]
} else if (typeof sourceObj[key] === "object" && sourceObj[key] !== null) {
targetObj[key] = targetObj[key] || {}
accumulate(sourceObj[key], targetObj[key])
}
}
}
function average(targetObj) {
for (const key in targetObj) {
if (typeof targetObj[key] === "number") {
targetObj[key] = targetObj[key] / count
} else if (typeof targetObj[key] === "object") {
average(targetObj[key])
}
}
}
average(sumObj)
return sumObj
}
function run(url) {
const response = context.http
.fetch(url, {
timeout: 300,
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.body.json()
// needs enough traffic to be collected
const cruxMetrics = {
"First Contentful Paint": response?.loadingExperience?.metrics?.FIRST_CONTENTFUL_PAINT_MS?.category,
"First Input Delay": response?.loadingExperience?.metrics?.FIRST_INPUT_DELAY_MS?.category,
}
const lighthouse = response.lighthouseResult
const lighthouseMetrics = {
FCPS: lighthouse.audits["first-contentful-paint"].score * 100,
FCPV: lighthouse.audits["first-contentful-paint"].numericValue / 1000,
FMPS: lighthouse.audits["first-meaningful-paint"].score * 100,
FMPV: lighthouse.audits["first-meaningful-paint"].numericValue / 1000,
SIS: lighthouse.audits["speed-index"].score * 100,
SIV: lighthouse.audits["speed-index"].numericValue / 1000,
TTIS: lighthouse.audits["interactive"].score * 100,
TTIV: lighthouse.audits["interactive"].numericValue / 1000,
FPIDS: lighthouse.audits["max-potential-fid"].score * 100,
FPIDV: lighthouse.audits["max-potential-fid"].numericValue / 1000,
}
let dbObject = {
cruxMetrics,
lighthouseMetrics,
performance: lighthouse.categories.performance.score * 100,
accessibility: lighthouse.categories.accessibility.score * 100,
bestPractices: lighthouse.categories["best-practices"].score * 100,
seo: lighthouse.categories.seo.score * 100,
}
return dbObject
}
function setUpQuery(subPath = "/") {
const api = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed"
let params = `category=performance&category=accessibility&category=best-practices&category=seo`
const parameters = {
url: encodeURIComponent(`https://allkids-erfurt.de/${subPath}`),
key: LIGHTHOUSE_TOKEN,
}
let query = `${api}?`
for (let key in parameters) {
query += `${key}=${parameters[key]}&`
}
query += params // Append other parameters without URL encoding
return query
}
module.exports = {
log,
clearSSRCache,
obj2str,
run,
setUpQuery,
calculateAverageDynamically,
}

View File

@@ -0,0 +1,16 @@
var { setUpQuery, calculateAverageDynamically, run } = require("../lib/utils")
;(function () {
let subPaths = context.db.find("lighthouseSubpath")
let urls = []
for (let i = 0; i < subPaths.length; i++) {
urls.push(setUpQuery(subPaths[i].lighthouseSubpath))
}
let dbObjs = []
urls.forEach((url) => {
console.log("URL:", url)
dbObjs.push(run(url))
})
let dbObject = calculateAverageDynamically(dbObjs)
dbObject.analyzedPaths = [...subPaths].map((subPath) => subPath.lighthouseSubpath)
return { data: dbObject }
})()

17
api/jobs/lighthouse.js Normal file
View File

@@ -0,0 +1,17 @@
var { setUpQuery, calculateAverageDynamically, run } = require("../hooks/lib/utils")
;(function () {
console.log("Running lighthouse job")
let subPaths = context.db.find("lighthouseSubpath")
let urls = []
for (let i = 0; i < subPaths.length; i++) {
urls.push(setUpQuery(subPaths[i].lighthouseSubpath))
}
let dbObjs = []
urls.forEach((url) => {
console.log("URL:", url)
dbObjs.push(run(url))
})
let dbObject = calculateAverageDynamically(dbObjs)
dbObject.analyzedPaths = [...subPaths].map((subPath) => subPath.lighthouseSubpath)
context.db.create("lighthouse", dbObject)
})()

View File

@@ -1,9 +0,0 @@
function requestTemperature() {
let response = context.http.fetch(
"https://api.openweathermap.org/data/2.5/weather?lat=50.98&lon=11.03&appid=21fa3d5930956682000f7a2db5f357c0"
)
let data = response.body.json()
let temperatureEntries = context.db.find("temperature")
context.db.update("temperature", temperatureEntries[0].id, { temperature: data.main.temp - 273.15 })
}
requestTemperature()