### Install @greenwood/plugin-markdown with yarn
Source: https://greenwoodjs.dev/docs/plugins/markdown
Install the plugin using yarn.
```bash
yarn add @greenwood/plugin-markdown --dev
```
--------------------------------
### Install @greenwood/plugin-markdown with pnpm
Source: https://greenwoodjs.dev/docs/plugins/markdown
Install the plugin using pnpm.
```bash
pnpm add -D @greenwood/plugin-markdown
```
--------------------------------
### Install with pnpm
Source: https://greenwoodjs.dev/docs/plugins/postcss
Install the plugin as a dev dependency using pnpm.
```bash
pnpm add -D @greenwood/plugin-postcss
```
--------------------------------
### Install @greenwood/plugin-import-raw with npm, yarn, or pnpm
Source: https://greenwoodjs.dev/docs/plugins/raw
Install the plugin with your preferred package manager. The package is installed as a dev dependency.
```bash
npm i -D @greenwood/plugin-import-raw
```
```bash
yarn add @greenwood/plugin-import-raw --dev
```
```bash
pnpm add -D @greenwood/plugin-import-raw
```
--------------------------------
### Install with yarn
Source: https://greenwoodjs.dev/docs/plugins/postcss
Install the plugin as a dev dependency using yarn.
```bash
yarn add @greenwood/plugin-postcss --dev
```
--------------------------------
### Install with npm
Source: https://greenwoodjs.dev/docs/plugins/postcss
Install the plugin as a dev dependency using npm.
```bash
npm i -D @greenwood/plugin-postcss
```
--------------------------------
### Install @greenwood/plugin-import-jsx with npm
Source: https://greenwoodjs.dev/docs/plugins/jsx
Install the plugin as a dev dependency using npm.
```bash
npm i -D @greenwood/plugin-import-jsx
```
--------------------------------
### Sample Project Source Layout
Source: https://greenwoodjs.dev/docs/reference/appendix
An example directory structure for a Greenwood project source workspace.
```text
src/
api/
greeting.js
nested/
endpoint.js
pages/
blog/
first-post.js
index.js
index.js
```
--------------------------------
### Install @greenwood/plugin-markdown with npm
Source: https://greenwoodjs.dev/docs/plugins/markdown
Install the plugin using npm. Use your favorite JavaScript package manager.
```bash
npm i -D @greenwood/plugin-markdown
```
--------------------------------
### Input CSS example
Source: https://greenwoodjs.dev/docs/plugins/postcss
Example CSS input that demonstrates placeholder styling and responsive images.
```css
/* input */
::placeholder {
color: gray;
}
.image {
background-image: url(image@1x.png);
}
@media (min-resolution: 2dppx) {
.image {
background-image: url(image@2x.png);
}
}
```
--------------------------------
### Install @greenwood/plugin-renderer-lit with npm
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Installs the plugin as a dev dependency using npm.
```bash
npm i -D @greenwood/plugin-renderer-lit
```
--------------------------------
### Install @greenwood/plugin-renderer-lit with pnpm
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Installs the plugin as a dev dependency using pnpm.
```bash
pnpm add -D @greenwood/plugin-renderer-lit
```
--------------------------------
### Generated Import Map Example
Source: https://greenwoodjs.dev/docs/introduction/web-standards
Sample of an import map that Greenwood generates after installing the lit package. Includes imports for 'lit', 'lit-html', and 'lit-element', mapping to /node_modules/ paths.
```html
```
--------------------------------
### Server plugin example: LiveReload server
Source: https://greenwoodjs.dev/docs/reference/plugins-api
Excerpt of Greenwood's internal LiveReload server plugin. It defines a LiveReloadServer class with start and stop methods (stop not shown) and exports a server plugin that provides the server instance.
```javascript
import livereload from "livereload";
class LiveReloadServer {
constructor(compilation, options = {}) {
this.compilation = compilation;
this.options = options;
this.liveReloadServer = livereload.createServer({
/* options */
});
}
async start() {
const { userWorkspace } = this.compilation.context;
return this.liveReloadServer.watch(userWorkspace, () => {
console.info(`Now watching directory "${userWorkspace}" for changes.`);
return Promise.resolve(true);
});
}
}
/** @type {import("@greenwood/cli").ServerPlugin} */
export function myServerPlugin(options = {}) {
return {
type: "server",
name: "plugin-livereload",
provider: (compilation) => new LiveReloadServer(compilation, options),
};
}
```
--------------------------------
### Install @greenwood/plugin-import-jsx with yarn
Source: https://greenwoodjs.dev/docs/plugins/jsx
Install the plugin as a dev dependency using yarn.
```bash
yarn add @greenwood/plugin-import-jsx --dev
```
--------------------------------
### Install @greenwood/plugin-import-jsx with pnpm
Source: https://greenwoodjs.dev/docs/plugins/jsx
Install the plugin as a dev dependency using pnpm.
```bash
pnpm add -D @greenwood/plugin-import-jsx
```
--------------------------------
### Resource Plugin Interface Example
Source: https://greenwoodjs.dev/docs/reference/plugins-api
Defines the base structure of a Greenwood resource plugin, including the constructor with compilation and options, the extensions and servePage properties, and the plugin export function that returns a resource provider. Use this as a starting point for creating custom resource plugins.
```javascript
class ExampleResource {
constructor(compilation, options = {}) {
this.compilation = compilation; // Greenwood's compilation object
this.options = options; // any optional configuration provided by the user of your plugin
this.extensions = ["foo", "bar"]; // add custom extensions for file watching + live reload here, ex. ts for TypeScript
this.servePage = `static|dynamic`; // optionally opt-in to Greenwood using the plugin's serve lifecycle for processing static pages ('static') or SSR pages and API routes ('dynamic')
}
// lifecycles go here
}
/** @type {import("@greenwood/cli").ResourcePlugin} */
export function myExampleResourcePlugin(options = {}) {
return {
type: "resource",
name: "my-example-resource-plugin",
provider: (compilation) => new ExampleResource(compilation, options),
};
}
```
--------------------------------
### Install @greenwood/plugin-renderer-lit with yarn
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Installs the plugin as a dev dependency using yarn.
```bash
yarn add @greenwood/plugin-renderer-lit --dev
```
--------------------------------
### Initialize a new Greenwood project with npx
Source: https://greenwoodjs.dev/docs/introduction/setup
Run this command to scaffold a new project. It will prompt for TypeScript setup and package manager selection.
```bash
$ npx @greenwood/init@latest
```
--------------------------------
### Example meta files in workspace root
Source: https://greenwoodjs.dev/docs/resources/assets
Shows the top-level workspace files that Greenwood automatically copies to the build output root.
```text
src/
favicon.ico
robots.txt
sitemap.xml
```
--------------------------------
### Example workspace structure with layouts directory
Source: https://greenwoodjs.dev/docs/pages/layouts
Shows the recommended directory structure for a Greenwood project with a layouts/ folder containing app.html and blog.html.
```text
src/
pages/
index.html
blog/
first-post.md
second-post.md
layouts/
app.html
blog.html
```
--------------------------------
### Create postcss.config.js
Source: https://greenwoodjs.dev/docs/plugins/postcss
Example PostCSS configuration file that uses the autoprefixer plugin.
```javascript
export default {
plugins: [(await import("autoprefixer")).default],
};
```
--------------------------------
### Install Lit as a peer dependency with pnpm
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Alternative to npm/yarn for installing the required Lit peer dependency.
```bash
pnpm add lit
```
--------------------------------
### Install Greenwood CLI with pnpm
Source: https://greenwoodjs.dev/docs/introduction/setup
Installs the Greenwood CLI as a dev dependency using pnpm.
```bash
pnpm add -D @greenwood/cli@latest
```
--------------------------------
### Install Greenwood CLI with npm
Source: https://greenwoodjs.dev/docs/introduction/setup
Installs the Greenwood CLI as a dev dependency using npm.
```bash
npm i -D @greenwood/cli@latest
```
--------------------------------
### Create a CSS Module file (header.module.css)
Source: https://greenwoodjs.dev/docs/plugins/css-modules
Create a CSS file ending in .module.css. This example defines classes like .container, .navBarMenu, and .navBarMenuItem with nested selectors and a media query.
```css
.container {
display: flex;
justify-content: space-between;
}
.navBarMenu {
border: 1px solid #020202;
}
.navBarMenuItem {
& a {
text-decoration: none;
color: #020202;
}
}
@media screen and (min-width: 768px) {
.container {
padding: 10px 20px;
}
}
```
--------------------------------
### Install Lit as a peer dependency with yarn
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Alternative to npm for installing the required Lit peer dependency.
```bash
yarn add lit
```
--------------------------------
### Reference asset from HTML
Source: https://greenwoodjs.dev/docs/resources/assets
HTML example linking to a PDF asset from the assets directory.
```html
Welcome to My Site!
Download our product catalog
```
--------------------------------
### Install Greenwood CLI with yarn
Source: https://greenwoodjs.dev/docs/introduction/setup
Installs the Greenwood CLI as a dev dependency using yarn.
```bash
yarn add @greenwood/cli@latest --save-dev
```
--------------------------------
### Web Components with CSS Modules: HeadingBox example and output
Source: https://greenwoodjs.dev/docs/plugins/markdown
Shows a complete Web Components example: a custom element class using a CSS Modules plugin, its usage in markdown with custom content, and the resulting HTML output. The component reads a heading attribute and projects slotted content into styled containers.
```javascript
import styles from "./heading-box.module.css";
export default class HeadingBox extends HTMLElement {
connectedCallback() {
const heading = this.getAttribute("heading");
this.innerHTML = `
```
--------------------------------
### Install Lit as a peer dependency with npm
Source: https://greenwoodjs.dev/docs/plugins/lit-ssr
Required because Lit is a peerDependency of the plugin. Run this in your project to install Lit.
```bash
npm i lit
```
--------------------------------
### Install @greenwood/plugin-css-modules with npm, yarn, or pnpm
Source: https://greenwoodjs.dev/docs/plugins/css-modules
Install the plugin with your preferred package manager. The package name is @greenwood/plugin-css-modules.
```bash
npm i -D @greenwood/plugin-css-modules
```
```bash
yarn add @greenwood/plugin-css-modules --dev
```
```bash
pnpm add -D @greenwood/plugin-css-modules
```
--------------------------------
### Fetch API Route Handler Example
Source: https://greenwoodjs.dev/docs/introduction/web-standards
An API route handler example showing the use of Fetch standard's Request and Response objects. It logs the request URL and returns a Response with headers.
```javascript
// a standard request object is passed in
// and a standard response object should be returned
export async function handler(request) {
console.log("endpoint visited", request.url);
return new Response("...", {
headers: new Headers({
/* ... */
}),
});
}
```
--------------------------------
### Output CSS example
Source: https://greenwoodjs.dev/docs/plugins/postcss
Generated CSS output after PostCSS processing, showing vendor prefixes and media query adjustments.
```css
/* output */
::-moz-placeholder {
color: gray;
}
::placeholder {
color: gray;
}
.image {
background-image: url(image@1x.png);
}
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
.image {
background-image: url(image@2x.png);
}
}
```
--------------------------------
### Example app.html layout with page placeholder
Source: https://greenwoodjs.dev/docs/pages/layouts
An app layout that wraps all pages. Uses to position the processed page layout content.
```html
Welcome to My Site!
```
--------------------------------
### Example assets directory structure
Source: https://greenwoodjs.dev/docs/resources/assets
Shows the layout of an assets/ directory in a Greenwood project. Files placed here are copied as-is to the build output.
```text
src/
assets/
my-image.webp
download.pdf
```
--------------------------------
### Set basePath for sub-path deployment
Source: https://greenwoodjs.dev/docs/reference/configuration
Configure basePath when hosting from a sub-path like GitHub Pages. Example uses '/app-a'.
```javascript
export default {
basePath: "/app-a",
};
```
--------------------------------
### Add Prism syntax highlighting plugin
Source: https://greenwoodjs.dev/docs/plugins/markdown
Install @mapbox/rehype-prism and pass it as a markdown plugin in the configuration file to enable syntax highlighting.
```javascript
export default {
markdown: {
plugins: ["@mapbox/rehype-prism"],
},
};
```
--------------------------------
### Reference asset from markdown
Source: https://greenwoodjs.dev/docs/resources/assets
Markdown example referencing an image from the assets directory using a relative path.
```markdown
# This is my page

```
--------------------------------
### Frontmatter imports example
Source: https://greenwoodjs.dev/docs/content-as-data/frontmatter
Includes scripts and styles on a per-page basis using the 'imports' key. Filepaths and attributes are space-delimited.
```markdown
---
imports:
- /components/my-component/component.js type="module" foo="bar"
- /components/my-component/component.css
---
# My Demo Page
```
--------------------------------
### Example page.html layout with content placeholder
Source: https://greenwoodjs.dev/docs/pages/layouts
A basic page layout that wraps page content. Uses to position the incoming page's content.
```html
Welcome to my site!
```
--------------------------------
### Configure devServer with extensions, port, and proxy
Source: https://greenwoodjs.dev/docs/reference/configuration
Example configuration for the devServer object in greenwood.config.js. Sets custom extensions to watch, a custom port, and proxy rules with highest specificity at the end.
```javascript
export default {
devServer: {
extensions: ["txt"],
port: 3000,
proxy: {
"/api": "https://stage.myapp.com",
"/api/foo": "https://foo.otherdomain.net",
},
},
};
```
--------------------------------
### API Route File Structure
Source: https://greenwoodjs.dev/docs/pages/api-routes
Example of the file-based routing convention where the file path determines the API endpoint.
```text
src/
pages/
api/
greeting.js
```
--------------------------------
### Importing CSS from node_modules
Source: https://greenwoodjs.dev/docs/resources/styles
Examples of importing CSS files from node_modules using relative paths, the /node_modules/ alias, or bare module specifiers.
```css
/* after having installed Open Props */
/* npm i open-props */
@import "../../node_modules/open-props/borders.min.css";
@import "../../node_modules/open-props/fonts.min.css";
/* this would also work */
@import "/node_modules/open-props/borders.min.css";
@import "/node_modules/open-props/fonts.min.css";
/* or for packages that support an exports map */
@import "open-props/borders";
@import "open-props/fonts";
```
--------------------------------
### Bare Specifier Import Example
Source: https://greenwoodjs.dev/docs/resources/scripts
Shows using a bare specifier to import a package from npm in a JavaScript file. Greenwood automatically builds an import map for bare specifiers.
```javascript
// after having installed Lit
import { html, LitElement } from "lit";
class SimpleGreeting extends LitElement {
static properties = {
name: { type: String },
};
render() {
return html`
Hello, ${this.name ?? "World"}!
`;
}
}
customElements.define("simple-greeting", SimpleGreeting);
```
--------------------------------
### Implement a Resource Plugin for Custom Import Maps
Source: https://greenwoodjs.dev/docs/introduction/web-standards
This example demonstrates creating a Greenwood Resource plugin to programmatically generate and inject an import map for heroicons SVG files, enabling the use of bare specifiers.
```javascript
import { mergeImportMap } from "@greenwood/cli/src/lib/node-modules-utils.js";
import fs from "node:fs";
const NODE_MODULES_LOCATION = new URL("./node_modules/", import.meta.url);
const PACKAGE_NAME = "heroicons";
let importMap;
function generateImportMap() {
if (!importMap) {
importMap = new Map();
fs.globSync("**/**/*.svg", {
cwd: `${NODE_MODULES_LOCATION.pathname}/${PACKAGE_NAME}/`,
}).forEach((file) => {
const resolved = new URL(`./${PACKAGE_NAME}/${file}`, NODE_MODULES_LOCATION);
// add the query param for import raw plugin support
importMap.set(`${PACKAGE_NAME}/${file}?type=raw`, `/~${resolved.pathname}?type=raw`);
});
}
return Object.fromEntries(importMap);
}
class HeroiconsImportMap {
constructor(compilation) {
this.compilation = compilation;
}
async shouldIntercept(url, request) {
const { protocol, pathname } = url;
const hasMatchingPageRoute = this.compilation.graph.find((node) => node.route === pathname);
return (
process.env.__GWD_COMMAND__ === "develop" &&
protocol.startsWith("http") &&
hasMatchingPageRoute &&
request.headers.get("Accept").indexOf("text/html") >= 0
);
}
async intercept(url, request, response) {
const body = await response.text();
const newBody = mergeImportMap(body, generateImportMap());
return new Response(newBody);
}
}
// make sure to include this into your Greenwood config file
export function heroiconsImportMapPlugin() {
return {
type: "resource",
name: "heroicons-import-map-plugin",
provider: (compilation) => new HeroiconsImportMap(compilation),
};
}
```
--------------------------------
### Register Greenwood plugins
Source: https://greenwoodjs.dev/docs/reference/configuration
Register an array of plugins, either from the Greenwood team or custom ones. The example imports and uses greenwoodCssModulesPlugin.
```javascript
import { greenwoodCssModulesPlugin } from "@greenwood/plugin-css-modules";
export default {
plugins: [greenwoodCssModulesPlugin()],
};
```
--------------------------------
### Frontmatter layout example
Source: https://greenwoodjs.dev/docs/content-as-data/frontmatter
Uses the 'layout' frontmatter key to wrap the page with a specific layout. By default, Greenwood uses _src/layouts/page.html_.
```markdown
---
layout: blog
---
# My First Blog Post
This is my first blog post, I hope you like it!
```
--------------------------------
### TypeScript configuration with Config type
Source: https://greenwoodjs.dev/docs/reference/appendix
Author a Greenwood configuration file in TypeScript using the Config type imported from @greenwood/cli. The example sets the prerender option to true and exports the config as default.
```typescript
import type { Config } from "@greenwood/cli";
const config: Config = {
prerender: true,
};
export default config;
```
--------------------------------
### Show @greenwood/init CLI options
Source: https://greenwoodjs.dev/docs/introduction/setup
Displays the full list of options for the init CLI, including flags for accepting defaults, specifying a name, enabling TypeScript, and choosing a package manager.
```text
Usage: @greenwood/init [options]
Options:
-V, --version output the version number
-y, --yes Accept all default options
--name Name and directory location to scaffold your application with
--ts [choice] Optionally configure your project with TypeScript (choices: "yes", "no")
-i, --install Install dependencies with the package manager of your choice (choices: "npm", "pnpm", "yarn", "no")
-h, --help display help for command
```
--------------------------------
### Script Tags Example
Source: https://greenwoodjs.dev/docs/resources/scripts
Shows standard HTML script tags in a Greenwood page. Greenwood uses these as entry points for bundling and production processing.
```html
```
--------------------------------
### Dynamic prerendering with getStaticPaths and getStaticParams
Source: https://greenwoodjs.dev/docs/pages/server-rendering
Use this example to prerender dynamic routes as static HTML. `getStaticPaths` must return an array of objects with at least one property matching the bracket value, and `getStaticParams` can augment the params object. This generates static HTML files for each product, e.g. `/product/1/index.html`.
```javascript
import { getProducts } from '../../services/products.js'
export async function getStaticPaths() {
const products = await getProducts();
return products.map((product) => {
return {
// return as many other params as you want
params: {
id: product.id,
name: product.name,
},
};
});
}
export async function getStaticParams({ params }) {
const products = await getProducts();
const product = products.find((product) => product.id === params.id);
return { product };
}
// you also use getBody if you prefer
export default class ProductDetailsPage extends HTMLElement {
#product;
constructor({ params }) {
super();
this.#product = params.product;
}
connectedCallback() {
this.innerHTML = `
${this.#product.name}
${this.#product.description}
`;
}
}
```
--------------------------------
### Sample Project Build Output
Source: https://greenwoodjs.dev/docs/reference/appendix
The resulting structure in the public directory after a Greenwood build, including route and chunk files.
```text
public/
api/
greeting.js
nested-endpoint.js
blog-first-post.route.js
blog-first-post.chunk.[hash].js
blog-index.route.js
blog-index.route.chunk.[hash].js
index.route.js
index.route.chunk.[hash].js
```
--------------------------------
### Show Greenwood CLI help with --help flag
Source: https://greenwoodjs.dev/docs/reference/cli
Run the Greenwood CLI with the --help flag to display all available commands, options, and version information. The output shows the current version (v0.33.0) and lists the build, develop, and serve commands.
```shell
$ ./node_modules/.bin/greenwood --help
-------------------------------------------------------
Welcome to Greenwood (v0.33.0) ♻️
-------------------------------------------------------
Usage: greenwood
Options:
-h, --help Show help information
-V, --version Show version number
Commands:
build Generate a production build.
develop Start a local development server.
serve Start a production server.
```
--------------------------------
### Create a dynamic server route with a JavaScript file in _pages/_
Source: https://greenwoodjs.dev/docs/pages/server-rendering
Create a JavaScript file in the _pages/_ directory to define a dynamic server route. The file structure shown results in the route being served at the path _/users/_.
```plaintext
src/
pages/
users.js
```
--------------------------------
### Linking CSS from node_modules in HTML
Source: https://greenwoodjs.dev/docs/resources/styles
Using a tag to reference a CSS file installed via npm.
```html
```
--------------------------------
### Invoke Custom Element in HTML
Source: https://greenwoodjs.dev/docs/introduction/web-standards
Usage example of the defined x-card custom element within an HTML document.
```html
```
--------------------------------
### Frontmatter in a markdown file
Source: https://greenwoodjs.dev/docs/content-as-data/active-frontmatter
Example frontmatter block with fields like layout, title, published, description, author, and image.
```markdown
---
layout: post
title: Git Explorer
published: 04.07.2020
description: Local git repository viewer
author: Owen Buckley
image: /assets/blog-post-images/git.png
---
```
--------------------------------
### Custom frontmatter data example
Source: https://greenwoodjs.dev/docs/content-as-data/frontmatter
Defines custom frontmatter properties that become available on the 'data' property of the page object.
```markdown
---
author: Jon Doe
date: 04/07/2020
---
# First Post
My first post
```
--------------------------------
### Reference a collection in HTML with activeFrontmatter
Source: https://greenwoodjs.dev/docs/content-as-data/collections
Use activeFrontmatter to access a collection in HTML. The example passes the 'navigation' collection to a custom element.
```html
Home Page
```
--------------------------------
### Frontmatter title example
Source: https://greenwoodjs.dev/docs/content-as-data/frontmatter
Sets the page title using the 'title' frontmatter key. If not set, the title is inferred from the file name.
```markdown
---
title: My Blog Post
---
# This is a post
The is a markdown file with the title defined in frontmatter.
```
--------------------------------
### Frontmatter label example
Source: https://greenwoodjs.dev/docs/content-as-data/frontmatter
Sets a custom label for a page using the 'label' frontmatter key. The label can be used for display in links.
```markdown
---
label: "My Blog Post from 3/5/2020"
---
# My Blog Post
```
--------------------------------
### Configure markdown plugin with rehype-slug
Source: https://greenwoodjs.dev/docs/plugins/markdown
Pass remark or rehype compatible plugins as an array to the markdown plugin options. This example adds rehype-slug.
```javascript
import { greenwoodPluginMarkdown } from '@greenwood/plugin-markdown';
export default {
plugins: [
greenwoodPluginMarkdown({
// npm i -D rehype-slug
plugins: [
"rehype-slug"
],
})
]
}
```
--------------------------------
### SPA project structure
Source: https://greenwoodjs.dev/docs/pages/routing
Example project structure for a Single Page Application (SPA) in Greenwood. Place an index.html at the root of the workspace with no _pages/ directory to opt out of file-based routing. Note: SPA projects do not support layouts or (active) frontmatter.
```text
src/
components/
footer.js
header.js
routes/
products.js
home.js
styles.css
index.js
index.html
```
--------------------------------
### Default greenwood.config.js configuration
Source: https://greenwoodjs.dev/docs/reference/configuration
Shows the default values for all Greenwood configuration options. Use as a starting point for customizing your project's configuration.
```javascript
/** @type {import('@greenwood/cli').Config} */
export default {
activeContent: false,
basePath: "",
devServer: {
extensions: [],
hud: true,
port: 1984,
host: "localhost",
},
isolation: false,
layoutsDirectory: "layouts", // e.g. ./src/layouts
optimization: "default",
pagesDirectory: "pages", // e.g. ./src/pages
plugins: [],
polyfills: {
importAttributes: null, // e.g. ['css', 'json']
importMaps: false,
},
port: 8080,
prerender: false,
staticRouter: false,
useTsc: false,
workspace: new URL("./src/", import.meta.url),
};
```
--------------------------------
### Import Prism theme CSS
Source: https://greenwoodjs.dev/docs/plugins/markdown
Include a Prism theme from a CSS file in your project to style highlighted code.
```css
@import url("../node_modules/prismjs/themes/prism-tomorrow.css");
```
--------------------------------
### Generated script tag with basePath
Source: https://greenwoodjs.dev/docs/reference/configuration
Greenwood automatically prefixes script and link tags with the basePath. This example shows a script tag referencing '/app-a/some-script.a243dccss.js'.
```html
```
--------------------------------
### Resolve Lifecycle Example
Source: https://greenwoodjs.dev/docs/reference/plugins-api
Implements the resolve lifecycle for a resource plugin that serves files from the user workspace. The shouldResolve method checks for a file extension, excludes node_modules, and verifies the file exists; the resolve method returns a new Request pointing to the workspace file. Use this when you need to resolve resources that are not in the default locations.
```javascript
import fs from "node:fs";
class UserWorkspaceResource {
async shouldResolve(url) {
const { pathname } = url;
const { userWorkspace } = this.compilation.context;
const hasExtension = !["", "/"].includes(pathname.split(".").pop());
return (
hasExtension &&
!pathname.startsWith("/node_modules") &&
fs.existsSync(new URL(`.${pathname}`, userWorkspace).pathname)
);
}
async resolve(url) {
const { pathname } = url;
const { userWorkspace } = this.compilation.context;
const workspaceUrl = new URL(`.${pathname}`, userWorkspace);
return new Request(workspaceUrl);
}
}
export function myWorkspaceResourcePlugin(options = {}) {
return {
type: "resource",
name: "my-workspace-resource-plugin",
provider: (compilation) => new UserWorkspaceResource(compilation, options),
};
}
```
--------------------------------
### Configure markdown plugin with rehype-autolink-headings and options
Source: https://greenwoodjs.dev/docs/plugins/markdown
Use object syntax to pass options to a markdown plugin. This example configures rehype-autolink-headings with behavior 'append'.
```javascript
import { greenwoodPluginMarkdown } from '@greenwood/plugin-markdown';
export default {
plugins: [
greenwoodPluginMarkdown({
plugins: [
"rehype-slug",
{
name: "rehype-autolink-headings",
options: {
behavior: "append"
},
},
],
})
]
}
```
--------------------------------
### Dynamic routing with [slug].js
Source: https://greenwoodjs.dev/docs/pages/server-rendering
Use this page component to serve all routes matching `/blog//`. The `params` object from the constructor provides the `slug` value, which is used to fetch and render the post content.
```javascript
import { getPostBySlug } from '../../services/posts.js';
export default class BlogPostPage extends HTMLElement {
#slug;
constructor({ params }) {
super();
this.#slug = params.slug;
}
async connectedCallback() {
const post = await getPostBySlug(this.#slug);
this.innerHTML = `
${post.title}
${post.content}
`;
}
}
```
--------------------------------
### Standard CSS Usage in HTML
Source: https://greenwoodjs.dev/docs/resources/styles
Demonstrates using