Repository: ProjectEvergreen/greenwood (js)

Issue:
source maps not resolving when running `serve`
## Type of Change
- [ ] New Feature Request
- [ ] Documentation / Website
- [ ] Improvement / Suggestion
- [x] Bug
- [ ] Other (please clarify below)

## Summary
Browsing the website with the dev tools console open and seeing a bunch of warnings that the source maps are not returning any content

![Screen Shot 2021-11-08 at 11 32 38 AM](https://user-images.githubusercontent.com/895923/140782696-65fae41e-34de-460e-a5a9-010a5ecf9e65.png)

## Details
Probably just missing something from the `prodServer` function in the serve lifecycle, since we curate what plugins should run in this particular scenario.

> _Note_: this is not the same as #714 , so for now this can be tested on the home page

Pull request description:
add source map support for greenwood serve command
<!--
## Submitting a Pull Request
We love contributions and appreciate any help you can offer!
-->

## Related Issue
resolves #795 

## Summary of Changes
1. Source maps now resolve when running `greenwood serve`
1. Added test case to ensure behavior

Patch:
diff --git a/packages/cli/src/lifecycles/serve.js b/packages/cli/src/lifecycles/serve.js
index be7761ac..eb9d9aa8 100644
--- a/packages/cli/src/lifecycles/serve.js
+++ b/packages/cli/src/lifecycles/serve.js
@@ -129,8 +129,9 @@ function getProdServer(compilation) {
     // html is intentionally omitted
     return plugin.isGreenwoodDefaultPlugin
       && plugin.type === 'resource'
-      && plugin.name.indexOf('plugin-standard') >= 0
-      && plugin.name.indexOf('plugin-standard-html') < 0;
+      && ((plugin.name.indexOf('plugin-standard') >= 0 // allow standard web resources
+      && plugin.name.indexOf('plugin-standard-html') < 0) // but _not_ our markdown / HTML plugin
+      || plugin.name.indexOf('plugin-source-maps') >= 0); // and source maps
   }).map((plugin) => {
     return plugin.provider(compilation);
   });


Test patch:
diff --git a/packages/cli/test/cases/serve.default/serve.default.spec.js b/packages/cli/test/cases/serve.default/serve.default.spec.js
index d12a3f69..f4587b9c 100644
--- a/packages/cli/test/cases/serve.default/serve.default.spec.js
+++ b/packages/cli/test/cases/serve.default/serve.default.spec.js
@@ -87,7 +87,7 @@ describe('Serve Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with image (png) specific behavior', function() {
+    describe('Serve command with image (png) specific behavior', function() {
       const ext = 'png';
       let response = {};
 
@@ -123,7 +123,7 @@ describe('Serve Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with image (ico) specific behavior', function() {
+    describe('Serve command with image (ico) specific behavior', function() {
       let response = {};
 
       before(async function() {
@@ -157,7 +157,7 @@ describe('Serve Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with SVG specific behavior', function() {
+    describe('Serve command with SVG specific behavior', function() {
       const ext = 'svg';
       let response = {};
 
@@ -192,7 +192,7 @@ describe('Serve Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with font specific (.woff) behavior', function() {
+    describe('Serve command with font specific (.woff) behavior', function() {
       const ext = 'woff';
       let response = {};
 
@@ -227,7 +227,7 @@ describe('Serve Greenwood With: ', function() {
       });
     });
 
-    describe('Develop command with JSON specific behavior', function() {
+    describe('Serve command with JSON specific behavior', function() {
       let response = {};
 
       before(async function() {
@@ -260,6 +260,41 @@ describe('Serve Greenwood With: ', function() {
         done();
       });
     });
+
+    describe('Serve command with source map specific behavior', function() {
+      let response = {};
+
+      before(async function() {
+        return new Promise((resolve, reject) => {
+          request.get(`${hostname}/assets/router.js.map`, (err, res, body) => {
+            if (err) {
+              reject();
+            }
+
+            response = res;
+            response.body = body;
+
+            resolve();
+          });
+        });
+      });
+
+      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.contain('application/json');
+        done();
+      });
+
+      it('should return the correct response body', function(done) {
+        expect(response.body).to.contain('"sources":["../packages/cli/src/lib/router.js"]');
+        done();
+      });
+    });
+
   });
 
   after(function() {
diff --git a/packages/cli/test/cases/serve.default/src/assets/router.js.map b/packages/cli/test/cases/serve.default/src/assets/router.js.map
new file mode 100644
index 00000000..59f99d8e
--- /dev/null
+++ b/packages/cli/test/cases/serve.default/src/assets/router.js.map
@@ -0,0 +1,1 @@
+{"version":3,"file":"router.e74094cc.js","sources":["../packages/cli/src/lib/router.js"],"sourcesContent":["/* eslint-disable no-underscore-dangle */\ndocument.addEventListener('click', function(e) {\n  const href = (e.path && e.path[0]\n    ? e.path[0].href // chrome + edge\n    : e.originalTarget && e.originalTarget.href\n      ? e.originalTarget.href // firefox\n      : '') || '';\n  // best case \"guess\" is that if the link originates on the current site when resolved by the browser\n  // treat it as a client side route, ex:  /about/, /docs/ and trigger the client side router\n  // https://github.com/ProjectEvergreen/greenwood/issues/562\n  const isOnCurrentDomain = href.indexOf(window.location.hostname) >= 0 || href.indexOf('localhost') >= 0;\n  const canClientSideRoute = href !== '' && isOnCurrentDomain;\n\n  if (canClientSideRoute) {\n    e.preventDefault();\n    \n    const route = href.replace(window.location.origin, '');\n    const routerOutlet = Array.from(document.getElementsByTagName('greenwood-route')).filter(outlet => {\n      return outlet.getAttribute('data-route') === route;\n    })[0];\n\n    if (routerOutlet.getAttribute('data-template') === window.__greenwood.currentTemplate) {\n      window.__greenwood.currentTemplate = routerOutlet.getAttribute('data-template');\n      routerOutlet.loadRoute();\n    } else {\n      window.location.href = href;\n    }\n  }\n});\n\nclass RouteComponent extends HTMLElement {\n  loadRoute() {\n    const route = this.getAttribute('data-route');\n    const key = this.getAttribute('data-key');\n    \n    fetch(key)\n      .then(res => res.text())\n      .then((response) => {\n        history.pushState(response, route, route);\n        document.getElementsByTagName('router-outlet')[0].innerHTML = response;\n      });\n  }\n}\n\nclass RouterOutletComponent extends HTMLElement { }\n\ncustomElements.define('greenwood-route', RouteComponent);\ncustomElements.define('router-outlet', RouterOutletComponent); "],"names":["document","addEventListener","e","href","path","originalTarget","isOnCurrentDomain","indexOf","window","location","hostname","preventDefault","route","replace","origin","routerOutlet","Array","from","getElementsByTagName","filter","outlet","getAttribute","__greenwood","currentTemplate","loadRoute","RouteComponent","HTMLElement","[object Object]","this","key","fetch","then","res","text","response","history","pushState","innerHTML","RouterOutletComponent","customElements","define"],"mappings":"AACAA,SAASC,iBAAiB,SAAS,SAASC,GAC1C,MAAMC,GAAQD,EAAEE,MAAQF,EAAEE,KAAK,GAC3BF,EAAEE,KAAK,GAAGD,KACVD,EAAEG,gBAAkBH,EAAEG,eAAeF,KACnCD,EAAEG,eAAeF,KACjB,KAAO,GAIPG,EAAoBH,EAAKI,QAAQC,OAAOC,SAASC,WAAa,GAAKP,EAAKI,QAAQ,cAAgB,EAGtG,GAFoC,KAATJ,GAAeG,EAElB,CACtBJ,EAAES,iBAEF,MAAMC,EAAQT,EAAKU,QAAQL,OAAOC,SAASK,OAAQ,IAC7CC,EAAeC,MAAMC,KAAKjB,SAASkB,qBAAqB,oBAAoBC,OAAOC,GAChFA,EAAOC,aAAa,gBAAkBT,GAC5C,GAECG,EAAaM,aAAa,mBAAqBb,OAAOc,YAAYC,iBACpEf,OAAOc,YAAYC,gBAAkBR,EAAaM,aAAa,iBAC/DN,EAAaS,aAEbhB,OAAOC,SAASN,KAAOA,MAK7B,MAAMsB,UAAuBC,YAC3BC,YACE,MAAMf,EAAQgB,KAAKP,aAAa,cAC1BQ,EAAMD,KAAKP,aAAa,YAE9BS,MAAMD,GACHE,KAAKC,GAAOA,EAAIC,QAChBF,KAAMG,IACLC,QAAQC,UAAUF,EAAUtB,EAAOA,GACnCZ,SAASkB,qBAAqB,iBAAiB,GAAGmB,UAAYH,KAKtE,MAAMI,UAA8BZ,aAEpCa,eAAeC,OAAO,kBAAmBf,GACzCc,eAAeC,OAAO,gBAAiBF"}
\ No newline at end of file