collection | title | label | order | tocHeading |
---|---|---|---|---|
docs |
Styles and Assets |
Styles and Assets |
6 |
3 |
Greenwood generally does not have any opinion on how you structure your site, aside from the pre-determined pages/ and (optional) layouts/ directories. It supports all standard files that you can open in a web browser.
Styles can be done in any standards compliant way that will work in a browser. So just as in HTML, you can do anything you need like below:
<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">
<head>
<style>
html {
background-color: white;
}
body {
font-family: 'Source Sans Pro', sans-serif;
background-image: url('../images/background.webp');
line-height: 1.4;
}
</style>
<link rel="stylesheet" href="/styles/theme.css"/>
</head>
<body>
<!-- content goes here -->
</body>
</html>
In the above example, Greenwood will also bundle any
url
references in your CSS automatically as well as inline any usages of@import
in your CSS files.
Import Attributes with Constructable Stylesheets and adoptedStyleSheets
are of course supported. This can allow you to share styles across both Light and Shadow DOM boundaries.
import themeSheet from '../styles/theme.css' with { type: 'css' };
import cardSheet from './card.css' with { type: 'css' }
export default class Card extends HTMLElement {
connectedCallback() {
if (!this.shadowRoot) {
const name = this.getAttribute('name') || 'World';
const template = document.createElement('template');
template.innerHTML = `
<div class="card">
<h2>Hello, ${name}!</h2>
</div>
`;
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
this.shadowRoot.adoptedStyleSheets = [themeSheet, cardSheet];
}
}
customElements.define('x-card', Card);
⚠️ Although Import Attributes are not baseline yet, Greenwood supports polyfilling them with a configuration flag.
For convenience, Greenwood does support an "assets" directory wherein anything included in that directory will automatically be copied into the build output directory. This can be useful if you have files you want available as part of your build output that are not bundled through CSS or JavaScript as generally anything that is not referenced through an import
, @import
, <script>
, <style>
or <link>
will not automatically be handled by Greenwood no matter where it is located in your workspace.
To use an image in a markdown file (which would not be automatically bundled), you would reference it as so using standard markdown syntax:
# This is my page
![my-image](/assets/images/my-image.webp)
You can do the same in your HTML
<header>
<h1>Welcome to My Site!</h1>
<a href="/assets/download.pdf">Download our product catalog</a>
</header>
In your JavaScript, you can also use a combination of new URL
and import.meta.url
which means you can put the file anywhere in your project, not just the assets/ directory and it will be resolved automatically! For production builds, Greenwood will generate a unique filename for the asset as well, e.g. logo-83bc009f.svg.
We are looking to improve the developer experience around using
new URL
+import.meta.url
as part of an overall isomorphic asset bundling strategy. You can visit this GitHub issue to follow along.
const logo = new URL('../images/logo.svg', import.meta.url);
class HeaderComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<header>
<h1>Welcome to My Site!</h1>
<!-- handles nested routes / deeplinking, e.g. https://www.mysite.com/some/page/ -->
<img src="${logo.pathname.replace(window.location.pathname, '/')}" alt="Greenwood logo"/>
</header>
`;
}
}
customElements.define('x-header', HeaderComponent);
If you like an all-the-things-in-JS approach, Greenwood can be extended with plugins to support "webpack" like behavior as seen in the below example for CSS:
import styles from './header.css'; const logo = new URL('../images/logo.svg', import.meta.url); class HeaderComponent extends HTMLElement { connectedCallback() { this.innerHTML = ` <style> ${styles} <style> <header> <h1>Welcome to My Site!</h1> <img src="${logo.pathname.replace(window.location.pathname, '/')}" alt="Greenwood logo"/> </header> `; } } customElements.define('x-header', HeaderComponent);
By default, Greenwood will automatically detect these "meta" files from the top-level of your workspace directory and automatically copy them over to the root of the build output directory.
- favicon.ico
- robots.txt
- sitemap.xml
Example:
src/
favicon.ico
robots.txt
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.