UNPKG

@tgwf/co2

Version:
250 lines (249 loc) 11.7 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var sustainable_web_design_exports = {}; __export(sustainable_web_design_exports, { SustainableWebDesign: () => SustainableWebDesign, default: () => sustainable_web_design_default }); module.exports = __toCommonJS(sustainable_web_design_exports); var import_constants = require("./constants/index.js"); var import_helpers = require("./helpers/index.js"); class SustainableWebDesign { constructor(options) { this.options = options; } /** * Accept a figure for bytes transferred and return an object representing * the share of the total enrgy use of the entire system, broken down * by each corresponding system component * * @param {number} bytes - the data transferred in bytes * @return {object} Object containing the energy in kilowatt hours, keyed by system component */ energyPerByteByComponent(bytes) { const transferedBytesToGb = bytes / import_constants.fileSize.GIGABYTE; const energyUsage = transferedBytesToGb * import_constants.KWH_PER_GB; return { consumerDeviceEnergy: energyUsage * import_constants.END_USER_DEVICE_ENERGY, networkEnergy: energyUsage * import_constants.NETWORK_ENERGY, productionEnergy: energyUsage * import_constants.PRODUCTION_ENERGY, dataCenterEnergy: energyUsage * import_constants.DATACENTER_ENERGY }; } /** * Accept an object keys by the different system components, and * return an object with the co2 figures key by the each component * * @param {object} energyByComponent - energy grouped by the four system components * @param {number} [carbonIntensity] - carbon intensity to apply to the datacentre values * @return {number} the total number in grams of CO2 equivalent emissions */ co2byComponent(energyByComponent, carbonIntensity = import_constants.GLOBAL_GRID_INTENSITY, options = {}) { let deviceCarbonIntensity = import_constants.GLOBAL_GRID_INTENSITY; let networkCarbonIntensity = import_constants.GLOBAL_GRID_INTENSITY; let dataCenterCarbonIntensity = import_constants.GLOBAL_GRID_INTENSITY; let globalEmissions = import_constants.GLOBAL_GRID_INTENSITY; if (options == null ? void 0 : options.gridIntensity) { const { device, network, dataCenter } = options.gridIntensity; if ((device == null ? void 0 : device.value) || (device == null ? void 0 : device.value) === 0) { deviceCarbonIntensity = device.value; } if ((network == null ? void 0 : network.value) || (network == null ? void 0 : network.value) === 0) { networkCarbonIntensity = network.value; } if ((dataCenter == null ? void 0 : dataCenter.value) || (dataCenter == null ? void 0 : dataCenter.value) === 0) { dataCenterCarbonIntensity = dataCenter.value; } } if (carbonIntensity === true) { dataCenterCarbonIntensity = import_constants.RENEWABLES_GRID_INTENSITY; } const returnCO2ByComponent = {}; for (const [key, value] of Object.entries(energyByComponent)) { if (key.startsWith("dataCenterEnergy")) { returnCO2ByComponent[key.replace("Energy", "CO2")] = value * dataCenterCarbonIntensity; } else if (key.startsWith("consumerDeviceEnergy")) { returnCO2ByComponent[key.replace("Energy", "CO2")] = value * deviceCarbonIntensity; } else if (key.startsWith("networkEnergy")) { returnCO2ByComponent[key.replace("Energy", "CO2")] = value * networkCarbonIntensity; } else { returnCO2ByComponent[key.replace("Energy", "CO2")] = value * globalEmissions; } } return returnCO2ByComponent; } /** * Accept a figure for bytes transferred and return a single figure for CO2 * emissions. Where information exists about the origin data is being * fetched from, a different carbon intensity figure * is applied for the data centre share of the carbon intensity. * * @param {number} bytes - the data transferred in bytes * @param {boolean} carbonIntensity - a boolean indicating whether the data center is green or not * @param {boolean} segmentResults - a boolean indicating whether to return the results broken down by component * @param {object} options - an object containing the grid intensity and first/return visitor values * @return {number|object} the total number in grams of CO2 equivalent emissions, or an object containing the breakdown by component */ perByte(bytes, carbonIntensity = false, segmentResults = false, options = {}) { if (bytes < 1) { bytes = 0; } const energyBycomponent = this.energyPerByteByComponent(bytes, options); if (typeof carbonIntensity !== "boolean") { throw new Error( `perByte expects a boolean for the carbon intensity value. Received: ${carbonIntensity}` ); } const co2ValuesbyComponent = this.co2byComponent( energyBycomponent, carbonIntensity, options ); const co2Values = Object.values(co2ValuesbyComponent); const co2ValuesSum = co2Values.reduce( (prevValue, currentValue) => prevValue + currentValue ); if (segmentResults) { return { ...co2ValuesbyComponent, total: co2ValuesSum }; } return co2ValuesSum; } /** * Accept a figure for bytes transferred and return a single figure for CO2 * emissions. This method applies caching assumptions from the original Sustainable Web Design model. * * @param {number} bytes - the data transferred in bytes * @param {boolean} carbonIntensity - a boolean indicating whether the data center is green or not * @param {boolean} segmentResults - a boolean indicating whether to return the results broken down by component * @param {object} options - an object containing the grid intensity and first/return visitor values * @return {number|object} the total number in grams of CO2 equivalent emissions, or an object containing the breakdown by component */ perVisit(bytes, carbonIntensity = false, segmentResults = false, options = {}) { const energyBycomponent = this.energyPerVisitByComponent(bytes, options); if (typeof carbonIntensity !== "boolean") { throw new Error( `perVisit expects a boolean for the carbon intensity value. Received: ${carbonIntensity}` ); } const co2ValuesbyComponent = this.co2byComponent( energyBycomponent, carbonIntensity, options ); const co2Values = Object.values(co2ValuesbyComponent); const co2ValuesSum = co2Values.reduce( (prevValue, currentValue) => prevValue + currentValue ); if (segmentResults) { return { ...co2ValuesbyComponent, total: co2ValuesSum }; } return co2ValuesSum; } /** * Accept a figure for bytes transferred and return the number of kilowatt hours used * by the total system for this data transfer * * @param {number} bytes * @return {number} the number of kilowatt hours used */ energyPerByte(bytes) { const energyByComponent = this.energyPerByteByComponent(bytes); const energyValues = Object.values(energyByComponent); return energyValues.reduce( (prevValue, currentValue) => prevValue + currentValue ); } /** * Accept a figure for bytes transferred, and return an object containing figures * per system component, with the caching assumptions applied. This tries to account * for webpages being loaded from a cache by browsers, so if you had a thousand page views, * and tried to work out the energy per visit, the numbers would reflect the reduced amounts * of transfer. * * @param {number} bytes - the data transferred in bytes for loading a webpage * @param {number} firstView - what percentage of visits are loading this page for the first time * @param {number} returnView - what percentage of visits are loading this page for subsequent times * @param {number} dataReloadRatio - what percentage of a page is reloaded on each subsequent page view * * @return {object} Object containing the energy in kilowatt hours, keyed by system component */ energyPerVisitByComponent(bytes, options = {}, firstView = import_constants.FIRST_TIME_VIEWING_PERCENTAGE, returnView = import_constants.RETURNING_VISITOR_PERCENTAGE, dataReloadRatio = import_constants.PERCENTAGE_OF_DATA_LOADED_ON_SUBSEQUENT_LOAD) { if (options.dataReloadRatio || options.dataReloadRatio === 0) { dataReloadRatio = options.dataReloadRatio; } if (options.firstVisitPercentage || options.firstVisitPercentage === 0) { firstView = options.firstVisitPercentage; } if (options.returnVisitPercentage || options.returnVisitPercentage === 0) { returnView = options.returnVisitPercentage; } const energyBycomponent = this.energyPerByteByComponent(bytes); const cacheAdjustedSegmentEnergy = {}; const energyValues = Object.values(energyBycomponent); for (const [key, value] of Object.entries(energyBycomponent)) { cacheAdjustedSegmentEnergy[`${key} - first`] = value * firstView; cacheAdjustedSegmentEnergy[`${key} - subsequent`] = value * returnView * dataReloadRatio; } return cacheAdjustedSegmentEnergy; } /** * Accept a figure for bytes, and return the total figure for energy per visit * using the default caching assumptions for loading a single website * * @param {number} bytes * @return {number} the total energy use for the visit, after applying the caching assumptions */ energyPerVisit(bytes) { let firstVisits = 0; let subsequentVisits = 0; const energyBycomponent = Object.entries( this.energyPerVisitByComponent(bytes) ); for (const [key, val] of energyBycomponent) { if (key.indexOf("first") > 0) { firstVisits += val; } } for (const [key, val] of energyBycomponent) { if (key.indexOf("subsequent") > 0) { subsequentVisits += val; } } return firstVisits + subsequentVisits; } emissionsPerVisitInGrams(energyPerVisit, carbonintensity = import_constants.GLOBAL_GRID_INTENSITY) { return (0, import_helpers.formatNumber)(energyPerVisit * carbonintensity); } annualEnergyInKwh(energyPerVisit, monthlyVisitors = 1e3) { return energyPerVisit * monthlyVisitors * 12; } annualEmissionsInGrams(co2grams, monthlyVisitors = 1e3) { return co2grams * monthlyVisitors * 12; } annualSegmentEnergy(annualEnergy) { return { consumerDeviceEnergy: (0, import_helpers.formatNumber)(annualEnergy * import_constants.END_USER_DEVICE_ENERGY), networkEnergy: (0, import_helpers.formatNumber)(annualEnergy * import_constants.NETWORK_ENERGY), dataCenterEnergy: (0, import_helpers.formatNumber)(annualEnergy * import_constants.DATACENTER_ENERGY), productionEnergy: (0, import_helpers.formatNumber)(annualEnergy * import_constants.PRODUCTION_ENERGY) }; } } var sustainable_web_design_default = SustainableWebDesign; //# sourceMappingURL=sustainable-web-design.js.map