All Projects → gajus → Isomorphic Webpack

gajus / Isomorphic Webpack

Licence: other
Abstracts universal consumption of application code base using webpack.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Isomorphic Webpack

Vortigern
A universal boilerplate for building web applications w/ TypeScript, React, Redux, Server Side Rendering and more.
Stars: ✭ 647 (+120.07%)
Mutual labels:  webpack, universal, isomorphic
React Isomorphic Starterkit
Create an isomorphic React app in less than 5 minutes
Stars: ✭ 2,326 (+691.16%)
Mutual labels:  webpack, universal, isomorphic
Isomorphic React
A simple but powerful React application built on a standards-compliant back-end
Stars: ✭ 318 (+8.16%)
Mutual labels:  webpack, universal, isomorphic
Universal
Seed project for Angular Universal apps featuring Server-Side Rendering (SSR), Webpack, CLI scaffolding, dev/prod modes, AoT compilation, HMR, SCSS compilation, lazy loading, config, cache, i18n, SEO, and TSLint/codelyzer
Stars: ✭ 669 (+127.55%)
Mutual labels:  webpack, universal, isomorphic
Webpack Isomorphic Dev Middleware
The webpack-dev-middleware, but for isomorphic applications
Stars: ✭ 38 (-87.07%)
Mutual labels:  webpack, universal, isomorphic
Razzle Material Ui Styled Example
Razzle Material-UI example with Styled Components using Express with compression
Stars: ✭ 117 (-60.2%)
Mutual labels:  webpack, universal, isomorphic
Razzle
✨ Create server-rendered universal JavaScript applications with no configuration
Stars: ✭ 10,547 (+3487.41%)
Mutual labels:  webpack, universal, isomorphic
React Redux Styled Hot Universal
react boilerplate used best practices and focus on performance
Stars: ✭ 147 (-50%)
Mutual labels:  webpack, universal, isomorphic
grand central
State-management and action-dispatching for Ruby apps
Stars: ✭ 20 (-93.2%)
Mutual labels:  isomorphic, universal
universal-react-relay-starter-kit
A starter kit for React in combination with Relay including a GraphQL server, server side rendering, code splitting, i18n, SEO.
Stars: ✭ 14 (-95.24%)
Mutual labels:  isomorphic, universal
server
Serve one or more react apps! - Custom routes, HotReloading, Authenticated Apps/routes, Relay, Webpack..
Stars: ✭ 20 (-93.2%)
Mutual labels:  isomorphic, universal
koa-webpack-server
Koa2 webpack all-in-one environment for universal development
Stars: ✭ 14 (-95.24%)
Mutual labels:  isomorphic, universal
Angular Awesome List
Список ресурсов по Angular на русском
Stars: ✭ 224 (-23.81%)
Mutual labels:  webpack, universal
Helium.js
Automating Universal React Applications
Stars: ✭ 63 (-78.57%)
Mutual labels:  isomorphic, universal
react-ssr-hydration
Example of React Server Side Rendering with Styled Components and Client Side Hydration
Stars: ✭ 15 (-94.9%)
Mutual labels:  isomorphic, universal
universal-progressive-todos
A Todo list with universal JavaScript & Progressive Enhancement
Stars: ✭ 30 (-89.8%)
Mutual labels:  isomorphic, universal
Vuesion
Vuesion is a boilerplate that helps product teams build faster than ever with fewer headaches and modern best practices across engineering & design.
Stars: ✭ 2,510 (+753.74%)
Mutual labels:  webpack, universal
fastify-vite
This plugin lets you load a Vite client application and set it up for Server-Side Rendering (SSR) with Fastify.
Stars: ✭ 497 (+69.05%)
Mutual labels:  isomorphic, universal
redux-pluto
redux pluto
Stars: ✭ 75 (-74.49%)
Mutual labels:  isomorphic, universal
react-ssr-spa
Server side rendered single page app using reactjs official libraries.
Stars: ✭ 30 (-89.8%)
Mutual labels:  isomorphic, universal

isomorphic-webpack

Travis build status Coveralls NPM version Canonical Code Style Twitter Follow

isomorphic-webpack

isomorphic-webpack is a program that runs server-side and enables rendering of the same code base client- and server-side.

Put it another way, it is a service for rendering webpack applications server-side. All that can be rendered client-side (e.g. React, Angular, etc. applications) will be processed server-side and served as static HTML.

Try it!

git clone [email protected]:gajus/isomorphic-webpack-demo.git
cd ./isomorphic-webpack-demo
npm install
export DEBUG=express:application,isomorphic-webpack
npm start

This will start the server on http://127.0.0.1:8000/.

$ curl http://127.0.0.1:8000/

<!doctype html>
<html>
  <head></head>
  <body>
    <div id='app'>
      <div class="app-___style___greetings" data-reactroot="" data-reactid="1" data-react-checksum="72097819">Hello, World!</div>
    </div>

    <script src='/static/app.js'></script>
  </body>
</html>

Goals


Table of contents

Setup

High-level abstraction

import {
	createIsomorphicWebpack
} from 'isomorphic-webpack';
import webpackConfiguration from './webpack.configuration';

createIsomorphicWebpack(webpackConfiguration);

API

/**
 * @see https://webpack.js.org/configuration/
 */
type WebpackConfigurationType = Object;

/**
 * @see https://github.com/gajus/gitdown#isomorphic-webpack-setup-high-level-abstraction-isomorphic-webpack-configuration
 */
type UserIsomorphicWebpackConfigurationType = {
  useCompilationPromise?: boolean
};

type IsomorphicWebpackType = {|
  /**
   * @see https://webpack.github.io/docs/node.js-api.html#compiler
   */
  +compiler: Compiler,
  +createCompilationPromise: Function,
  +evalBundleCode: Function,
  +formatErrorStack: Function
|};

createIsomorphicWebpack(webpackConfiguration: WebpackConfigurationType, isomorphicWebpackConfiguration: UserIsomorphicWebpackConfigurationType): IsomorphicWebpackType;

Isomorphic webpack configuration

{
  "additionalProperties": false,
  "properties": {
    "nodeExternalsWhitelist": {
      "description": "An array of paths to whitelist in the webpack `external` configuration. The default behaviour is to externalise all modules present in the `node_modules/` directory.",
      "items": {
        "oneOf": [
          {
            "type": "string"
          },
          {
            "instanceof": "RegExp"
          }
        ]
      },
      "type": "array"
    },
    "useCompilationPromise": {
      "description": "Toggles compilation observer. Enable this feature to use `createCompilationPromise`.",
      "type": "boolean"
    }
  },
  "type": "object"
}

If you have a requirement for a configuration, raise an issue describing your use case.

Handling errors

When a runtime error originates in a bundle, the stack trace refers to the code executed in the bundle (#4).

Use formatErrorStack to replace references to the VM code with the references resolved using the sourcemap, e.g.

const {
  formatErrorStack
} = createIsomorphicWebpack(webpackConfiguration);

app.get('*', isomorphicMiddleware);

app.use((err, req, res, next) => {
  console.error(formatErrorStack(err.stack));
});
ReferenceError: props is not defined
-   at TopicIndexContainer (evalmachine.<anonymous>:485:15)
+   at TopicIndexContainer (/src/client/containers/TopicIndexContainer/index.js:14:14)
    at WrappedComponent (/node_modules/react-css-modules/dist/wrapStatelessFunction.js:55:38)
    at /node_modules/react-dom/lib/ReactCompositeComponent.js:306:16
    at measureLifeCyclePerf (/node_modules/react-dom/lib/ReactCompositeComponent.js:75:12)
    at ReactCompositeComponentWrapper._constructComponentWithoutOwner (/node_modules/react-dom/lib/ReactCompositeComponent.js:305:14)
    at ReactCompositeComponentWrapper._constructComponent (/node_modules/react-dom/lib/ReactCompositeComponent.js:280:21)
    at ReactCompositeComponentWrapper.mountComponent (/node_modules/react-dom/lib/ReactCompositeComponent.js:188:21)
    at Object.mountComponent (/node_modules/react-dom/lib/ReactReconciler.js:46:35)
    at /node_modules/react-dom/lib/ReactServerRendering.js:45:36
    at ReactServerRenderingTransaction.perform (/node_modules/react-dom/lib/Transaction.js:140:20)

Note: References to a generated code that cannot be resolved in a source map are ignored (#5).

Reading list

FAQ

How to get started?

The easiest way to start is to analyse the demo application.

To start the server:

git clone [email protected]:gajus/isomorphic-webpack-demo.git
cd ./isomorphic-webpack-demo
npm install
export DEBUG=express:application,isomorphic-webpack
npm start

This will start the server on http://127.0.0.1:8000/.

open http://127.0.0.1:8000/

How does isomorphic-webpack work?

Refer to the Low-level abstraction documentation.

How to use webpack *-loader loader?

Loaders allow you to preprocess files as you require() or "load" them. [..] Loaders can transform files from a different language like, CoffeeScript to JavaScript, or inline images as data URLs.

– https://webpack.github.io/docs/loaders.html

isomorphic-webpack is simulating the browser environment to evaluate loaders that are designed to run in a browser, e.g. style-loader. Therefore, all webpack loaders work out of the box with isomorphic-webpack.

If you have found a loader that does not work, report an issue.

How does the hot-reloading work?

I have been asked a question:

I have setup https://github.com/gajus/isomorphic-webpack-demo and navigated to http://127.0.0.1:8000/. It printed 'Hello, World!'.

Then I have changed ./src/app/index.js to say Hello, HRM!. I was expecting the message 'Hello, World!' to change to 'Hello, HMR!' in the already open browser window. However, it didn't.

The message changed to 'Hello, HRM!' only after I have refreshed the browser window.

How is this hot-reloading?

I have used the term "hot-reloading" to describe a process where the webpack bundle is rebuilt every time a file in the project changes. The change will be visible on the next HTTP request.

It is "hot-reloading" in a sense that you do not need to restart the HTTP server every time you make a change to the application.

There is no logic that would force-refresh the page on completion of the compilation. There are several ways to achieve this, e.g. using a custom script that queries the backend. However, this does logic does not belong in isomorphic-webpack.

The purpose of the server-side rendering is to generate HTML response to a HTTP request. isomorphic-webpack does perform hot-reloading that satisfies this use case.

The primary purpose of hot module reloading (HRM) is to enable better developer experience. Given that it is a development feature, it is safe to assume that the developer is in control over the development environment. Therefore, to achieve HMR you need to implement the logic in your frontend application and configure webpack as described in the Hot module replacement with webpack guide.

How to differentiate between Node.js and browser environment?

Check for presence of ISOMORPHIC_WEBPACK variable.

Presence of ISOMORPHIC_WEBPACK indicates that code is executed using Node.js.

if (typeof ISOMORPHIC_WEBPACK === 'undefined') {
	// Browser
} else {
	// Node.js
}

How to enable logging?

isomorphic-webpack is using debug to log messages.

To enable logging, export DEBUG environment variable:

export DEBUG=isomorphic-webpack:*

How to subscribe to compiler events?

Using createIsomorphicWebpack result has a compiler property. compiler is an instance of a webpack Compiler. Use it to subscribe to all compiler events.

How to delay route initialisation until the first successful compilation?

See also:

Attempting to render a route server-side before the compiler has completed at least one compilation will produce an error, e.g.

+SyntaxError: /src/app/style.css: Unexpected token (1:0)
+> 1 | .greetings {
+    | ^
+  2 |   font-weight: bold;
+  3 | }
+  4 |
    at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4246:13)
    at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1627:8)
    at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3586:12)
    at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6402:22)
    at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3331:19)
    at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3311:19)
    at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3241:19)
    at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3218:19)
    at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3181:19)
    at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5694:20)

The error will vary depending on what loaders your application code depends on.

Therefore, it is desirable to delay the first server-side render until the compiler has completed at least one compilation.

const {
  compiler
} = createIsomorphicWebpack(webpackConfiguration);

let routesAreInitialized;

compiler.plugin('done', () => {
  if (routesAreInitialized) {
    return;
  }

  routesAreInitialized = true;

  app.get('/', isomorphicMiddleware);
});

This pattern is demonstrated in the isomorphic-webpack-demo.

How to delay request handling while compilation is in progress?

See also:

WARNING!

Do not use this in production. This implementation has a large overhead.

It might be desirable to stall HTTP request handling until whatever in-progress compilation has completed. This ensures that during the development you do not receive a stale response.

To achieve this:

  • Enable compilation observer using useCompilationPromise configuration.
  • Use createCompilationPromise to create a promise that resolves when a current compilation completes.
  • Use the resulting promise to create a middleware that queues all HTTP requests until the promise is resolved.

Note:

You must enable this feature using useCompilationPromise configuration.

If you use createCompilationPromise without configuring useCompilationPromise, you will get an error:

"createCompilationPromise" feature has not been enabled.

Example usage:

const {
  createCompilationPromise
} = createIsomorphicWebpack(webpackConfiguration, {
  useCompilationPromise: true
});

app.use(async (req, res, next) => {
  await createCompilationPromise();

  next();
});

app.get('/', isomorphicMiddleware);

What makes isomorphic-webpack different from webpack-isomorphic-tools, universal-webpack, ...?

Feature isomorphic-webpack webpack-isomorphic-tools universal-webpack
Only one running node process.
Does not require a separate webpack configuration.
Enables use of all webpack loaders.
Server-side hot reloading of modules.
Supports stack trace.
Prevents serving stale data.
Does not override Node.js require().
Uses webpack target: "node".
Provides low-level API.

From a subjective perspective, isomorphic-webpack is a lot easier to setup than any of the existing alternatives.

I apologise in advance if I have misrepresented either of the frameworks.

Contact me to correct an error in the above comparison table, if you'd like to add another comparison criteria, or to add another framework.

I thought we agreed to use the term "universal"?

TL;DR: Isomorphism is the functional aspect of seamlessly switching between client- and server-side rendering without losing state. Universal is a term used to emphasize the fact that a particular piece of JavaScript code is able to run in multiple environments.

– https://medium.com/@ghengeveld/isomorphism-vs-universal-javascript-4b47fb481beb#.h7fikpuyk

isomorphic-webpack is a program that runs server-side and enables rendering of the same code base client- and server-side.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].