Skip to content

Commit

Permalink
Merge pull request #61 from martinabab/main
Browse files Browse the repository at this point in the history
Add lighter-video-files rule
  • Loading branch information
martinabab committed Nov 15, 2022
2 parents 2ab0f6f + 79fdd1b commit a2f310e
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Let's build an eco-friendly website!

- :ballot_box_with_check: Image format (lighter-image-files, ec0lint)
- :hammer: Video format (lighter-video-files, ec0lint-plugin-react)
- :hammer: Video format (lighter-video-files, ec0lint)
- :ballot_box_with_check: Video format (lighter-video-files, ec0lint)
- :hammer: Plugin HTML (ec0lint-plugin-html)
- :hammer: Lazy loading (require-lazy-loading, ec0lint-style)
- :hammer: Lazy loading (require-lazy-loading, ec0lint-plugin-html)
Expand Down
54 changes: 54 additions & 0 deletions docs/rules/lighter-video-files.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# lighter-video-files

Encourages to use WebM video file format in React code.

Video files inside web applications should be in WebM format. It is an open, royalty-free media file format designed specifically for the web, hence it is supported by HTML and has a good compatibility with all modern browsers. Clips in the WebM format are on average much smaller than those in MP4 or OGG (other video formats supported by HTML). We can achieve even a 66% reduction of the file size using WebM instead of the popular MP4 format which quality is only slightly better.

## CO<sub>2</sub> reduction

The table below shows the comparison between file sizes and CO<sub>2</sub> emission for a short (23 s) exemplary video (in 1366 x 720 resolution).

Link to the exemplary video: https://www.pexels.com/video/alpaca-closeup-5795043/

![alt text](https://github.com/martinabab/ec0lint/blob/main/docs/video_table.webp)
_Converting the exemplary video from MP4 to WebM format can reduce the carbon footprint by 1.15 g of CO<sub>2</sub> per website view._

By multiplying the file size by the end-user traffic (0.81 kWh / GB) and by thy energy emissions (442 g / kWh), the carbon footprint of the exemplary video in MP4 sums up to 2.06 g. The same file in WebM format generates 0.91 g of CO<sub>2</sub>. So, by subtracting 0.91 g from 2.06 g, we get 1.15 g (__56% less CO<sub>2</sub>__).

Exemplary video was downloaded from https://www.pexels.com/search/videos/ and converted to WebM online with https://www.veed.io/convert/video-converter.

## examples
__The following patterns are considered problems:__

```js
import video from './video.ogg';
```
```js
import video from './video.mp4';
```
```js
import {ReactComponent as video} from './video.m4a';
```
```js
import {ReactComponent as video} from './video.m4p';
```
```js
let Video = require('../src/video.m4b');
```
```js
let Video = require('../src/video.m4r');
```
```js
let Video = require('../src/video.m4v');
```

__The following patterns are _not_ considered problems:__
```js
import video from './video.webm';
```
```js
import {ReactComponent as video} from './video.webm';
```
```js
let Video = require('../src/video.webm');
```
Binary file added docs/video_table.webp
Binary file not shown.
1 change: 1 addition & 0 deletions lib/rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
"no-ajax-events": () => require("./no-ajax-events"),
"no-moment-js": () => require("./no-moment-js"),
"no-date-fns": () => require("./no-date-fns"),
"lighter-video-files": () => require("./lighter-video-files"),
"lighter-image-files": () => require("./lighter-image-files")
}));
5 changes: 2 additions & 3 deletions lib/rules/lighter-image-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ module.exports = {
url: "https://eslint.org/docs/rules/lighter-image-files"
},
messages: {
rejected: 'Format of image files can be changed to WebP or SVG. CO2 reduction: up to 99% of the image file.\n' +
'Your image can be converted online at https://cloudconvert.com/\n' +
'Estimated CO2 reduction that you can achieve by converting your file is: '
rejected: 'Format of image files can be changed to WebP or SVG. Your image can be converted online at https://cloudconvert.com/\n' +
'Estimated CO2 reduction that you can achieve by converting your file is: '
},
schema: [] // no options,
},
Expand Down
70 changes: 70 additions & 0 deletions lib/rules/lighter-video-files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @fileoverview Rule to avoid heavy video file formats
* @author Martyna Babiak
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const moduleVisitor = require("eslint-module-utils/moduleVisitor");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
type: "problem",

docs: {
description: "Avoid heavy formats of video files",
category: "Code improvements",
recommended: false,
url: "https://eslint.org/docs/rules/lighter-video-files"
},
messages: {
rejected: 'Format of video files can be changed to WebM. Your video can be converted online at https://www.veed.io/convert/video-converter\n' +
'Estimated CO2 reduction that you can achieve by converting your file is: '
},
schema: [] // no options,
},
create: function(context) {

/**
* Returns if the video file format is heavy
* @param {string} name
* @returns {boolean} Returns true or false
*/
function isBanned(name) {

if (!name) {
return false;
}
const result = name.match(/\.ogg|\.mp4|\.m4a|\.m4p|\.m4b|\.m4r|\.m4v/);

return result;
}

/**
* Reports the given import
* @param {Node} node Import node to check
* @param {string} name Name of the import
* @returns {void}
*/
function reportMessage(node, name) {

if (isBanned(name)) {
context.report({ node, messageId: "rejected", data: { name }});
}
}

return moduleVisitor.default((source, node) => {
reportMessage(node, source.value);
},
{ commonjs: true });
}
};
1 change: 1 addition & 0 deletions packages/ec0lint-config-ec0lint/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ rules:
no-ajax-events: "error"
no-date-fns: "error"
no-moment-js: "error"
lighter-video-files: "error"
lighter-image-files: "error"
48 changes: 48 additions & 0 deletions tests/lib/rules/lighter-video-files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use strict";

const rule = require("../../../lib/rules/lighter-video-files"),
{ RuleTester } = require("../../../lib/rule-tester");

const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2022, sourceType: "module" } });

ruleTester.run("lighter-video-files", rule, {
valid: [
"import video from './video.webm'",
"import {ReactComponent as video} from './video.webm'",
"let Video = require('../src/video.webm')"
],
invalid: [
{
code: "import foo from './foo.ogg'",
errors: [{ messageId: "rejected" }]
},
{
code: "import foo from './foo.mp4'",
errors: [{ messageId: "rejected" }]
},
{
code: "import foo from './foo.m4a'",
errors: [{ messageId: "rejected" }]
},
{
code: "import foo from './foo.m4p'",
errors: [{ messageId: "rejected" }]
},
{
code: "import {ReactComponent as foo} from './foo.m4b'",
errors: [{ messageId: "rejected" }]
},
{
code: "import {ReactComponent as foo} from './foo.m4r'",
errors: [{ messageId: "rejected" }]
},
{
code: "import {ReactComponent as foo} from './foo.m4v'",
errors: [{ messageId: "rejected" }]
},
{
code: "let Foo = require('../src/foo.m4v')",
errors: [{ messageId: "rejected" }]
}
]
});
1 change: 1 addition & 0 deletions tools/rule-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"no-and-self": "problem",
"no-date-fns": "problem",
"lighter-image-files": "problem",
"lighter-video-files": "problem",
"no-moment-js": "problem"
}

0 comments on commit a2f310e

Please sign in to comment.