From f75d0229d035f9b6c19e235be0d3f4dc57ebffd7 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sun, 3 Nov 2024 13:58:12 -0500 Subject: [PATCH 01/12] link checker script --- CONTRIBUTING.md | 11 ++++ link-checker.js | 65 +++++++++++++++++++ package.json | 1 + src/components/run-anywhere/run-anywhere.js | 2 +- src/pages/blog/release/v0-27-0.md | 2 +- src/pages/blog/state-of-greenwood-2022.md | 2 +- src/pages/docs/content-as-data/collections.md | 2 +- src/pages/docs/content-as-data/data-client.md | 2 +- src/pages/docs/content-as-data/index.md | 4 +- src/pages/docs/index.md | 2 +- src/pages/docs/pages/api-routes.md | 2 +- src/pages/docs/pages/server-rendering.md | 8 +-- src/pages/docs/plugins/index.md | 2 +- src/pages/docs/plugins/lit-ssr.md | 2 +- src/pages/docs/plugins/typescript.md | 2 +- src/pages/docs/reference/configuration.md | 2 +- src/pages/docs/reference/plugins-api.md | 10 +-- .../docs/reference/rendering-strategies.md | 2 +- src/pages/docs/resources/assets.md | 2 +- src/pages/docs/resources/markdown.md | 4 +- .../guides/getting-started/going-further.md | 4 +- src/pages/guides/hosting/github.md | 2 +- src/pages/guides/tutorials/theme-packs.md | 6 +- 23 files changed, 109 insertions(+), 32 deletions(-) create mode 100644 link-checker.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea50fb26..7233926d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,17 @@ Where `issue-xxx` is the corresponding issue in the GreenwoodJS project. General changes to the website can be made by submitting a PR directly to the main branch. This includes typos, style changes, and general enhancements to the website as a whole. +### Link Checker + +There is a **npm** script that you can run that will check all relative links and hashes (except for blog pages) to check that links aren't broken. Running the command will build the site for production automatically and generate a report. + +```sh +$ npm run lint:links +#... + +✅ all links checked successfully and no broken links found +``` + ## Development ### Styling diff --git a/link-checker.js b/link-checker.js new file mode 100644 index 00000000..e5f9cd09 --- /dev/null +++ b/link-checker.js @@ -0,0 +1,65 @@ +import graph from "./public/graph.json" with { type: "json" }; +import { parse } from "node-html-parser"; +import fs from "fs/promises"; + +const report = {}; + +for (const page of graph) { + const { outputHref, route } = page; + const html = await fs.readFile(new URL(outputHref), "utf-8"); + const root = parse(html); + const links = root.querySelectorAll("a"); + + links.forEach((link) => { + if (!route.startsWith("/blog/") && link.getAttribute("href").startsWith("/")) { + const linkUrl = new URL(`https://www.greenwoodjs.dev${link.getAttribute("href")}`); + const { pathname, hash } = linkUrl; + const matchingRoute = graph.find((page) => page.route === pathname); + + if (!matchingRoute) { + if (!report[route]) { + report[route] = { + violations: [], + }; + } + + report[route].violations.push({ + link: pathname, + }); + } + + if (matchingRoute && hash !== "") { + const { tableOfContents } = matchingRoute.data; + const match = tableOfContents.find((toc) => toc.slug === hash.replace("#", "")); + + if (!match) { + if (!report[route]) { + report[route] = { + violations: [], + }; + } + + report[route].violations.push({ + hash, + }); + } + } + } + }); +} + +if (Object.keys(report).length === 0) { + console.log("✅ all links checked successfully and no broken links found"); +} else { + for (const r of Object.keys(report)) { + console.log("---------------------------------"); + console.log(`🚨 reporting violations for route ${r}...`); + report[r].violations.forEach((violation, idx) => { + if (violation.link) { + console.error(`${idx + 1}) Could not find matching route for href => ${violation.link}`); + } else if (violation.hash) { + console.error(`${idx + 1}) Could not find matching heading for hash => ${violation.hash}`); + } + }); + } +} diff --git a/package.json b/package.json index 27a4a072..41773518 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "lint:ls": "ls-lint", "lint:js": "eslint", "lint:css": "stylelint \"./src/**/*.css\"", + "lint:links": "npm run build && node ./link-checker.js", "format": "prettier . --write", "format:check": "prettier . --check", "prepare": "husky install" diff --git a/src/components/run-anywhere/run-anywhere.js b/src/components/run-anywhere/run-anywhere.js index 0ebef917..55588689 100644 --- a/src/components/run-anywhere/run-anywhere.js +++ b/src/components/run-anywhere/run-anywhere.js @@ -17,7 +17,7 @@ export default class RunAnywhere extends HTMLElement { this.innerHTML = `

Run anywhere the web can run

-

Greenwood helps you take your application to production by embracing platforms that embrace web standards.

+

Greenwood helps you take your application to production by embracing platforms that embrace web standards.

${platforms diff --git a/src/pages/blog/release/v0-27-0.md b/src/pages/blog/release/v0-27-0.md index 39e07d27..a40af8ae 100644 --- a/src/pages/blog/release/v0-27-0.md +++ b/src/pages/blog/release/v0-27-0.md @@ -72,7 +72,7 @@ So that is what we did! From this release forward, all CSS minification and bund ### Build Capacity -The last highlight we would like to feature from this release was the introduction of thread pooling for static builds that rely on SSR based page generation, like when using the [`prerender` configuration option](/docs/configuration/#prerender). In adopting this [SSG benchmark](https://github.com/thescientist13/bench-framework-markdown), it was clear that without some work, Greenwood would not be able to build thousands of pages in this way, let alone quickly. +The last highlight we would like to feature from this release was the introduction of thread pooling for static builds that rely on SSR based page generation, like when using the [`prerender` configuration option](/docs/reference/configuration/#prerender). In adopting this [SSG benchmark](https://github.com/thescientist13/bench-framework-markdown), it was clear that without some work, Greenwood would not be able to build thousands of pages in this way, let alone quickly. So under the hood, Greenwood now introduces thread pooling to avoid crashing NodeJS through the spawning of too many Worker threads, based on our [_Getting Started_ repo](https://github.com/ProjectEvergreen/greenwood-getting-started). While it might not be the fastest, at least Greenwood will now be able handle the [thousands of pages](https://github.com/thescientist13/bench-framework-markdown) you may throw at it! 😅 diff --git a/src/pages/blog/state-of-greenwood-2022.md b/src/pages/blog/state-of-greenwood-2022.md index b12e91d2..56822afb 100644 --- a/src/pages/blog/state-of-greenwood-2022.md +++ b/src/pages/blog/state-of-greenwood-2022.md @@ -154,7 +154,7 @@ And Greenwood will statically generate this ### Interpolate Frontmatter -When setting the [`interpolateFrontmatter`](/docs/configuration/#interpolate-frontmatter) flag in your _greenwood.config.js_, frontmatter in your markdown will be available in your HTML or markdown similar to how variable interpolation works in JavaScript. Great for `` tags! +When setting the [`interpolateFrontmatter`](/docs/reference/configuration/#interpolate-frontmatter) flag in your _greenwood.config.js_, frontmatter in your markdown will be available in your HTML or markdown similar to how variable interpolation works in JavaScript. Great for `` tags! #### How It Works diff --git a/src/pages/docs/content-as-data/collections.md b/src/pages/docs/content-as-data/collections.md index 321b9513..9948f4aa 100644 --- a/src/pages/docs/content-as-data/collections.md +++ b/src/pages/docs/content-as-data/collections.md @@ -6,7 +6,7 @@ tocHeading: 2 # Collections -Collections are a feature in Greenwood by which you can use [frontmatter](/docs/resources/markdown#frontmatter) to group pages that can the be referenced through JavaScript or [`activeFrontmatter`](/docs/configuration/#active-frontmatter). +Collections are a feature in Greenwood by which you can use [frontmatter](/docs/resources/markdown/#frontmatter) to group pages that can the be referenced through [JavaScript](/docs/content-as-data/data-client/) or [active frontmatter](/docs/content-as-data/active-frontmatter/). This can be a useful way to group pages for things like navigation menus based on the content in your pages directory. diff --git a/src/pages/docs/content-as-data/data-client.md b/src/pages/docs/content-as-data/data-client.md index b3c6050a..b8e30e9d 100644 --- a/src/pages/docs/content-as-data/data-client.md +++ b/src/pages/docs/content-as-data/data-client.md @@ -10,7 +10,7 @@ To access your content as data with Greenwood, there are three pre-made APIs you This way, you can serialize and / or hydrate from this data as needed based on your application's needs. -> These features works best when used for build time templating combining our [**prerender**](/docs/configuration/#prerender) and [**static** optimization](/docs/configuration/#optimization) configurations. +> These features works best when used for build time templating combining our [**prerender**](/docs/reference/configuration/#prerender) and [**static** optimization](/docs/reference/configuration/#optimization) configurations. ## Content diff --git a/src/pages/docs/content-as-data/index.md b/src/pages/docs/content-as-data/index.md index fc532ac3..6495141c 100644 --- a/src/pages/docs/content-as-data/index.md +++ b/src/pages/docs/content-as-data/index.md @@ -20,6 +20,6 @@ But what happens over time, when that list grows to 10, 50, 100+ posts? Imagine To assist with this, Greenwood provides a set of "content as data" capabilities on the left sidebar you can take advantage of. -> First thing though, make sure you've set the [`activeContent`](/docs/configuration/#active-content) flag to `true` in your _greenwood.config.js_. +> First thing though, make sure you've set the [`activeContent`](/docs/reference/configuration/#active-content) flag to `true` in your _greenwood.config.js_. > -> These features works best when used for build time templating combining our [**prerender**](/docs/configuration/#prerender) and [**static** optimization](/docs/configuration/#optimization) configurations. +> These features works best when used for build time templating combining our [**prerender**](/docs/reference/configuration/#prerender) and [**static** optimization](/docs/reference/configuration/#optimization) configurations. diff --git a/src/pages/docs/index.md b/src/pages/docs/index.md index 918e82f0..c94be948 100644 --- a/src/pages/docs/index.md +++ b/src/pages/docs/index.md @@ -12,7 +12,7 @@ order: 1 The content is broken down across these sections: - [Introduction](/docs/introduction/) - An intro to Greenwood, its philosophy, and how it install it -- [Pages](/docs/hosting/) - Learn about file-based routing and how to leverage SSR pages, API routes, and more +- [Pages](/docs/pages/) - Learn about file-based routing and how to leverage SSR pages, API routes, and more - [Resources](/docs/resources/) - Scripts? Styles? Fonts and images? This section has you covered - [Plugins](/docs/plugins/) - Check out all plugins created by the Greenwood team - [Content as Data](/docs/content-as-data/) - See Greenwood's capabilities for leveraging your content programmatically diff --git a/src/pages/docs/pages/api-routes.md b/src/pages/docs/pages/api-routes.md index 2e8c30be..f5ec891b 100644 --- a/src/pages/docs/pages/api-routes.md +++ b/src/pages/docs/pages/api-routes.md @@ -119,4 +119,4 @@ To execute an API route in its own isolated request context when running `greenw export const isolation = true; ``` -> For more information and how you can enable this for all pages, please see the [isolation configuration](/docs/reference/configuration/#isolation) docs. +> For more information and how you can enable this for all pages, please see the [isolation configuration](/docs/reference/configuration/#isolation-mode) docs. diff --git a/src/pages/docs/pages/server-rendering.md b/src/pages/docs/pages/server-rendering.md index 496e001e..72f79da2 100644 --- a/src/pages/docs/pages/server-rendering.md +++ b/src/pages/docs/pages/server-rendering.md @@ -6,7 +6,7 @@ tocHeading: 2 # Server Rendering -Greenwood provides a couple of mechanisms for server-side rendering, building on top of our [file-based routing](/docs/routing/) convention. +Greenwood provides a couple of mechanisms for server-side rendering, building on top of our [file-based routing](/docs/pages/) convention. To create a dynamic server route, just create a JavaScript file in the _pages/_ directory, and that's it! @@ -24,7 +24,7 @@ In your page file, Greenwood supports the following functions that you can `expo - **default** (recommended): Use the custom elements API to render out your page content, aka **Web (Server) Components** - **getBody**: Return a string of HTML for the contents of the page -- **getLayout**: Return a string of HTML to act as the [page's layout](/docs/pages/layouts/#page-layouts) +- **getLayout**: Return a string of HTML to act as the [page's layout](/docs/pages/layouts/#pages) - **getFrontmatter**: Provide an object of [frontmatter](/docs/resources/markdown/#frontmatter) properties. Useful in conjunction with [content as data](/docs/content-as-data/), or otherwise setting static configuration / metadata through SSR. @@ -134,7 +134,7 @@ export async function getBody(compilation, page, request) { ### Layouts -For creating a [layout](/docs/pages/layouts) dynamically, you can provide a `getLayout` function and return the HTML you need. +For creating a [layout](/docs/pages/layouts/) dynamically, you can provide a `getLayout` function and return the HTML you need. You can pull in data from Greenwood's [compilation](/docs/reference/appendix/#compilation) object as well as the specific route: @@ -208,7 +208,7 @@ To execute an SSR page in its own request context when running `greenwood serve` export const isolation = true; ``` -> For more information and how you can enable this for all pages, please see the [isolation configuration](/docs/reference/configuration/#isolation) docs. +> For more information and how you can enable this for all pages, please see the [isolation configuration](/docs/reference/configuration/#isolation-mode) docs. ## Request Data diff --git a/src/pages/docs/plugins/index.md b/src/pages/docs/plugins/index.md index 097f3cd2..11eb6600 100644 --- a/src/pages/docs/plugins/index.md +++ b/src/pages/docs/plugins/index.md @@ -4,7 +4,7 @@ order: 4 --- -

Greenwood provides some first-party plugins allowing you to extend Greenwood to support capabilities not already supported by web standards. The full list is below, with some of our featured plugins on the left side nav. You can also create your own.

+

Greenwood provides some first-party plugins allowing you to extend Greenwood to support capabilities not already supported by web standards. The full list is below, with some of our featured plugins on the left side nav. You can also create your own.

Below is the official list of supported first-party plugins available by the Greenwood team with links to the plugin specific README for full installation and usage documentation. diff --git a/src/pages/docs/plugins/lit-ssr.md b/src/pages/docs/plugins/lit-ssr.md index e72bccf7..3ce9e59d 100644 --- a/src/pages/docs/plugins/lit-ssr.md +++ b/src/pages/docs/plugins/lit-ssr.md @@ -48,7 +48,7 @@ export default { ## Usage -Now, you can author [SSR pages](/docs/server-rendering/) using Lit templates using Greenwood's [`getBody` API](https://www.greenwoodjs.io/docs/server-rendering/#usage) or prerender components included via ` ``` -This is also supported for pages with an additional option": +This is also supported for pages with the **servePage** option that you can pass: ```js import { greenwoodPluginTypeScript } from "@greenwood/plugin-typescript"; diff --git a/src/pages/docs/reference/configuration.md b/src/pages/docs/reference/configuration.md index 2ccd071c..37b50688 100644 --- a/src/pages/docs/reference/configuration.md +++ b/src/pages/docs/reference/configuration.md @@ -54,7 +54,7 @@ export default { There are cases where an application might be deployed and hosted from a "sub" pathname that acts as the relative "web root". (GitHub Pages is an example of this) -So with a URL of _http://www.example.com/app-a/_, the \*_basePath_ would be set as follows: +So with a URL of _http://www.example.com/app-a/_, the _basePath_ would be set as follows: ```js export default { diff --git a/src/pages/docs/reference/plugins-api.md b/src/pages/docs/reference/plugins-api.md index c853c4ec..7c350f0e 100644 --- a/src/pages/docs/reference/plugins-api.md +++ b/src/pages/docs/reference/plugins-api.md @@ -53,12 +53,12 @@ export default { The **provider** function takes a Greenwood [**compilation** object](/docs/reference/appendix/#compilation) consisting of the following properties: - **config** - Current values for of Greenwood's [configuration](/docs/reference/configuration/) settings -- **graph** - All the pages in your project per Greenwood's [Content as Data page schema](/docs/content-as-data/page-data/) +- **graph** - All the pages in your project per Greenwood's [Content as Data page schema](/docs/content-as-data/pages-data/) - **context** - Access to relevant build directories like project workspace, output directory, etc ## Adapter -Adapter plugins are designed with the intent to be able to post-process the Greenwood standard build output. For example, moving [build output files](/docs/reference/appendix#build-output/) around into the desired location for a specific hosting provider, like Vercel or AWS. +Adapter plugins are designed with the intent to be able to post-process the Greenwood standard build output. For example, moving [build output files](/docs/reference/appendix/#build-output) around into the desired location for a specific hosting provider, like Vercel or AWS. ### Usage @@ -157,7 +157,7 @@ Context plugins allow users to extend where Greenwood can look for certain files Similar in spirit to [**CSS Zen Garden**](http://www.csszengarden.com/) -> 🔎 For more information on developing and publishing a Theme Pack, check out [our guide on theme packs](/guides/theme-packs/). +> 🔎 For more information on developing and publishing a Theme Pack, check out [our guide on theme packs](/guides/tutorials/theme-packs/). ### API @@ -279,7 +279,7 @@ This plugin type supports the following options: - `executeModuleUrl` (recommended) - `URL` to the location of a file with the SSR rendering implementation - `customUrl` - `URL` to a file that has a `default export` of a function for handling the _prerendering_ lifecyle of a Greenwood build, and running the provided `callback` function -- `prerender` (optional) - Flag can be used to indicate if this custom renderer should be used to statically [prerender](/docs/configuration/#prerender) pages too. +- `prerender` (optional) - Flag can be used to indicate if this custom renderer should be used to statically [prerender](/docs/reference/configuration/#prerender) pages too. ### Examples @@ -645,7 +645,7 @@ The source plugin allows users to include external content as pages that will be ### API -This plugin supports providing an array of "page" objects that will be added as nodes in [the graph](/docs/data/). +This plugin supports providing an array of "page" objects that will be added as nodes in [the graph](/docs/content-as-data/). ```js // my-source-plugin.js diff --git a/src/pages/docs/reference/rendering-strategies.md b/src/pages/docs/reference/rendering-strategies.md index ea66df5b..f767b13d 100644 --- a/src/pages/docs/reference/rendering-strategies.md +++ b/src/pages/docs/reference/rendering-strategies.md @@ -75,7 +75,7 @@ For example, take a list of blog posts rendered based on the project's pages dir customElements.define("blog-posts-list", BlogPostsList); ``` -1. Add it to your HTML page with the [**static** optimization attribute](/docs/reference/configuration/#optimizations) +1. Add it to your HTML page with the [**static** optimization attribute](/docs/reference/configuration/#optimization) ```html diff --git a/src/pages/docs/resources/assets.md b/src/pages/docs/resources/assets.md index 1260730c..d8189345 100644 --- a/src/pages/docs/resources/assets.md +++ b/src/pages/docs/resources/assets.md @@ -84,4 +84,4 @@ src/ sitemap.xml ``` -> If you need support for more custom copying of static files like this, please check out our docs on creating your own [copy plugin](/docs/reference/plugins/#copy). +> If you need support for more custom copying of static files like this, please check out our docs on creating your own [copy plugin](/docs/reference/plugins-api/#copy). diff --git a/src/pages/docs/resources/markdown.md b/src/pages/docs/resources/markdown.md index 7f3ae969..fd3954ab 100644 --- a/src/pages/docs/resources/markdown.md +++ b/src/pages/docs/resources/markdown.md @@ -10,7 +10,7 @@ In this section we'll cover some of the Markdown related feature of **Greenwood* ## Plugins -Using your _greenwood.config.js_ you can have additional [markdown customizations and configurations](/docs/configuration#markdown) using unified presets and plugins. +Using your _greenwood.config.js_ you can have additional [markdown customizations and configurations](/docs/reference/configuration/#markdown) using unified presets and plugins. For example, to use the [**remark-github**](https://github.com/remarkjs/remark-github) plugin: @@ -70,7 +70,7 @@ console.log(hello); ## Frontmatter -Frontmatter is a [YAML](https://yaml.org/) block at the top of any markdown file. It gives you the ability to define variables that are made available to Greenwood's [build process and then your HTML](/docs/content-as-data). You can also use it to `import` additional files. +Frontmatter is a [YAML](https://yaml.org/) block at the top of any markdown file. It gives you the ability to define variables that are made available to Greenwood's [build process and then your HTML](/docs/content-as-data/). You can also use it to `import` additional files. The following options are available: diff --git a/src/pages/guides/getting-started/going-further.md b/src/pages/guides/getting-started/going-further.md index 63ac26d8..b347e972 100644 --- a/src/pages/guides/getting-started/going-further.md +++ b/src/pages/guides/getting-started/going-further.md @@ -12,7 +12,7 @@ Now that we've had a chance to introduce some of the [basics](/guides/getting-st A fair observation from the walkthrough might be that the header and footer are really just producing static content. While the footer calculates a year, that really only needs to be done once at build time. Since Greenwood can easily server render Web Components leaning on [DOM based hydration techniques](https://web.dev/articles/declarative-shadow-dom#component_hydration), we can make a couple useful optimizations here. -First, we can enable the [`prerender`](/docs/config/#prerender) flag in a _greenwood.config.js_ file which will do a one-time server render for any custom element tags in our HTML. +First, we can enable the [`prerender`](/docs/reference/configuration/#prerender) flag in a _greenwood.config.js_ file which will do a one-time server render for any custom element tags in our HTML. ```js export default { @@ -129,7 +129,7 @@ customElements.define("app-picture-frame", PictureFrame); ## Content as Data -Greenwood also provides some general purpose helpers for more static driven sites (e.g. SSG) through our [content as data](/docs/content-as-data/) features, including a programmatic `Fetch` based API. When combined with [`activeFrontmatter`](/docs/config/) this enables HTML-first templating which can then be used to initialize attributes for custom element tags on a per page basis. Very useful for creating navigation menus and other sorts of collections of content, even with active link highlighting, no runtime JS needed! 💯 +Greenwood also provides some general purpose helpers for more static driven sites (e.g. SSG) through our [content as data](/docs/content-as-data/) features, including a programmatic `Fetch` based API. When combined with [`activeFrontmatter`](/docs/reference/configuration/) this enables HTML-first templating which can then be used to initialize attributes for custom element tags on a per page basis. Very useful for creating navigation menus and other sorts of collections of content, even with active link highlighting, no runtime JS needed! 💯 For example, we can define some frontmatter in a markdown file: diff --git a/src/pages/guides/hosting/github.md b/src/pages/guides/hosting/github.md index 1c7f1993..d2a521a7 100644 --- a/src/pages/guides/hosting/github.md +++ b/src/pages/guides/hosting/github.md @@ -17,7 +17,7 @@ Greenwood can easily be configured to work with [GitHub Pages](https://pages.git Following the steps [outlined here](https://pages.github.com/), first make sure you have already: 1. Created a repo in the format `.github.io` or `.github.io/` -1. If using `.github.io/`, make sure to set Greenwood's [base path](/docs/configuration/#base-peth) configuration to match +1. If using `.github.io/`, make sure to set Greenwood's [base path](/docs/reference/configuration/#base-path) configuration to match ```js export default { basePath: "/repo-name", diff --git a/src/pages/guides/tutorials/theme-packs.md b/src/pages/guides/tutorials/theme-packs.md index c91b80b1..9b6dca03 100644 --- a/src/pages/guides/tutorials/theme-packs.md +++ b/src/pages/guides/tutorials/theme-packs.md @@ -7,7 +7,7 @@ tocHeading: 2 # Creating a Theme Pack -Introduced as a concept in the [Context Plugin docs](/docs/plugins/api/#context), a theme pack is what Greenwood uses to refer to a plugin that aims to provide a set of reusable layouts, pages and more to a user (think of [**CSS Zen Garden**](http://www.csszengarden.com/)). A good example (and the one this guide is based on) is [**greenwood-starter-presentation**](https://github.com/thescientist13/greenwood-starter-presentation), which provides the starting point for creating a [slide deck entirely from markdown](https://github.com/thescientist13/knowing-your-tco), using Greenwood! +Introduced as a concept in the [Context Plugin docs](/docs/reference/plugins-api/#context), a theme pack is what Greenwood uses to refer to a plugin that aims to provide a set of reusable layouts, pages and more to a user (think of [**CSS Zen Garden**](http://www.csszengarden.com/)). A good example (and the one this guide is based on) is [**greenwood-starter-presentation**](https://github.com/thescientist13/greenwood-starter-presentation), which provides the starting point for creating a [slide deck entirely from markdown](https://github.com/thescientist13/knowing-your-tco), using Greenwood! ![greenwood-starter-presentation](/assets/guides/greenwood-starter-presentation.png) @@ -147,7 +147,7 @@ const myThemePackPlugin = (options = {}) => [ export { myThemePackPlugin }; ``` -And our final _greenwood.config.js_ would look like this, which adds a "one-off" [resource plugin](/plugins/resource/) to tell Greenwood to route requests to your theme pack files away from \_node_modules+ and to the location of your projects files for development. +And our final _greenwood.config.js_ would look like this, which adds a "one-off" [resource plugin](/docs/reference/plugins-api/#resource) to tell Greenwood to route requests to your theme pack files away from _node_modules_ and to the location of your projects files for development. Additionally, we make sure to pass the flag from above for `__isDevelopment` to our plugin. @@ -270,7 +270,7 @@ For users, they would just need to do the following: Success! 🥳 -> Don't forget, user's can also [include additional CSS / JS files in their frontmatter](/docs/front-matter/#imports), to further extend, customize, and override your layouts! +> Don't forget, user's can also [include additional CSS / JS files in their frontmatter](/docs/resources/markdown/#frontmatter), to further extend, customize, and override your layouts! ## FAQ From 6f612ec37de6c671f92e81b5192d61baf31465b5 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sun, 3 Nov 2024 14:00:00 -0500 Subject: [PATCH 02/12] install html parser dep --- package-lock.json | 143 +++++++++++++++++++++++++++++++++++++++++----- package.json | 1 + 2 files changed, 131 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index aea0b64a..e87b4e21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "husky": "^9.0.11", "lint-staged": "^15.2.2", "lit": "^3.1.2", + "node-html-parser": "^6.1.13", "prettier": "^3.2.5", "rehype-autolink-headings": "^4.0.0", "rehype-slug": "^3.0.0", @@ -2363,6 +2364,15 @@ "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==", "dev": true }, + "node_modules/@greenwood/cli/node_modules/node-html-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", + "integrity": "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==", + "dev": true, + "dependencies": { + "he": "1.2.0" + } + }, "node_modules/@greenwood/plugin-css-modules": { "version": "0.30.0-alpha.7", "resolved": "https://registry.npmjs.org/@greenwood/plugin-css-modules/-/plugin-css-modules-0.30.0-alpha.7.tgz", @@ -2399,6 +2409,15 @@ "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==", "dev": true }, + "node_modules/@greenwood/plugin-css-modules/node_modules/node-html-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", + "integrity": "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==", + "dev": true, + "dependencies": { + "he": "1.2.0" + } + }, "node_modules/@greenwood/plugin-import-raw": { "version": "0.30.0-alpha.7", "resolved": "https://registry.npmjs.org/@greenwood/plugin-import-raw/-/plugin-import-raw-0.30.0-alpha.7.tgz", @@ -6173,6 +6192,12 @@ "node": ">= 0.8" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "node_modules/bplist-parser": { "version": "0.2.0", "dev": true, @@ -7272,16 +7297,32 @@ "node": ">=12 || >=16" } }, - "node_modules/css-tree": { - "version": "2.3.1", + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, - "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, "node_modules/css.escape": { @@ -7665,6 +7706,61 @@ "dev": true, "license": "MIT" }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "16.4.5", "dev": true, @@ -7745,6 +7841,18 @@ "once": "^1.4.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "dev": true, @@ -12284,11 +12392,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdn-data": { - "version": "2.0.30", - "dev": true, - "license": "CC0-1.0" - }, "node_modules/mdurl": { "version": "1.0.1", "dev": true, @@ -13163,10 +13266,12 @@ "license": "MIT" }, "node_modules/node-html-parser": { - "version": "1.4.9", + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", "dev": true, - "license": "MIT", "dependencies": { + "css-select": "^5.1.0", "he": "1.2.0" } }, @@ -13213,6 +13318,18 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nypm": { "version": "0.3.8", "dev": true, diff --git a/package.json b/package.json index 41773518..bb684b6d 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "husky": "^9.0.11", "lint-staged": "^15.2.2", "lit": "^3.1.2", + "node-html-parser": "^6.1.13", "prettier": "^3.2.5", "rehype-autolink-headings": "^4.0.0", "rehype-slug": "^3.0.0", From fd94481a80bc76d855ddb40e86bcdbceff958e80 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sun, 3 Nov 2024 16:33:47 -0500 Subject: [PATCH 03/12] docs content final walk through --- .../content-as-data/active-frontmatter.md | 20 +------- src/pages/docs/content-as-data/collections.md | 6 +-- src/pages/docs/content-as-data/data-client.md | 4 +- src/pages/docs/content-as-data/pages-data.md | 4 +- src/pages/docs/index.md | 6 +-- src/pages/docs/introduction/about.md | 4 +- src/pages/docs/introduction/index.md | 4 +- src/pages/docs/introduction/setup.md | 2 +- src/pages/docs/introduction/web-standards.md | 43 +++++++++++------ src/pages/docs/pages/api-routes.md | 11 +++-- src/pages/docs/pages/index.md | 2 +- src/pages/docs/pages/layouts.md | 6 +-- src/pages/docs/pages/routing.md | 8 ++-- src/pages/docs/pages/server-rendering.md | 14 +++--- src/pages/docs/plugins/css-modules.md | 4 +- src/pages/docs/plugins/index.md | 6 +-- src/pages/docs/reference/appendix.md | 4 +- src/pages/docs/reference/configuration.md | 30 ++++++------ src/pages/docs/reference/plugins-api.md | 48 +++++++++---------- .../docs/reference/rendering-strategies.md | 24 +++++----- src/pages/docs/resources/assets.md | 6 +-- src/pages/docs/resources/index.md | 2 +- src/pages/docs/resources/scripts.md | 9 ++-- 23 files changed, 131 insertions(+), 136 deletions(-) diff --git a/src/pages/docs/content-as-data/active-frontmatter.md b/src/pages/docs/content-as-data/active-frontmatter.md index 7c3ea8f7..c768577a 100644 --- a/src/pages/docs/content-as-data/active-frontmatter.md +++ b/src/pages/docs/content-as-data/active-frontmatter.md @@ -12,23 +12,7 @@ Really useful for passing page content or collections as attributes to a custom ## Usage -Say for instance we want to - -```html - - - - Home Page - - - - - - - -``` - -Or given some frontmatter in a markdown file: +Given some frontmatter in a markdown file: ```md --- @@ -72,7 +56,7 @@ Or HTML: ## Data Client -You can also access this content using our data client. +You can also access this content using our data client: ```js import { getContentByCollection } from "@greenwood/cli/src/data/client.js"; diff --git a/src/pages/docs/content-as-data/collections.md b/src/pages/docs/content-as-data/collections.md index 9948f4aa..ae5f2ac0 100644 --- a/src/pages/docs/content-as-data/collections.md +++ b/src/pages/docs/content-as-data/collections.md @@ -6,13 +6,13 @@ tocHeading: 2 # Collections -Collections are a feature in Greenwood by which you can use [frontmatter](/docs/resources/markdown/#frontmatter) to group pages that can the be referenced through [JavaScript](/docs/content-as-data/data-client/) or [active frontmatter](/docs/content-as-data/active-frontmatter/). +Collections are a feature in Greenwood by which you can use [frontmatter](/docs/resources/markdown/#frontmatter) to group pages that can then be referenced through [JavaScript](/docs/content-as-data/data-client/) or [active frontmatter](/docs/content-as-data/active-frontmatter/). This can be a useful way to group pages for things like navigation menus based on the content in your pages directory. ## Usage -To define a collections, just add a **collection** property to the frontmatter of any static file: +To define a collection, just add a **collection** property to the frontmatter of any static file: ```md --- @@ -23,7 +23,7 @@ order: 2 # About Page ``` -You can now a reference to that collection either in HTML using [`activeFrontmatter`](/docs/content-as-data/active-frontmatter/): +You can now a reference to that collection either in HTML using [**activeFrontmatter**](/docs/content-as-data/active-frontmatter/): ```html diff --git a/src/pages/docs/content-as-data/data-client.md b/src/pages/docs/content-as-data/data-client.md index b8e30e9d..fcdd69c8 100644 --- a/src/pages/docs/content-as-data/data-client.md +++ b/src/pages/docs/content-as-data/data-client.md @@ -6,7 +6,7 @@ tocHeading: 2 # Data Client -To access your content as data with Greenwood, there are three pre-made APIs you can use, based on your use case. These are isomorphic in that they will consume live data during development, and statically build out each query at build time to its own JSON file that can be fetched client side independently. +To access your content as data with Greenwood, there are three pre-made APIs you can use, based on your use case. These are isomorphic in that they will consume live data during development, and statically build out each query at build time to its own JSON file that can be fetched client side. This way, you can serialize and / or hydrate from this data as needed based on your application's needs. @@ -14,7 +14,7 @@ This way, you can serialize and / or hydrate from this data as needed based on y ## Content -To get every page back in one array, simple call `getContent` +To get every page back in one array, simple call `getContent`: ```js // get turn the entire set of pages as an array diff --git a/src/pages/docs/content-as-data/pages-data.md b/src/pages/docs/content-as-data/pages-data.md index d6f5a56a..f6bf2255 100644 --- a/src/pages/docs/content-as-data/pages-data.md +++ b/src/pages/docs/content-as-data/pages-data.md @@ -16,7 +16,7 @@ Each page will return data in the following schema: - **title** (customizable) - inferred title based on the filename - **label** (customizable) - inferred from the **title** if not configured - **route** - the filename converted into a path as per file based routing -- **data** (customizable) - any custom frontmatter keys you've added to your page +- **data** (customizable) - any custom frontmatter keys you've defined for your page So for a page at _src/pages/blog/first-post.md_, this is the data you would get back: @@ -46,7 +46,7 @@ This is my first post. ## Table of Contents -Additionally for markdown pages, you can add a frontmatter property called `tocHeading` that will read all the HTML heading tags that match that number, and provide a subset of data, useful for generated a table of contents. +Additionally for markdown pages, you can add a frontmatter property called `tocHeading` that will read all the HTML heading tags that match that number, and provide that as a subset of the data object. This is most useful for generating the table of contents for a page. Taking our previous example, if we were to configure this for `

` tags: diff --git a/src/pages/docs/index.md b/src/pages/docs/index.md index c94be948..d8cf162d 100644 --- a/src/pages/docs/index.md +++ b/src/pages/docs/index.md @@ -6,14 +6,14 @@ order: 1 --- -

Welcome to our docs, we're excited to help you get the most out of Greenwood and the web!

+

Welcome to our documentation, we're excited to help you get the most out of Greenwood and the web!

The content is broken down across these sections: -- [Introduction](/docs/introduction/) - An intro to Greenwood, its philosophy, and how it install it +- [Introduction](/docs/introduction/) - An intro to Greenwood, its philosophy, and how to install it - [Pages](/docs/pages/) - Learn about file-based routing and how to leverage SSR pages, API routes, and more - [Resources](/docs/resources/) - Scripts? Styles? Fonts and images? This section has you covered - [Plugins](/docs/plugins/) - Check out all plugins created by the Greenwood team - [Content as Data](/docs/content-as-data/) - See Greenwood's capabilities for leveraging your content programmatically -- [Reference](/docs/reference/) - Configuration options, Plugin API docs, and other useful content for help you to build your project +- [Reference](/docs/reference/) - Configuration options, Plugin API docs, and other useful content for helping you extend Greenwood diff --git a/src/pages/docs/introduction/about.md b/src/pages/docs/introduction/about.md index 51edc839..12f96b40 100644 --- a/src/pages/docs/introduction/about.md +++ b/src/pages/docs/introduction/about.md @@ -14,7 +14,7 @@ Greenwood's goal is to bring the power of the modern web right to your fingertip Some of Greenwood's feature include: -- Unbundled local development workflow, using `E-Tags` headers for efficient caching and live reloads +- Unbundled local development workflow, using `ETag` headers for efficient caching and live reloads - Out of the box support for ESM and Web APIs, on both the client and server - Server Side Rendering of Web Components (Light and Shadow DOM) - File-based routing, including API Routes @@ -28,7 +28,7 @@ Greenwood aims to be a low point of friction as part of a general purpose web de > We would be remiss if we didn't call out what are probably some obvious influences; in particular **Next.js**, **SvelteKit**, and of course, **Gatsby**. We are in debt to amazing tools like **Rollup**, **parse5**, and **acorn**. 🙇 > -> The JavaScript ecosystem is great, and we're very happy to be a part of it. 💚 +> The JavaScript ecosystem is amazing, and we're very happy to be a part of it. 💚 ## Goals diff --git a/src/pages/docs/introduction/index.md b/src/pages/docs/introduction/index.md index 654400c5..64bd2101 100644 --- a/src/pages/docs/introduction/index.md +++ b/src/pages/docs/introduction/index.md @@ -4,11 +4,11 @@ order: 1 --- -

As enthusiasts of the web, we hope to provide an authentic, hands-on, and unbiased option for web development, inspired by the web itself. Whether you roll your own or build with friends, we can all win when we bet on the web.

+

As enthusiasts of the web, we hope Greenwood can provide an authentic, predictable, and pragmatic experience for web development, inspired by the web itself. Whether you prefer to roll your own or want build with friends, we can all win together when we bet on the web.

This introductory section is great for first time users of Greenwood, and covers the following topics: - [About](/docs/introduction/about/) - Learn about the project and its motivations and goals - [Setup](/docs/introduction/setup/) - Get your first Greenwood project started with a single command -- [Web Standards](/docs/introduction/web-standards/) - Web APIs promoted by Greenwood and featured throughout the docs +- [Web Standards](/docs/introduction/web-standards/) - Web APIs promoted by Greenwood and featured throughout the docs and guides diff --git a/src/pages/docs/introduction/setup.md b/src/pages/docs/introduction/setup.md index 819a9276..1ef355ae 100644 --- a/src/pages/docs/introduction/setup.md +++ b/src/pages/docs/introduction/setup.md @@ -10,7 +10,7 @@ Greenwood has a few options for getting a new project started. You can also chec ## Init -The recommended way to start a new Greenwood project, our **init** CLI will scaffold out a starter project for you. Just run a single command, and then just follow the prompts. +The recommended way to start a new Greenwood project, our **init** CLI will scaffold out a starter project for you. Just run a single command and then follow the prompts. To scaffold into the _current_ directory, run: diff --git a/src/pages/docs/introduction/web-standards.md b/src/pages/docs/introduction/web-standards.md index 7ab9c554..93b60d87 100644 --- a/src/pages/docs/introduction/web-standards.md +++ b/src/pages/docs/introduction/web-standards.md @@ -6,7 +6,7 @@ tocHeading: 2 # Web Standards -Throughout our docs we make heavy use of, and reference, some of the following Web APIs, either indirectly or as part of the core surface area of Greenwood itself. This section is an general introduction to them with relevant links and resources. +Throughout our docs we make heavy use of, and reference to, some of the following Web APIs, either indirectly or as part of the core surface area of Greenwood itself. This section is a general introduction to them with relevant links and resources. ## Import Attributes @@ -42,10 +42,13 @@ A simple example putting it all together might look like this: ```js import sheet from "./card.css" with { type: "css" }; +// create a template element +// to be populated with dynamic HTML const template = document.createElement("template"); export default class Card extends HTMLElement { connectedCallback() { + // this block can be SSR'd and thus wont need to be re-run on the client if (!this.shadowRoot) { const thumbnail = this.getAttribute("thumbnail"); const title = this.getAttribute("title"); @@ -57,34 +60,43 @@ export default class Card extends HTMLElement {

`; + // attach our template to our Shadow root this.attachShadow({ mode: "open" }); this.shadowRoot.appendChild(template.content.cloneNode(true)); } + // adopt our CSS Module Script this.shadowRoot.adoptedStyleSheets = [sheet]; } } +// defining the HTML tag that will invoke this definition customElements.define("x-card", Card); ``` +And would be used like this: + +```html + +``` + > Greenwood promotes Web Components not only as a great way to add sprinkles of JavaScript to an otherwise static site, but also for [static templating through prerendering](docs/reference/rendering-strategies/#prerendering) with all the power and expressiveness of JavaScript as well as completely [full-stack web components](/guides/tutorials/full-stack-web-components/). ## Fetch (and Friends) -[**Fetch**](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a web standard for making HTTP requests and is supported both on the client and the server. It also bring along "companion" APIs like [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), and [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers). +[**Fetch**](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a web standard for making HTTP requests and is supported both on the client and the server. It also brings along "companion" APIs like [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), and [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers). -This suite of APIs is featured prominently in our API Route handlers: +This suite of APIs is featured prominently in our API Route examples: ```js +// a standard request object is passed in +// and a standard response object should be returned 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}! 👋` }; + console.log("endpoint visited", request.url); - return new Response(JSON.stringify(body), { + return new Response("...", { headers: new Headers({ - "Content-Type": "application/json", + /* ... */ }), }); } @@ -92,9 +104,7 @@ export async function handler(request) { ## Import Maps -During local development, Greenwood loads all assets from your browser unbundled, serving the content right off disk, or through any additional plugins defined for the project in a _greenwood.config.js_. Combined with live reloading and `E-Tag` cache tag headers, [**import maps**](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) allow bare specifiers typically found when referencing packages from npm, to work natively in the browser without having to load all of _node_modules_ up front. All pages and assets are only requested on load. - -When installing a package as a `dependency` in your _package.json_, Greenwood will walk your dependencies and all their transitive dependencies, to build up a map to be injected in the `` of your HTML. +During local development, Greenwood loads all assets from your browser unbundled, serving the content right off disk. [**Import maps**](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) allow bare specifiers typically found when referencing packages from npm, to work natively in the browser. When installing a package as a **dependency** in your _package.json_, Greenwood will walk your dependencies and all their dependencies, to build up a map to be injected into the `` of your HTML. This is a sample of an import map that would be generated after having installed the **lit** package: @@ -122,16 +132,19 @@ This is a sample of an import map that would be generated after having installed The [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) constructor provides an elegant way for referencing [static assets](/docs/resources/assets/) on the client and on the server, and it works great when combined with [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) for easily interacting with search params in a request. -Here is an example of some of these APIs in action in an API Route handler: +Below is an example used in an API Route handler: ```js 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 msg = `Hello, ${name}! `; - console.log({ name }); - - // ... + return new Response(JSON.stringify({ msg }), { + headers: new Headers({ + "Content-Type": "application/json", + }), + }); } ``` diff --git a/src/pages/docs/pages/api-routes.md b/src/pages/docs/pages/api-routes.md index f5ec891b..9b9e6373 100644 --- a/src/pages/docs/pages/api-routes.md +++ b/src/pages/docs/pages/api-routes.md @@ -8,7 +8,7 @@ tocHeading: 2 # API Routes -Greenwood has support for API routes, which are just functions that run on the server, and take in a [**Request**](https://developer.mozilla.org/en-US/docs/Web/API/Request) and return a [**Response**](https://developer.mozilla.org/en-US/docs/Web/API/Response). Each API route must export an `async` function called **handler**. +Greenwood has support for API routes, which are just functions that run on the server, and take in a [**Request**](https://developer.mozilla.org/en-US/docs/Web/API/Request) and return a [**Response**](https://developer.mozilla.org/en-US/docs/Web/API/Response). Each API route must export an async function called **handler**. ## Usage @@ -47,7 +47,7 @@ Inspired by [**Doug Parker's**](https://blog.dwac.dev/) blog post [_A Simpler HT An example of rendering a "card" component in an API Route might look like look this: ```js -// component/card.js +// src/component/card.js export default class Card extends HTMLElement { connectedCallback() { if (!this.shadowRoot) { @@ -74,7 +74,10 @@ export default class Card extends HTMLElement { customElements.define("x-card", Card); ``` +And here is it being used in an API Route handler: + ```js +// src/pages/api/search.js import { renderFromHTML } from "wc-compiler"; import { getProducts } from "../../db/products.js"; @@ -98,7 +101,7 @@ export async function handler(request) { }) .join("")} `, - [new URL("../path/to/card.js", import.meta.url)], + [new URL("../../components/card.js", import.meta.url)], ); return new Response(html, { @@ -113,7 +116,7 @@ export async function handler(request) { ## Isolation Mode -To execute an API route in its own isolated request context when running `greenwood serve`, you can export an **isolation** option from your page, set to `true`. +To execute an API route in its own isolated rendering context, you can export an **isolation** option from your page, set to `true`. ```js export const isolation = true; diff --git a/src/pages/docs/pages/index.md b/src/pages/docs/pages/index.md index b2112029..f7565f49 100644 --- a/src/pages/docs/pages/index.md +++ b/src/pages/docs/pages/index.md @@ -7,7 +7,7 @@ order: 2

Greenwood supports hybrid, file-based routing, to easily create routes for your project based on the file contents of your pages directory.

-This section will cover the various aspects of creating static and dynamic content for your project, covering: +This section will cover the various aspects of creating static and dynamic content for your project: - [Routing Conventions](/docs/pages/routing/) - [Server Side Rendering (SSR)](/docs/pages/server-rendering/) diff --git a/src/pages/docs/pages/layouts.md b/src/pages/docs/pages/layouts.md index 5be35a68..420f6a77 100644 --- a/src/pages/docs/pages/layouts.md +++ b/src/pages/docs/pages/layouts.md @@ -6,10 +6,10 @@ tocHeading: 2 # Layouts -Greenwood defines two types of layouts to help layout your pages with common HTML +Greenwood defines two types of layouts that can be used to wrap your pages with common HTML - _App Layout_: The ["app shell"](https://developers.google.com/web/fundamentals/architecture/app-shell) that will wrap all pages. -- _Page Layouts_: Layouts that can be re-used across multiple pages using [frontmatter](/docs/resources/markdown/#frontmatter). +- _Page Layouts_: Layouts that can be re-used across multiple pages and defined using [frontmatter](/docs/resources/markdown/#frontmatter). Greenwood will handle merging the `` and `` tag contents when building up your pages and layouts. @@ -33,7 +33,7 @@ src/ ## Pages -Pages in your project will generally want a layout so you can control the output of the HTML and include all your own custom components and styles to wrap the content. By default all pages will default to looking for a _page.html_ in _layouts/_ directory within your workspace. A placeholder of `` can be used to position where the processed content from the incoming page will go. +Pages in your project will generally want a layout so you can control the output of the HTML and include all your own custom components and styles to wrap the content. By default all pages will default to looking for a _page.html_ in the _layouts/_ directory. A placeholder of `` can be used to position where the processed content from the incoming page will go. Below is an example of a _page.html_ layout: diff --git a/src/pages/docs/pages/routing.md b/src/pages/docs/pages/routing.md index ec9b26c0..88fe999a 100644 --- a/src/pages/docs/pages/routing.md +++ b/src/pages/docs/pages/routing.md @@ -33,7 +33,7 @@ The following routes will be accessible from the browser: ## SSR -Greenwood supports the intermingling of static pages like HTML and markdown with dynamic pages. Taking the example above, if we wanted a server rendered route, like a "Products" page, we can simply create a JavaScript file following the same naming convention. +Greenwood supports the intermingling of static pages with dynamic pages. Taking the example above, if we wanted a server rendered route, like a "Products" page, we can simply create a JavaScript file following the same naming convention. ```shell src/ @@ -67,9 +67,9 @@ Now the route _/api/search_ will be available to return a Web API `Response`. ## SPA -If you would like to opt-out of all file-based routing, like a **Single Page Application (SPA)**, you can opt-out of pages routing entirely and go full client-side only mode by just putting an _index.html_ at the root of your workspace. +You can opt-out of all file-based routing, like for a **Single Page Application (SPA)**, and go full client-side only mode by just putting an _index.html_ at the root of your workspace. (e.g. **no** _pages/_ directory). -Below is an example project structure of a typical SPA (no _pages/_ directory): +Below is an example project structure for a typical SPA: ```shell src/ @@ -86,7 +86,7 @@ src/ ## Not Found -As is a [common convention with most hosting providers](https://docs.netlify.com/routing/redirects/redirect-options/#custom-404-page-handling) and web servers, you can create a `404` page in your _pages/_ directory which will be used as the default Not Found page for your site. +As is a [common convention with most hosting providers](https://docs.netlify.com/routing/redirects/redirect-options/#custom-404-page-handling) and web servers, you can create a `404` page in your _pages/_ directory which will be used as the default **Not Found** page for your site. ```shell src/ diff --git a/src/pages/docs/pages/server-rendering.md b/src/pages/docs/pages/server-rendering.md index 72f79da2..d2737c9c 100644 --- a/src/pages/docs/pages/server-rendering.md +++ b/src/pages/docs/pages/server-rendering.md @@ -16,7 +16,7 @@ src/ users.js ``` -The above would serve content in a browser at the path `/users/`. +The above would serve content in a browser at the path _/users/_. ## Usage @@ -59,7 +59,7 @@ export { getFrontmatter, getBody, getLayout }; ### Web (Server) Components -Everyone else gets to use their component model for authoring pages, so why not Web Components! When using `export default`, Greenwood supports providing a custom element as the export for your page content, which Greenwood refers to as **Web Server Components (WSCs)** and uses [**WCC**](https://github.com/ProjectEvergreen/wcc) as the default renderer. +Everyone else gets to use their component model for authoring pages, so why not Web Components!? When using `export default`, Greenwood supports providing a custom element as the export for your page content, which Greenwood refers to as **Web Server Components (WSCs)** and uses [**WCC**](https://github.com/ProjectEvergreen/wcc) as the default renderer. This is the recommended pattern for SSR in Greenwood: @@ -89,7 +89,7 @@ export default class UsersPage extends HTMLElement { A couple of notes: - WSCs run only on the server, thus you have full access to any APIs of the runtime, with the ability to perform one time `async` operations for [data loading](/docs/pages/server-rendering/#request-data) in `connectedCallback`. -- Keep in mind that for these "page" components, you will likely want to _avoid_ rendering into a shadow root so as to avoid wrapping your static content in a `