# webpack-isomorphic-tools
[](https://www.npmjs.com/package/webpack-isomorphic-tools)
[](https://www.npmjs.com/package/webpack-isomorphic-tools)
[](https://travis-ci.org/catamphetamine/webpack-isomorphic-tools)
[](https://coveralls.io/r/catamphetamine/webpack-isomorphic-tools?branch=master)
**THIS PACKAGE IS DEPRECATED. LOOK ELSEWHERE.**
`webpack-isomorphic-tools` is a small helper module providing very basic support for isomorphic (universal) rendering when using Webpack. It was created a long time ago when Webpack was `v1` and the whole movement was just starting. Therefore `webpack-isomorphic-tools` is a hacky solution. It allowed many projects to set up basic isomorphic (universal) rendering in the early days but is now considered deprecated and new projects shouldn't use it. This library can still be found in legacy projects. For new projects use either [`universal-webpack`](https://github.com/catamphetamine/universal-webpack) or all-in-one frameworks like [Next.js](https://github.com/zeit/next.js).
## Topics
- [What it does](#what-it-does)
- [A simple example](#a-simple-example)
- [Installation](#installation)
- [Usage](#usage)
- [A working example](#a-working-example)
- [Configuration](#configuration)
- [Configuration examples](#configuration-examples)
- [What are webpack-assets.json?](#what-are-webpack-assetsjson)
- [What are Webpack stats?](#what-are-webpack-stats)
- [What's a "module"?](#whats-a-module)
- [API](#api)
- [Troubleshooting](#troubleshooting)
- [Miscellaneous](#miscellaneous)
- [References](#references)
- [Contributing](#contributing)
## What it does
Suppose you have an application which is built using Webpack. It works in the web browser.
Should it be "isomorphic" ("universal")? It's better if it is. One reason is that search engines will be able to index your page. The other reason is that we live in a realtime mobile age which declared war on network latency, and so it's always better to fetch an already rendered content than to first fetch the application code and only then fetch the content to render the page. Every time you release a client-side only website to the internet someone writes a [frustrated blog post](https://ponyfoo.com/articles/stop-breaking-the-web).
So, it's obvious then that web applications should be "isomorphic" ("universal"), i.e. be able to render both on the client and the server, depending on circumstances. And it is perfectly possible nowadays since javascript runs everywhere: both in web browsers and on servers.
Ok, then one can just go ahead and run the web application in Node.js and its done. But, there's one gotcha: a Webpack application will usually crash when tried to be run in Node.js straight ahead (you'll get a lot of `SyntaxError`s with `Unexpected token`s).
The reason is that Webpack introduces its own layer above the standard javascript. This extra layer handles all `require()` calls magically resolving them to whatever it is configured to. For example, Webpack is perfectly fine with the code `require()`ing CSS styles or SVG images.
Bare Node.js doesn't come with such trickery up its sleeve. Maybe it can be somehow enhanced to be able to do such things? Turned out that it can, and that's what `webpack-isomorphic-tools` do: they inject that `require()` magic layer above the standard javascript in Node.js.
Still it's a hacky solution, and a better way would be to compile server-side code with Webpack the same way it already compiles the client-side code. This is achieved via [`target: "node"`](https://webpack.js.org/configuration/target/#target) configuration option, and that's what [`universal-webpack`](https://github.com/catamphetamine/universal-webpack) library does. However, `webpack-isomorphic-tools` happened to be a bit simpler to set up, so they made their way into many now-legacy projects, so some people still use this library. It's not being maintained anymore though, and in case of any issues people should just migrate to [`universal-webpack`](https://github.com/catamphetamine/universal-webpack) or something similar.
`webpack-isomorphic-tools` mimics (to a certain extent) Webpack's `require()` magic when running application code on a Node.js server without Webpack. It basically fixes all those `require()`s of assets and makes them work instead of throwing `SyntaxError`s. It doesn't provide all the capabilities of Webpack (for example, plugins won't work), but for the basic stuff, it works.
## A simple example
For example, consider images. Images are `require()`d in React components and then used like this:
```javascript
// alternatively one can use `import`,
// but with `import`s hot reloading won't work
// import imagePath from '../image.png'
// Just `src` the image inside the `render()` method
class Photo extends React.Component
{
render()
{
// When Webpack url-loader finds this `require()` call
// it will copy `image.png` to the build folder
// and name it something like `9059f094ddb49c2b0fa6a254a6ebf2ad.png`,
// because Webpack is set up to use the `[hash]` file naming feature
// which makes browser asset caching work correctly.
return
}
}
```
It works on the client-side because Webpack intelligently replaces all the `require()` calls with a bit of magic.
But it wouldn't work on the server-side because Node.js only knows how to `require()` javascript modules. It would just throw a `SyntaxError`.
To solve this issue one can use `webpack-isomorphic-tools`. With the help of `webpack-isomorphic-tools` in this particular case the `require()` call will return the real path to the image on the disk. It would be something like `../../build/9059f094ddb49c2b0fa6a254a6ebf2ad.png`. How did `webpack-isomorphic-tools` figure out this weird real file path? It's just a bit of magic.
`webpack-isomorphic-tools` is extensible, and finding the real paths for assets is the simplest example of what it can do inside `require()` calls. Using [custom configuration](#configuration) one can make `require()` calls (on the server) return anything (not just a String; it may be a JSON object, for example).
For example, if one is using Webpack [css-loader](https://github.com/webpack/css-loader) modules feature (also referred to as ["local styles"](https://medium.com/seek-ui-engineering/the-end-of-global-css-90d2a4a06284)) one can make `require(*.css)` calls return JSON objects with generated CSS class names maps like they do in [este](https://github.com/este/este/blob/master/webpack/assets.js) and [react-redux-universal-hot-example](https://github.com/erikras/react-redux-universal-hot-example#styles).
## Installation
`webpack-isomorphic-tools` are required both for development and production
```bash
$ npm install webpack-isomorphic-tools --save
```
## Usage
First you add `webpack-isomorphic-tools` plugin to your Webpack configuration.
### webpack.config.js
```javascript
var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin')
var webpackIsomorphicToolsPlugin =
// webpack-isomorphic-tools settings reside in a separate .js file
// (because they will be used in the web server code too).
new WebpackIsomorphicToolsPlugin(require('./webpack-isomorphic-tools-configuration'))
// also enter development mode since it's a development webpack configuration
// (see below for explanation)
.development()
// usual Webpack configuration
module.exports =
{
context: '(required) your project path here',
module:
{
loaders:
[
...,
{
test: webpackIsomorphicToolsPlugin.regularExpression('images'),
loader: 'url-loader?limit=10240', // any image below or equal to 10K will be converted to inline base64 instead
}
]
},
plugins:
[
...,
webpackIsomorphicToolsPlugin
]
...
}
```
What does `.development()` method do? It enables development mode. In short, when in development mode, it disables asset caching (and enables asset hot reload), and optionally runs its own "dev server" utility (see `port` configuration setting). Call it in development webpack build configuration, and, conversely, don't call it in production webpack build configuration.
For each asset type managed by `webpack-isomorphic-tools` there should be a corresponding loader in your Webpack configuration. For this reason `webpack-isomorphic-tools/plugin` provides a `.regularExpression(assetType)` method. The `assetType` parameter is taken from your `webpack-isomorphic-tools` configuration:
### webpack-isomorphic-tools-configuration.js
```javascript
import WebpackIsomorphicToolsPlugin from 'webpack-isomorphic-tools/plugin'
export default
{
assets:
{
images:
{
extensions: ['png', 'jpg', 'gif', 'ico', 'svg']
}
}
}
```
That's it for the client side. Next, the server side. You create your server side instance of `webpack-isomorphic-tools` in the very main server javascript file (and your web application code will reside in some `server.js` file which is `require()`d in the bottom)
### main.js
```javascript
var WebpackIsomorphicTools = require('webpack-isomorphic-tools')
// this must be equal to your Webpack configuration "context" parameter
var projectBasePath = require('path').resolve(__dirname, '..')
// this global variable will be used later in express middleware
global.webpackIsomorphicTools = new WebpackIsomorphicTools(require('./webpack-isomorphic-tools-configuration'))
// initializes a server-side instance of webpack-isomorphic-tools
// (the first parameter is the base path for your project
// and is equal to the "context" parameter of you Webpack configuration)
// (if you prefer Promises over callbacks
// you can omit the callback parameter
// and then it will return a Promise instead)
.server(projectBasePath, function()
{
// webpack-isomorphic-tools is all set now.
// here goes all your web application code:
// (it must reside in a separate *.js file
// in order for the whole thing to work)
require('./server')
})
```
Then you, for example, create an express middleware to render your pages on the server
```javascript
import React from 'react'
// html page markup
import Html from './html'
// will be used in express_application.use(...)
export function pageRenderingMiddleware(request, response)
{
// clear require() cache if in development mode
// (makes asset hot reloading work)
if (process.env.NODE_ENV !== 'production')
{
webpackIsomorphicTools.refresh()
}
// for react-router example of determining current page by URL take a look at this:
// https://github.com/catamphetamine/webapp/blob/master/code/server/webpage%20rendering.js
const pageComponent = [determine your page component here using request.path]
// for a Redux Flux store implementation you can see the same example:
// https://github.com/catamphetamine/webapp/blob/master/code/server/webpage%20rendering.js
const fluxStore = [initialize and populate your flux store depending on the page being shown]
// render the page to string and send it to the browser as text/html
response.send('\n' +
React.renderToString())
}
```
And finally you use the `assets` inside the `Html` component's `render()` method
```javascript
import React, {Component, PropTypes} from 'react'
import serialize from 'serialize-javascript'
export default class Html extends Component
{
static propTypes =
{
assets : PropTypes.object,
component : PropTypes.object,
store : PropTypes.object
}
// a sidenote for "advanced" users:
// (you may skip this)
//
// this file is usually not included in your Webpack build
// because this React component is only needed for server side React rendering.
//
// so, if this React component is not `require()`d from anywhere in your client code,
// then Webpack won't ever get here
// which means Webpack won't detect and parse any of the `require()` calls here,
// which in turn means that if you `require()` any unique assets here
// you should also `require()` those assets somewhere in your client code,
// otherwise those assets won't be present in your Webpack bundle and won't be found.
//
render()
{
const { assets, component, store } = this.props
// "import" will work here too
// but if you want hot reloading to work while developing your project
// then you need to use require()
// because import will only be executed a single time
// (when the application launches)
// you can refer to the "Require() vs import" section for more explanation
const picture = require('../assets/images/cat.jpg')
// favicon
const icon = require('../assets/images/icon/32x32.png')
const html =
(