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

enhancement/issue 955 support multiple custom page formats at once #1265

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
20 changes: 13 additions & 7 deletions packages/cli/src/lifecycles/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,28 @@ const generateGraph = async (compilation) => {
pages = nextPages.pages;
apiRoutes = nextPages.apiRoutes;
} else {
const req = new Request(filenameUrl, { headers: { 'Accept': 'text/html' } });
const extension = `.${filenameUrl.pathname.split('.').pop()}`;
const isCustom = customPageFormatPlugins[0] && customPageFormatPlugins[0].shouldServe && await customPageFormatPlugins[0].shouldServe(filenameUrl, req)
? customPageFormatPlugins[0].servePage
: null;
const relativePagePath = filenameUrl.pathname.replace(pagesDir.pathname, '/');
const relativeWorkspacePath = directory.pathname.replace(projectDirectory.pathname, '');
const isApiRoute = relativePagePath.startsWith('/api');
const req = isApiRoute
? new Request(filenameUrl)
: new Request(filenameUrl, { headers: { 'Accept': 'text/html' } });
let isCustom = null;

for (const plugin of customPageFormatPlugins) {
if (plugin.shouldServe && await plugin.shouldServe(filenameUrl, req)) {
isCustom = plugin.servePage;
break;
}
}

const isStatic = isCustom === 'static' || extension === '.md' || extension === '.html';
const isDynamic = isCustom === 'dynamic' || extension === '.js';
const isApiRoute = relativePagePath.startsWith('/api');
const isPage = isStatic || isDynamic;

if (isApiRoute) {
const req = new Request(filenameUrl);
const extension = filenameUrl.pathname.split('.').pop();
const isCustom = customPageFormatPlugins[0] && customPageFormatPlugins[0].shouldServe && await customPageFormatPlugins[0].shouldServe(filenameUrl, req);

if (extension !== 'js' && !isCustom) {
console.warn(`${filenameUrl} is not a supported API file extension, skipping...`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,31 @@ class FooResource {
this.servePage = options.servePage;

this.extensions = ['foo'];
this.contentType = 'text/html';
}

async shouldServe(url) {
return url.pathname.split('.').pop() === this.extensions[0] && this.servePage;
}

async serve(url) {
const body = await fs.readFile(url, 'utf-8');

return new Response(body, {
headers: new Headers({
'Content-Type': this.contentType
})
});
}
}

class BarResource {
constructor(compilation, options) {
this.compilation = compilation;
this.options = options;
this.servePage = options.servePage;

this.extensions = ['bar'];
this.contentType = 'text/javascript';
}

Expand All @@ -17,7 +42,7 @@ class FooResource {
async serve(url) {
let body = await fs.readFile(url, 'utf-8');

body = body.replace(/interface (.*){(.*)}/s, '');
body = body.replace(/interface (.*){(.*)}/, '');

return new Response(body, {
headers: new Headers({
Expand All @@ -35,10 +60,21 @@ const greenwoodPluginFooResource = (options = {}) => {
}];
};

const greenwoodPluginBarResource = (options = {}) => {
return [{
type: 'resource',
name: 'plugin-import-bar:resource',
provider: (compilation) => new BarResource(compilation, options)
}];
};

export default {
plugins: [
greenwoodPluginFooResource({
servePage: 'static'
}),
greenwoodPluginBarResource({
servePage: 'dynamic'
})
]
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*
* Use Case
* Run Greenwood with a custom resource plugin and default workspace with a custom page format.
* Run Greenwood with a custom resource plugin and default workspace with a custom page formats.
*
* User Result
* Should generate a bare bones Greenwood build with expected custom file (.foo) behavior.
* Should generate a bare bones Greenwood build with expected custom page format behaviors.
*
* User Command
* greenwood build
Expand All @@ -13,17 +13,27 @@
* // see complete implementation in the greenwood.config.js file used for this spec
* }
*
* class BarResource extends ResourceInterface {
* // see complete implementation in the greenwood.config.js file used for this spec
* }
*
* {
* plugins: [{
* type: 'resource',
* name: 'plugin-foo',
* provider: (compilation, options) => new FooResource(compilation, options)
* },{
* type: 'resource',
* name: 'plugin-bar',
* provider: (compilation, options) => new BarResource(compilation, options)
* }]
* }
*
* Custom Workspace
* src/
* pages/
* api
* greeting.bar
* about.foo
* contact.bar
* index.html
Expand All @@ -39,7 +49,7 @@ import { fileURLToPath, URL } from 'url';
const expect = chai.expect;

describe('Build Greenwood With: ', function() {
const LABEL = 'Custom FooResource Plugin and Default Workspace';
const LABEL = 'Custom Static and Dynamic Page Loaders';
const cliPath = path.join(process.cwd(), 'packages/cli/src/index.js');
const outputPath = fileURLToPath(new URL('.', import.meta.url));
let runner;
Expand All @@ -48,7 +58,7 @@ describe('Build Greenwood With: ', function() {
this.context = {
publicDir: path.join(outputPath, 'public')
};
runner = new Runner();
runner = new Runner(false, true);
});

describe(LABEL, function() {
Expand Down Expand Up @@ -89,24 +99,39 @@ describe('Build Greenwood With: ', function() {
});
});

// TODO not sure why this was disabled, but should enable this test case
xdescribe('Custom Format Dynamic Contact Page', function() {
let aboutPage;
describe('Custom Format Dynamic Contact Page (exported with prerendering)', function() {
let contactPage;

before(async function() {
aboutPage = await glob.promise(path.join(this.context.publicDir, 'contact.html'));
contactPage = await glob.promise(path.join(this.context.publicDir, 'contact/index.html'));
});

it('should have the expected JavaScript equivalent file in the output directory', function() {
expect(aboutPage).to.have.lengthOf(1);
it('should have the expected pre-rendered HTML file in the output directory', function() {
expect(contactPage).to.have.lengthOf(1);
});

it('should have expected text from from my-other-custom-file.foo in the script output file', function() {
const contents = fs.readFileSync(aboutPage[0], 'utf-8');
it('should have expected text from the output HTML file', function() {
const contents = fs.readFileSync(contactPage[0], 'utf-8');

expect(contents).to.contain('Welcome to our About page!');
expect(contents).to.contain('Welcome to our Contact page!');
});
});

describe('Custom Format Dynamic API Route', function() {
let handler;

before(async function() {
handler = (await import(new URL('./public/api/greeting.js', import.meta.url))).handler;
});

it('should have the expected output from the API route', async function() {
const response = await handler(new Request(new URL('http://localhost:8080/api/greeting')));
const data = await response.json();

expect(data.message).to.equal('Hello World!!!');
});

});
});

after(function() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
interface User { }

export async function handler(request) {
const params = new URLSearchParams(request.url.slice(request.url.indexOf('?')));
const name = params.has('name') ? params.get('name') : 'World';
const body = { message: `Hello ${name}!!!` };

return new Response(JSON.stringify(body), {
headers: new Headers({
'Content-Type': 'application/json'
})
});
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
interface User { }

export default class ContactPage extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<h1>Welcome to our Contact page!</h1>
`;
}
}
}

export const prerender = true;
Loading