Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug/issue 1354 support isomorphic data client APIs without prerender configuration option #1358

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions packages/cli/src/data/client.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import { filterContentByCollection, filterContentByRoute } from '@greenwood/cli/src/lib/content-utils.js';

const CONTENT_STATE = globalThis.__CONTENT_AS_DATA_STATE__ ?? false; // eslint-disable-line no-underscore-dangle
const PORT = globalThis?.__CONTENT_SERVER__?.PORT ?? 1984; // eslint-disable-line no-underscore-dangle
const PRERENDER = globalThis.__CONTENT_OPTIONS__?.PRERENDER === 'true'; // eslint-disable-line no-underscore-dangle
const PORT = globalThis?.__CONTENT_OPTIONS__?.PORT ?? 1984; // eslint-disable-line no-underscore-dangle
const BASE_PATH = globalThis?.__GWD_BASE_PATH__ ?? ''; // eslint-disable-line no-underscore-dangle

async function getContentAsData(key = '') {
return CONTENT_STATE
? await fetch(`${window.location.origin}${BASE_PATH}/data-${key.replace(/\//g, '_')}.json`)
.then(resp => resp.json())
: await fetch(`http://localhost:${PORT}${BASE_PATH}/___graph.json`, { headers: { 'X-CONTENT-KEY': key } })
if (CONTENT_STATE && PRERENDER) {
// fetch customized query files when a user has opted-in for prerendering with active content
await fetch(`${window.location.origin}${BASE_PATH}/data-${key.replace(/\//g, '_')}.json`)
.then(resp => resp.json());
} else if (CONTENT_STATE && !PRERENDER) {
// if user is not prerendering, just fetch the entire graph but apply the same filtering
const graph = await fetch('/graph.json').then(resp => resp.json());
const value = key.split('-').pop();

if (key === 'graph') {
return graph;
} else if (key.startsWith('collection')) {
return filterContentByCollection(graph, value);
} else if (key.startsWith('route')) {
return filterContentByRoute(graph, value);
}
} else {
// otherwise users is developing locally, so hit the dev server
return await fetch(`http://localhost:${PORT}${BASE_PATH}/___graph.json`, { headers: { 'X-CONTENT-KEY': key } })
.then(resp => resp.json());
}
}

async function getContent() {
Expand Down
12 changes: 11 additions & 1 deletion packages/cli/src/lib/content-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,18 @@ function cleanContentCollection(collection = []) {
});
}

function filterContentByCollection(graph, collection) {
return graph.filter(page => page?.data?.collection === collection);
}

function filterContentByRoute(graph, route) {
return graph.filter(page => page?.route.startsWith(route));
}

export {
pruneGraph,
activeFrontmatterKeys,
cleanContentCollection
cleanContentCollection,
filterContentByCollection,
filterContentByRoute
};
20 changes: 11 additions & 9 deletions packages/cli/src/plugins/resource/plugin-active-content.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { mergeImportMap } from '../../lib/node-modules-utils.js';
import { ResourceInterface } from '../../lib/resource-interface.js';
import { checkResourceExists } from '../../lib/resource-utils.js';
import { activeFrontmatterKeys, cleanContentCollection, pruneGraph } from '../../lib/content-utils.js';
import { activeFrontmatterKeys, cleanContentCollection, pruneGraph, filterContentByCollection, filterContentByRoute } from '../../lib/content-utils.js';
import fs from 'fs/promises';

const importMap = {
'@greenwood/cli/src/data/client.js': '/node_modules/@greenwood/cli/src/data/client.js'
'@greenwood/cli/src/data/client.js': '/node_modules/@greenwood/cli/src/data/client.js',
'@greenwood/cli/src/lib/content-utils.js': '/node_modules/@greenwood/cli/src/lib/content-utils.js'
};

class ContentAsDataResource extends ResourceInterface {
Expand Down Expand Up @@ -38,9 +39,9 @@ class ContentAsDataResource extends ResourceInterface {
if (contentKey === 'graph') {
body = graph;
} else if (keyPieces[0] === 'collection') {
body = graph.filter(page => page?.data?.collection === keyPieces[1]);
body = filterContentByCollection(graph, keyPieces[1]);
} else if (keyPieces[0] === 'route') {
body = graph.filter(page => page?.route.startsWith(keyPieces[1]));
body = filterContentByRoute(graph, keyPieces[1]);
}

if (process.env.__GWD_COMMAND__ === 'build') { // eslint-disable-line no-underscore-dangle
Expand Down Expand Up @@ -78,11 +79,12 @@ class ContentAsDataResource extends ResourceInterface {

newBody = newBody.replace('<head>', `
<head>
<script id="content-server">
globalThis.__CONTENT_SERVER__ = globalThis.__CONTENT_SERVER__
? globalThis.__CONTENT_SERVER__
<script id="data-client-options">
globalThis.__CONTENT_OPTIONS__ = globalThis.__CONTENT_OPTIONS__
? globalThis.__CONTENT_OPTIONS__
: {
PORT: ${devServer.port}
PORT: ${devServer.port},
PRERENDER: "${this.compilation.config.prerender}",
}
</script>
`);
Expand Down Expand Up @@ -127,7 +129,7 @@ class ContentAsDataResource extends ResourceInterface {

body = body.replace('<head>', `
<head>
<script id="content-state">
<script id="content-as-data-state">
globalThis.__CONTENT_AS_DATA_STATE__ = true;
</script>
`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,28 @@ describe('Build Greenwood With: ', function() {
});
});

describe('<script> tag setup for active content', function() {
let stateScripts;
let optionsScript;

before(function() {
stateScripts = dom.window.document.querySelectorAll('script#content-as-data-state');
optionsScript = dom.window.document.querySelectorAll('script#data-client-options');
});

it('should have a <script> tag that confirms content as data is set', function() {
expect(stateScripts.length).to.equal(1);
expect(stateScripts[0].textContent).to.contain('globalThis.__CONTENT_AS_DATA_STATE__ = true;');
});

it('should have a <script> tag that captures content as data related options', function() {
expect(optionsScript.length).to.equal(1);

expect(optionsScript[0].textContent).to.contain('PORT:1984');
expect(optionsScript[0].textContent).to.contain('PRERENDER:"true"');
});
});

describe('navigation links from getContentByCollection', function() {
let navLinks;

Expand Down
3 changes: 2 additions & 1 deletion packages/cli/test/cases/serve.default/greenwood.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export default {
'/posts': 'https://jsonplaceholder.typicode.com'
}
},
port: 8181
port: 8181,
activeContent: true // just here to test some of the setup <script> output
};
28 changes: 27 additions & 1 deletion packages/cli/test/cases/serve.default/serve.default.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
* '/post': 'https://jsonplaceholder.typicode.com'
* }
* },
* port: 8181
* port: 8181,
* activeContent: true // just here to test some basic content as data defaults
* }
*
* User Workspace
Expand All @@ -33,6 +34,7 @@
* webcomponents.svg
*/
import chai from 'chai';
import { JSDOM } from 'jsdom';
import path from 'path';
import { getOutputTeardownFiles } from '../../../../../test/utils.js';
import { runSmokeTest } from '../../../../../test/smoke-test.js';
Expand Down Expand Up @@ -72,6 +74,30 @@ describe('Serve Greenwood With: ', function() {

runSmokeTest(['serve'], LABEL);

describe('<script> tag setup for active content', function() {
let dom;

before(async function() {
const response = await fetch(`${hostname}`);
dom = new JSDOM(await response.text());
});

it('should have a <script> tag that confirms content as data is set', function() {
const stateScripts = dom.window.document.querySelectorAll('script#content-as-data-state');

expect(stateScripts.length).to.equal(1);
expect(stateScripts[0].textContent).to.contain('globalThis.__CONTENT_AS_DATA_STATE__ = true;');
});

it('should have a <script> tag that captures content as data related options', function() {
const optionsScript = dom.window.document.querySelectorAll('script#data-client-options');

expect(optionsScript.length).to.equal(1);
expect(optionsScript[0].textContent).to.contain('PORT:1984');
expect(optionsScript[0].textContent).to.contain('PRERENDER:"false"');
});
});

// proxies to https://jsonplaceholder.typicode.com/posts via greenwood.config.js
describe('Serve command with dev proxy', function() {
let response = {};
Expand Down
Loading