npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@nico-martin/spa-server

v0.2.7

Published

SPA Server

Downloads

15

Readme

SPA Server

"SPA Server" is a NodeJS library that starts a production ready NodeJS Webserver, that mostly serves static files and also allows you to manipulate any non-static response.

This is super useful if you you want to control the response headers or meta tags of the returned html file.

Install

yarn add @nico-martin/spa-server
npm install @nico-martin/spa-server

Ok, but why?!?

I love JavaScript applications. But in general, they have one problem. If all the logic happens on the client-side, there are several negative side effects.

I know some frameworks will render everything on the server. But I never really warmed to it. Does it really make sense to have the logic for building the page on the server and then still send the same logic to the client? I doubt that.

Furthermore, frameworks like Next.JS or Nuxt.JS require a rather rigid structure of pages and components.

When I look at my projects, the requirements for server-side rendering are relatively simple. In most cases I only needed it for some meta tags (for example for social media sharing) and a clean status code designation. That's why this library follows a much simpler approach. This being said it works with any kind of framework. It just takes the public dir, serves the files and adds meta tags for routes that are defined under "routes".

API

In essence, the library provides the ability to define your own routes and create a function (synchronous or asynchronous) that returns a status code and an object of HTML metas

{
  path: '/',
  response: request => {
    return {
      metas: {
        'name-of-the-meta': 'content of the meta',
        url: '/',
      },
      statusCode: 200
    }
  },
}

Full example

import spaServer from './lib/index';
import fetch from 'node-fetch';

spaServer({
  routes: [
    {
      path: '/user/:id/',
      response: request => ({    
        metas: {
          'user-id': 'id' in request.params ? request.params.id : '',
          hello: 'world',
          custom: {
            tag: 'link',
            attributes: {
              rel: 'canonical',
              href: 'some-url'
            }       
          }         
        },
        statusCode: 200
      }),
    },
    {
      path: '/post/:id/',
      response: async request => {
        const id = 'id' in request.params ? request.params.id : 0;
        let metas = {};
        let statusCode = 200;
        try {
          const resp = await (
            await fetch(`https://sayhello.ch/wp-json/wp/v2/posts/${id}/`)
          ).json();
          metas = {
            title: resp.title.rendered,
          };
        } catch (error) {
          console.log('Error for /post/:id/');
          statusCode = 404;
        }
        return {
          metas,
          statusCode
        };
      },
    },
  ],
  redirects: [
    {
      path: '/nutzer/:id/',
      to: '/user/:id/',
    },
  ],
  port: 3000, // default 8080
  indexFile: 'index.gtml',
  serveDir: 'dist/',
  errorPagesDir: 'path/to/custom/error/templates/',
  onError: e => console.log(e),
  logLevel: 'ERROR', // 'DEBUG' | 'WARNING' | 'ERROR' | 'SYSTEM'
  serverOptions: {}, // additional options for the node-http server
});

server.config.js

"SPA Server" comes with a handy single executable. npm spa-server (or yarn spa-server) will start the server with default configurations. Additionally it looks for a server.config.js file that expects one default export with all the arguments from above.

// server.config.js
import fetch from 'node-fetch';

export default {
  routes: [
    {
      path: '/myapi/',
      response: async request => {
        const resp = await (
          await fetch(`https://myapi.com/`)
        ).json();
        return {
          metas: {
            title: resp.title,
          },
        }
      },
    },
  ],
  port: 8888,
};

Config

routes

An Array of routes. Each route consists of a path and a response.

The path is defined as a string that will be parsed to a Regex where the matches will be passed to the response.

The response is a function that returns the metas, headers and the statusCode as an object.

export default {
  routes: [
    {
      path: '/:slug/',
      response: request => {
        return {
          metas: {
            title: 'Slug ' + request.params.slug,
          },
          headers: {
            'my-header': 'Hello World'
          },
          statusCode: 200
        }
      },
    }
  ]
};

metascan also be an async function where await can be used.

redirects

With redirects sources and targets where the server immediately returns a 302 status with the target as Location header.

Both, source (path) and target (to) can contain variables:

export default {
  redirects: [
    {
      path: '/my/source/',
      to: '/my/target/',
    },
    {
      path: '/nutzer/:id/', // /nutzer/5/
      to: '/user/:id/', // /user/5/
    },
  ],
};

port

Default port is 8080 but can easily be changed to a different port.

indexFile

In general, most Single Page Applications have an index.html file as an entry point. If for whatever reason your setup has a a different file, it cn be adjusted as well.

serverDir

By default, "SPA Server" expects the whole application inside the dist/ folder. But can be any othe folder.

errorPagesDir

When the server experiences difficulties, it will throw an error page. But you can esily set a custom page yourself. Let's assume you have a page for a 500 error inside en error/ folder:

File: error/500.html:

export default {
  errorPagesDir: 'error/',
};

onError

A callback that will be called whenever anything trows and e 500 will be returned.

logLevel

"SPA Server" is riddled with different logs on specific levels: 'DEBUG' | 'WARNING' | 'ERROR' | 'SYSTEM'.
default: ERROR

serverOptions

If you want to serve your content over HTTPS (SSL) you can pass the path to the key and the cert within the serverOptions:

export default {
  serverOptions: {
    key: 'path/to/ssl/cert.key',
    cert: 'path/to/ssl/cert.crt',
  },
};