Static Shock
repository·main·Indexed 41 days ago
https://github.com/flutter-bounty-hunters/static_shockA static site generator written in Dart. It includes the static_shock_cli for project scaffolding, building sites, and running a local development server with automatic reloading. It can be used via the command line with the shock CLI or programmatically by instantiating the StaticShock class.
What's inside Static Shock
- The Static Shock documentation website (https://staticshock.io) is the official documentation site for the Static Shock project. Notably, the website itself is built using Static Shock.
What is a Static Shock plugin?
mainA plugin is a collection ofStaticShockconfigurations designed to be shared across projects. Plugins are primarily used for code organization rather than providing unique capabilities; any behavior a plugin provides can also be achieved by configuring aStaticShockPipelinedirectly. A plugin typically handles tasks like selecting specific files, applying asset transformations, or implementing HTML templating.How the Static Shock pipeline works
mainAll Static Shock build behavior is driven by the
StaticShockPipeline. The pipeline processes source files and outputs final static website build files through several stages. A plugin implements theStaticShockPlugininterface by providing aconfiguremethod that adds various objects to this pipeline.Key pipeline components include:
Pickers: Choose which files/directories enter the pipeline.DataLoaders: Load external data forPagerendering.AssetTransformers: Transform asset content (e.g., Sass to CSS).PageLoaders: Identify source files asPageobjects.PageTransformers: TransformPageobjects before rendering.PageRenderers: RenderPageobjects into final HTML files.Finishers: Execute arbitrary logic after all pages are rendered.
Core data structures in Static Shock
mainThe pipeline operates on several key data structures that represent the content of the site:
- pages: Represents a URL-addressable HTML page.
- assets: Represents any URL-addressable file that is not a page (e.g., CSS, JavaScript, images, video).
- DataIndex: A high-level data structure where plugins can store arbitrary data to make it available to the rest of the pipeline.
- PagesIndex: A collection holding references to all loaded pages, used for searching pages based on various criteria.
Use Frontmatter for Markdown page metadata
mainStatic Shock uses YAML Frontmatter to allow authors to specify page-specific metadata. Frontmatter must be placed at the very beginning of your
.mdfile, delimited by triple dashes (---).Commonly used keys include:
title: The title of the page.publishDate: The date the content should be published.layout: The specific template/layout file to use for rendering (e.g.,layouts/guide.jinja).
This metadata is passed directly to your templating engine (such as Jinja) during the rendering process.
--- title: Welcome publishDate: 2025-05-12 layout: layouts/guide.jinja --- # Welcome This is a welcome guide.Register data using DataLoaders
mainDevelopers can implement and register
DataLoaders to merge arbitrary data into theDataIndex. When aDataLoaderreturns data, it is merged key-by-key into the existing structure.Best Practice: Plugins should use unique top-level keys (e.g.,
github) to avoid collisions with other plugins or user-defined data.Transform assets using AssetTransformer
mainOnce assets are loaded into the pipeline, you can modify them by implementing an
AssetTransformer.An
AssetTransformercan take an existing asset and produce a new one. Common use cases include:- Compiling source code (e.g., converting Sass to CSS).
- Changing the destination file path or extension.
- Modifying the content (text or binary) of the asset.
Understand Jinja templating in Static Shock
mainJinja is the templating system used by Static Shock to inject dynamic values into text files (typically HTML). It allows you to replace placeholders with variables, execute loops, and use conditional logic. Static Shock uses a Dart port of the original Python Jinja library.
Key capabilities include:
- Variable Replacement: Inserting values into placeholders using
{{ variable_name }}. - Execution Controls: Using loops (e.g.,
{% for ... %}) and conditionals to control content structure. - Filters: Calling Dart functions to transform data (e.g.,
{{ value | filter_name }}). - Tests: Performing Dart boolean checks (e.g.,
{% if value is test_name %}).
<!-- Variable Replacement --> <title>{{ title }}</title> <!-- Loops --> <ul> {% for item in menuItem.items %} <li><a href="{{ item.url }}">{{ item.title }}</a></li> {% endfor %} </ul>- Variable Replacement: Inserting values into placeholders using
Understand the DataIndex abstraction
mainThe
DataIndexis a hierarchical, JSON-like data structure used to share information between pipeline steps, plugins, and page renderers (like Jinja). It is accessed via theStaticShockPipelineContext.Key characteristics:
- Hierarchical: It functions like a nested JSON object.
- Merged: Data from multiple sources (files, plugins, manual merges) is combined into this single index.
- Path-based: Data is accessed and managed using paths rather than simple keys.
- Inheritance-capable: It supports a mechanism where data from higher levels (e.g., root or parent directories) is inherited by lower levels (e.g., specific pages), allowing for scoped overrides.
How plugins work in Static Shock
mainStatic Shock is designed to be highly pluggable. Most core behaviors—such as Markdown parsing, Jinja templating, Sass compilation, and RSS feed generation—are implemented as individual plugins.
Instead of a monolithic configuration, you build your site's functionality by selecting and configuring plugins. This approach allows you to activate only the specific behaviors your project requires and enables 3rd-party developers to extend the system easily.
final staticShock = StaticShock( site: SiteMetadata( rootUrl: 'https://staticshock.io', basePath: '/', ), ) ..pick(DirectoryPicker.parse("images")) ..plugin(const MarkdownPlugin()) ..plugin(JinjaPlugin(filters: [menuItemsWherePageExistsFilterBuilder])) ..plugin(const PrettyUrlsPlugin()) ..plugin(const SassPlugin()) ..loadData(/*...*/);Load assets using AssetLoaders
mainWhen assets originate from sources other than local files (e.g., generated during the build process), use an
AssetLoader.An
AssetLoaderallows you to programmatically createAssetdata structures, which consist of a source and a destination (each containing a file path and content). This is useful for assets like website screenshots that are captured during the build rather than read from disk.Use Statement Bounds in Jinja templates
mainIn Static Shock, Jinja statements are identified by specific delimiters. Anything placed between
{{and}}will be interpreted and processed by the Jinja engine.{{ statement }}