@pierrad/web-carbon-analyzer
Version:
A tool to measure the carbon footprint of websites using CO2.js
189 lines • 8.08 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
* CO2 Calculator module
* Calculates carbon emissions using CO2.js
*/
const CO2 = __importStar(require("@tgwf/co2"));
const logger_1 = __importDefault(require("../utils/logger"));
const default_1 = __importDefault(require("../config/default"));
class CO2Calculator {
constructor(customConfig = {}) {
this.config = { ...default_1.default.co2, ...customConfig };
// Initialize CO2.js with the configured model
this.co2 = new CO2.co2({
model: this.config.model,
});
// Initialize green hosting checker if enabled
if (this.config.includeGreenHostingCheck) {
this.greenHostingCheck = CO2.hosting;
}
else {
this.greenHostingCheck = null;
}
}
/**
* Calculate carbon emissions for a set of resources
* @param {ResourcesData} resourcesData - Processed resources data from NetworkInterceptor
* @returns {EmissionsData} - Carbon emissions data
*/
async calculateEmissions(resourcesData) {
logger_1.default.info('Calculating carbon emissions');
if (!resourcesData || !resourcesData.allResources) {
throw new Error('Invalid resources data');
}
// Start with the calculation summary structure
const result = {
totalEmissions: 0,
byType: {},
byDomain: {},
byGreenHosting: {
green: { size: 0, emissions: 0, count: 0 },
nonGreen: { size: 0, emissions: 0, count: 0 },
unknown: { size: 0, emissions: 0, count: 0 }
},
perResource: [],
comparisons: {}
};
// Initialize emissions by type
Object.keys(resourcesData.sizeByType).forEach(type => {
result.byType[type] = {
size: resourcesData.sizeByType[type],
emissions: 0,
count: resourcesData.resourcesByType[type].length
};
});
// Process each domain
for (const [domain, domainData] of Object.entries(resourcesData.domains)) {
// Check if the domain is green-hosted
let isGreen = false;
if (this.config.includeGreenHostingCheck && this.greenHostingCheck) {
try {
isGreen = await this.greenHostingCheck.check(domain);
logger_1.default.debug(`Domain ${domain} is ${isGreen ? 'green' : 'non-green'} hosted`);
}
catch (error) {
logger_1.default.debug(`Could not determine green hosting status for ${domain}: ${error.message}`);
isGreen = null; // Unknown status
}
}
// Calculate emissions for this domain
const emissions = this.co2.perByte(domainData.size, isGreen === true);
// Add to domain results
result.byDomain[domain] = {
size: domainData.size,
emissions,
count: domainData.count,
isGreen
};
// Add to green hosting breakdown
if (isGreen === true) {
result.byGreenHosting.green.size += domainData.size;
result.byGreenHosting.green.emissions += emissions;
result.byGreenHosting.green.count += domainData.count;
}
else if (isGreen === false) {
result.byGreenHosting.nonGreen.size += domainData.size;
result.byGreenHosting.nonGreen.emissions += emissions;
result.byGreenHosting.nonGreen.count += domainData.count;
}
else {
result.byGreenHosting.unknown.size += domainData.size;
result.byGreenHosting.unknown.emissions += emissions;
result.byGreenHosting.unknown.count += domainData.count;
}
// Update total emissions
result.totalEmissions += emissions;
}
// Process individual resources
for (const resource of resourcesData.allResources) {
let domain = '';
try {
domain = new URL(resource.url).hostname;
}
catch (error) {
logger_1.default.debug(`Could not parse URL ${resource.url}: ${error.message}`);
}
const isGreen = result.byDomain[domain]?.isGreen;
const resourceType = resource.resourceType;
const size = resource.size.compressed || 0;
// Calculate emissions for this resource
const emissions = this.co2.perByte(size, isGreen === true);
// Add to per-resource results
result.perResource.push({
url: resource.url,
type: resourceType,
size,
domain,
isGreen,
emissions
});
// Add to type breakdown
if (result.byType[resourceType]) {
result.byType[resourceType].emissions += emissions;
}
}
// Generate comparison metrics
result.comparisons = this.generateComparisons(result.totalEmissions);
logger_1.default.info(`Total calculated emissions: ${result.totalEmissions.toFixed(6)} gCO2e`);
return result;
}
/**
* Generate human-readable comparisons for the emissions
* @param {number} emissions - Total emissions in gCO2e
* @returns {Comparisons} - Comparison metrics
*/
generateComparisons(emissions) {
// Conversion factors for comparisons
// Note: These are approximate values and should be updated with more accurate data
const comparisons = {
// Tree seconds: how many seconds a mature tree takes to absorb this CO2
treeSeconds: emissions / 0.0035, // Assuming a tree absorbs ~0.0035g CO2 per second
// Car distance: equivalent distance driven in a passenger car
carMeters: emissions * 3.75, // ~3.75 meters per gram of CO2
// Smartphone charging: number of full smartphone charges
smartphoneCharges: emissions / 7, // ~7g CO2 per full smartphone charge
// Boiling water: cups of water boiled in an electric kettle
waterBoiledML: emissions * 32, // ~32ml of water per gram of CO2
};
return comparisons;
}
}
exports.default = CO2Calculator;
//# sourceMappingURL=co2-calculator.js.map