You can hover/tap source code tokens, like in your local code editor, to get more insights.📄 /src/document.tsimport { htmlfunction html(strings: TemplateStringsArray, ...values: unknown[]): ServerRenderedTemplate
A lit-html template that can only be rendered on the server, and cannot be
hydrated.
These templates can be used for rendering full documents, including the
doctype, and rendering into elements that Lit normally cannot, like
<title>, <textarea>, <template>, and non-executing <script> tags
like <script type="text/json">. They are also slightly more efficient than
normal Lit templates, because the generated HTML doesn't need to include
markers for updating.
Server-only html templates can be composed, and combined, and they support
almost all features that normal Lit templates do, with the exception of
features that don't have a pure HTML representation, like event handlers or
property bindings.
Server-only html templates can only be rendered on the server, they will
throw an Error if created in the browser. However if you render a normal Lit
template inside a server-only template, then it can be hydrated and updated.
Likewise, if you place a custom element inside a server-only template, it can
be hydrated and update like normal.
A server-only template can't be rendered inside a normal Lit template.
} from '@gracile/gracile/server-html';export constdocument
A lit-html template that can only be rendered on the server, and cannot be
hydrated.
These templates can be used for rendering full documents, including the
doctype, and rendering into elements that Lit normally cannot, like
<title>, <textarea>, <template>, and non-executing <script> tags
like <script type="text/json">. They are also slightly more efficient than
normal Lit templates, because the generated HTML doesn't need to include
markers for updating.
Server-only html templates can be composed, and combined, and they support
almost all features that normal Lit templates do, with the exception of
features that don't have a pure HTML representation, like event handlers or
property bindings.
Server-only html templates can only be rendered on the server, they will
throw an Error if created in the browser. However if you render a normal Lit
template inside a server-only template, then it can be hydrated and updated.
Likewise, if you place a custom element inside a server-only template, it can
be hydrated and update like normal.
A server-only template can't be rendered inside a normal Lit template.
` <!doctype html> <html lang="en"> <head> Global assets <link rel="stylesheet" href="/src/styles/global.scss" /> <script type="module" src="/src/document.client.ts"></script> SEO <title>${props
Defines a file-based route for Gracile to consume.
Important: Property order matters for type inference.handler (or staticPaths) must be declared beforedocument and
template in the options object. TypeScript resolves generic type
parameters from object properties in declaration order — the handler's
return type feeds into RouteContext.props, which is then used to type
the context parameter of document and template.
If document/template appear first, props will be inferred as
undefined.
The html tag returns a description of the DOM to render as a value. It is
lazy, meaning no work is done until the template is rendered. When rendering,
if a template comes from the same expression as a previously rendered result,
it's efficiently updated instead of replaced.
} from '../document.js';importhomeReadmeconst homeReadme: MarkdownModulefrom '../content/README.md';import type { MyElementclass MyElement } from '../features/my-element.ts';import '../features/my-element.js';export defaultdefineRoute
Defines a file-based route for Gracile to consume.
Important: Property order matters for type inference.handler (or staticPaths) must be declared beforedocument and
template in the options object. TypeScript resolves generic type
parameters from object properties in declaration order — the handler's
return type feeds into RouteContext.props, which is then used to type
the context parameter of document and template.
If document/template appear first, props will be inferred as
undefined.
A function or an object containing functions named after HTTP methods.
A handler can return either a standard Response that will terminate the
request pipeline, or any object to populate the current route template
and document contexts.
Must be declared before document and template so TypeScript can
infer RouteContext.props from the handler's return type.
The html tag returns a description of the DOM to render as a value. It is
lazy, meaning no work is done until the template is rendered. When rendering,
if a template comes from the same expression as a previously rendered result,
it's efficiently updated instead of replaced.
Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
@paramvalue A JavaScript value, usually an object or array, to be converted.@paramreplacer A function that transforms the results.@paramspace Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.@throws{TypeError} If a circular reference or a BigInt value is found.
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
The html tag returns a description of the DOM to render as a value. It is
lazy, meaning no work is done until the template is rendered. When rendering,
if a template comes from the same expression as a previously rendered result,
it's efficiently updated instead of replaced.
}</small> </footer> `; },});📄 /src/routes/index.client.ts Importing your components in this page's client bundle entrypoint will make the server markup alive.requestIdleCallbackfunction requestIdleCallback(callback: IdleRequestCallback, options?: IdleRequestOptions): number
The window.requestIdleCallback() method queues a function to be called during a browser's idle periods.
(() => import('../features/my-element.js'));// ... Don't import on server-side, if you want a client-only element.import '../features/my-client-only-element.js';consolevar console: Console.logConsole.log(...data: any[]): void
The console.log() static method outputs a message to the console.
The Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
Base element class that manages element properties and attributes, and
renders a lit-html template.
To define a component, subclass LitElement and implement a
render method to provide the component's template. Define properties
using the
{@linkcode
LitElement.properties
properties
}
property or the
A template literal tag which can be used with LitElement's
{@linkcode
LitElement.styles
}
property to set element styles.
For security reasons, only literal string values and number may be used in
embedded expressions. To incorporate non-literal values
{@linkcode
unsafeCSS
}
The html tag returns a description of the DOM to render as a value. It is
lazy, meaning no work is done until the template is rendered. When rendering,
if a template comes from the same expression as a previously rendered result,
it's efficiently updated instead of replaced.
} from 'lit';import { customElementconst customElement: (tagName: string) => CustomElementDecorator
Class decorator factory that defines the decorated class as a custom element.
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html``;
}
}
```@categoryDecorator@paramtagName The tag name of the custom element to define.
A class field or accessor decorator which creates a reactive property that
reflects a corresponding attribute value. When a decorated property is set
the element will update and render. A
{@linkcode
PropertyDeclaration
}
may
optionally be supplied to configure property features.
This decorator should only be used for public fields. As public fields,
properties should be considered as primarily settable by element users,
either via attribute or the property itself.
Generally, properties that are changed by the element should be private or
protected fields and should use the
{@linkcode
state
}
decorator.
However, sometimes element code does need to set a public property. This
should typically only be done in response to user interaction, and an event
should be fired informing the user; for example, a checkbox sets its
checked property when clicked and fires a changed event. Mutating public
properties should typically not be done for non-primitive (object or array)
properties. In other cases when an element needs to manage state, a private
property decorated via the
{@linkcode
state
}
decorator should be used. When
needed, state properties can be initialized via public properties to
facilitate complex interactions.
A directive that applies CSS properties to an element.
styleMap can only be used in the style attribute and must be the only
expression in the attribute. It takes the property names in the
{@link
StyleInfo
styleInfo
}
object and adds the properties to the inline
style of the element.
Property names with dashes (-) are assumed to be valid CSS
property names and set on the element's style object using setProperty().
Names without dashes are assumed to be camelCased JavaScript property names
and set on the element's style object using property assignment, allowing the
style object to translate JavaScript-style names to CSS property names.
For example styleMap({backgroundColor: 'red', 'border-top': '5px', '--size': '0'}) sets the background-color, border-top and --size properties.
@paramstyleInfo@see{@link https://lit.dev/docs/templates/directives/#stylemap styleMap code samples on Lit.dev}
} from 'lit/directives/style-map.js';@customElementfunction customElement(tagName: string): CustomElementDecorator
Class decorator factory that defines the decorated class as a custom element.
@customElement('my-element')
class MyElement extends LitElement {
render() {
return html``;
}
}
```@categoryDecorator@paramtagName The tag name of the custom element to define.
Base element class that manages element properties and attributes, and
renders a lit-html template.
To define a component, subclass LitElement and implement a
render method to provide the component's template. Define properties
using the
{@linkcode
LitElement.properties
properties
}
property or the
A class field or accessor decorator which creates a reactive property that
reflects a corresponding attribute value. When a decorated property is set
the element will update and render. A
{@linkcode
PropertyDeclaration
}
may
optionally be supplied to configure property features.
This decorator should only be used for public fields. As public fields,
properties should be considered as primarily settable by element users,
either via attribute or the property itself.
Generally, properties that are changed by the element should be private or
protected fields and should use the
{@linkcode
state
}
decorator.
However, sometimes element code does need to set a public property. This
should typically only be done in response to user interaction, and an event
should be fired informing the user; for example, a checkbox sets its
checked property when clicked and fires a changed event. Mutating public
properties should typically not be done for non-primitive (object or array)
properties. In other cases when an element needs to manage state, a private
property decorated via the
{@linkcode
state
}
decorator should be used. When
needed, state properties can be initialized via public properties to
facilitate complex interactions.
A class field or accessor decorator which creates a reactive property that
reflects a corresponding attribute value. When a decorated property is set
the element will update and render. A
{@linkcode
PropertyDeclaration
}
may
optionally be supplied to configure property features.
This decorator should only be used for public fields. As public fields,
properties should be considered as primarily settable by element users,
either via attribute or the property itself.
Generally, properties that are changed by the element should be private or
protected fields and should use the
{@linkcode
state
}
decorator.
However, sometimes element code does need to set a public property. This
should typically only be done in response to user interaction, and an event
should be fired informing the user; for example, a checkbox sets its
checked property when clicked and fires a changed event. Mutating public
properties should typically not be done for non-primitive (object or array)
properties. In other cases when an element needs to manage state, a private
property decorated via the
{@linkcode
state
}
decorator should be used. When
needed, state properties can be initialized via public properties to
facilitate complex interactions.
Invoked on each update to perform rendering tasks. This method may return
any value renderable by lit-html's ChildPart - typically a
TemplateResult. Setting properties inside this method will not trigger
the element to update.
The html tag returns a description of the DOM to render as a value. It is
lazy, meaning no work is done until the template is rendered. When rendering,
if a template comes from the same expression as a previously rendered result,
it's efficiently updated instead of replaced.
` <div @click=${() => (this.bgTintMyElement.bgTint: number=Mathvar Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
A directive that applies CSS properties to an element.
styleMap can only be used in the style attribute and must be the only
expression in the attribute. It takes the property names in the
{@link
StyleInfo
styleInfo
}
object and adds the properties to the inline
style of the element.
Property names with dashes (-) are assumed to be valid CSS
property names and set on the element's style object using setProperty().
Names without dashes are assumed to be camelCased JavaScript property names
and set on the element's style object using property assignment, allowing the
style object to translate JavaScript-style names to CSS property names.
For example styleMap({backgroundColor: 'red', 'border-top': '5px', '--size': '0'}) sets the background-color, border-top and --size properties.
@paramstyleInfo@see{@link https://lit.dev/docs/templates/directives/#stylemap styleMap code samples on Lit.dev}
({ '--bg-tint': this.bgTintMyElement.bgTint: number })} > ${this.initialData
Array of styles to apply to the element. The styles should be defined
using the
{@linkcode
css
}
tag function, via constructible stylesheets, or
imported from native CSS module scripts.
Note on Content Security Policy:
Element styles are implemented with <style> tags when the browser doesn't
support adopted StyleSheets. To use such <style> tags with the style-src
CSP directive, the style-src value must either include 'unsafe-inline' or
nonce-<base64-value> with <base64-value> replaced be a server-generated
nonce.
To provide a nonce to use on generated <style> elements, set
window.litNonce to a server-generated nonce in your page's HTML, before
loading application code:
<script>
// Generated and unique per request:
window.litNonce = 'a1b2c3d4';
</script>
A template literal tag which can be used with LitElement's
{@linkcode
LitElement.styles
}
property to set element styles.
For security reasons, only literal string values and number may be used in
embedded expressions. To incorporate non-literal values
{@linkcode
unsafeCSS
}
Write the same markup, styling and scripting languages for both server and
client side.
The ones that you already know and use everywhere else: HTML, CSS and
JavaScript.
Simplicity doesn’t mean obfuscation. You’re still in charge without abandoning
flexibility to your framework.
Standards oriented
Built with a platform-minded philosophy. Every time a standard can be leveraged
for a task, it should be.
It also means fewer vendor-specific idioms to churn on and a more portable
codebase overall.
Stop re-implementing the wheel, and embrace future-proof APIs, you’ll thank
yourself later!
Developer experience
The DX bar has been constantly raised, alongside developers’ expectations about
their everyday tooling.
The “Vanilla” community is full of gems, in a scattered way.
Gracile provides an integrated, out-of-the-box experience while keeping
non-core opinions as opt-ins.
Convention over configuration
Finding the right balance between convenience and freedom is tricky.
Hopefully, more and more patterns will be established in the full-stack JS
space.
Gracile is inspired by those widespread practices that will make you feel at
home.
Light and unobtrusive
All in all, the Gracile framework is just Vite, Lit SSR and a very restricted
set of helpers and third parties.
Check its
dependency tree on npmgraph,
you’ll see by yourself.
Also, everything is done to keep your Vite configuration as pristine as
possible. Augmenting an existing project can be done in a pinch, with no
interference.
Performances
Speed is not the main goal for Gracile, that’s because it is just the sane
default you’ll start with.
Avoiding complex template transformations, or surgically shipping client-side JS
are just a few facets of what makes Gracile a “do more with less” power tool.