Open thescientist13 opened 3 years ago
A couple options I attempted at the moment, as we don't have support for #21 yet.
One option I tried was using Resource
in a couple ways, as the primary advantage here is that the user of the theme pack doesn't have to do anything, the plugin author can handle this entirely from their end.
One way could be to just "hijack" the path to /
and override by providing a path to index.html
class ThemePackPageOverrideResource extends ResourceInterface {
constructor(compilation, options) {
super(compilation, options);
this.extensions = ['.html'];
}
async shouldResolve(url) {
console.debug('ThemePackPageOverrideResource shouldResolve', url)
return Promise.resolve(url.replace(this.compilation.context.userWorkspace, '') === '/');
}
async resolve(url) {
return Promise.resolve(path.join(__dirname, 'dist/pages/index.html'));
}
}
However, it looks like Greenwood heavily filters what counts as a page so maybe we have to add some sort of "simple" check like
path.extname(url) === 'html' && fs.existsSync(url)
After getting it to work
% git diff
diff --git a/packages/cli/src/plugins/resource/plugin-standard-html.js b/packages/cli/src/plugins/resource/plugin-standard-html.js
index ed181169..39b0ae81 100644
--- a/packages/cli/src/plugins/resource/plugin-standard-html.js
+++ b/packages/cli/src/plugins/resource/plugin-standard-html.js
@@ -30,16 +30,21 @@ const getPageTemplate = (barePath, templatesDir, template, contextPlugins = [])
const customPluginDefaultPageTemplates = getCustomPageTemplates(contextPlugins, 'page');
const customPluginPageTemplates = getCustomPageTemplates(contextPlugins, template);
+ console.debug('pageIsHtmlPath', pageIsHtmlPath);
+ console.debug('barePath', barePath);
if (template && customPluginPageTemplates.length > 0 || fs.existsSync(`${templatesDir}/${template}.html`)) {
// use a custom template, usually from markdown frontmatter
contents = customPluginPageTemplates.length > 0
? fs.readFileSync(`${customPluginPageTemplates[0]}/${template}.html`, 'utf-8')
: fs.readFileSync(`${templatesDir}/${template}.html`, 'utf-8');
- } else if (fs.existsSync(`${barePath}.html`) || fs.existsSync(pageIsHtmlPath)) {
+ } else if (fs.existsSync(barePath) || fs.existsSync(`${barePath}.html`) || fs.existsSync(pageIsHtmlPath)) {
// if the page is already HTML, use that as the template
+ console.debug('// if the page is already HTML, use that as the template');
const indexPath = fs.existsSync(pageIsHtmlPath)
? pageIsHtmlPath
- : `${barePath}.html`;
+ : fs.existsSync(barePath)
+ ? barePath
+ :`${barePath}.html`;
contents = fs.readFileSync(indexPath, 'utf-8');
} else if (customPluginDefaultPageTemplates.length > 0 || fs.existsSync(`${templatesDir}/page.html`)) {
@@ -269,12 +274,16 @@ class StandardHtmlResource extends ResourceInterface {
? `${pagesDir}${relativeUrl}index`
: `${pagesDir}${relativeUrl.replace('.html', '')}`;
- return Promise.resolve(this.extensions.indexOf(path.extname(relativeUrl)) >= 0 || path.extname(relative
Url) === '') &&
- (fs.existsSync(`${barePath}.html`) || barePath.substring(barePath.length - 5, barePath.length) === 'ind
ex')
- || fs.existsSync(`${barePath}.md`) || fs.existsSync(`${barePath.substring(0, barePath.lastIndexOf(`${pa
th.sep}index`))}.md`);
+ return Promise.resolve((fs.existsSync(url) && path.extname(url)) === '.html' ||
+ this.extensions.indexOf(path.extname(relativeUrl)) >= 0 || path.extname(relativeUrl) === '') &&
+ (fs.existsSync(`${barePath}.html`) || barePath.substring(barePath.length - 5, barePath.length) === 'i
ndex')
+ || fs.existsSync(`${barePath}.md`) || fs.existsSync(`${barePath.substring(0, barePath.lastIndexOf(`${
path.sep}index`))}.md`);
}
async serve(url) {
+ console.debug('serve HTML url@@@@@@@@@@@@@@@', url);
+ console.debug('text', path.extname(url));
+ console.debug('true', fs.existsSync(url) && path.extname(url) === '.html');
return new Promise(async (resolve, reject) => {
try {
const config = Object.assign({}, this.compilation.config);
@@ -286,14 +295,17 @@ class StandardHtmlResource extends ResourceInterface {
let body = '';
let template = null;
let processedMarkdown = null;
- const barePath = normalizedUrl.endsWith(path.sep)
- ? `${pagesDir}${normalizedUrl}index`
- : `${pagesDir}${normalizedUrl.replace('.html', '')}`;
+ const barePath = fs.existsSync(url) && path.extname(url) === '.html'
+ ? url
+ : normalizedUrl.endsWith(path.sep)
+ ? `${pagesDir}${normalizedUrl}index`
+ : `${pagesDir}${normalizedUrl.replace('.html', '')}`;
const isMarkdownContent = fs.existsSync(`${barePath}.md`)
|| fs.existsSync(`${barePath.substring(0, barePath.lastIndexOf(`${path.sep}index`))}.md`)
|| fs.existsSync(`${barePath.replace(`${path.sep}index`, '.md')}`);
- if (isMarkdownContent) {
+ console.debug('barePath??????', barePath);
+ if (!(fs.existsSync(url) && path.extname(url) === '.html') && isMarkdownContent) {
const markdownPath = fs.existsSync(`${barePath}.md`)
? `${barePath}.md`
: fs.existsSync(`${barePath.substring(0, barePath.lastIndexOf(`${path.sep}index`))}.md`)
seeing this issue now running yarn serve
though 😫
done prerendering all pages
copying assets/ directory...
copying graph.json...
Initializing project config
Initializing project workspace contexts
Generating graph of workspace files...
Started production test server at localhost:8080
Error: ENOENT: no such file or directory, open '/Users/owenbuckley/Workspace/github/repos/knowing-your-tco/public/index.html'
Trying to intercept
on the default HTML response from [plugin-standard-html]() so as to re-write it on the fly. Unfortunately, this takes the page out of the flow of the templating process that's done in the earlier serve
phase.
class ThemePackPageOverrideResource extends ResourceInterface {
constructor(compilation, options) {
super(compilation, options);
this.extensions = ['*'];
}
async shouldIntercept(url) {
console.debug('ThemePackPageOverrideResource shouldIntercept', url)
return Promise.resolve(url.replace(this.compilation.context.userWorkspace, '') === '/');
}
async intercept(url) {
console.debug('ThemePackPageOverrideResource intercept', url)
return Promise.resolve({ body: 'hello world!'});
}
}
This means that you get the content of index.html but without
<head>
and <body>
tagsSo this just means that the plugin author just has to merge the content of their own index.html into the default returned by Greenwood. I suppose since Greenwood bring along with it an html parser, plugins could piggy back off this and do it just like Greenwood does it?
Another quick option, the would require user "intervention" is by publishing index.html as a template and then having the user specify that in their project.
src/
assets/
background.png
pages/
index.md
slides/
1.md
2.md
.
.
styles/
overrides.css
index.md
---
template: 'index'
---
Naturally the downside here is the user has to do something on their side, but it's a pretty low effort / impact step, and is explicit, as opposed to the above solution, which is very much implicit. However, in this case, this isn't really a template, it's the home / landing page so... 🤷♂️
I suppose the better alternative will be when we can allow direct users of Greenwood to push content directly into the graph, but I think it doesn't necessarily hurts if Greenwood is robust enough to allow for a large degree of flexibility in how its APIs are used. As long as they are clear and stable and consistent, it should be a net positive for everyone.
Either way, here are something we can document for now at least.
Type of Change
Summary
Coming out of #570 / #669 was that currently Context plugins (or more specifically theme packs) are limited to just providing additional templates/ directories. Although Greenwood can effectively resolve anything during development, it can only build pages that are part of its graph, so being able to ship an actual page as part of a plugin is not possible and is already being tracked as part of #21 . (so this may be more of a reminder to update the docs / examples is all, but may require some work as well, we shall see)
Details
For example, like in greenwood-starter-presentation I would like to provide the actual home / landing / index.html page for users, to act as the entire interface to all their content (slides).
So from a user perspective, they would literally only have this for their directory layout, with everything else coming from the plugin (note: you can pull in overrides on a per page already! 💥 )
Literally a user would only actually have this in their repo