Skip to content

Commit 87969f8

Browse files
authored
Merge pull request #55 from liamgold/feature/swdm-v4-green-hosting
Upgrade to SWDM v4 and add green hosting detection
2 parents a0a612d + d7fa786 commit 87969f8

18 files changed

+354
-156
lines changed

.github/RELEASE.md

Lines changed: 0 additions & 78 deletions
This file was deleted.

CLAUDE.md

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ A community-driven open-source NuGet package that brings sustainability insights
1515
- **Xperience by Kentico** (>= 30.4.2)
1616
- **Microsoft Playwright** (1.52.0) - Headless browser automation
1717
- **React + TypeScript** - Admin UI components
18-
- **@tgwf/co2** library - Carbon emission calculations
18+
- **@tgwf/co2** library (v0.16.9) - Carbon emission calculations using SWDM v4
1919

2020
## Project Structure
2121

@@ -40,7 +40,7 @@ C:\Projects\xperience-community-sustainability\
4040
│ ├── Models/ # Data structures
4141
│ │ ├── SustainabilityResponse.cs # API response model
4242
│ │ ├── SustainabilityData.cs # Raw data from JS (naming: lowercase for JSON mapping)
43-
│ │ ├── SustainabilityOptions.cs # Configuration options (PlaywrightBrowserPath)
43+
│ │ ├── SustainabilityOptions.cs # Configuration options (TimeoutMilliseconds, EnableBrowserConsoleLogging)
4444
│ │ ├── ExternalResource.cs # Individual resource model
4545
│ │ └── ExternalResourceGroup.cs # Resource grouping by type (Images, Scripts, CSS, etc.)
4646
│ ├── Extensions/ # Extension methods
@@ -105,8 +105,9 @@ C:\Projects\xperience-community-sustainability\
105105
3. **Data loaded**: Displays comprehensive dashboard with hero carbon rating
106106

107107
**Key Features**:
108-
- **Hero Carbon Rating Section** - Large 120px rating letter with gradient background themed by rating color
108+
- **Hero Carbon Rating Section** - Large 120px rating letter with gradient background themed by rating color, includes link to SWDM v4 methodology
109109
- **Stat Cards Grid** - 2x2 grid showing CO₂ Emissions, Page Weight, Resources count, and Efficiency rating
110+
- **Green Hosting Info Banner** - Displays hosting status (Green/Standard/Unknown) with color-coded badge between hero and resources
110111
- **Collapsible Resource Lists** - Shows 3 resources by default with "Show X more" button
111112
- **Resource Breakdown** - Sorted by size (largest first) with filename/path separation
112113
- **Percentage Badges** - Shows what % of total page weight each resource group represents
@@ -121,16 +122,28 @@ C:\Projects\xperience-community-sustainability\
121122
### 4. JavaScript Analysis (src/wwwroot/scripts/resource-checker.js)
122123

123124
**Process**:
124-
1. Scrolls page to trigger lazy-loaded resources (line 21)
125-
2. Waits 2 seconds for resources to load (line 22)
126-
3. Collects all resources via `performance.getEntriesByType("resource")` (line 47)
127-
4. Calculates total transfer size (line 51)
128-
5. Checks if host uses green energy via `@tgwf/co2` (line 33)
129-
6. Calculates CO2 emissions using SWD model (line 36)
130-
7. Assigns grade A+ through F (line 56-64)
131-
8. Outputs JSON to DOM element with `data-testid="sustainabilityData"` (line 14)
132-
133-
**External Dependency**: `https://cdn.skypack.dev/@tgwf/co2@0.15` (line 1)
125+
1. Scrolls page to trigger lazy-loaded resources
126+
2. Waits 2 seconds for resources to load
127+
3. Collects all resources via `performance.getEntriesByType("resource")`
128+
4. Calculates total transfer size
129+
5. Checks if host uses green energy via `@tgwf/co2` hosting check (returns Green/NotGreen/Unknown)
130+
6. Calculates CO2 emissions using **SWDM v4** with `perByteTrace()` method
131+
7. Retrieves built-in rating (A+ through F) from `@tgwf/co2` v0.16
132+
8. Outputs JSON to DOM element with `data-testid="sustainabilityData"`
133+
134+
**Key Implementation Details**:
135+
- Uses **SWDM v4** (`{ model: "swd", version: 4, rating: true }`)
136+
- Uses `perByteTrace()` instead of deprecated `perVisitTrace()`
137+
- Bundled library (no external CDN dependency) - webpack bundles `@tgwf/co2` locally
138+
- Hosting check handles both function and object patterns for compatibility
139+
- Rating thresholds (grams CO₂ per page view):
140+
- A+: < 0.040g
141+
- A: < 0.079g
142+
- B: < 0.145g
143+
- C: < 0.209g
144+
- D: < 0.278g
145+
- E: < 0.359g
146+
- F: >= 0.360g
134147

135148
### 5. Module Installation (src/Admin/SustainabilityModuleInstaller.cs)
136149

@@ -139,14 +152,15 @@ C:\Projects\xperience-community-sustainability\
139152
2. `InitializeModule` invoked when app initialized (line 29)
140153
3. `Install()` creates database table for `SustainabilityPageDataInfo` (line 15)
141154

142-
**Database Schema** (lines 58-119):
155+
**Database Schema**:
143156
- `SustainabilityPageDataID` (PK)
144157
- `WebPageItemID` (Foreign key to page)
145158
- `LanguageName` (Language variant)
146159
- `DateCreated`
147160
- `TotalSize` (decimal)
148161
- `TotalEmissions` (double)
149162
- `CarbonRating` (string: A+, A, B, C, D, E, F)
163+
- `GreenHostingStatus` (string: Green, NotGreen, Unknown)
150164
- `ResourceGroups` (JSON serialized)
151165

152166
## Configuration
@@ -156,13 +170,15 @@ C:\Projects\xperience-community-sustainability\
156170
```json
157171
{
158172
"Sustainability": {
159-
"TimeoutMilliseconds": 60000
173+
"TimeoutMilliseconds": 60000,
174+
"EnableBrowserConsoleLogging": false
160175
}
161176
}
162177
```
163178

164179
**Options**:
165180
- `TimeoutMilliseconds`: Timeout in milliseconds for waiting for sustainability data to be collected. Default: 60000 (60 seconds)
181+
- `EnableBrowserConsoleLogging`: Enable browser console logging to Kentico Event Log for debugging. Default: false. When enabled, all console messages from the headless browser (including those from resource-checker.js) are logged to the Event Log with source "SustainabilityService" and event code "BrowserConsole"
166182

167183
### Service Registration (Program.cs)
168184

@@ -175,6 +191,43 @@ This registers:
175191
- `ISustainabilityModuleInstaller` as Singleton
176192
- Binds `SustainabilityOptions` from configuration
177193

194+
## Data Models
195+
196+
### SustainabilityData (from JavaScript)
197+
198+
The JavaScript returns data with a nested `Co2Result` structure:
199+
200+
```json
201+
{
202+
"pageWeight": 1234567,
203+
"carbonRating": "B",
204+
"greenHostingStatus": "Green",
205+
"emissions": {
206+
"co2": {
207+
"total": 0.123,
208+
"rating": "B"
209+
},
210+
"green": true
211+
},
212+
"resources": [...]
213+
}
214+
```
215+
216+
### Backend Models
217+
218+
**SustainabilityData.cs**:
219+
- `PageWeight` (int) - Total bytes transferred
220+
- `CarbonRating` (string) - Letter grade from JavaScript
221+
- `GreenHostingStatus` (string) - Green, NotGreen, or Unknown
222+
- `Emissions` (Emissions object)
223+
- `Co2` (Co2Result object) - **Note: Nested structure**
224+
- `Total` (double) - Grams CO₂ per page view
225+
- `Rating` (string) - Built-in rating from @tgwf/co2
226+
- `Green` (bool) - Whether green hosting was used in calculation
227+
- `Resources` (Resource array)
228+
229+
**Important**: The backend reads `sustainabilityData.Emissions?.Co2?.Total` (nested) to get the emission value, not a flat `Co2` property.
230+
178231
## Data Flow
179232

180233
### Running a New Report
@@ -210,7 +263,6 @@ This registers:
210263

211264
## Known Issues & Limitations
212265

213-
- **External CDN dependency**: Skypack CDN for @tgwf/co2 (availability risk) - see GitHub issues for planned improvements
214266
- **No automated tests**: Unit/integration tests needed for service and UI components
215267
- **Future enhancements**: See GitHub issues for planned features (global dashboard, historical trends, etc.)
216268

@@ -249,9 +301,7 @@ npm run build
249301
- `@kentico/xperience-admin-base` (30.4.2) - Base admin framework
250302
- `@kentico/xperience-admin-components` (30.4.2) - Native XbyK UI components
251303
- React (18.3.1) and React DOM (18.3.1)
252-
253-
### External Runtime
254-
- `@tgwf/co2` (v0.15) via Skypack CDN
304+
- `@tgwf/co2` (v0.16.9) - Bundled locally via webpack (no external CDN)
255305

256306
## Common Tasks
257307

@@ -264,7 +314,11 @@ npm run build
264314

265315
### Modifying Carbon Rating Thresholds
266316

267-
Edit `resource-checker.js` line 56-64 (grades) and update React component's `ratingDescriptions` (SustainabilityTabTemplate.tsx:41-49).
317+
**Note**: Carbon ratings now come from the built-in `@tgwf/co2` library using SWDM v4 official thresholds. The library automatically assigns ratings based on grams CO₂ per page view.
318+
319+
If you need to customize rating descriptions or UI display:
320+
- Update React component's `ratingDescriptions` (SustainabilityTabTemplate.tsx)
321+
- Update `getHostingStatusDisplay()` helper for hosting status colors and text
268322

269323
### Changing Resource Categories
270324

@@ -278,8 +332,10 @@ Update `ResourceGroupType` enum (ExternalResourceGroup.cs:43-55) and `GetInitiat
278332

279333
## Debugging Tips
280334

281-
1. **Playwright issues**: Check event log in Kentico admin for logged errors
282-
2. **Script not loading**: Verify `/_content/XperienceCommunity.Sustainability/scripts/resource-checker.js` is accessible
283-
3. **Timeout errors**: Increase timeout in SustainabilityService.cs:60 or check if page loads slowly
284-
4. **CSP errors**: Ensure `BypassCSP = true` is set (line 45)
285-
5. **Browser not found**: Playwright requires browser installation (`playwright install chromium`)
335+
1. **Enable console logging**: Set `EnableBrowserConsoleLogging: true` in appsettings.json to log all browser console messages to Kentico Event Log. View logs in Admin → System → Event log (source: `SustainabilityService`, event code: `BrowserConsole`)
336+
2. **Playwright issues**: Check event log in Kentico admin for logged errors
337+
3. **Script not loading**: Verify `/_content/XperienceCommunity.Sustainability/scripts/resource-checker.js` is accessible
338+
4. **Timeout errors**: Increase `TimeoutMilliseconds` in appsettings.json or check if page loads slowly
339+
5. **CSP errors**: Ensure `BypassCSP = true` is set in SustainabilityService.cs
340+
6. **Browser not found**: Playwright requires browser installation (`playwright install chromium`)
341+
7. **Hosting status Unknown**: Check Event Log with console logging enabled to see if Green Web Foundation API is accessible

README.md

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,36 @@ dotnet add package XperienceCommunity.Sustainability
5555

5656
> **Note**: Playwright browsers (Chromium) are automatically installed on first application startup. The installation path defaults to `App_Data/playwright` unless you're hosting on a UNC path.
5757
58+
## Features
59+
60+
### Carbon Emissions Calculation
61+
62+
The package uses the **Sustainable Web Design Model v4 (SWDM v4)** from [The Green Web Foundation](https://www.thegreenwebfoundation.org/) to calculate carbon emissions. Carbon ratings (A+ through F) follow the [official Digital Carbon Ratings](https://sustainablewebdesign.org/digital-carbon-ratings/) methodology.
63+
64+
### Green Hosting Detection
65+
66+
The package automatically checks if your website is hosted on a green energy provider using The Green Web Foundation's database. This affects the carbon calculation:
67+
68+
- **Green hosting**: Uses renewable energy intensity values (lower emissions)
69+
- **Standard hosting**: Uses global grid intensity values
70+
- **Unknown**: When verification fails, conservative estimates are used
71+
72+
The hosting status is displayed in the Sustainability report with three possible states:
73+
74+
-**Green hosting** - Site uses renewable/green energy
75+
-**Standard hosting** - Site uses standard grid energy
76+
-**Unknown hosting** - Unable to verify hosting provider
77+
78+
### Sustainability Report
79+
80+
Each report includes:
81+
82+
- **Carbon Rating**: Letter grade (A+ through F) based on grams CO₂ per page view
83+
- **CO₂ Emissions**: Total carbon emissions with hosting status indicator
84+
- **Page Weight**: Total size of all resources loaded
85+
- **Resource Breakdown**: Categorized by type (Images, Scripts, CSS, etc.) with individual file sizes
86+
- **Optimization Tips**: Xperience-specific recommendations for reducing page weight
87+
5888
## Configuration
5989

6090
The package can be configured using the `Sustainability` section in your `appsettings.json` file.
@@ -63,7 +93,8 @@ The package can be configured using the `Sustainability` section in your `appset
6393
{
6494
"Sustainability": {
6595
"TimeoutMilliseconds": 60000,
66-
"PlaywrightBrowserPath": "/custom/path/to/playwright/browsers"
96+
"PlaywrightBrowserPath": "/custom/path/to/playwright/browsers",
97+
"EnableBrowserConsoleLogging": false
6798
}
6899
}
69100
```
@@ -74,6 +105,7 @@ The package can be configured using the `Sustainability` section in your `appset
74105
| ------ | ----------- | ------- |
75106
| `TimeoutMilliseconds` | Timeout in milliseconds for waiting for sustainability data to be collected from the page. | `60000` (60 seconds) |
76107
| `PlaywrightBrowserPath` | Custom path where Playwright browsers should be installed. **Only required when hosting on UNC paths (network shares starting with `\\`)**. For standard hosting, browsers are automatically installed in `App_Data/playwright`. | `null` |
108+
| `EnableBrowserConsoleLogging` | Enable browser console logging to Kentico Event Log for debugging purposes. When enabled, all console messages from the headless browser are logged to help troubleshoot issues. | `false` |
77109

78110
> **Note on UNC Hosting**: When hosting on UNC paths (network shares), you **must** configure `PlaywrightBrowserPath` or the application will throw an error during startup. This setting is ignored for standard hosting scenarios.
79111

examples/DancingGoat/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
"CMSHashStringSalt": "792155e3-6bc0-4eb3-ae03-47db9331b540",
2020
"Sustainability": {
2121
"PlaywrightBrowserPath": "#{WebsitePath}#\\App_Data\\playwright",
22-
"TimeoutMilliseconds": 6000
22+
"TimeoutMilliseconds": 60000
2323
}
2424
}

src/Admin/SustainabilityModuleInstaller.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,15 @@ private static void InstallSustainabilityPageDataClass(ResourceInfo resourceInfo
118118
};
119119
formInfo.AddFormItem(formItem);
120120

121+
formItem = new FormFieldInfo
122+
{
123+
Name = nameof(SustainabilityPageDataInfo.GreenHostingStatus),
124+
Visible = false,
125+
DataType = FieldDataType.Text,
126+
Enabled = true,
127+
};
128+
formInfo.AddFormItem(formItem);
129+
121130
SetFormDefinition(info, formInfo);
122131

123132
if (info.HasChanged)

src/Classes/XperienceCommunity/SustainabilityPageData/SustainabilityPageDataInfo.generated.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,17 @@ public virtual string ResourceGroups
118118
}
119119

120120

121+
/// <summary>
122+
/// Green hosting status.
123+
/// </summary>
124+
[DatabaseField]
125+
public virtual string GreenHostingStatus
126+
{
127+
get => ValidationHelper.GetString(GetValue(nameof(GreenHostingStatus)), String.Empty);
128+
set => SetValue(nameof(GreenHostingStatus), value);
129+
}
130+
131+
121132
/// <summary>
122133
/// Deletes the object using appropriate provider.
123134
/// </summary>

0 commit comments

Comments
 (0)