Static Shock

repository·main·Indexed 41 days ago

https://github.com/flutter-bounty-hunters/static_shock

A 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.

Tokens
27.9K
Snippets
110
Records
144
Agent score
98%

What's inside Static Shock

  1. What is a Static Shock plugin?

    main
    A plugin is a collection of StaticShock configurations 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 a StaticShockPipeline directly. A plugin typically handles tasks like selecting specific files, applying asset transformations, or implementing HTML templating.
  2. How the Static Shock pipeline works

    main

    All 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 the StaticShockPlugin interface by providing a configure method that adds various objects to this pipeline.

    Key pipeline components include:

    • Pickers: Choose which files/directories enter the pipeline.
    • DataLoaders: Load external data for Page rendering.
    • AssetTransformers: Transform asset content (e.g., Sass to CSS).
    • PageLoaders: Identify source files as Page objects.
    • PageTransformers: Transform Page objects before rendering.
    • PageRenderers: Render Page objects into final HTML files.
    • Finishers: Execute arbitrary logic after all pages are rendered.
  3. Core data structures in Static Shock

    main

    The 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.
  4. Use Frontmatter for Markdown page metadata

    main

    Static Shock uses YAML Frontmatter to allow authors to specify page-specific metadata. Frontmatter must be placed at the very beginning of your .md file, 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.
  5. Transform assets using AssetTransformer

    main

    Once assets are loaded into the pipeline, you can modify them by implementing an AssetTransformer.

    An AssetTransformer can 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.
  6. Understand Jinja templating in Static Shock

    main

    Jinja 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>
  7. Understand the DataIndex abstraction

    main

    The DataIndex is a hierarchical, JSON-like data structure used to share information between pipeline steps, plugins, and page renderers (like Jinja). It is accessed via the StaticShockPipelineContext.

    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.
  8. How plugins work in Static Shock

    main

    Static 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(/*...*/);
  9. Load assets using AssetLoaders

    main

    When assets originate from sources other than local files (e.g., generated during the build process), use an AssetLoader.

    An AssetLoader allows you to programmatically create Asset data 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.