Giter Site home page Giter Site logo

underdog's Introduction

underdog

HTTP/2 server-push for hapi

Build Status Coverage Status

Lead Maintainer - Devin Ivy

Installation

npm install underdog

Usage

See also the API Reference

Underdog is intended for use with hapi v19+ and nodejs v12+ (see v4 for lower support).

This module is currently under ad hoc maintenance, which means it relies fully on community support.

Underdog brings HTTP/2 server-push to hapi. The way it works is that you specify paths to resources that you'd like to push alongside a particular response. This is achieved with a call to the response toolkit decoration h.push(). Before hapi responds to the original request, those push-requests will be made internally and their results will be streamed to the client as push-responses. Even pushed resources can specify additional resources to push. You can't make this stuff up!

Example

const Fs = require('fs');
const Http2 = require('http2');
const Hapi = require('@hapi/hapi');
const Underdog = require('underdog');

(async () => {

    const listener = Http2.createSecureServer({
        // See tests for a key/cert that you can use to try this out
        key: Fs.readFileSync(`${__dirname}/localhost.key`),
        cert: Fs.readFileSync(`${__dirname}/localhost.cert`)
    });

    const server = Hapi.server({
        listener,
        tls: true,
        port: 3000
    });

    await server.register(Underdog);

    server.route([
        {
            method: 'get',
            path: '/',
            handler: (request, h) => {

                const response = h.response('<script src="/push-me.js"></script>');

                h.push(response, 'push-me.js');

                return response;
            }
        },
        {
            method: 'get',
            path: '/push-me.js',
            handler: (request) => {

                return 'document.write(\'I was definitely pushed!\');';
            },
            // To demonstrate that it must have been pushed, not requested directly
            config: { isInternal: true }
        }
    ]);

    await server.start();

    console.log(`Check-out ${server.info.uri} in your favorite HTTP/2-supporting client`);
})();

Compatibility

Underdog is compatible with nodejs's Http2Server and Http2SecureServer under the Compatibility API. Using any other HTTP server will simply disable server-push; h.push() will no-op and return { response, allowed: false } and h.pushAllowed() will return false.

Extras

  • The HTTP/2 spec (here)
  • For debugging HTTP/2 in Chrome, see chrome://net-internals/#http2
  • Nodejs's HTTP/2 docs (here)
  • Shout-out to the original userland spdy and http2 modules.

underdog's People

Contributors

devinivy avatar nargonath avatar zemccartney avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

underdog's Issues

Suggestion: allow `path` to optionally be an array.

It would be really nice to be able to do something like:

reply(content).push([
    somefile.js,
    someotherfile.css
]);

Rather than repeatedly doing .push calls. This would also allow easily setting the same headers for those resources (if required).

Thoughts? Criticisms? Reactions of pure unabated horror?

Switch to ad hoc maintenance

I propose we switch this module to ad hoc maintenance. Most modules in the hapi pal organization receive similar or equal treatment to each other. For example, when a new version of node or hapi is released, all modules are actively updated to remain compatible. Under "ad hoc maintenance" issues for those tasks would be created and PRs welcome, but the work wont actively be completed. When updates do occur they will be accepted if they stick with pal's standards and conventions.
This means that this module would receive looser maintenance and may not stay up to date with nodejs or hapi unless the community makes a point to keep it up to date. A note of this fact would display in the readme. The main factor leading to this decision is that this module hasn't received many contributions, doesn't have any dependents, receives very few downloads, and there just isn't a big appetite for http2 in nodejs in general. If the module ends-up unmaintained it will likely be deprecated, and if it is maintained or becomes more popular then it could come out of ad hoc maintenance, so nothing is absolutely final here.

Support hapi v19+

This entails also dropping support for node v10, v12 (and adding support for v14).

Unable to push compressed assets

Hapi: v17.2.0
Inert: v5.1.0
Underdog: v2.0.1

Unless I am going about this all wrong, I cannot get h.push() to push back .gz assets for the array of paths provided as the second argument. Is this supported currently?

From what I understand, Hapi handles compression out of the box, but in my use case I have gzipped the assets myself and want to respond to requests for compressible assets (js, css, etc..) with their compressed counterparts.

// This works, but the assets returned are uncompressed
  const index = readFileSync(join(__dirname, 'public/index.html')).toString();
  server.route({
    method: 'GET',
    path: '/',
    handler: (request, h) => {
      const response = h.response(index);
      h.push(response, ['/app.js', '/pure.css', '/assets/hero-bg.jpg']);

      return response;
    }
  });

/*This is not supported. The compressed resources are not pushed to the client,
  but instead the client discovers the assets after parsing through the `index .html` 
  and the automatically compressed assets are returned */
  const index = readFileSync(join(__dirname, 'public/index.html')).toString();
  server.route({
    method: 'GET',
    path: '/',
    handler: (request, h) => {
      const response = h.response(index);
      h.push(response, ['/app.js.gz', '/pure.css.gz', '/assets/hero-bg.jpg']);

      return response;
    }
  });

This is a simplified version of my config for clarity:

(async () => {
  const listener = h2.createSecureServer({
    key: readFileSync(join(__dirname, '/keys/key.pem'), 'UTF-8'),
    cert: readFileSync(join(__dirname, '/keys/server.crt'), 'UTF-8')
  });

  const port = configs.port;
  const server = new Hapi.Server({
    port,
    listener,
    tls: true,
    routes: {
      files: {
        relativeTo: join(__dirname, 'public')
      }
    }
  });

  await server.register([
    Inert,
    ...
    Underdog
  ]);

  /* FOR SERVING FRONT END ASSETS FOR ALL REQUESTS. */
  server.route({
    method: 'GET',
    path: '/{param*}',
    handler: {
      directory: {
        path: '.',
        index: true,
        redirectToSlash: true
      }
    }
  });

  /* ~Other route handlers~ */
})()

Hapi v17 Support

Overview

If you are not aware yet, Hapi v17 is making the transition from callbacks to async/await, as well as deprecating some other rarely used functionality. This is a breaking change that may make your plugin no longer compatible with the Hapi API.

Changelog

Draft release notes can be found here: hapijs/hapi#3658

Target Release

The target release date for v17 is the beginning of November.

Tasks

  • Reply to this to acknowledge that you are actively maintaining this module and are willing to update it
  • Update plugin to be fully async/await compatible using the v17 branch from Hapi for testing

    Possible dev flow for updating

    • Clone Hapi
    • npm link within the Hapi repo
    • npm link hapi within your plugin repo
    • Your plugin will now be using v17 of Hapi branch for tests
  • Release new major version of your plugin on npm. Please use a major version increment as this will be a breaking change and it would be terrible for it to sneak into current versions of Hapi.

Notes

  • Support is being dropped for all versions of Node <8.0.0.
  • Hapi v16 will continue to be supported for as long as there exists a Node LTS actively being supported that is not compatible with v17.
  • Targeted release date is November 1st, 2017. Please try to have your plugin updated before then.
  • This issue is being opened because your plugin is listed on the official hapi website

Support hapi v18

Also drop support for hapi v17, due to changes to server.inject().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.