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

webpack-universal-compiler

v1.5.5

Published

Library that creates a hot reloadable client and server webpack instance for universal (SSR) apps.

Downloads

51

Readme

Webpack Universal Compiler

A toolkit to make your universal web app MUCH easier to develop. I've noticed a weird disconnect between client and server development methods, and this attempts to bridge that gap. Thanks to webpack-isomorphic-dev-middleware. I typed out most of the code, patched up the in-memory filesystem, and updated his package for more use cases.

Getting Started

Webpack Universal Compiler is still at alpha so use with caution. It should be just a single package installation to get your webpack universal development off the ground.

Installing

Yarn

yarn webpack-universal-compiler -D

NPM

npm install webpack-universal-compiler --save-dev

Prerequisites

For a working example check out out SSR-Example

It's important that your server side bundle exports middleware in the form of (req, res, next) => void. You may export many middleware if you'd like and then compose them together. We will be using the following 2 webpack entry files as examples. Some examples of usage are below. This package allows a lot of flexibility, so use as you wish.

Example Client webpack entry

src/client/entry.ts

import React from 'react'
import { hydrate } from 'react-dom'
import App from '../app/containers/app'

hydrate(<App />, document.querySelector('.app-root'))

Example Server webpack entry

src/server/entry.ts

import { logger } from './middleware/logger'
import { someOtherMiddleware } from './middleware/someOtherMiddleware'
import { reactRenderer } from './middleware/render'

export const middleware = [
  logger,
  someOtherMiddleware,
  reactRenderer
]

Usage

As an express middleware

src/bin/development.js

import express from 'express'
import * as path from 'path'
import { webpackClientServerMiddleware } from 'webpack-universal-compiler'
import { compose } from 'compose-middleware'

// Import your various webpack configs
import clientConfig from '../webpack/webpack.client.config'
import serverConfig from '../webpack/webpack.server.config'

const app = express()
const options = {
  inMemoryFilesystem: true
}
const middleware = webpackClientServerMiddleware(
  clientConfig,
  serverConfig,
  options
)

app.use(middleware)

app.use((req,, res, next) => {
  if (res.locals.universal && res.locals.universal.bundle) {
    // This is the middleware export from `src/server/entry.ts
    const { middleware } = res.locals.universal.bundle

    return compose(middleware)(req, res, next)
  }

  return next()
})

app.listen(8080, () => {
  console.log('Listening on port 8080')
})

With hot reloading

Hot reloading should be simple.

  1. You must add it as an option to the webpackClientServerMiddleware.
  2. Add webpack-hot-middleware/client to your client webpack entry array/object.
  3. Add new webpack.HotModuleReplacementPlugin() to your array of plugins.

Important: To prevent memory leaks, do not have hashes in your output.filename, output.chunkFilename, output.hotUpdateMainFilename, or hotUpdateChunkFilename. This is ONLY for dev mode. You may enable chunk hashing for production/CDN use.

src/bin/development.js

const options = {
  inMemoryFilesystem: true,
  hot: true
}

const middleware = webpackClientServerMiddleware(
  clientConfig,
  serverConfig,
  options
)

app.use(middleware)

webpack/webpack.client.config

import * as path from 'path'
import webpack from 'webpack'

module.exports = {
  ...,
  entry: [
    'webpack-hot-middleware/client',
    path.resolve(__dirname, '../src/client.ts')
  ],
  output {
    // if using inMemoryFilesystem
    chunkFilename: '[name].js',
    hotUpdateMainFilename: 'main.hot-update.json',
    hotUpdateChunkFilename: '[id].hot-update.js',

  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
}

webpackClientServerMiddleware API

webpack-universal-compiler itself returns an express (connect) middleware: (req, res, next): void, but the middleware object also has the running instance of the dual webpack compiler (client and server). Documentation below shows how to access the compilers.

middleware

This is the middleware that provides your express application with both the client and the server bundles. The middleware provides client and server compilation information in to res.locals.universal

Type: Function (express middleware) Example:

const { middleware } = webpackClientServerMiddleware(
  clientConfig,
  serverConfig,
  options
)

app.use(middleware)

app.use((req, res, next) => {
  type Compilation = {
    duration: number,
    clientStats: webpack.Stats,
    serverStats: webpack.Stats,
    // This is your server entry file exports
    bundle: Object [Module] { [x: string ]: [Getter] }
  }

  const compilation: Compilation = res.locals.compilation
})

middleware.compiler

An object containing information about the compiler running in the background for both client and server.

Type: Object Example:

const middleware = webpackClientServerMiddleware(
  clientConfig,
  serverConfig,
  options
)

middleware.compiler.on('end', compilation => {
  if (compilation.clientStats.hasErrors()) {
    //etc
  }
})

app.use(middleware)

Methods

Most of these compiler methods return the same compilation Type.

type Compilation = {
  duration?: number
  clientStats?: webpack.Stats
  serverStats?: webpack.Stats
}
  • compiler.client

    Object containing the client configuration and the instance of the client Compiler webpack.Compiler.

  • compiler.server

    Object containing the server configuration and the instance of the server Compiler webpack.Compiler.

  • compiler.isCompiling()

    Returns if either the client or server compiler is compiling.

    Type: Function
    Returns: boolean

  • compiler.getCompilation()

    Returns the last successful compilation stats.

    Type: Function
    Returns: Compilation

  • compiler.getError()

    Returns errors if there are any, useful mainly for watching. By default errors will get printed to console.

    Type: Function
    Returns: webpack.Stats

  • compiler.run()

    Runs the compiler, this is more for production builds. Not as useful for middleware.

    Type: Function
    Returns: Promise<Compilation>

  • compiler.watch()

    Starts webpack in watch mode. This is useful to pair with compiler.resolve() to resolve the last watch-compiled build.

    Type: Function

  • compiler.resolve()

    Returns a Promise that resolves to the last compilation sequentially built by webpack's watch. This is the backbone of the middleware.

    Type: Function
    Returns: Promise<Compilation>

  • compiler.on(event: 'begin' | 'end' | 'error' | 'invalidate', cb: Function)

    There are a few events you may listen on, and react to with a callback function.

    • 'begin' - Compiler has started compiling.
    • 'end', stats => void - Compiler has finished compiling without errors. You have access to the stats object in the callback.
    • 'error', err => void - Compiler has finished compiling with errors. You have access to error and error stats with err.stats (if webpack didn't fail catastraphically).
    • 'invalidate' - Compiler has invalidated the last watch build.
  • compiler.emit(event: string | symbol, cb: Function)

    You may also add your own emitters if you'd like.

Important: All of these methods are available to the clientServerCompiler so you can build your own universal webpack compiler that's (more or less) pain free. It does not provide as much error catching, or set up the in-memory filesystem for you, but it streamlines the compilation process and keeps things in-sync.

Example:

import { clientServerCompiler } from 'webpack-universal-compiler'

import clientConfig from '../webpack/webpack.client.config'
import serverConfig from '../webpack/webpack.server.config'

const compilerInstance = clientServerCompiler(clientConfig, serverConfig)

const runCompiler = async () => {
  compilerInstance.watch()
  compilerInstance.on('end', async () => {
    const { clientStats, serverStats } = await compilerInstance.resolve()

    // Do stuff with stats, start up server, build your own middleware.
  })
}

webpackClientServerMiddleware Options

Compiler, Configuration, or Configuration[]

Type: MultiCompiler | Compiler | Configuration | [ Configuration, Configuration ]

You may supply either a webpack multicompiler: webpack([ config1, config2 ]), a single compiler, webpack(config), an array of configs, or single configs.

IMPORTANT: The client config must come first, webpack-universal-compiler tries to warn you about order, but sometimes it can't determine based on ones strange webpack configs. Example:

const clientCompiler = webpack(clientConfig)
const serverCompiler = webpack(serverConfig)

const MultiCompiler = [clientCompiler, serverCompiler]

const { middleware } = webpackClientServerMiddleware(MultiCompiler)

// or

const { middleware } = webpackClientServerMiddleware(clientCompiler, serverCompiler)

// 

const { middleware } = webpackClientServerMiddleware(clientConfig, serverConfig)

Middleware Options

Type: Object

inMemoryFilesystem

Type: boolean
Default: false

Creates an in-memory filesystem for faster compilation. Dynamic imports and split chunks work too due to a patched memory filesystem. So import() server-side works how it would client-side, no need to add strange babel plugins.

hot

Type: boolean
Default: false

Injects the hot-dev-middleware into final list of middleware. You must set client webpack config options to support this, otherwise it won't work.

headers

Type: Object
Default: { 'Cache-Control': 'max-age=0, must-revalidate' }

Headers to provide to the webpack-dev-middleware.

Credits