Repository: ProjectEvergreen/greenwood (js)

Issue:
extend format support for font and image extensions
## Type of Change
- [ ] New Feature Request
- [ ] Documentation / Website
- [x] Improvement / Suggestion
- [ ] Bug
- [ ] Other (please clarify below)

## Summary
For our two standard plugins for [images](https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/src/plugins/resource/plugin-standard-images.js#L14) and [fonts](https://github.com/ProjectEvergreen/greenwood/blob/master/packages/cli/src/plugins/resource/plugin-standard-font.js#L14), we only have limited support for image formats
- images: `['.jpg', '.png', '.gif', '.svg', '.ico']`
- fonts: `['.woff2', '.woff', '.ttf']`

## Details
I feel like we're probably missing a bunch and so should do some research to these supported quickly.
- [images](https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types): `.concat(['.webp', '.avif'])`
- [fonts](https://developer.mozilla.org/en-US/docs/Learn/CSS/Styling_text/Web_fonts): `.concat(['.tbd'])`

Pull request description:
Feature/issue 521 complete image font content type support
<!--
## Submitting a Pull Request
We love contributions and appreciate any help you can offer!
-->

## Related Issue
resolves #521 

## Summary of Changes
1.  Added _.webp_ and _.avif_ support for images and added test cases
1.  Added _.eot_ (legacy) support for fonts

Patch:
diff --git a/.gitattributes b/.gitattributes
index bf5e7c53..d1bb0add 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4,9 +4,13 @@
 *.sh      text eol=lf
 
 *.jpg     binary
+*.jpeg    binary
 *.png     binary
+*.avif    binary
+*.webp    binary
 *.gif     binary
 *.ico     binary
 *.woff    binary
 *.woff2   binary
-*.ttf     binary
\ No newline at end of file
+*.ttf     binary
+*.eot     binary
\ No newline at end of file
diff --git a/packages/cli/src/lib/resource-interface.js b/packages/cli/src/lib/resource-interface.js
index 0fdf9647..e1e10df8 100644
--- a/packages/cli/src/lib/resource-interface.js
+++ b/packages/cli/src/lib/resource-interface.js
@@ -6,7 +6,7 @@ class ResourceInterface {
     this.compilation = compilation;
     this.options = options;
     this.extensions = [];
-    this.contentType = '';
+    this.contentType = ''; // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
   }
 
   // get rid of things like query string parameters
diff --git a/packages/cli/src/plugins/resource/plugin-standard-font.js b/packages/cli/src/plugins/resource/plugin-standard-font.js
index bbbb48a5..e19e06e7 100644
--- a/packages/cli/src/plugins/resource/plugin-standard-font.js
+++ b/packages/cli/src/plugins/resource/plugin-standard-font.js
@@ -11,13 +11,16 @@ import { ResourceInterface } from '../../lib/resource-interface.js';
 class StandardFontResource extends ResourceInterface {
   constructor(compilation, options) {
     super(compilation, options);
-    this.extensions = ['.woff2', '.woff', '.ttf'];
+
+    // https://developer.mozilla.org/en-US/docs/Learn/CSS/Styling_text/Web_fonts
+    this.extensions = ['.woff2', '.woff', '.ttf', '.eot'];
   }
 
   async serve(url) {
     return new Promise(async (resolve, reject) => {
       try {
-        const contentType = path.extname(url).replace('.', '');
+        const ext = path.extname(url).replace('.', '');
+        const contentType = ext === 'eot' ? 'application/vnd.ms-fontobject' : ext;
         const body = await fs.promises.readFile(url);
 
         resolve({
diff --git a/packages/cli/src/plugins/resource/plugin-standard-image.js b/packages/cli/src/plugins/resource/plugin-standard-image.js
index a75620aa..0e39e64d 100644
--- a/packages/cli/src/plugins/resource/plugin-standard-image.js
+++ b/packages/cli/src/plugins/resource/plugin-standard-image.js
@@ -11,7 +11,9 @@ import { ResourceInterface } from '../../lib/resource-interface.js';
 class StandardFontResource extends ResourceInterface {
   constructor(compilation, options) {
     super(compilation, options);
-    this.extensions = ['.jpg', '.png', '.gif', '.svg', '.ico'];
+
+    // https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
+    this.extensions = ['.avif', '.webp', '.jpg', '.jpeg', '.png', '.gif', '.svg', '.ico'];
   }
 
   async serve(url) {
@@ -24,7 +26,7 @@ class StandardFontResource extends ResourceInterface {
           ? `${ext.replace('.', '')}+xml`
           : ext.replace('.', '');
 
-        if (['.jpg', '.png', '.gif', '.svg'].includes(ext)) {
+        if (['.avif', '.webp', '.jpg', '.jpeg', '.png', '.gif', '.svg'].includes(ext)) {
           contentType = `image/${type}`;
 
           if (ext === '.svg') {


Test patch:
diff --git a/packages/cli/test/cases/develop.default/develop.default.spec.js b/packages/cli/test/cases/develop.default/develop.default.spec.js
index 2eea4ce6..46ac1a45 100644
--- a/packages/cli/test/cases/develop.default/develop.default.spec.js
+++ b/packages/cli/test/cases/develop.default/develop.default.spec.js
@@ -18,8 +18,13 @@
  * User Workspace
  * src/
  *   assets/
+ *     data.json
+ *     favicon.ico
+ *     fox.avif
  *     logo.png
+ *     river-valley.webp
  *     source-sans-pro.woff
+ *     webcomponents.svg
  *   components/
  *     header.js
  *   pages/
@@ -732,7 +737,75 @@ describe('Develop Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with SVG specific behavior', function() {
+    describe('Develop command with image (webp) specific behavior', function() {
+      let response = {};
+
+      before(async function() {
+        return new Promise((resolve, reject) => {
+          request.get(`${hostname}:${port}/assets/river-valley.webp`, (err, res, body) => {
+            if (err) {
+              reject();
+            }
+
+            response = res;
+            response.body = body;
+
+            resolve(response);
+          });
+        });
+      });
+
+      it('should return a 200 status', function(done) {
+        expect(response.statusCode).to.equal(200);
+        done();
+      });
+
+      it('should return the correct content type', function(done) {
+        expect(response.headers['content-type']).to.equal('image/webp');
+        done();
+      });
+
+      it('should return binary data', function(done) {
+        expect(response.body).to.contain('\u0000');
+        done();
+      });
+    });
+
+    describe('Develop command with image (avif) specific behavior', function() {
+      let response = {};
+
+      before(async function() {
+        return new Promise((resolve, reject) => {
+          request.get(`${hostname}:${port}/assets/fox.avif`, (err, res, body) => {
+            if (err) {
+              reject();
+            }
+
+            response = res;
+            response.body = body;
+
+            resolve(response);
+          });
+        });
+      });
+
+      it('should return a 200 status', function(done) {
+        expect(response.statusCode).to.equal(200);
+        done();
+      });
+
+      it('should return the correct content type', function(done) {
+        expect(response.headers['content-type']).to.equal('image/avif');
+        done();
+      });
+
+      it('should return binary data', function(done) {
+        expect(response.body).to.contain('\u0000');
+        done();
+      });
+    });
+
+    describe('Develop command with image (svg) specific behavior', function() {
       const ext = 'svg';
       let response = {};