1.0.3 • Published 5 years ago

koa-parcel-middleware v1.0.3

Weekly downloads
5
License
MIT
Repository
github
Last release
5 years ago

koa-parcel-middleware

parcel middleware for koa

JavaScript Style Guide semantic-release Greenkeeper badge CircleCI TypeScript package

why

parcel middleware enables you to:

  • wire in advanced features, such as server-side-rendering. isomorphic js in compact form
  • serve your ui application from your server application
  • combine the parcel dev server functionality with an existing server application, rather than an extra process

install

yarn add koa-parcel-middleware koa koa-static

koa and koa-static are required peerDependencies. koa-static is required such that non-js assets (e.g. css, images, etc) may be served gracefully as requested by your ui.

usage

import { createMiddleware } from 'koa-parcel-middleware'
const middleware = createMiddleware({
  bundler: `parcelBundlerInstance`,
  renderHtmlMiddleware?: `<optionally-own-serving-your-entrypoint>`,
  staticMiddleware: `koaStaticInstance` // serving parcel's built assets
})

the following is a rich, complete example of using the middleware api.

import { createMiddleware } from 'koa-parcel-middleware' // :)
import { App } from './app' // e.g. a react <App /> component
import { promises as fs } from 'fs'
import * as path from 'path'
import * as ReactDOMServer from 'react-dom/server'
import Bundler from 'parcel-bundler'
import CombinedStream from 'combined-stream'
import Koa from 'koa'
import serveStatic from 'koa-static'

// your parcel application's _unbuilt_ entry point!
const ENTRY_FILENAME = path.resolve(__dirname, 'index.html')
const isDev = process.env.NODE_ENV === 'development'

async function start () {
  const app = new Koa()
  // your parcel application's _built_ entry point!
  const outFile = path.resolve(__dirname, 'dist', 'index.html')
  const outDir = path.resolve(__dirname, 'dist')
  const options = {
    outDir,
    outFile,
    watch: isDev,
    minify: !isDev,
    scopeHoist: false,
    hmr: isDev,
    detailedReport: isDev
  }
  const bundler = new Bundler(ENTRY_FILENAME, options)
  bundler.bundle()
  const staticMiddleware = serveStatic(outDir)
  const parcelMiddleware = createMiddleware({
    bundler,
    renderHtmlMiddleware: async (ctx, next) => {
      // optionally wire in SSR!

      // index.html
      //
      // <html>
      //   <div id="app"><!-- ssr-content --></div>
      //   <script src="app.tsx"></script>
      // </html>
      const outFileBuffer = await fs.readFile(outFile)
      const [preAppEntry, postAppEntry] = outFileBuffer.toString()
        .split(/<!--.*ssr.*-->/)
      ctx.status = 200
      const htmlStream = new CombinedStream()
      ;[
        preAppEntry,
        ReactDOMServer.renderToNodeStream(App()),
        postAppEntry
      ].map(content => htmlStream.append(content))
      ctx.body = htmlStream
      ctx.type = 'html'
      await next()
    },
    staticMiddleware
  })
  app.use((ctx, next) => parcelMiddleware(ctx, next))
  app.listen(3000)
}
start()