• Stars
    star
    382
  • Rank 112,241 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 5 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Add dynamic content loading to static sites with only 1 KiB of JS

Pill logo

badge: npm version badge: size 1.45 KiB badge: deps 0

Pill adds dynamic content loading to static sites and makes content loading smooth for users. It's pretty small only 1.45 KiB minified and gzipped. It fits perfectly for static sites with WebComponents.

  • 🐥 Tiny: 1.45 KiB gzipped.
  • 🥤 Easy-to-use: single function call.
  • 🎮 Handful: hooks and callbacks could modify the default behavior.

Pill development started with the tweet by Andrey Sitnik @ai.

How pill works. It:

  1. Intercepts navigation attempts: links clicks and history navigation.
  2. Loads requested url using fetch.
  3. Grabs content from received HTML.
  4. Replaces current page content.

Initialize in one line:

pill('#content') // Yep, that's it.

Table of Contents

Install

  • Include script from unpkg.com:

    <script src="https://unpkg.com/pill@1/dist/pill.min.js"></script>

    ⚠️ Remember about security! Add subresource integrity (SRI) checksum from checksum.txt.

  • Install via npm:

    npm i pill
    

Usage

  1. Inject pill's <script> into page.
  2. Create content root element and give it id.
  3. Create loading indicator element.
  4. Initialize pill:
// Get loading indicator element
const indicator = document.querySelector('#indicator')
// Assign Pill to specified selector
pill('#content', {
  onLoading() {
    // Show loading indicator
    indicator.style.display = 'initial'
  },
  onReady() {
    // Hide loading indicator
    indicator.style.display = 'none'
  }
})

Complete example

<html>
  <head>
    <title>Home</title>
    <script src="https://unpkg.com/pill@1/dist/pill.min.js"></script>
    <style>
      /* global styles */
      #indicator {
        position: fixed;
        top: 0;
        right: 0;
        display: none;
      }
    </style>
  </head>
  <body>
    <div id="indicator">Loading...</div>
    <div id="content">
      <style>/* page styles */</style>

      <!-- page content here -->
    </div>
    <script>
      const indicator = document.querySelector('#indicator')

      pill('#content', {
        onLoading() {
          // Show loading indicator
          indicator.style.display = 'initial'
        },
        onReady() {
          // Hide loading indicator
          indicator.style.display = 'none'
        }
      })
    </script>
  </body>
</html>

Each document of the site should surround #content element with the same HTML. All page-related content should be located inside #content. It could be styles, scripts, etc.

Corner Cases

No script inside of the content element

Script elements placed inside of your content element wouldn't be evaluated after loading. You should place all scripts out of your content element (in the head or body) and run JS manually. This behavior prevents your site from memory licks and race conditions caused by inner scripts different lifetime. And then you can react on page change with onReady hook to change your app behavior.

Example:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="content"></div>
    <!-- common scripts -->
    <script src="/scripts/pill.js"></script>
    <script src="/scripts/app.js"></script>
    <script>
      pill('#content', {
          onMounting(page, url, element) {
            // Init page, for example bind event listeners, start timers, etc.
            App.initPage(url, element)
          },
          onUnmounting(page, url, element) {
            // Uninitialise page, for example remove event listeners, stop timers, etc.
            App.destroyPage(url, element)
          },
       })
       App.initPage(new URL(window.location), document.querySelector('#content'))
    </script>
</html>

API

pill()

(selector:string, options:PillOptions) -> void

Initialize pill. Start listening for navigation attempts and history state changes. Puts loaded content into selector element.

Events

You can handle Pill's events by binding handlers on document element:

document.addEventListener('pill:loading', (e) => {
  e.detail.page; // Current page
})

pill:error Event

{
  detail: {
    url: URL
    element: HTMLElement
    error: Error
  }
}

Is emitted when the new page loading has been started. This event wouldn't be emitted if page is cached.

Could be replaced with PillOptions.onLoading() hook.

pill:loading Event

{
  detail: {
    url: URL
    element: HTMLElement
  }
}

Is emitted when the new page loading has been started. This event wouldn't be emitted if page is cached.

Could be replaced with PillOptions.onLoading() hook.

pill:mounting Event

{
  detail: {
    page: Page
    url: URL
    element: HTMLElement
  }
}

Is emitted when new page content is about to be added into the DOM.

Could be replaced with PillOptions.onMounting() hook.

pill:ready Event

{
  detail: {
    page: Page
    url: URL
    element: HTMLElement
  }
}

Is emitted when the requested page is mounted into DOM and no futher work would be done.

Could be replaced with PillOptions.onReady() hook.

pill:unmounting Event

{
  detail: {
    page: Page
    url: URL
    element: HTMLElement
  }
}

Is emitted when new page content is about to be removed from the DOM.

Could be replaced with PillOptions.onMounting() hook.

Hooks

PillOptions.onError()

(error) -> void

Handle page loading exception. By default is console.error.

PillOptions.onLoading()

(page:Page) -> void

Handle loading start.

Could be replaced with pill:loading Event listener.

PillOptions.onMounting()

(page:Page, url:URL, element:HTMLElement) -> void

Fires everytime new content is about to be loaded to the DOM.

Could be replaced with pill:mounting Event listener.

PillOptions.onReady()

(page:Page) -> void

Handle loading finish.

Could be replaced with pill:ready Event listener.

PillOptions.onUnmounting()

(page:Page, url:URL, element:HTMLElement) -> void

Fires everytime content is about to be removed from the DOM.

Could be replaced with pill:unmounting Event listener.

Other options

PillOptions.fromError()

(error:Error) -> {title, content}

Use it to display notification when something went wrong. If an error was thrown while handling request. You still able to render content using method fromError

PillOptions.getKeyFromUrl()

(url:URL) -> String

Get cache key from URL. It's useful when URL contains query params which are unknown to server and could not affect response. By default any new pathname and search string combination will cause new request.

PillOptions.shouldReload()

(page:Page) -> Boolean

Determine wether previously loaded page should be loaded from server.

PillOptions.shouldServe()

(url:URL, target:HTMLElement) -> Boolean

Developer-defined logic to determine whether the URL could be served by Pill. If you return false then the link will be served by browser.

License

MIT © Rumkin

More Repositories

1

favicon-switcher

Make favicon react on media queries
JavaScript
80
star
2

plant

🌳 JS web server charged with WebAPI and neat HTTP2 support
JavaScript
79
star
3

bake

Bake is a bash task runner
Shell
26
star
4

mighty-input

Text input for modern web
JavaScript
20
star
5

piggy-bank

Nodejs with Ethereum smart contract tutorial app
HTML
19
star
6

file-storage

Multi-backend file storage with REST interface and synchronization
JavaScript
19
star
7

error3

💢⚠️ Error object for JS and TS
TypeScript
15
star
8

hypemail

SMTP server example
JavaScript
13
star
9

typed-props

Facebook's PropTypes standalone extensible implementation for browser and server
JavaScript
9
star
10

plant-browser-demo

Nodeless web server demo
7
star
11

emoji-favicon

Emoji-favicon middleware
JavaScript
6
star
12

nginx-auth-proxy

nginx authentication proxy for web-signature
Lua
6
star
13

duotone-reader

Screen reading enhancement with duo-voice text reading.
5
star
14

testup

TestUp is a test running suit
JavaScript
5
star
15

uuid

uuid generator web app
HTML
4
star
16

crypto-stamp

🖋 Web-ready signature format and library
JavaScript
4
star
17

copybar

CopyBar: supportive development component specification
4
star
18

ethereum-cloudconfig

⚡️Cloud-config to setup ethereum node in seconds
3
star
19

pure-saga

Functional implementation of redux-saga alike asynchronous flow manager
JavaScript
3
star
20

lc3vm

Little Computer 3 (LC-3) TypeScript implementation
TypeScript
3
star
21

tc39-synced-function

TC39 Proposal for synchronized function
3
star
22

ultimate-web-app-checklist

Ultimate web app requirements list
3
star
23

web3-postmessage-provider

🔌 Ethereum Web3 provider for extensions based on PostMessage and Message Сhannels
JavaScript
2
star
24

token-swap

Token Swap App
JavaScript
2
star
25

emoji-img

Emoji images map
JavaScript
2
star
26

ssh-shell

SSH remote shell client implementation
JavaScript
2
star
27

rsynced

Rsync your node.js project with VM, staging and production.
JavaScript
2
star
28

ng-validate

Angular validation library
JavaScript
2
star
29

mongoose-map

ES2015 Map type support for Mongoose ORM
JavaScript
2
star
30

moongo

Mongo query atomation cli app
JavaScript
2
star
31

npm-lite

🌱 Lite npm package boilerplate
1
star
32

cha-cha-chat

Example of ChaCha20 encrypted chat with ECDH key exchange
JavaScript
1
star
33

keyget

Tiny kit for nested objects modification.
JavaScript
1
star
34

crewman

Microservice framework for DevOps and distributed web apps
JavaScript
1
star
35

urpc

μRPC is a transport agnostic JSONRPC 1.0 implementation
JavaScript
1
star
36

almighty-web

The next web after web 2.0
1
star
37

tc39-proposal-block-string

Block string
1
star
38

mongo-rest-api

Mongo REST API middleware
JavaScript
1
star
39

npx-esm

Run ESM programs with Node.js’ NPX util
JavaScript
1
star
40

argentum

Node.js cli arguments parser
JavaScript
1
star
41

stylex

Color palette as dependency
JavaScript
1
star
42

vm-sandbox

Nodejs VM sandbox example
JavaScript
1
star
43

allow-publish-tag

Publish package with allowed dist-tags only
JavaScript
1
star
44

acw

Awesome Crypto Wallet
HTML
1
star
45

anyhook

Emit console scripts on webhook request
JavaScript
1
star
46

cli-complete

Missing node.js/io.js bash completion tool
JavaScript
1
star