Parklife

repository·main·Indexed 43 days ago

https://github.com/benpickles/parklife

A Ruby library that renders Rack-based applications, such as Rails or Sinatra, into static sites for hosting on providers like Netlify, GitHub Pages, or S3. It features a crawler that discovers linked pages, a DSL for route configuration via a Parkfile, and a CLI for building and managing static output.

Tokens
5.3K
Snippets
24
Records
31
Agent score
54%

What's inside Parklife

  1. List and build the static site

    main

    After configuring your Parkfile, you can use the following CLI commands:

    1. List routes: Run parklife routes to see all routes that will be processed and whether they are set to crawl.

      $ bundle exec parklife routes
    2. Build the site: Run parklife build to fetch all routes and save them to the build directory (defaults to build/).

      $ bundle exec parklife build

    Note: Parklife does not handle assets (images, CSS, etc.). You must manually generate assets and copy them into the build directory.

  2. Configure routes in the Parkfile

    main

    Parklife uses a Parkfile in your project root to define which routes to render. You use Parkfile.application.routes to declare paths.

    • Use root crawl: true to start from the homepage and automatically discover all linked pages.
    • Use get '/path' to include specific paths that might not be discovered by crawling (e.g., sitemaps or feeds).
    • Use get '/path', crawl: true to include a specific path and then continue crawling from there.

    Example Parkfile for a Rack app:

    require_relative 'app'
    
    Parkfile.application.routes do
      root crawl: true
      get '/feed.atom'
      get '/sitemap.xml'
      get '/easter_egg', crawl: true
      get '/404.html'
    end
    # Assuming your Rack app lives in ./app.rb:
    require_relative 'app'
    
    Parkfile.application.routes do
      # Start from the homepage and crawl all links.
      root crawl: true
    
      # Some extra paths that aren't discovered while crawling.
      get '/feed.atom'
      get '/sitemap.xml'
    
      # A couple more hidden pages.
      get '/easter_egg', crawl: true
    
      # Services typically allow a custom 404 page.
      get '/404.html'
    end
  3. Install and initialize Parklife

    main

    To use Parklife, add it to your Gemfile and run bundle install.

    To set up your project, run the init command. You can pass flags to include framework-specific settings or automate deployment:

    • --rails: Includes Rails-specific settings.
    • --sinatra: Includes Sinatra-specific settings.
    • --github-pages: Creates a GitHub Actions workflow to build and deploy to GitHub Pages.
    $ bundle exec parklife init
    gem 'parklife'
  4. Understand how Parklife maps routes to file paths

    main

    Parklife converts web routes into filesystem paths using specific logic for HTML content and the nested_index configuration:

    1. Root Path: An empty path (the root /) always maps to index.html.
    2. Slash Normalization: Leading and trailing slashes are removed from the route.
    3. HTML Handling: If the response media_type is text/html (or nil) and the path does not end in .html:
      • If nested_index is true: The path is appended with /index.html (e.g., /about becomes about/index.html).
      • If nested_index is false: The path is appended with .html (e.g., /about becomes about.html).
    4. Other Media Types: Non-HTML content is mapped directly to the path without appending .html.
  5. Configure Parklife application settings

    main

    You can customize Parklife's behavior using Parkfile.application.config.

    Base URL

    To ensure Rails *_url helpers point to the correct host (useful for feeds or social tags), set the base configuration. This can also be overridden at build-time via the CLI.

    Parkfile.application.config.base = 'https://foo.example.com'

    CLI override:

    $ bundle exec parklife build --base https://benpickles.github.io/parklife

    Output Directory

    Set the directory where the static site will be saved. The directory is cleared before each build. Defaults to 'build'.

    Parkfile.application.config.build_dir = 'my/build/dir'

    Nested Index Files

    By default, Parklife uses nested index.html files (e.g., /path/index.html) to ensure link compatibility. To use flat .html files instead (e.g., /path.html), set nested_index to false. This is useful for services like Netlify or GitHub Pages with 'Pretty URLs' enabled.

    Parkfile.application.config.nested_index = false

    Defining the Rack App

    If you are not using the Rails-specific configuration, you must manually define the Rack application.

    Parkfile.application.config.app = MyRackApp
  6. How the Crawler handles route discovery and visiting

    main

    The crawler uses a crawl flag on routes to manage traversal logic. This flag determines how the visited? check behaves:

    1. crawl: true routes: These are routes intended to be traversed for new links. A route with crawl: true is only considered visited once it has actually been crawled. If a route was previously visited via a non-crawl route, it must be visited again to satisfy the crawl: true requirement.
    2. crawl: false routes: These are typically terminal pages. A route with crawl: false is considered visited if either the route itself or its crawl: true counterpart has been visited.

    Additionally, if your application is mounted at a subdirectory (defined by config.base), the crawler automatically trims this prefix from discovered links to ensure correct application routes are created.

  7. Configure Parklife build behavior via build.yml

    main

    Parklife uses a configuration file located at .parklife/build.yml to manage build settings and path mappings. You can initialize a Parklife::Build instance from a directory containing this file using Parklife::Build.from_dir(dir).

    Key configuration options include:

    • config.nested_index: A boolean that determines how text/html responses are stored when they do not already end in .html.
    • paths: A mapping of route paths to metadata (like build_path and etag).
    # Example structure of .parklife/build.yml
    config:
      nested_index: true
    paths:
      "/about":
        build_path: "about/index.html"
        etag: "some-etag-value"
  8. Configure Parklife settings via the Config class

    main

    The Parklife::Config class manages the build directory, caching, logging, and how the crawler handles different HTTP response codes. You can instantiate a new configuration object and set its attributes to customize your crawl and build process.

    Key Configuration Attributes

    AttributeTypeDefaultDescription
    base=String or URIhttp://example.comThe base URI for the application being crawled.
    build_dir=String'build'The directory where the build output will be placed.
    cache_dir=StringnilThe directory used for caching.
    loggerLogger instanceLogger.newThe logger used for internal messages.
    nested_indexBooleantrueWhether to enable nested index.html files (set to false to disable).
    no_colour=BooleanfalseDisables color in the logger and reporter output.
    on_301Symbol:errorAction to take on 301 redirects.
    on_302Symbol:errorAction to take on 302 redirects.
    on_404Symbol:errorAction to take on 404 errors.
    reporter=String'null'The type of reporter to use. Options: 'log', 'progress', or 'null'.
    skip_build_metaBooleanfalseWhether to skip generating build metadata.
    config = Parklife::Config.new
    config.base = 'https://my-app.com'
    config.build_dir = 'dist'
    config.reporter = 'progress'
    config.on_404 = :error
  9. Handle 301, 302, and 404 responses

    main

    You can control how Parklife reacts when it encounters redirects or missing pages. For on_301, on_302, and on_404, the following values are supported:

    • :error (default): Raises an exception and stops the build.
    • :skip: Does not save the response and continues processing.
    • :warn: Outputs a message to stderr and continues processing.
    # Handle redirects
    Parkfile.application.config.on_301 = :warn
    Parkfile.application.config.on_302 = :warn
    
    # Handle 404s
    Parkfile.application.config.on_404 = :warn
    Parkfile.application.config.on_301 = :warn
    Parkfile.application.config.on_302 = :warn
    Parkfile.application.config.on_404 = :warn
  10. Execute the Parklife build process

    main

    The build method is the primary entry point to start the crawling process. It performs the following steps:

    1. Validates that a Rack application is defined in the configuration (raises RackAppNotDefinedError if missing).
    2. Prepares the cache and build directories.
    3. Executes all before_build callbacks.
    4. Starts the crawler.
    5. Executes all after_build callbacks.
    app = Parklife::Application.new
    # ... configuration ...
    app.build
  11. Register build lifecycle callbacks

    main

    You can hook into the Parklife build process by registering blocks that execute before or after the crawler runs. These callbacks receive the Parklife::Application instance as an argument.

    • before_build(&block): Executes logic before the crawler starts.
    • after_build(&block): Executes logic after the crawler finishes.
    app = Parklife::Application.new
    
    app.before_build do |application|
      puts "Starting build..."
    end
    
    app.after_build do |application|
      puts "Build complete!"
    end
    
    app.build
  12. Manage routes with Parklife::RouteSet

    main

    The Parklife::RouteSet class acts as a collection for managing both discovered and manually defined routes within a crawl. It includes the Enumerable module, allowing you to iterate over the routes directly. You can add routes using get or define the starting point of a crawl using root.

    route_set = Parklife::RouteSet.new
    
    # Add specific paths
    route_set.get('/about')
    route_set.get('/contact', crawl: true)
    
    # Add the root path
    route_set.root(crawl: true)
    
    # Iterate over all routes
    route_set.each do |route|
      puts route.path
    end