There are three types of components in Temple: Document,
Template, and Component. Each type of component has a
different strategy for rendering and updating the DOM. The
Document component is the root component of the application
and is responsible for rendering the entire application. The
Template component is a reusable component that can be used
in multiple places in the application. The Component component
is a custom component that can be used to create complex UI
elements.
Document
A document denoted by files with the
.dtml extension, is the root of
each page view that should include the document markup
starting with <html>. While
it looks like another Temple component, there are some key
differences in how it is used.
A document logic (<script>)
is executed on the client side but is not a
TempleComponent, which means
it cannot be re-rendered and does not have access to
this context.
A document props() are the
server props passed down to the client.
A document does not have access to NodeJS functionality. So
things like fs are not available.
Recommendation: You should do server related
logic on the server framework and pass the neccesary data
to the client.
src/index.ts
src/page.dtml
src
index.ts
page.dtml
import http from 'http';
import temple from '@ossph/temple/compiler';
const compiler = temple({ cwd: __dirname });
const server = http.createServer(async (req, res) => {
//pass server props to document
res.end(await compiler.render('./index.dtml', {
title: 'Hello World'
}));
});
<script>
import { props } from '@ossph/temple';
//from the server
const { title } = props();
</script>
<html>
<body>
<h1 class="title">{title}</h1>
</body>
</html>
Template
A template is resuable partial markup that can be imported by
a component, document or another template. A template is
not is not a TempleComponent, but
rather adds its markup to the parent component's final markup.
You will not see a template in the DOM, but rather the
markup it contains.
For example, consider a document that contains the following
markup.
<script>
const title = 'Hello World';
</script>
<html>
<head>
<meta charset="utf-8" />
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
</body>
</html>
You can create a template for the head of your
document and then import it. This allows you to
reuse the head markup in multiple documents.
src/page.dtml
src/head.tml
src
page.dtml
head.tml
<link rel="import" type="template" href="./head.tml" name="html-head" />
<script>
const title = 'Hello World';
</script>
<html>
<html-head />
<body>
<h1>{title}</h1>
</body>
</html>
<head>
<meta charset="utf-8" />
<title>{title}</title>
</head>
Note: Template partials do not process
attributes or children if given.
Variables used in a template should be declared in the
parent component or document. This allows you to pass
data to the template from the parent.
Component
All temple components are
TempleComponent that extends
HTMLElement and therefore is
both a web component and element just like any other element
in the browser DOM. Components that do not use the
<style> tag are affected by
the global styles of the application. Components with the
<style> tag enable the
component's shadow DOM and will encapsulate the styles within
the component and not be affected by global styles. With that
said, there are several strategies that can be applied to
Temple components.
Strategy 1: No Components
This strategy uses only documents and templates. This
strategy is useful for simple applications that do not require
complex UI elements. This is the best strategy for
performant applications.
This strategy uses components that do not have a
<style> tag and is useful for
applications that require complex logic in components but
using a shared global stylesheet.
This strategy uses components that do not have a
<style> tag,
but imports style via the
<link> tag to utilize both
global styles and specific styles that are needed for the
component.
This strategy uses components that have a
<style> tag and encapsulates
the styles within the component. This strategy is useful for
applications that require complex UI elements that need to be
styled in a specific way. This is also useful for components
that are designed to be used in multiple projects.
Web Components (custom elements) are 100% defined in
JavaScript. That includes their HTML and CSS. Those are
programmatically added to the DOM through APIs. By the time
the browser has interpreted and executed that code, there is
a good chance that the rendering pipeline has already put the
custom element on the screen. Since the browser doesn't know
about the element the first time around it will render it
without the intended styling. After the JavaScript of the
custom element definition is executed and the browser,
therefore, knows about the CSS rules that apply to that
element it can update the view.
A flash of unstyled content (FOUC) can cause irritating layout
shifts as well as reveal content that should have been
progressively disclosed. In order to prevent a reflow of other
content you can add the following general solution to your
global stylesheet.
*:not(:defined) {
opacity: 0;
}
This style will apply to all elements that are not defined,
which are usually web components and will hide the content
until the browser has fully rendered the component.