├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── bench
├── express.js
├── fastify.js
├── native.js
├── polka.js
└── readme.md
├── examples
├── async-json
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── sub-app
│ ├── index.js
│ ├── package.json
│ ├── readme.md
│ └── users.js
├── with-afterjs
│ ├── .gitignore
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── robots.txt
│ ├── readme.md
│ └── src
│ │ ├── About.js
│ │ ├── Home.css
│ │ ├── Home.js
│ │ ├── client.css
│ │ ├── client.js
│ │ ├── index.js
│ │ ├── react.svg
│ │ ├── routes.js
│ │ └── server.js
├── with-apollo
│ ├── index.js
│ ├── package.json
│ ├── readme.md
│ └── screenshot.png
├── with-body-parser
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── with-firebase-admin
│ ├── .gitignore
│ ├── api
│ │ ├── index.js
│ │ ├── items.js
│ │ └── services.js
│ ├── client
│ │ ├── .babelrc
│ │ ├── index.html
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── tags
│ │ │ ├── App.js
│ │ │ ├── Footer.js
│ │ │ ├── Item.js
│ │ │ ├── Login.js
│ │ │ └── TodoMVC.js
│ │ └── utils
│ │ │ ├── api.js
│ │ │ └── local.js
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── with-graphql
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── with-https
│ ├── index.js
│ ├── package.json
│ ├── readme.md
│ └── ssl
│ │ └── .gitkeep
├── with-morgan
│ ├── index.js
│ ├── items.js
│ ├── package.json
│ ├── readme.md
│ └── util.js
├── with-nextjs
│ ├── .gitignore
│ ├── index.js
│ ├── package.json
│ ├── pages
│ │ ├── about.js
│ │ └── index.js
│ └── readme.md
├── with-nuxtjs
│ ├── .gitignore
│ ├── index.js
│ ├── package.json
│ └── pages
│ │ ├── about.vue
│ │ └── index.vue
├── with-sapper
│ ├── .gitignore
│ ├── assets
│ │ ├── favicon.png
│ │ ├── global.css
│ │ ├── great-success.png
│ │ ├── manifest.json
│ │ ├── svelte-logo-192.png
│ │ └── svelte-logo-512.png
│ ├── package.json
│ ├── readme.md
│ ├── routes
│ │ ├── _components
│ │ │ ├── Layout.html
│ │ │ └── Nav.html
│ │ ├── about.html
│ │ ├── api
│ │ │ └── blog
│ │ │ │ ├── [slug].js
│ │ │ │ ├── _posts.js
│ │ │ │ └── index.js
│ │ ├── blog
│ │ │ ├── [slug].html
│ │ │ └── index.html
│ │ └── index.html
│ ├── server.js
│ ├── templates
│ │ ├── 2xx.html
│ │ ├── 4xx.html
│ │ ├── 5xx.html
│ │ ├── main.js
│ │ └── service-worker.js
│ ├── webpack.client.config.js
│ └── webpack.server.config.js
├── with-serve-static
│ ├── index.js
│ ├── package.json
│ ├── public
│ │ ├── app.js
│ │ ├── index.html
│ │ └── style.css
│ └── readme.md
├── with-server-sent-events
│ ├── index.js
│ ├── package.json
│ ├── public
│ │ └── index.html
│ └── readme.md
├── with-sirv
│ ├── index.js
│ ├── package.json
│ ├── public
│ │ ├── app.js
│ │ ├── index.html
│ │ └── style.css
│ └── readme.md
├── with-socketio
│ ├── index.js
│ ├── package.json
│ ├── public
│ │ ├── index.html
│ │ ├── main.js
│ │ └── style.css
│ └── readme.md
└── with-uws
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── lerna.json
├── license
├── package.json
├── packages
├── polka
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── send-type
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── send
│ ├── index.js
│ ├── package.json
│ └── readme.md
└── url
│ ├── index.js
│ ├── package.json
│ └── readme.md
├── polka.png
├── readme.md
└── tests
├── polka.js
├── send-type.js
├── send.js
├── url.js
└── util
├── index.js
└── mock.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_size = 2
6 | indent_style = tab
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.{json,yml,md}]
13 | indent_style = space
14 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: lukeed
2 | open_collective: polka
3 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | name: Node.js v${{ matrix.nodejs }}
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | nodejs: [8, 10, 12]
12 |
13 | steps:
14 | - uses: actions/checkout@master
15 | with:
16 | fetch-depth: 1
17 | - uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.nodejs }}
20 |
21 | - name: Install
22 | run: |
23 | npm install
24 | npm install -g nyc@13
25 |
26 | - name: Bootstrap, Lint, and Test
27 | run: nyc --exclude=tests npm test
28 |
29 | - name: Report
30 | if: matrix.nodejs >= 12
31 | run: |
32 | nyc report --reporter=text-lcov > coverage.lcov
33 | bash <(curl -s https://codecov.io/bash)
34 | env:
35 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | .nyc_output
4 | coverage
5 | *.lock
6 | *.log
7 |
--------------------------------------------------------------------------------
/bench/express.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 |
3 | function one(req, res, next) {
4 | req.one = true;
5 | next();
6 | }
7 |
8 | function two(req, res, next) {
9 | req.two = true;
10 | next();
11 | }
12 |
13 | express()
14 | .use(one, two)
15 | .get('/favicon.ico', _ => {})
16 | .get('/', (req, res) => res.send('Hello'))
17 | .get('/user/:id', (req, res) => {
18 | res.end(`User: ${req.params.id}`);
19 | })
20 | .listen(3000);
21 |
--------------------------------------------------------------------------------
/bench/fastify.js:
--------------------------------------------------------------------------------
1 | const fastify = require('fastify');
2 |
3 | function one(req, res, next) {
4 | req.one = true;
5 | next();
6 | }
7 |
8 | function two(req, res, next) {
9 | req.two = true;
10 | next();
11 | }
12 |
13 | fastify()
14 | .use(one)
15 | .use(two)
16 | .get('/favicon.ico', _ => {})
17 | .get('/', (_, res) => res.send('Hello'))
18 | .get('/user/:id', (req, res) => {
19 | res.send(`User: ${req.params.id}`);
20 | })
21 | .listen(3000);
22 |
--------------------------------------------------------------------------------
/bench/native.js:
--------------------------------------------------------------------------------
1 | const http = require('http');
2 |
3 | http.createServer((req, res) => {
4 | if (req.url === '/favicon.ico') return;
5 | if (req.url === '/') return res.end('Hello');
6 | }).listen(3000);
7 |
--------------------------------------------------------------------------------
/bench/polka.js:
--------------------------------------------------------------------------------
1 | const polka = require('../packages/polka');
2 |
3 | function one(req, res, next) {
4 | req.one = true;
5 | next();
6 | }
7 |
8 | function two(req, res, next) {
9 | req.two = true;
10 | next();
11 | }
12 |
13 | polka()
14 | .use(one, two)
15 | .get('/favicon.ico', _ => {})
16 | .get('/', (req, res) => res.end('Hello'))
17 | .get('/user/:id', (req, res) => {
18 | res.end(`User: ${req.params.id}`);
19 | })
20 | .listen(3000);
21 |
--------------------------------------------------------------------------------
/bench/readme.md:
--------------------------------------------------------------------------------
1 | # Benchmarks
2 |
3 | All apps employ two global middlewares with `req` mutations, an empty `GET` route handler for `favicon.ico` and a `GET` handler for the `/users/:id`, returning a `User: {id}` string response.
4 |
5 | Results are taken after 1 warm-up run. The tool used for results is the following:
6 |
7 | ```sh
8 | $ wrk -t8 -c100 -d30s http://localhost:3000/user/123
9 | ```
10 |
11 | > Please remember that _your application code_ is most likely the slowest part of your application!
Switching from Express to Polka will (likely) not guarantee the same performance gains.
12 |
13 |
14 | ## Node v9.1.0
15 |
16 | ```
17 | #=> POLKA
18 | Thread Stats Avg Stdev Max +/- Stdev
19 | Latency 2.39ms 173.68us 7.90ms 89.40%
20 | Req/Sec 5.03k 110.03 5.80k 70.42%
21 | 1204800 requests in 30.10s, 124.09MB read
22 | Requests/sec: 40022.18
23 | Transfer/sec: 4.12MB
24 |
25 | #=> EXPRESS
26 | Thread Stats Avg Stdev Max +/- Stdev
27 | Latency 3.24ms 388.15us 9.84ms 92.78%
28 | Req/Sec 3.72k 105.01 4.38k 63.96%
29 | 889146 requests in 30.01s, 111.08MB read
30 | Requests/sec: 29623.83
31 | Transfer/sec: 3.70MB
32 | ```
33 |
34 | ## Node v8.9.0
35 |
36 | ```
37 | #=> POLKA
38 | Thread Stats Avg Stdev Max +/- Stdev
39 | Latency 2.59ms 186.29us 5.82ms 67.71%
40 | Req/Sec 4.66k 142.28 5.29k 68.67%
41 | 1115653 requests in 30.10s, 114.91MB read
42 | Requests/sec: 37059.21
43 | Transfer/sec: 3.82MB
44 |
45 | #=> EXPRESS
46 | Thread Stats Avg Stdev Max +/- Stdev
47 | Latency 3.41ms 347.21us 8.07ms 69.60%
48 | Req/Sec 3.53k 104.84 3.91k 69.83%
49 | 844077 requests in 30.01s, 105.45MB read
50 | Requests/sec: 28127.26
51 | Transfer/sec: 3.51MB
52 | ```
53 |
54 |
55 | ## Node v6.11.1
56 |
57 | ```
58 | #=> POLKA
59 | Thread Stats Avg Stdev Max +/- Stdev
60 | Latency 3.16ms 208.50us 6.93ms 75.13%
61 | Req/Sec 3.82k 101.28 5.34k 75.58%
62 | 911888 requests in 30.01s, 93.92MB read
63 | Requests/sec: 30384.16
64 | Transfer/sec: 3.13MB
65 |
66 | #=> EXPRESS
67 | Thread Stats Avg Stdev Max +/- Stdev
68 | Latency 4.61ms 289.07us 14.19ms 75.35%
69 | Req/Sec 2.61k 62.88 2.92k 70.71%
70 | 623917 requests in 30.01s, 77.95MB read
71 | Requests/sec: 20788.27
72 | Transfer/sec: 2.60MB
73 | ```
74 |
--------------------------------------------------------------------------------
/examples/async-json/index.js:
--------------------------------------------------------------------------------
1 | const fetch = require('node-fetch');
2 | const send = require('@polka/send-type');
3 | const polka = require('polka');
4 |
5 | const { PORT=3000 } = process.env;
6 | const API = 'https://hnpwa.com/api/v0';
7 |
8 | function load(type) {
9 | return fetch(`${API}/${type}.json`).then(r => r.json());
10 | }
11 |
12 | polka()
13 | .get('/:type?', async (req, res) => {
14 | let type = req.params.type || 'news';
15 | let data = await load(type).catch(err => {
16 | send(res, 404);
17 | });
18 | send(res, 200, data);
19 | })
20 | .listen(PORT, () => {
21 | console.log(`> Running on localhost:${PORT}`);
22 | });
23 |
--------------------------------------------------------------------------------
/examples/async-json/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "@polka/send-type": "latest",
7 | "node-fetch": "^2.6.1",
8 | "polka": "latest"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/async-json/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Async
2 |
3 | > **WARNING** This will only work with Node 7.4 or later!
4 |
5 | This example makes use of Node's built-in `async`/`await` — no compiling required!
6 |
7 | It forwards all requests to [HNPWA's JSON API](https://hnpwa.com/), utilizing [`node-fetch`](https://github.com/bitinn/node-fetch) for the server-side requests.
8 |
9 | ## Setup
10 |
11 | ```sh
12 | $ npm install
13 | $ npm start
14 | ```
15 |
16 | ## Usage
17 |
18 | There are only a few valid paths: `/`, `/news`, `/newest`, `/jobs`, `/ask`, and `/show`.
19 |
20 | Anything else will return `(404) Not Found`.
21 |
22 | ```sh
23 | $ curl localhost:3000
24 | #=> (200) JSON
25 | $ curl localhost:3000/news
26 | #=> (200) JSON
27 | $ curl localhost:3000/foobar
28 | #=> (404) Not Found
29 | ```
30 |
--------------------------------------------------------------------------------
/examples/sub-app/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const users = require('./users');
3 |
4 | const { PORT=3000 } = process.env;
5 |
6 | function reply(req, res) {
7 | res.end(`Main: Hello from ${req.method} ${req.url}`);
8 | }
9 |
10 | // Main app
11 | polka()
12 | .get('/', reply)
13 | .get('/about', reply)
14 | .use('users', users)
15 | .listen(PORT, () => {
16 | console.log(`> Running on localhost:${PORT}`);
17 | });
18 |
--------------------------------------------------------------------------------
/examples/sub-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "polka": "latest"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/sub-app/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Sub-Application
2 |
3 | This example mounts a `/users` sub-application onto the "main" application.
4 |
5 | ## Setup
6 |
7 | ```sh
8 | $ npm install
9 | $ npm start
10 | ```
11 |
12 | ## Usage
13 |
14 | ```sh
15 | $ curl localhost:3000
16 | #=> (200) Main: Hello from GET /
17 |
18 | $ curl localhost:3000/about
19 | #=> (200) Main: Hello from GET /about
20 |
21 | $ curl localhost:3000/users
22 | #=> (200) Sub: Howdy from GET /users
23 |
24 | $ curl localhost:3000/users/123
25 | #=> (200) Sub: Howdy from GET /users/123
26 |
27 | $ curl -X PUT localhost:3000/users/123
28 | #=> (201) Sub: Updated user via PUT /users/123
29 | ```
30 |
--------------------------------------------------------------------------------
/examples/sub-app/users.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 |
3 | module.exports = polka()
4 | .get('/:id?', (req, res) => {
5 | res.end(`Sub: Howdy from ${req.method} ${req.url}`);
6 | })
7 | .put('/:id', (req, res) => {
8 | res.statusCode = 201; // why not?
9 | res.end(`Sub: Updated user via ${req.method} ${req.url}`);
10 | });
11 |
--------------------------------------------------------------------------------
/examples/with-afterjs/.gitignore:
--------------------------------------------------------------------------------
1 | .env.*.local
2 | build
3 |
--------------------------------------------------------------------------------
/examples/with-afterjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "razzle start",
4 | "build": "razzle build",
5 | "test": "razzle test --env=jsdom",
6 | "start:prod": "NODE_ENV=production node build/server.js"
7 | },
8 | "dependencies": {
9 | "@jaredpalmer/after": "latest",
10 | "polka": "latest",
11 | "razzle": "^0.8.11",
12 | "react": "^16.2.0",
13 | "react-dom": "^16.2.0",
14 | "react-helmet": "^5.2.0",
15 | "react-router-dom": "^4.2.2",
16 | "serve-static": "^1.13.2"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/with-afterjs/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-afterjs/public/favicon.ico
--------------------------------------------------------------------------------
/examples/with-afterjs/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 |
--------------------------------------------------------------------------------
/examples/with-afterjs/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Razzle + After.js
2 |
3 | > Ported from Razzle's [`examples/with-afterjs`](https://github.com/jaredpalmer/razzle/tree/master/examples/with-afterjs) — _nearly_ identical!
4 |
5 | This example combines Polka with [Razzle](https://github.com/jaredpalmer/razzle) and [After.js](https://github.com/jaredpalmer/after.js), creating a robust & performant server-rendered React application.
6 |
7 | Setup includes a production build, a production server, and live-reload [HMR](https://webpack.js.org/concepts/hot-module-replacement/) for _both_ client and server! :tada:
8 |
9 | ## Setup
10 |
11 | ```sh
12 | $ npm install
13 | # develop / HMR
14 | $ npm start
15 | # production
16 | $ npm run build
17 | $ npm run start:prod
18 | ```
19 |
20 | ## Usage
21 |
22 | Open a browser to `localhost:3000`!
23 |
24 | To use the built-in live-reload / HMR development server, run:
25 |
26 | ```sh
27 | $ npm start
28 | ```
29 |
30 | > The dev-server also runs on Polka! :dancers:
31 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/About.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export default class About extends Component {
4 | render() {
5 | return
about
;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/Home.css:
--------------------------------------------------------------------------------
1 | .Home {
2 | text-align: center;
3 | }
4 | .Home-logo {
5 | animation: logo-spin infinite 20s linear;
6 | height: 80px;
7 | }
8 |
9 | .Home-header {
10 | background-color: #222;
11 | height: 150px;
12 | padding: 20px;
13 | color: white;
14 | }
15 |
16 | .Home-intro {
17 | font-size: large;
18 | }
19 |
20 | .Home-resources {
21 | list-style: none;
22 | }
23 |
24 | .Home-resources > li {
25 | display: inline-block;
26 | padding: 1rem;
27 | }
28 |
29 | @keyframes logo-spin {
30 | from {
31 | transform: rotate(0deg);
32 | }
33 | to {
34 | transform: rotate(360deg);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './react.svg';
3 | import './Home.css';
4 | import { Link } from 'react-router-dom';
5 |
6 | export default class Home extends Component {
7 | static async getInitialProps({ req, res, match, history, location, ...ctx }) {
8 | return { whatever: 'stuff' };
9 | }
10 |
11 | render() {
12 | return (
13 |
14 |
15 |

16 |
Welcome to After.js
17 |
18 |
19 | To get started, edit src/Home.js
or{' '}
20 | src/About.js
and save to reload.
21 |
22 |
About ->
23 |
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/client.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
5 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
6 | }
7 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/client.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { hydrate } from 'react-dom';
3 | import { BrowserRouter } from 'react-router-dom';
4 | import { ensureReady, After } from '@jaredpalmer/after';
5 | import './client.css';
6 | import routes from './routes';
7 |
8 | ensureReady(routes).then(data =>
9 | hydrate(
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | )
15 | );
16 |
17 | if (module.hot) {
18 | module.hot.accept();
19 | }
20 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/index.js:
--------------------------------------------------------------------------------
1 | import app from './server';
2 |
3 | let { handler, server } = app;
4 |
5 | server.listen(process.env.PORT || 3000, () => {
6 | console.log('🚀 started');
7 | });
8 |
9 | if (module.hot) {
10 | console.log('✅ Server-side HMR Enabled!');
11 |
12 | module.hot.accept('./server', () => {
13 | console.log('🔁 HMR Reloading `./server`...');
14 | server.removeListener('request', handler);
15 | let nxt = require('./server').default;
16 | server.on('request', nxt.handler);
17 | handler = nxt.handler;
18 | });
19 | }
20 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { asyncComponent } from '@jaredpalmer/after';
4 |
5 | export default [
6 | {
7 | path: '/',
8 | exact: true,
9 | component: asyncComponent({
10 | loader: () => import('./Home'), // required
11 | Placeholder: () => ...LOADING...
, // this is optional, just returns null by default
12 | }),
13 | },
14 | {
15 | path: '/about',
16 | exact: true,
17 | component: asyncComponent({
18 | loader: () => import('./About'), // required
19 | Placeholder: () => ...LOADING...
, // this is optional, just returns null by default
20 | }),
21 | },
22 | ];
23 |
--------------------------------------------------------------------------------
/examples/with-afterjs/src/server.js:
--------------------------------------------------------------------------------
1 | import polka from 'polka';
2 | import { render } from '@jaredpalmer/after';
3 | import serve from 'serve-static';
4 | import routes from './routes';
5 |
6 | const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);
7 | const statics = serve(process.env.RAZZLE_PUBLIC_DIR);
8 |
9 | const server = polka();
10 |
11 | server
12 | .use(statics)
13 | .get('/*', async (req, res) => {
14 | try {
15 | const html = await render({
16 | req,
17 | res,
18 | routes,
19 | assets,
20 | // Anything else you add here will be made available
21 | // within getInitialProps(ctx)
22 | // e.g a redux store...
23 | customThing: 'thing',
24 | });
25 | res.end(html);
26 | } catch (error) {
27 | let json = JSON.stringify(error);
28 | res.setHeader('Content-Type', 'application/json');
29 | res.setHeader('Content-Length', json.length);
30 | res.end(json);
31 | }
32 | });
33 |
34 | export default server;
35 |
--------------------------------------------------------------------------------
/examples/with-apollo/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { json } = require('body-parser');
3 | const { makeExecutableSchema } = require('graphql-tools');
4 | const { graphqlExpress, graphiqlExpress } = require('apollo-server-express');
5 |
6 | const { PORT=3000 } = process.env;
7 |
8 | const tasks = [
9 | { id: 1, name: 'Go to Market', complete: false },
10 | { id: 2, name: 'Walk the dog', complete: true },
11 | { id: 3, name: 'Take a nap', complete: false }
12 | ];
13 |
14 | const typeDefs = `
15 | type Task {
16 | id: Int!
17 | name: String!
18 | complete: Boolean!
19 | }
20 |
21 | type Query {
22 | tasks: [Task]
23 | task(id: Int!): Task
24 | }
25 | `;
26 |
27 | const resolvers = {
28 | Query: {
29 | tasks: () => tasks,
30 | task: (_, args) => tasks.find(o => o.id === args.id)
31 | }
32 | };
33 |
34 | const schema = module.exports = makeExecutableSchema({ typeDefs, resolvers });
35 |
36 | polka()
37 | .use(json())
38 | .post('/graphql', graphqlExpress(req => ({
39 | schema
40 | })))
41 | .get('/graphiql', graphiqlExpress({
42 | endpointURL: '/graphql'
43 | }))
44 | .listen(PORT, () => {
45 | console.log(`> Ready on localhost:${PORT}`)
46 | });
47 |
--------------------------------------------------------------------------------
/examples/with-apollo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "apollo-server-express": "^1.3.6",
7 | "body-parser": "^1.18.3",
8 | "graphql": "^0.13.2",
9 | "graphql-tools": "^3.0.2",
10 | "polka": "latest"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/examples/with-apollo/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Apollo Graphql
2 |
3 | Tiny example with [Apollo Graphql](https://www.apollographql.com/)
4 |
5 | It uses the [`Apollo Server`](https://github.com/apollographql/apollo-server) a community-maintained open-source GraphQL server.
6 |
7 | ## Setup
8 | ```sh
9 | $ npm install
10 | $ npm start
11 | ```
12 |
13 | ## Usage
14 | You can use it with any apollo client or with the [Graphiql](https://github.com/graphql/graphiql) in [localhost](http://localhost:3000/graphiql)
15 |
16 | ## Available queries
17 | ```
18 | {
19 | tasks {
20 | id
21 | name
22 | complete
23 | }
24 | }
25 | ```
26 |
27 | ```
28 | {
29 | task (id: Int!) {
30 | id
31 | name
32 | complete
33 | }
34 | }
35 | ```
36 |
37 | 
38 |
--------------------------------------------------------------------------------
/examples/with-apollo/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-apollo/screenshot.png
--------------------------------------------------------------------------------
/examples/with-body-parser/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { json } = require('body-parser');
3 | const { PORT=3000 } = process.env;
4 |
5 | polka()
6 | .use(json())
7 | .post('/', (req, res) => {
8 | res.writeHead(200, { 'Content-Type': 'application/json' });
9 | let json = JSON.stringify(req.body);
10 | res.end(json);
11 | })
12 | .listen(PORT, () => {
13 | console.log(`> Running on localhost:${PORT}`);
14 | });
15 |
--------------------------------------------------------------------------------
/examples/with-body-parser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "body-parser": "^1.18.2",
7 | "polka": "latest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/with-body-parser/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Body Parser
2 |
3 | Tiny example that echoes the JSON that it received.
4 |
5 | It uses the popular [`body-parser`](https://github.com/expressjs/body-parser) middleware from Express to _parse_ the incoming body. As per the middleware behavior, an object is made available at the `req.body` location.
6 |
7 | ## Setup
8 |
9 | ```sh
10 | $ npm install
11 | $ npm start
12 | ```
13 |
14 | ## Usage
15 |
16 | There is only one route (`POST /`) for the purpose of this demo.
17 |
18 | ```sh
19 | $ curl localhost:3000
20 | #=> (501) Not Implemented
21 |
22 | $ curl localhost:3000 -X POST -d '{"hello":"world"}'
23 | #=> (200) {}
24 |
25 | $ curl localhost:3000 -X POST -d '{"hello":"world"}' -H "content-type: application/json"
26 | #=> (200) {"hello":"world"}
27 | ```
28 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/.gitignore:
--------------------------------------------------------------------------------
1 | firebase.json
2 | secret.json
3 | .cache
4 | dist
5 | public
6 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/api/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const items = require('./items');
3 |
4 | module.exports = polka().use('items', items);
5 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/api/items.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const send = require('@polka/send-type');
3 | const { DB, isUser } = require('./services');
4 |
5 | const ITEMS = DB.ref('items');
6 |
7 | module.exports = polka()
8 | .use(isUser) // verify token
9 | .get('/', (req, res) => {
10 | ITEMS.once('value').then(s => {
11 | let k, out=[], obj=s.val();
12 | for (k in obj) {
13 | (obj[k].id=k) && out.push(obj[k]);
14 | }
15 | send(res, 200, out);
16 | });
17 | })
18 | .post('/', (req, res) => {
19 | let obj = req.body;
20 | ITEMS.push(req.body).then(data => {
21 | obj.id = data.key;
22 | send(res, 201, obj);
23 | });
24 | })
25 | .get('/:id', (req, res) => {
26 | ITEMS.child(req.params.id).then(s => {
27 | let obj = s.val();
28 | obj.id = s.key;
29 | send(res, 200, obj);
30 | });
31 | })
32 | .put('/:id', (req, res) => {
33 | let obj = req.body;
34 | ITEMS.child(req.params.id).set(obj).then(data => {
35 | send(res, 200, obj);
36 | });
37 | })
38 | .delete('/:id', (req, res) => {
39 | ITEMS.child(req.params.id).remove().then(_ => {
40 | send(res, 204);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/api/services.js:
--------------------------------------------------------------------------------
1 | const send = require('@polka/send-type');
2 | const firebase = require('firebase-admin');
3 | const secret = require('../secret.json');
4 |
5 | firebase.initializeApp({
6 | credential: firebase.credential.cert(secret),
7 | databaseURL: 'https://temp123-1414d.firebaseio.com'
8 | });
9 |
10 | const Auth = exports.Auth = firebase.auth();
11 | const DB = exports.DB = firebase.database();
12 |
13 | // Middleware: Authenticate Incoming Request
14 | exports.isUser = (req, res, next) => {
15 | let token = req.headers['authorization'];
16 | if (!token) return send(res, 401, 'Token not found.');
17 | token = token.split(' ')[1]; // strip "Bearer"
18 | Auth.verifyIdToken(token)
19 | .then(user => (req.user=user) && next())
20 | .catch(err => send(res, 401, 'Invalid token.'));
21 | };
22 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "comments": false,
3 | "presets": [
4 | ["env", {
5 | "loose": true,
6 | "uglify": true,
7 | "modules": false,
8 | "exclude": [
9 | "transform-regenerator",
10 | "transform-es2015-typeof-symbol"
11 | ]
12 | }]
13 | ],
14 | "plugins": [
15 | "transform-class-properties",
16 | "transform-react-constant-elements",
17 | ["transform-react-jsx", { "pragma": "h" }],
18 | ["jsx-pragmatic", {
19 | "module": "preact",
20 | "export": "h",
21 | "import": "h"
22 | }]
23 | ]
24 | }
25 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Polka • Firebase • Preact • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/index.js:
--------------------------------------------------------------------------------
1 | import { h, render } from 'preact';
2 | import App from './tags/App';
3 | import 'todomvc-app-css';
4 |
5 | let root = document.getElementById('root');
6 | let diff = root.firstElementChild;
7 | diff = render(, root, diff);
8 |
9 | if (module.hot) {
10 | module.hot.accept();
11 | }
12 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "build": "parcel build -d ../public index.html",
5 | "watch": "parcel watch -d ../public index.html"
6 | },
7 | "dependencies": {
8 | "is-ready": "^1.0.0",
9 | "obj-str": "^1.0.0",
10 | "preact": "^8.2.7",
11 | "preact-router": "^2.6.0",
12 | "todomvc-app-css": "^2.1.0",
13 | "todomvc-common": "^1.0.4"
14 | },
15 | "devDependencies": {
16 | "babel-plugin-jsx-pragmatic": "^1.0.2",
17 | "babel-plugin-transform-class-properties": "^6.24.1",
18 | "babel-plugin-transform-react-constant-elements": "^6.23.0",
19 | "babel-plugin-transform-react-jsx": "^6.24.1",
20 | "babel-preset-env": "^1.6.1",
21 | "parcel-bundler": "^1.5.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/tags/App.js:
--------------------------------------------------------------------------------
1 | import isReady from 'is-ready';
2 | import { h, Component } from 'preact';
3 | import { Router, route } from 'preact-router';
4 | import { isUser } from '../utils/local';
5 | import CONFIG from '../firebase.json';
6 | import TodoMVC from './TodoMVC';
7 | import Login from './Login';
8 |
9 | export default class App extends Component {
10 | state = { user:isUser() }
11 |
12 | onRoute = obj => {
13 | let isUser = !!this.state.user;
14 | let isLogin = !!~obj.url.indexOf('login');
15 | if (!isUser) return route('/login', true);
16 | if (isUser && isLogin) return route('/', true);
17 | }
18 |
19 | componentWillMount() {
20 | isReady('firebase').then(_ => {
21 | let user = this.state.user;
22 | let app = firebase.initializeApp(CONFIG)
23 | isReady('firebase.auth').then(_ => {
24 | app.auth().onAuthStateChanged(obj => {
25 | let isNew = (!!user !== !!obj);
26 | this.setState({ user:obj }, _ => {
27 | isNew && route(obj ? '/' : '/login', true);
28 | });
29 | });
30 | });
31 | });
32 | }
33 |
34 | render(_, state) {
35 | return (
36 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/tags/Footer.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'preact-router/match';
2 |
3 | export default function (props) {
4 | let num = props.active;
5 | let now = props.filter;
6 |
7 | return (
8 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/tags/Item.js:
--------------------------------------------------------------------------------
1 | import cx from 'obj-str';
2 | import { h, Component } from 'preact';
3 |
4 | export default class TodoItem extends Component {
5 | state = { text:'' }
6 |
7 | onSubmit = e => {
8 | if (!this.props.editing) return;
9 | let obj = this.props.data;
10 | let val = e.target.value.trim();
11 | val ? this.props.onSave(obj, val): this.props.onDestroy(obj);
12 | }
13 |
14 | handleEdit = () => {
15 | let obj = this.props.data;
16 | this.setState({ text:obj.title });
17 | this.props.onEdit(obj.id);
18 | }
19 |
20 | onToggle = e => {
21 | e.preventDefault();
22 | let obj = this.props.data;
23 | this.props.onToggle(obj);
24 | }
25 |
26 | onKeydown = e => {
27 | if (e.which === 13) {
28 | this.onSubmit(e);
29 | } else if (e.which === 27) {
30 | this.setState({ text:'' });
31 | this.props.onCancel();
32 | }
33 | }
34 |
35 | onDelete = () => {
36 | this.props.onDestroy(this.props.data);
37 | }
38 |
39 | componentDidUpdate() {
40 | let node = this.base && this.base.querySelector('.edit');
41 | if (node) node.focus();
42 | }
43 |
44 | render(props, state) {
45 | let editing = props.editing;
46 | let { title, completed } = props.data;
47 |
48 | return (
49 |
50 |
51 |
52 |
53 |
54 |
55 | { editing && (
56 |
58 | ) }
59 |
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/tags/Login.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'preact';
2 |
3 | export default class Login extends Component {
4 | state = { email:'', password:'' }
5 |
6 | onSubmit = ev => {
7 | ev.preventDefault();
8 | let { email, password } = this.state;
9 | if (!email || !password) return console.error('[TODO]: An email and password are required!');
10 | firebase.auth().signInWithEmailAndPassword(email, password).catch(err => {
11 | console.error('[AUTH]', err.message);
12 | }).then(data => {
13 | console.log('> data', data);
14 | })
15 | }
16 |
17 | onInput = key => ev => {
18 | this.setState({ [key]: ev.target.value });
19 | }
20 |
21 | render() {
22 | return (
23 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/tags/TodoMVC.js:
--------------------------------------------------------------------------------
1 | import isReady from 'is-ready';
2 | import { Component } from 'preact';
3 | import { get, post, put, del } from '../utils/api';
4 | import TodoFooter from './Footer';
5 | import TodoItem from './Item';
6 |
7 | const toAuth = str => (str && { Authorization:`Bearer: ${str}` });
8 |
9 | const FILTERS = {
10 | all: obj => true,
11 | active: obj => !obj.completed,
12 | completed: obj => obj.completed
13 | };
14 |
15 | export default class Todos extends Component {
16 | state = { editing:'', items:[], filter:'all' }
17 |
18 | onAddItem = e => {
19 | if (e.keyCode !== 13) return;
20 | let title = e.target.value.trim();
21 | if (!title) return; // exit
22 | let items = this.state.items;
23 | post('items', { completed:false, title }).then(obj => {
24 | this.setState({ items:items.concat(obj) });
25 | e.target.value = null; // reset
26 | });
27 | }
28 |
29 | onEdit = id => this.setState({ editing:id })
30 | onCancel = _ => this.setState({ editing:null })
31 |
32 | onSave = (obj, text) => {
33 | obj.title = text;
34 | put(`items/${obj.id}`, obj).then(_ => {
35 | let items = this.state.items.map(x => x.id === obj.id ? obj : x);
36 | this.setState({ editing:null, items });
37 | });
38 | }
39 |
40 | onToggle = obj => {
41 | obj.completed = !obj.completed;
42 | put(`items/${obj.id}`, obj).then(_ => {
43 | let items = this.state.items.map(x => x.id === obj.id ? obj : x);
44 | this.setState({ items });
45 | });
46 | }
47 |
48 | clearCompleted = e => {
49 | let items = this.state.items;
50 | return Promise.all(
51 | items.filter(FILTERS.completed).map(o => del(`items/${o.id}`))
52 | ).then(_ => {
53 | this.setState({
54 | items: items.filter(FILTERS.active)
55 | });
56 | });
57 | }
58 |
59 | onDestroy = obj => {
60 | let id = obj.id;
61 | del(`items/${id}`).then(_ => {
62 | let items = this.state.items.filter(x => x.id !== id);
63 | this.setState({ items });
64 | });
65 | }
66 |
67 | componentDidMount() {
68 | let filter = this.props.filter || 'all';
69 | get('items').then(arr => {
70 | this.setState({ items:arr, filter });
71 | });
72 | }
73 |
74 | componentWillReceiveProps(nxt) {
75 | this.setState({ filter:nxt.filter || 'all' });
76 | }
77 |
78 | render(_, state) {
79 | let items = state.items;
80 | let visible = items.filter(FILTERS[state.filter]);
81 | let numActive = items.reduce((x, obj) => x + Number(!obj.completed), 0);
82 | let numComplete = items.length - numActive;
83 |
84 | return (
85 |
86 |
92 |
93 | {
94 | items.length > 0 && (
95 |
110 | )
111 | }
112 |
113 | {
114 | (numActive || numComplete) > 0 && (
115 |
117 | )
118 | }
119 |
120 | );
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/utils/api.js:
--------------------------------------------------------------------------------
1 | import { getToken } from './local';
2 |
3 | const API = '/api/';
4 |
5 | const HEADERS = {
6 | 'Content-Type': 'application/json;charset=UTF-8',
7 | 'Accept': 'application/json, text/plain, */*'
8 | };
9 |
10 | function handle(r) {
11 | let act = r.ok ? 'resolve' : 'reject';
12 | let type = r.status === 204 ? 'text' : 'json';
13 | return r[type]().then(data => Promise[act](data));
14 | }
15 |
16 | function send(method, uri, data, opts) {
17 | opts = opts || {};
18 | opts.method = method;
19 | opts.headers = HEADERS;
20 | let token = getToken(); // fresh check on localstorage
21 | token && (opts.headers.Authorization = `Bearer ${token}`);
22 | data && (opts.body = JSON.stringify(data));
23 | return fetch(`${API}${uri}`, opts).then(handle);
24 | }
25 |
26 | export const get = send.bind(null, 'get');
27 | export const put = send.bind(null, 'put');
28 | export const post = send.bind(null, 'post');
29 | export const del = send.bind(null, 'delete');
30 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/client/utils/local.js:
--------------------------------------------------------------------------------
1 | import CONFIG from '../firebase.json';
2 |
3 | const STORAGE = localStorage;
4 | const KEYID = `firebase:authUser:${CONFIG.apiKey}:[DEFAULT]`;
5 |
6 | export function isUser() {
7 | let str = STORAGE.getItem(KEYID);
8 | return str && JSON.parse(str);
9 | }
10 |
11 | export function getToken() {
12 | let user = isUser() || {};
13 | return (user.stsTokenManager || {}).accessToken;
14 | }
15 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { json } = require('body-parser');
3 | const cors = require('cors')({ origin:true });
4 | const serve = require('serve-static')('public');
5 | const compress = require('compression')();
6 |
7 | const { PORT=3000 } = process.env;
8 |
9 | polka()
10 | .use(cors, compress, json(), serve)
11 | .use('api', require('./api'))
12 | .listen(PORT, () => {
13 | console.log(`> Running on localhost:${PORT}`);
14 | });
15 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "@polka/send-type": "latest",
7 | "body-parser": "^1.18.2",
8 | "compression": "^1.7.1",
9 | "cors": "^2.8.4",
10 | "firebase-admin": "^5.8.1",
11 | "polka": "latest",
12 | "serve-static": "^1.13.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/examples/with-firebase-admin/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Firebase-Admin TodoMVC
2 |
3 | This example uses Polka as an API layer (via [`firebase-admin`](https://www.npmjs.com/package/firebase-admin)) and as a static asset server (via [`serve-static`](https://www.npmjs.com/package/serve-static)).
4 |
5 | It's also using [Parcel](https://github.com/parcel-bundler/parcel), a zero-config bundler, to compile a [Preact](https://github.com/developit/preact) implementation of the [TodoMVC](http://todomvc.com) application.
6 |
7 | Once up and running, you will be forced to Register/Login (`/login`) before accessing the TodoMVC app. All TodoMVC actions are sent to the Firebase Real-time Database for confirmation _before_ applying the change(s) in the browser.
8 |
9 | > This is partly to illustrate how quickly the Firebase RTDB operates!
10 |
11 | ## Setup
12 |
13 | 1. You must create a [new Firebase project](https://firebase.google.com/docs/web/setup)
14 |
15 | _For the purposes of this demo, it's free!_
16 |
17 | 2. You must retrieve a [Firebase Service Account](https://firebase.google.com/docs/admin/setup#add_firebase_to_your_app).
18 |
19 | _**Hint:** Click "Generate New Private Key"_
20 |
21 | 3. Save the Account credentials to `with-firebase/secret.json`
22 |
23 | _This file is accessed inside `with-firebase/api/services.js` to connect to your Database._
24 |
25 | 4. Save your [Firebase WEB config](https://firebase.google.com/docs/database/web/start) to `with-firebase/client/firebase.json`.
26 |
27 | _This is used to connect the Firebase client to your Database from within the browser._
28 |
29 | 5. Install & build dependencies
30 |
31 | ```sh
32 | # Install server dependencies
33 | $ npm install
34 | # Install client dependencies & build
35 | $ cd client && npm install && npm run build
36 | # Run the server!
37 | $ cd .. && npm start
38 | ```
39 |
40 | ## Usage
41 |
42 | Open a browser to `localhost:3000`!
43 |
44 | You can also try interacting with the API, but all routes require a Firebase Token identifier.
45 | > AKA, it won't work :D
46 |
47 | ```sh
48 | $ curl localhost:3000/api/items
49 | #=> (401) Token not found.
50 |
51 | $ curl -H "Authorization: Bearer foobar" localhost:3000/api/items
52 | #=> (401) Invalid token.
53 | ```
54 |
--------------------------------------------------------------------------------
/examples/with-graphql/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { json } = require('body-parser');
3 | const send = require('@polka/send-type');
4 | const { graphql, buildSchema } = require('graphql');
5 |
6 | const { PORT=3000 } = process.env;
7 |
8 | const tasks = [
9 | { id:1, name:'Go to Market', complete:false },
10 | { id:2, name:'Walk the dog', complete:true },
11 | { id:3, name:'Take a nap', complete:false }
12 | ];
13 |
14 | const schema = buildSchema(`
15 | type Task {
16 | id: Int!
17 | name: String!
18 | complete: Boolean!
19 | }
20 |
21 | type Query {
22 | tasks: [Task]
23 | task(id: Int!): Task
24 | }
25 | `);
26 |
27 | let ctx = {
28 | tasks: () => tasks,
29 | task: (args) => tasks.find(o => o.id === args.id)
30 | };
31 |
32 | polka()
33 | .use(json())
34 | .post('/', (req, res) => {
35 | let { query } = req.body;
36 | // We could use `async` & `await` here
37 | // but requires Node 8.x environment to run
38 | graphql(schema, query, ctx).then(data => {
39 | send(res, 200, data);
40 | });
41 | })
42 | .listen(PORT, () => {
43 | console.log(`> Ready on localhost:${PORT}`);
44 | });
45 |
--------------------------------------------------------------------------------
/examples/with-graphql/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "@polka/send-type": "^0.3.4",
7 | "body-parser": "^1.18.2",
8 | "graphql": "^0.13.1",
9 | "polka": "^0.3.4"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples/with-graphql/readme.md:
--------------------------------------------------------------------------------
1 | # Example: GraphQL
2 |
3 | Tiny example that exposes a [GraphQL](https://github.com/graphql/graphql-js) API via JSON queries.
4 |
5 | It uses the popular [`body-parser`](https://github.com/expressjs/body-parser) middleware from Express to _parse_ the incoming body. As per the middleware behavior, an object is made available at the `req.body` location.
6 |
7 | An inline `tasks` dataset is included for this example -- you wouldn't do this in a real project! :laughing:
8 |
9 | > _Disclaimer:_ I don't actually use GraphQL, so am not sure if this is the best way to handle it in a Node.js server.
It seems to work just fine without a load of dependencies; however, there are many ways & tools available!
10 |
11 | ## Setup
12 |
13 | ```sh
14 | $ npm install
15 | $ npm start
16 | ```
17 |
18 | ## Usage
19 |
20 | There is only one route (`POST /`) for the purpose of this demo.
21 |
22 | ```sh
23 | $ curl localhost:3000
24 | #=> (404) Not Found
25 |
26 | $ curl localhost:3000 -d '{"query":"{ tasks { id, name, complete } }"}' -H "content-type: application/json"
27 | #=> (200) {"data": {"tasks": [...] }}
28 |
29 | $ curl localhost:3000 -d '{"query":"{ task(id:2) { name, complete } }"}' -H "content-type: application/json"
30 | #=> (200) {"data":{"task":{"name":"Walk the dog","complete":true}}}
31 | ```
32 |
--------------------------------------------------------------------------------
/examples/with-https/index.js:
--------------------------------------------------------------------------------
1 | const { createServer } = require('https');
2 | const { readFileSync } = require('fs');
3 | const polka = require('polka');
4 |
5 | const { PORT=3000 } = process.env;
6 |
7 | const options = {
8 | key: readFileSync('ssl/foobar.key'),
9 | cert: readFileSync('ssl/foobar.crt')
10 | };
11 |
12 | // Main app
13 | const { handler } = polka().get('*', (req, res) => {
14 | res.end(`POLKA: Hello from ${req.pathname}`);
15 | });
16 |
17 | // Mount Polka to HTTPS server
18 | createServer(options, handler).listen(PORT, _ => {
19 | console.log(`> Running on https://localhost:${PORT}`);
20 | });
21 |
--------------------------------------------------------------------------------
/examples/with-https/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "polka": "^0.2.3"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/with-https/readme.md:
--------------------------------------------------------------------------------
1 | # Example: HTTPS
2 |
3 | This example shows how to mount Polka inside a HTTPS server.
4 |
5 | All requests are handled by Polka, echoing the `req.pathname` it received.
6 |
7 | ## Setup
8 |
9 | ```sh
10 | $ npm install
11 | # Import or Generate SSL keys
12 | $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ssl/foobar.key -out ssl/foobar.crt
13 | $ npm start
14 | ```
15 |
16 | > **Note:** You'll likely see a "Not Secure" warning — it's because of the fake certificate we just generated.
17 |
18 | ## Usage
19 |
20 | ```sh
21 | $ curl -k https://localhost:3000
22 | #=> (200) POLKA: Hello from /
23 |
24 | $ curl -k https://localhost:3000/users/123
25 | #=> (200) POLKA: Hello from /users/123
26 | ```
27 |
--------------------------------------------------------------------------------
/examples/with-https/ssl/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-https/ssl/.gitkeep
--------------------------------------------------------------------------------
/examples/with-morgan/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const morgan = require('morgan');
3 | const { send } = require('./util');
4 | const items = require('./items');
5 |
6 | const { PORT=3000 } = process.env;
7 |
8 | // init Polka (HTTP) server
9 | polka()
10 | .use(morgan('dev'))
11 | .use('/items', items)
12 | .get('/', (req, res) => {
13 | send(res, 'Index');
14 | })
15 | .listen(PORT, () => {
16 | console.log(`> Ready on localhost:${PORT}`);
17 | });
18 |
--------------------------------------------------------------------------------
/examples/with-morgan/items.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { send } = require('./util');
3 |
4 | module.exports = polka()
5 | .get('/', (req, res) => {
6 | send(res, 'items@index');
7 | })
8 | .post('/', (req, res) => {
9 | send(res, 'items@create');
10 | })
11 | .get('/:id', (req, res) => {
12 | send(res, `items@show(${req.params.id})`);
13 | })
14 | .put('/:id', (req, res) => {
15 | send(res, `items@edit(${req.params.id})`);
16 | })
17 | .delete('/:id', (req, res) => {
18 | send(res, `items@delete(${req.params.id})`);
19 | });
20 |
--------------------------------------------------------------------------------
/examples/with-morgan/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "node index"
4 | },
5 | "dependencies": {
6 | "morgan": "latest",
7 | "polka": "latest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/examples/with-morgan/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Morgan logger
2 |
3 | This example shows how to mount [`morgan`](https://www.npmjs.com/package/morgan) as a global logger within a Polka application.
4 |
5 | Additionally, a sub-application is attached to the `/items` base path, illustrating that all routes & methods are recorded correctly!
6 |
7 | ## Setup
8 |
9 | ```sh
10 | $ npm install
11 | $ npm start
12 | ```
13 |
14 | ## Usage
15 |
16 | Open a browser to `localhost:3000` or run the `curl` commands below.
17 |
18 | > Check your Terminal for `morgan` output! :tada:
19 |
20 | ```sh
21 | $ curl localhost:3000
22 | #=> (200) Index
23 |
24 | $ curl localhost:3000/items
25 | #=> (200) items@index
26 |
27 | $ curl localhost:3000/items/123
28 | #=> (200) items@show(123)
29 |
30 | $ curl localhost:3000/items -X POST
31 | #=> (200) items@create
32 |
33 | $ curl localhost:3000/items/123 -X PUT
34 | #=> (200) items@update(123)
35 |
36 | $ curl localhost:3000/items/123 -X DELETE
37 | #=> (200) items@delete(123)
38 |
39 | $ curl localhost:3000/foobar
40 | #=> (404) Not Found
41 | ```
42 |
--------------------------------------------------------------------------------
/examples/with-morgan/util.js:
--------------------------------------------------------------------------------
1 | // SUPER basic send() helper
2 | // ~> Just setting Content-Length
3 | // ~> because Morgan wants to print it
4 | exports.send = function (res, data) {
5 | res.setHeader('Content-Length', data.length);
6 | res.end(data);
7 | }
8 |
--------------------------------------------------------------------------------
/examples/with-nextjs/.gitignore:
--------------------------------------------------------------------------------
1 | .next
2 | node_modules
3 | package-lock.json
4 |
--------------------------------------------------------------------------------
/examples/with-nextjs/index.js:
--------------------------------------------------------------------------------
1 | const next = require('next');
2 | const polka = require('polka');
3 |
4 | const { PORT=3000, NODE_ENV } = process.env;
5 |
6 | const dev = NODE_ENV !== 'production';
7 | const app = next({ dev });
8 | const handle = app.getRequestHandler();
9 |
10 | app.prepare().then(() => {
11 | polka()
12 | .get('*', handle)
13 | .listen(PORT, () => {
14 | console.log(`> Ready on http://localhost:${PORT}`);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/examples/with-nextjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "dev": "node index.js",
4 | "build": "next build",
5 | "start": "NODE_ENV=production node index.js"
6 | },
7 | "dependencies": {
8 | "next": "8.1.0",
9 | "polka": "latest",
10 | "react": "16.8.6",
11 | "react-dom": "16.8.6"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/with-nextjs/pages/about.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'next/link';
3 |
4 | export default () => (
5 |
11 | )
12 |
--------------------------------------------------------------------------------
/examples/with-nextjs/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from 'next/link';
3 |
4 | export default () => (
5 |
11 | )
12 |
--------------------------------------------------------------------------------
/examples/with-nextjs/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Next.js
2 |
3 | It uses [`Next.js`](https://github.com/zeit/next.js) a Framework for server-rendered or statically-exported React apps.
4 |
5 | ## Setup
6 | ```sh
7 | $ npm install
8 | $ npm run build
9 | $ npm start
10 | ```
11 | or
12 | ```sh
13 | $ npm install
14 | $ npm run dev
15 | ```
16 |
17 | ## Usage
18 | Go to `localhost:3000` after starting the server and get the welcome message
19 |
--------------------------------------------------------------------------------
/examples/with-nuxtjs/.gitignore:
--------------------------------------------------------------------------------
1 | .nuxt
2 |
--------------------------------------------------------------------------------
/examples/with-nuxtjs/index.js:
--------------------------------------------------------------------------------
1 | const polka = require('polka');
2 | const { Nuxt, Builder } = require('nuxt');
3 |
4 | const { PORT=3000, NODE_ENV } = process.env;
5 |
6 | const dev = NODE_ENV !== 'production';
7 | const nuxt = new Nuxt({ dev });
8 | const app = polka();
9 |
10 | // Render every route with Nuxt.js
11 | app.use(nuxt.render);
12 |
13 | // Build only in dev mode with hot-reloading
14 | if (dev) {
15 | new Builder(nuxt).build()
16 | .then(listen)
17 | .catch((error) => {
18 | console.error(error);
19 | process.exit(1);
20 | })
21 | } else {
22 | listen();
23 | }
24 |
25 | function listen() {
26 | return app.listen(PORT, () => {
27 | console.log(`> Ready on localhost:${PORT}`);
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/examples/with-nuxtjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "build": "nuxt build",
4 | "prestart": "npm run build",
5 | "start": "cross-env NODE_ENV=production node index",
6 | "watch": "node index"
7 | },
8 | "dependencies": {
9 | "cross-env": "^5.1.3",
10 | "nuxt": "latest",
11 | "polka": "latest"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/examples/with-nuxtjs/pages/about.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
About Page
4 | Link to Home Page
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples/with-nuxtjs/pages/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Home Page
4 | Link to About Page
5 |
6 |
7 |
--------------------------------------------------------------------------------
/examples/with-sapper/.gitignore:
--------------------------------------------------------------------------------
1 | .sapper
2 | templates/.*
3 |
--------------------------------------------------------------------------------
/examples/with-sapper/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-sapper/assets/favicon.png
--------------------------------------------------------------------------------
/examples/with-sapper/assets/global.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
4 | font-size: 14px;
5 | line-height: 1.5;
6 | color: #333;
7 | }
8 |
9 | main {
10 | position: relative;
11 | max-width: 56em;
12 | background-color: white;
13 | padding: 2em;
14 | margin: 0 auto;
15 | box-sizing: border-box;
16 | }
17 |
18 | h1, h2, h3, h4, h5, h6 {
19 | margin: 0 0 0.5em 0;
20 | font-weight: 400;
21 | line-height: 1.2;
22 | }
23 |
24 | h1 {
25 | font-size: 2em;
26 | }
27 |
28 | a {
29 | color: inherit;
30 | }
31 |
32 | code {
33 | font-family: menlo, inconsolata, monospace;
34 | font-size: calc(1em - 2px);
35 | color: #555;
36 | background-color: #f0f0f0;
37 | padding: 0.2em 0.4em;
38 | border-radius: 2px;
39 | }
40 |
41 | @media (min-width: 400px) {
42 | body {
43 | font-size: 16px;
44 | }
45 | }
--------------------------------------------------------------------------------
/examples/with-sapper/assets/great-success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-sapper/assets/great-success.png
--------------------------------------------------------------------------------
/examples/with-sapper/assets/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "background_color": "#ffffff",
3 | "theme_color": "#aa1e1e",
4 | "name": "TODO",
5 | "short_name": "TODO",
6 | "display": "minimal-ui",
7 | "start_url": "/",
8 | "icons": [
9 | {
10 | "src": "svelte-logo-192.png",
11 | "sizes": "192x192",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "svelte-logo-512.png",
16 | "sizes": "512x512",
17 | "type": "image/png"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/examples/with-sapper/assets/svelte-logo-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-sapper/assets/svelte-logo-192.png
--------------------------------------------------------------------------------
/examples/with-sapper/assets/svelte-logo-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukeed/polka/c36cf8b5d1a57164e64fdd7d4e0d0f80ab262dc0/examples/with-sapper/assets/svelte-logo-512.png
--------------------------------------------------------------------------------
/examples/with-sapper/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "build": "sapper build",
4 | "start": "cross-env NODE_ENV=production node server.js",
5 | "watch": "node server.js"
6 | },
7 | "dependencies": {
8 | "compression": "^1.7.1",
9 | "cross-env": "^5.1.3",
10 | "node-fetch": "^2.6.1",
11 | "polka": "latest",
12 | "sapper": "^0.6.1",
13 | "serve-static": "^1.13.1",
14 | "svelte": "^1.51.1"
15 | },
16 | "devDependencies": {
17 | "css-loader": "^0.28.7",
18 | "extract-text-webpack-plugin": "^3.0.2",
19 | "style-loader": "^0.19.1",
20 | "svelte-loader": "^2.3.3",
21 | "uglifyjs-webpack-plugin": "^1.1.5",
22 | "webpack": "^3.10.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/with-sapper/readme.md:
--------------------------------------------------------------------------------
1 | # Example: Sapper
2 |
3 | > Polka and Sapper make for an exceptional combo! :tada: _([DEMO](https://polka-sapper.now.sh/))_
4 |
5 | [Sapper](https://github.com/sveltejs/sapper) is a structure-dependent framework that all allows you to build highly-performant, universal [Svelte](https://github.com/sveltejs/svelte) apps! Sapper operates as a middleware layer, which allows you to attach it to _any_ Node.js server.
6 |
7 | This example shows how easy it is to use Polka with the default [`sapper-template`](https://github.com/sveltejs/sapper-template).
8 |
9 | ## Setup
10 |
11 | ```sh
12 | $ npm install
13 | $ npm run build
14 | $ npm start
15 | ```
16 |
17 | ## Usage
18 |
19 | Open a browser to `localhost:3000`!
20 |
21 | To use the built-in live-reload / [HMR](https://webpack.js.org/concepts/hot-module-replacement/) development server, run:
22 |
23 | ```sh
24 | $ npm run watch
25 | ```
26 |
27 | > The dev-server also runs on Polka! :dancers:
28 |
--------------------------------------------------------------------------------
/examples/with-sapper/routes/_components/Layout.html:
--------------------------------------------------------------------------------
1 |