-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a09b85a
commit e443451
Showing
6 changed files
with
297 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
--- | ||
layout: docs | ||
order: 1 | ||
tocHeading: 2 | ||
--- | ||
|
||
# About | ||
|
||
Greenwood's goal is to bring the power of modern development to the web we all know and love. For those who still want the option to just start with an HTML file, Greenwood aims to be a faithful and authentic gateway to the web platform and web friendly JavaScript runtimes. It's why we consider Greenwood your _**workbench**_ for the web, and not a framework per se; we don't mind going vanilla. 🍦 | ||
|
||
> Whether you are building a blog or a single page application, a hobby project or passion project, we encourage you to give Greenwood a try! | ||
## Features | ||
|
||
Some of Greenwood's feature include: | ||
|
||
- Unbundled local development flow, with `E-Tags` 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) | ||
- API Routes | ||
- Automatic code splitting through user defined `<script>` and `<link>` tags | ||
- Self-host, or deploy to your favorite hosting platform | ||
- Build with friends like Lit, Tailwind, and more! | ||
- Hybrid rendering strategies (CSR, SSR, SSG, or mix and match!) | ||
- Extensible through plugins | ||
|
||
Greenwood aims to be a low point of friction as part of a general purpose web development workflow, and will strive to find a good balance between what tools and dependencies are considered core to Greenwood. We hope to avoid the common "meta" framework paradigm and instead want to hone in on a lean and efficient core with good extension points and output adaptability. | ||
|
||
## Goals | ||
|
||
First and foremost, Greenwood recognizes that too much magic and trust in _node_modules_ can be both a blessing and a curse, and Greenwood wants to help you walk that line a little more safely. If there is a web standard, you can be assured it's supported by Greenwood out of the box, if not turned into an entire API! We want Greenwood to be a project that everyone can use without pre-existing knowledge of libraries and frameworks. Start with an _index.html_ and work your way up to a completely server rendered application if you need! | ||
|
||
As the web grows and evolves, so will Greenwood. We are active collaborators in the [WCCG (Web Components Community Group)](https://github.com/w3c/webcomponents-cg) and participant in initiatives like the [Interop Project](https://github.com/web-platform-tests/interop) and [TPAC](https://www.w3.org/news-events/w3c-tpac/). | ||
|
||
If we did our job well, the only docs you should need are [MDN](https://developer.mozilla.org/). | ||
|
||
## Roadmap | ||
|
||
The Greenwood team are working hard towards a [1.0 release](https://github.com/ProjectEvergreen/greenwood/milestone/3) and are eager to get there quickly and provide a stable foundation to expand Greenwood's features and capabilities. We want to make sure Greenwood is the best experience it can be, for users and developers. If you have [any issues](https://github.com/ProjectEvergreen/greenwood/issues) or are curious to see what we're [working on next](https://github.com/ProjectEvergreen/greenwood/projects), please feel free to checkout our [GitHub repo](https://github.com/ProjectEvergreen/greenwood) and poke around. | ||
|
||
We are also [on Discord](https://discord.gg/bsy9jvWh), so feel free to join us there to chat. 👋 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,57 @@ | ||
--- | ||
layout: docs | ||
order: 3 | ||
order: 2 | ||
tocHeading: 2 | ||
--- | ||
|
||
# Setup | ||
|
||
Greenwood has a few options for getting a new project started. You can also check out our [_Getting Started_ guide](/guides/getting-started/) for a full walk-through of creating a simple blog site with Greenwood. | ||
|
||
## 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. | ||
|
||
To scaffold into the _current_ directory, run: | ||
|
||
```shell | ||
$ npx @greenwood/init@latest | ||
``` | ||
|
||
To scaffold into a _custom_ directory, run: | ||
|
||
```shell | ||
# initialize a new directory called my-app for your Greenwood project | ||
$ npx @greenwood/init@latest my-app | ||
``` | ||
|
||
## Install | ||
|
||
You can install the Greenwood CLI manually through your preferred package manager: | ||
|
||
```shell | ||
# npm | ||
$ npm i -D @greenwood/cli@latest | ||
|
||
# yarn | ||
$ yarn add @greenwood/cli@latest --save-dev | ||
``` | ||
|
||
## Commands | ||
|
||
The CLI supports three commands, that can be easily mapped to npm scripts in your _package.json_. You'll also want to make sure you've set the `type` field to **module**: | ||
|
||
- **develop** - Start Greenwood's local development server | ||
- **build** - Build a Greenwood project for production | ||
- **serve** - Start a production server for self-hosting a Greenwood build | ||
|
||
```json | ||
{ | ||
"type": "module", | ||
"scripts": { | ||
"dev": "greenwood develop", | ||
"build": "greenwood build", | ||
"serve": "greenwood serve" | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,201 @@ | ||
--- | ||
layout: docs | ||
order: 2 | ||
order: 3 | ||
tocHeading: 2 | ||
--- | ||
|
||
# Web Standards | ||
|
||
Throughout our docs we make heavy use and reference to some of the following Web APIs, either indirectly or as part of the core surface area of Greenwood itself. | ||
|
||
## Import Attributes | ||
|
||
Building upon ECMAScript Modules, Greenwood supports [Import Attributes](https://github.com/tc39/proposal-import-attributes) on the client and on [the server](/docs/pages/server-rendering/#custom-imports) seamlessly, supporting both CSS and JSON module out of the box. | ||
|
||
```js | ||
// returns a Constructable StyleSheet | ||
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/CSSStyleSheet | ||
import sheet from "./styles.css" with { type: "css" }; | ||
|
||
console.log({ sheet }); | ||
``` | ||
|
||
```js | ||
// returns an object | ||
import data from "./data.json" with { type: "json" }; | ||
|
||
console.log({ data }); | ||
``` | ||
|
||
> ⚠️ _Although Import Attributes are not baseline yet, Greenwood supports polyfilling them with a [configuration flag](/docs/reference.configuration/#polyfills)._ | ||
## Web Components | ||
|
||
Web Components are a collection of standard Web APIs that can be mixed and matched to create your own encapsulated styles and behaviors: | ||
|
||
- [**Custom Elements**](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements) - Define your own custom HTML tags | ||
- [**Shadow DOM**](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) - Encapsulation mechanism for custom elements | ||
- [**<template>** tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) - Commonly used for initializing the HTML contents of a Shadow Root | ||
|
||
A simple example putting it all together might look like this: | ||
|
||
```js | ||
import sheet from "./card.css" with { type: "css" }; | ||
|
||
const template = document.createElement("template"); | ||
|
||
export default class Card extends HTMLElement { | ||
connectedCallback() { | ||
if (!this.shadowRoot) { | ||
const thumbnail = this.getAttribute("thumbnail"); | ||
const title = this.getAttribute("title"); | ||
|
||
template.innerHTML = ` | ||
<div class="card"> | ||
<h3>${title}</h3> | ||
<img src="${thumbnail}" alt="${title}" loading="lazy" width="100%"> | ||
</div> | ||
`; | ||
|
||
this.attachShadow({ mode: "open" }); | ||
this.shadowRoot.appendChild(template.content.cloneNode(true)); | ||
} | ||
|
||
this.shadowRoot.adoptedStyleSheets = [sheet]; | ||
} | ||
} | ||
|
||
customElements.define("x-card", Card); | ||
``` | ||
|
||
> 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 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 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). | ||
|
||
This suite of APIs is featured prominently in our API Route handlers: | ||
|
||
```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 body = { message: `Hello ${name}! 👋` }; | ||
|
||
return new Response(JSON.stringify(body), { | ||
headers: new Headers({ | ||
"Content-Type": "application/json", | ||
}), | ||
}); | ||
} | ||
``` | ||
|
||
## 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 with 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 `<head>` of your HTML. | ||
|
||
This is a sample of an import map that would be generated after having installed the **lit** package: | ||
|
||
```html | ||
<html> | ||
<head> | ||
<script type="importmap"> | ||
{ | ||
"imports": { | ||
"lit": "/node_modules/lit/index.js", | ||
"lit-html": "/node_modules/lit-html/lit-html.js", | ||
"lit-element": "/node_modules/lit-element/index.js", | ||
"...": "..." | ||
} | ||
} | ||
</script> | ||
</head> | ||
<body> | ||
<!-- ... --> | ||
</body> | ||
</html> | ||
``` | ||
|
||
## URL | ||
|
||
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, 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: | ||
|
||
```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"; | ||
|
||
console.log({ name }); | ||
|
||
// ... | ||
} | ||
``` | ||
|
||
## FormData | ||
|
||
[`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) is a great example of a Web API that works great both on the client and the server. | ||
|
||
In the browser, it can be used to easily gather the inputs of a `<form>` tag for communicating with a backend API: | ||
|
||
```html | ||
<html> | ||
<head> | ||
<script> | ||
window.addEventListener("DOMContentLoaded", () => { | ||
window.document.querySelector("form").addEventListener("submit", async (e) => { | ||
e.preventDefault(); | ||
// with FormData we can pass the whole <form> to the constructor | ||
// and send a URL Encoded request to the API backend | ||
const formData = new FormData(e.currentTarget); | ||
const term = formData.get("term"); | ||
const response = await fetch("/api/search", { | ||
method: "POST", | ||
body: new URLSearchParams({ term }).toString(), | ||
headers: new Headers({ | ||
"content-type": "application/x-www-form-urlencoded", | ||
}), | ||
}); | ||
// ... | ||
}); | ||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<h1>Search Page</h1> | ||
|
||
<form> | ||
<label for="term"> | ||
<input type="search" name="term" placeholder="a product..." required /> | ||
</label> | ||
<button type="submit">Search</button> | ||
</form> | ||
</body> | ||
</html> | ||
``` | ||
|
||
On the server, we can use the same API to collect the inputs from that form request: | ||
|
||
<!-- eslint-disable no-unused-vars --> | ||
|
||
```js | ||
// src/pages/api/search.js | ||
// we pull in WCC here to generate HTML fragments for us | ||
import { getProductsBySearchTerm } from "../../db/client.js"; | ||
|
||
export async function handler(request) { | ||
// use the web standard FormData to get the incoming form submission | ||
const formData = await request.formData(); | ||
const term = formData.has("term") ? formData.get("term") : ""; | ||
const products = await getProductsBySearchTerm(term); | ||
|
||
// ... | ||
} | ||
``` | ||
|
||
<!-- eslint-enable --> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters