A blazingly fast router for static sites

Overview

Flamethrower 🔥

Status: Meme

A 2kB zero-config router and prefetcher that makes a static site feel like a blazingly fast SPA.

Why?

Problem: Static sites feel slow and cannot easily share state between pages. This makes it hard to create a good UX with JavaScript libraries because each new page needs to reboot your JS from scratch.

The goal is to make route changes on static sites feel faster, like an SPA, without the need for a frontend framework to take over the entire DOM.

How?

  1. It tells the browser to prefetch visible links in the current page with IntersectionObserver.
  2. Intercepts click and popstate events, then updates the HTML5 history on route changes.
  3. Uses fetch to get the next page, swaps the <body> out, merges the <head>, but does not re-execute head scripts (unless asked to).

This means you can have long-lived JavaScript behaviors between navigations. It works especially well with native web components.

QuickStart

npm i flamethrower-router
import flamethrower from 'flamethrower-router';
const router = flamethrower();

That's it. Your site now feels blazingly fast.

Advanced Usage

// with opts
const router = flamethrower({ prefetch: 'visible', log: false, pageTransitions: false });

// Navigate manually
router.go('/somewhere');
router.back();
router.forward();

// Listen to events
window.addEventListener('router:fetch', showLoader);
window.addEventListener('router:end', hideLoader);

// Disable it
router.enabled = false;

Opt-out of specific links for full page load.

<a href="/somewhere" data-cold></a>

Scripts in <body> will run on every page change, but you can force scripts in the <head> to run:

<script src="..." data-reload></script>

Prefetching

Prefecthing is disabled by default.

  • visible: prefetch visible links on the page with IntersectionObserver
  • hover: prefetch links on hover
const router = flamethrower({ prefetch: 'visible' });

Misc

Supported in all browsers? Yes. It will fallback to standard navigation if window.history does not exist.

Does it work with Next.js? No, any framework that fully hydrates to an SPA does not need this - you already have a client-side router.

Does it work with Astro? I think so. It can share state between routes, but partially hydrated components may flash between routes.

Other things to know:

  • <head> scripts run only on the first page load. <body> scripts will still run on every page change (by design).
  • It's a good idea to show a global loading bar in case of a slow page load.
  • This library is inspired by Turbo Drive.
  • This project is experimental.

Contributing

Build it:

npm run dev

Serve the example:

npm run serve

Make sure all playwright tests pass before submitting new features.

npm run test
Comments
  • :bug: Fixes head dom diffing

    :bug: Fixes head dom diffing

    Solves: https://github.com/fireship-io/flamethrower/issues/45

    I had introduced a bug not caught on the tests (in https://github.com/fireship-io/flamethrower/pull/28 ) that this fixes. It was preventing the loop from running and correctly identifying fresh/stale nodes beyond the first few while not otherwise sacrificing performance.

    Also implements a simple short circuit on the lookbacks in the event old nodes or new nodes are undefined.

    opened by ekwoka 8
  • [help] cannot find imported module

    [help] cannot find imported module

    hello everyone, I've tried to implement page object model for the playwright test, but I have an issue related to import module.

    • here's my code image

    • folder structure image

    • error message Error: Cannot find module '/Users/user/open-source/flamethrower/test/home.page' imported from /Users/user/open-source/flamethrower/test/main.spec.ts image

    is there any missing configuration? thanks in advance for any help 🙏🏻

    opened by depapp 5
  • Title is not updating

    Title is not updating

    I am using flamethrower for deserve.deno.dev a documentation site and the title is not updating between page changes, I haven't looked into what's going on but it shows the correct title when I refresh the page

    opened by shreyassanthu77 5
  • Load array scripts synchronously

    Load array scripts synchronously

    Hi, this PR add function loadScriptSync to replace function replaceAndRunScript

    Because when use replaceAndRunScript, script load not synchronous, so sometime it show error because other script not loaded

    • Use function replaceAndRunScript:

    Screenshot_2

    • Use function loadScriptSync:

    Screenshot_3

    opened by nguyenhuylinhdev 4
  • # Scrolling not working

    # Scrolling not working

    a element

    <li><a href="http://localhost:5501/#contact">Contact</a></li>
    

    Creates url http://localhost:5501/#contact/ => thinks its link => wont scroll

    local debugging flamethrower.js:32 creates const o with value o = http://localhost:5501/#contact/ which causes next if to falsewhich would otherwise process the scroll flamethrower.js:33 if (e.preventDefault(), o != null && o.startsWith("#")) => false

    local dirty workaround starting line flamethrower.js:31

    if (t != null && t.hasAttribute("href")) {
      const o = t.getAttribute("href"), s = new URL(o, location.href);
    - if (e.preventDefault(), o != null && o.startsWith("#"))
    + if (e.preventDefault(), o != null && o.includes("#"))
    -   return w(o), { type: "scrolled" };
    +   return w("#" + o.split("#")[1]), { type: "scrolled" };
      {
    ....
    

    this will always scroll to the first # in the url.

    No time myself creating an PR maybe someone else can fix it.

    opened by Oskar1504 4
  • option to preserve nodes when replacing the body.

    option to preserve nodes when replacing the body.

    this pull request avoids that web components are recreated on each page navigation.

    how: nodes with the attribute "flamethrower-preserve" will be moved to the new page body instead of recreating them. (id has to be unique and match on the old and new page)

    example with an "app-drawer" web component: <app-drawer id="preserve-drawer" flamethrower-preserve>content</app-drawer>

    opened by prowebat 3
  • Add a 🔥 favicon to the example

    Add a 🔥 favicon to the example

    This adds the 🔥emoji as a favicon to the example:

    • Adds the 🔥ico file
    • Adds the favicon to example/404.html
    • Adds the favicon to example/about/index.html
    • Adds the favicon to example/index.html
    • Adds the favicon to example/test/index.html
    opened by SebastianOpperman 3
  • Flamethrower breaks mermaid.js

    Flamethrower breaks mermaid.js

    Hello @fireship-io, I like to use a this great project, but I could not get mermaid diagrams working with it. I tried to embed flamethrower into Zola blog, and managed to get TOC working, but I could not get mermaid diagrams rendered - I had to hit the refresh button in a browser for mermaid diagram to appear, despite flamethrower documentation saying scripts inside body reload, so I had to revert the change, despite adding flamethrower gave really good user experience overall. Commit history: https://github.com/reference-architecture-ai/reference-architecture.ai/commit/9f79341244c4b69c0b6731621afc32578d632507

    Ways to replicate: Add example below into home and similar into about, switch between tabs. Observe markdown is not rendered.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
    </head>
    <body>
      <div class="mermaid">
      graph LR
          A --- B
          B-->C[fa:fa-ban forbidden]
          B-->D(fa:fa-spinner);
      </div>
     <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
     <script>mermaid.initialize({startOnLoad:true});
    </script>
    </body>
    </html>```
    
    opened by AlexMikhalev 2
  • iframes cause issues

    iframes cause issues

    I have a discord widget on my website, and it creates this error:

    document.requestStorageAccess() may not be called in a sandboxed iframe without allow-storage-access-by-user-activation in its sandbox attribute.
    
    opened by ImDaBigBoss 2
  • docs: Add documentation

    docs: Add documentation

    Adds documentation to the docs director. This is not a GUIDE! It's documentation for every function, type, interface, class and method in the lib directory!

    opened by micziz 1
  • Unable to get out of the site using browser's navigation button

    Unable to get out of the site using browser's navigation button

    After serving it on http://localhost:3000, I manually typed the URL and it loaded the example site.

    I can get out of this site if I press the back button now. But if I click on About and then try to do the same it fails to get me out.

    The back button is highlighted but is not working.

    opened by dhirajgagrai 1
  • routerdata 🔥

    routerdata 🔥

    extended router class with routerdata class added ability to subscribe routes to functions functions are stored in a pool (array), no 2 same functions are in this pool routes are stored with the index of the function they are subscribed to in the pool

    opened by boreddad 0
  • Keep existing target in <a>

    Keep existing target in

    Flamethrower currently replaces existing link target:

    <a href="https://astro.build" target="astro">

    is replaced by

    <a href="https://astro.build" target="_blank">

    Existing target should be kept untouched.

    https://github.com/fireship-io/flamethrower/blob/79883a4fb64cc2f2b29f465c7c9556111c58e7ae/lib/handlers.ts#L78

    should be replaced by

    anchor.target = anchor.target || '_blank';
    
    opened by pierredewilde 1
  • Uncaught TypeError: Cannot read properties of undefined (reading 'log')

    Uncaught TypeError: Cannot read properties of undefined (reading 'log')

    https://github.com/fireship-io/flamethrower/blob/79883a4fb64cc2f2b29f465c7c9556111c58e7ae/lib/main.ts#L12

    should be replaced by

    opts && opts.log && console.log('🔥 flamethrower engaged');

    opened by pierredewilde 0
  • added dispatchEvent

    added dispatchEvent

    I just added a utility file which should contain every utility method.

    • Wrote the first one, dispatchEvent which will dispatch a new window event and it can be more customizable ;-)
    • Edited the existing window.dispatchEvent() in the router.ts to the new dispatchEvent() method.
    opened by khalidsheet 0
Owner
Fireship
Fireship
A blazingly fast CDN, at par and up-to-date with modern web technologies

A blazingly fast CDN, at par and up-to-date with modern web technologies

Compey 6 Sep 22, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Gofiber with NextJS Static HTML is a small Go program to showcase for bundling a static HTML export of a Next.js app

Gofiber and NextJS Static HTML Gofiber with NextJS Static HTML is a small Go program to showcase for bundling a static HTML export of a Next.js app. R

Mai 1 Jan 22, 2022
🛣️ A tiny and fast http request router designed for use with deno and deno deploy

Rutt Rutt is a tiny http router designed for use with deno and deno deploy. It is written in about 200 lines of code and is pretty fast, using an exte

Denosaurs 26 Dec 10, 2022
⚡️A minimalistic and sweet router for blazing fast bun

Melonpan is a simple and minimalistic web-router designed to work with Bun, keeping performance in mind. ?? Why Melonpan? no/minimal learning curve De

Hemanth Krishna 66 Jan 6, 2023
Turn any dynamic website (especially wordpress) into a fast, secure, stable static site

Static site publisher Turn any dynamic website (especially wordpress) into a fast, secure, stable static site Reduced complexity - no need to run simp

Alex Ivkin 7 Apr 6, 2022
⚡ A blazing fast, lightweight, and open source comment system for your static website, blogs powered by Supabase

SupaComments ⚡ A blazing fast, lightweight, and open source comment system for your static website, blogs ?? Demo You can visit the Below demo blog po

MC Naveen 112 Dec 27, 2022
A tiny, fast and fun static site generator for quick blogging

1POST A tiny, fast and fun static site generator for quick blogging. 1POST is written entirely in NodeJS and has no dependencies. You can install as a

Felippe Regazio 141 Dec 5, 2022
Adds external & internal translators to various sites.

Twitter External Translator Adds a "Translate with ..." button to Tweets and User Bios. This was a fork of DeepL Twitter translation Version Link Alte

Magic 6 Oct 17, 2022
A simple browser extension, intended to get you "Back To Work" when you start slacking off to one of those really addictive sites.

Back to Work A simple browser extension, intended to get you Back To Work when you start slacking off to one of those really addictive sites. What doe

Dheeraj Lalwani 29 Nov 19, 2022
Chrome extension for replacing addictive and annoying features of various social media sites with inspirational quotes.

Saner Social Media Chrome extension for replacing addictive and annoying features of various social media sites with inspirational quotes. Saner Socia

Tobi Dalhof 9 Oct 4, 2022
Markdoc is a Markdown-based syntax and toolchain for creating custom documentation sites and experiences.

A powerful, flexible, Markdown-based authoring framework. Markdoc is a Markdown-based syntax and toolchain for creating custom documentation sites and

Markdoc 5.8k Jan 2, 2023
Superkeys allow users to add short keys for websites and make search query in those sites.

Superkeys is a browser extension which allow users to add short keys for websites and make search query in those sites. Made with ❤️ @nilooy ??‍?? Dem

Niloy 9 Aug 17, 2022
The most advanced responsive front-end framework in the world. Quickly create prototypes and production code for sites that work on any kind of device.

Install | Documentation | Releases | Contributing Foundation is the most advanced responsive front-end framework in the world. Quickly go from prototy

Foundation 29.4k Jan 4, 2023
This is a Google Chrome Extension which blocks social media sites.

Social Media Blocks (1.0.3) This is a Google Chrome Extension which blocks social media sites like Twitter: Facebook, Instagram, LinkedIn, WhatsApp, R

Helitha Rupasinghe 20 Dec 15, 2022
Build Schema.org graphs for JavaScript Runtimes (Browser, Node, etc). Improve your sites SEO with quick and easy Rich Results.

schema-org-graph-js The quickest and easiest way to build Schema.org graphs for JavaScript Runtimes (Browser, Node, etc). Status: ?? In Development Pl

Harlan Wilton 17 Dec 21, 2022
Statichunt is a free open-source Jamstack directory that lists hundreds of themes, starters, and resources for Jamstack sites.

Statichunt Statichunt is an open-source directory that enlists hundreds of themes, starters, and resources for static site generators submitted by the

Statichunt 12 Dec 29, 2022