Getting Started with Elder.js

You have the starter template of Elder.js running. So what is next? This guide will help you explore the project.

How to Build a Blog With Elder.js

Building a simple blog with Elder.js is easy. Just toss a few markdown files in a folder of this project!

Is Elder.js Right For You?

What types of sites can you build with Elder.js? Can I use it for ______? Find out here.

About This Template

This example project is made up of 5 routes; you can find them by looking within the ./src/routes/ folder. They are:

The goal in showing off these 3 routes is to give you enough of an example to see how a site is built with Elder.js (but one that isn't too complex to overwhelm you).

Development Environment:

If you ran npm start to see this page this is the same as npm run dev which will:

  1. Spawn a dev server on the port defined in your .env. (Pro-tip: add .env to your .gitignore now)
  2. It will reload that dev server when changes are detected including rebundling your Svelte templates.

Other NPM commands

  1. npm run build: will statically generate this same site so that it can be deployed with a static site host such as Netlify, Cloudflare Pages, Vercel, or S3.
  2. npm run serve: will start the server in production SSR mode which can be used with cluster mode or PM2 to host Elder.js in a SSR fashion.

Partial Hydration:

Svelte.js shines at bringing interactivity to otherwise static websites.

By default, Elder.js statically renders Svelte components, only mounting them in the browser when it encounters a Svelte component which includes the hydrate-client={} prop.

This means that if a page doesn't need dynamic JS it will have 0KB of JS code resulting in faster loading, lighter weight websites.

The clock on this page is an example of a component that has been hydrated on the client.

This approach makes it easy to build SEO friendly websites, with Svelte for interactivity when needed.

By default all hydrated components are lazy loaded with an intersection observer, but you can have full control over how hydration is handled via several different hydration options.

The Elder.js Hook Interface

Once you've digested the guides above and understand how to handle client hydration, we encourage you to explore the hook interface below.

Hooks are the primary way to customize Elder.js and the list below outlines exactly what each hook can be used for.

Elder.js hook Lifecycle v1.3
1.
customizeHooks : Used to modify what hooks can mutate which properties all hooks.

This hook receives the hookInterface.ts file which defines all hook interactions. You can customize all 'props' and 'mutable' of all hooks by using this hook. This is a power user hook and unless you know Elder.js internals don't mess with it.

Props :
perf
hookInterface
errors
Mutable :
hookInterface
errors
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Elder.ts
2.
bootstrap : Routes, plugins, and hooks have been collected and validated.
  • Often used to populate the empty query object with a database or API connection as query is passed to the all() function which is used to generate request objects.
  • Internally used to automatically populate the helpers object with the helpers found in './src/helpers/index.js'.
  • Can be used to set information on the data object that is needed throughout the entire lifecycle. (sitewide settings)
Props :
perf
helpers
data
settings
routes
hooks
query
errors
Mutable :
errors
helpers
data
settings
query
Stable · Location: Elder.ts
3.
allRequests : allRequests which represents all of the request objects have been collected from route and plugins. This makes the 'allRequests' array mutable.

The main use here is to allow users to adjust the requests that Elder.js is aware of.

  • This could be used for incremental builds. By filtering and overwriting the allRequests array building just a single route or even a single request is doable.
  • This hook is used by elderjs-plugin-random to register temporary requests that it later intercepts to redirect to a random page of a route.
  • This hook is used by elderjs-plugin-markdown to register processed markdown files and their slugs Elder.js

NOTE: If you are modifying 'allRequests' you must set 'request.route' key for each request.

Props :
perf
helpers
data
settings
allRequests
routes
query
errors
Mutable :
errors
allRequests
Stable · Location: Elder.ts
4.
middleware : Fired upon a request that originates from the express/polka middleware version of Elder.js. The hook has access to "req" and "next" common in express like middleware.

If you're looking to use Elder.js with express/polka to build a server rendered website, then you'll be interested in this hook as it includes the familiar 'req' and 'next' objects as often used in Express middleware.

  • Under the hood Elder.js uses this hook to power the server implementation.
  • If you want to change the route of a request, you can do so by modifying the 'request.route' to the name of the new request, and it will be picked up by the default Elder.js server.
  • If you're looking to set user or session information stored on the 'req' prop we recommend using a hook to modify the 'request' object or 'data' objects. Change to the request object will be passed down.
  • If you're looking to pass in details about the query string deeper into your application, you could use this hook to do so.
  • Anything you'd use an Express 'req' or 'next' for you can do and customize other parts of the Elder.js on this hook.
Props :
perf
errors
query
helpers
data
settings
allRequests
routes
req
next
res
serverLookupObject
runHook
shortcodes
request
router
Mutable :
errors
query
helpers
data
settings
allRequests
routes
req
next
res
request
serverLookupObject
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: prepareServer.ts
5.
request : This is executed at the beginning the request object being processed.

This hook gives access to the entire state of a request lifecycle before it starts.

  • Primarily used to set 'request' specific data that is required by all routes so doesn't make sense to share across multiple 'data' functions.
  • If you have helper functions that need a closure isolated to a specific page generation lifecycle here is where you should attach them.
  • If you need to programmatically change the route, you can do so here. This is how the elderjs-plugin-random works.
  • This hook is commonly uses by plugins that need to add route level data that is dependent on the request to populate.
Props :
perf
helpers
data
settings
request
allRequests
query
errors
routes
route
Mutable :
errors
helpers
data
settings
request
route
Stable · Location: Page.ts
6.
data : This hook is run after the route's "data" function has executed.

This hook is mainly used by plugins/hooks to offer functionality at the route level that is dependent on the route's "data" function has returning but isn't suitable to live in multiple data function across many routes due to code duplication.

Examples of things we (ElderGuide.com) have done or have seen users do:

  • LD+JSON: Plugins/hooks that add LD+JSON may need the a route's "data" function to be executed before they have the data needed to run.
  • Breadcrumbs: Plugins/hooks that add breadcrumbs may be dependent on the "data" function of a route.
  • Table Of Contents: Plugins/hooks that automatically generate a table of contents will be dependent on data from a route's data function.
  • Reference Plugins: Plugins/hooks that collect references from content and add them to the footer of the page content.
  • Last Updated Data: Determining the last updated date for a page is often better to do in a central place instead of in many "data" functions.

Stacks are made available here so that strings can be added to the head or footer of the page easily.

Props :
perf
data
request
errors
helpers
query
routes
cssStack
headStack
beforeHydrateStack
hydrateStack
customJsStack
footerStack
settings
next
Mutable :
errors
data
cssStack
headStack
beforeHydrateStack
hydrateStack
customJsStack
footerStack
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Page.ts
7.
shortcodes : Executed after the route's html has been compiled, but before the layout html has been compiled.

Elder.js uses this hook to process shortcodes. The vast majority of users won't need to use this hook, but if you were so inclined you could write your own shortcode parser or if you'd like to disable shortcodes completely, you can add 'elderProcessShortcodes' to hooks.disable in your elder.config.js file.

NOTE: Don't use this hook for anything besides shortcodes.

Props :
perf
helpers
data
settings
request
query
errors
cssStack
headStack
customJsStack
layoutHtml
shortcodes
allRequests
Mutable :
errors
layoutHtml
cssStack
headStack
customJsStack
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Page.ts
8.
stacks : Executed just before processing all of the stacks into strings.

Elder.js uses 'stacks' to manage it's string concatenation. If you are unfamiliar, stacks are basically an array of strings, with a priority, and some meta data. This hook let's you manipulate or view the stacks before they are written to the page and is designed for use by plugins.

This hook will mainly be used when you need to add arbitrary strings to the footer. In most cases, users should be using <svelte:head></svelte:head> to add content to the head.

  • headStack: Internally all content used in are added to the head stack. If you were looking to add ld+json to the page, you could do it here. If you're looking to write <title> tags, we recommend doing it within Svelte templates unless you are writing a plugin in which case you may want to also look at the 'head' hook.
  • cssStack: The 'cssStack' represents all of the css strings added by hooks and plugins. Plugins can add css here (our in the head stack if you need to add CSS before the Elder.js CSS file), but we recommend users add them directly in Svelte files. Note: Do not wrap strings added to the stack in <style></style>.
  • beforeHydrateStack: Polyfills for hydration could be added here. This stack is not run unless there are Svelte components to be hydrated.
  • hydrateStack: the hydrateStack contains strings which represent all of the root svelte components which will be hydrated.
  • customJsStack: Used to add custom JS to the site. This is done after the Svelte components are written to the page.
  • footerStack: the footerStack which is an array of html or html friendly strings that will be written to the footer. This is generally the ideal place for plugins to add Analytics scripts as it fires after all other JS.
Props :
perf
helpers
data
settings
request
query
errors
cssStack
htmlAttributesStack
bodyAttributesStack
headStack
beforeHydrateStack
hydrateStack
customJsStack
footerStack
Mutable :
errors
cssStack
htmlAttributesStack
bodyAttributesStack
headStack
beforeHydrateStack
hydrateStack
customJsStack
footerStack
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Page.ts
9.
head : Executed just before writing the <head> tag to the page.

This hook's headSting represents everything that will be written to <head> tag.

There are many possible SEO uses to this hook, especially for plugins. That said, we recommend users who want to set common SEO elements such as tags <title> and meta descriptions programmatically to do it from within Svelte templates using the <svelte:head></svelte:head> tag. Chances are you won't need this field unless you're a power user and need access to the raw head.

Props :
perf
helpers
data
settings
request
headString
query
errors
Mutable :
errors
headString
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Page.ts
10.
compileHtml : This is where Elder.js merges the html from the Svelte layout with stacks and wraps it in an <html> tag.

This hook should only be used when you need to have full control over the <html> document. Make sure if you use this to add 'elderCompileHtml' to the 'hooks.disable' array in your elder.config.js or your template will be overwritten.

Props :
perf
helpers
data
settings
htmlAttributesString
bodyAttributesString
request
headString
footerString
layoutHtml
htmlString
Mutable :
errors
htmlString
This hook is an 'advanced' hook meaning it geared towards advanced users or plugins.
Stable · Location: Page.ts
11.
html : Executed when all of the html has been compiled.

This hook receives the full html of the document. With great power comes great responsibility.

  • Can be used to compress the html/css/js.
  • Could be used to programmatically extract h2/h3 tags and build/inject a table of contents with something like Cheeriojs.
  • If you need to modify the final html output, here is where you can do it.
Props :
perf
helpers
data
settings
request
htmlString
query
errors
Mutable :
errors
htmlString
Stable · Location: Page.ts
12.
requestComplete : This hook marks the end of the request lifecycle.

This hook is triggered on an individual 'request object' completing whether Elder.js is being used in the "build" or a "server" mode.

  • Internally, Elder.js uses this hook to write html to the "public folder".
  • Useful for uploading static html to s3 or another source.
  • Could also be used to write the output of a route's "data" function file to help with client site routing if you were so inclined.
  • This hook may also be used by plugins to clean up any request specific 'state' they have stored.
  • By default Elder.js adds a hook here to all server requests that outputs how long the request took to generate. If you want to see detailed output from this hook set debug.speed = true in your config file.
Props :
perf
request
htmlString
query
settings
errors
timings
data
Mutable :
errors
Stable · Location: Page.ts
13.
error : Executed only if the script has encountered errors and they are pushed to the errors array.

As the script encounters errors, they are collected and presented on this hook at the end of a request and the end of an entire build.

Props :
perf
helpers
data
settings
request
query
errors
Mutable :
Stable · Location: Page.ts, build.ts
14.
buildComplete : Executed after a build is complete

Contains whether the build was successful. If not it contains errors for the entire build. Also includes average performance details, and a granular performance object. Could be used to fire off additional scripts such as generating a sitemap or copying asset files to the public folder.

Plugins: Because builds are split across processes, a plugin doesn't not have a shared memory space across all processes.

Props :
perf
helpers
data
settings
timings
query
errors
routes
allRequests
Mutable :
Stable · Location: build.ts