Skip to content

Commit

Permalink
fix(demos): watch node integrator
Browse files Browse the repository at this point in the history
By also bundling the node integrator with webpack-dev-middleware we can
avoid having to restart the demo server when changes to server-side
rendered demos are made.

This is based on https://github.com/webpack/webpack-dev-middleware#server-side-rendering.

fixes #250
  • Loading branch information
unstubbable committed Feb 5, 2021
1 parent 08f4f52 commit ddb29bf
Show file tree
Hide file tree
Showing 25 changed files with 735 additions and 266 deletions.
12 changes: 6 additions & 6 deletions packages/demos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
"@types/pino": "^5.8.5",
"@types/react-router": "^5.0.2",
"@types/styled-components": "^5.1.4",
"@types/webpack": "^4.4.20",
"@types/webpack-dev-middleware": "^2.0.2",
"@types/webpack-merge": "^4.1.3",
"@types/webpack": "^4.41.26",
"@types/webpack-dev-middleware": "^4.1.0",
"@types/webpack-merge": "^4.1.5",
"copy-webpack-plugin": "^5.0.0",
"css-loader": "^3.0.0",
"express": "^4.16.4",
Expand All @@ -51,9 +51,9 @@
"tsconfig-paths": "^3.7.0",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"url-loader": "^2.0.0",
"webpack": "^4.27.0",
"webpack-cli": "^3.2.3",
"webpack-dev-middleware": "^3.4.0",
"webpack": "^4.46.0",
"webpack-cli": "^4.5.0",
"webpack-dev-middleware": "^4.1.0",
"webpack-merge": "^4.2.1"
}
}
2 changes: 1 addition & 1 deletion packages/demos/src/advanced-routing/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ describe('integration test: "advanced-routing"', () => {
let url: string;

beforeAll(async () => {
server = await startServer(webpackConfigs, undefined);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
2 changes: 1 addition & 1 deletion packages/demos/src/custom-logging/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('integration test: "custom logging"', () => {
let consoleMessages: ConsoleMessage[];

beforeAll(async () => {
server = await startServer(webpackConfigs, undefined);
server = await startServer(webpackConfigs);
consoleMessages = [];

page.on('console', consoleMessages.push.bind(consoleMessages));
Expand Down
5 changes: 2 additions & 3 deletions packages/demos/src/custom-logging/integrator.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {FeatureHubContextProvider} from '@feature-hub/react';
import pino from 'pino';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {getPkgVersion} from '../get-pkg-version';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {AppRendererOptions, AppRendererResult} from '../node-integrator';
import {App} from './app';

export default async function renderApp({
Expand All @@ -17,7 +16,7 @@ export default async function renderApp({
const {featureAppManager} = createFeatureHub('test:integrator', {
logger,
moduleLoader: loadCommonJsModule,
providedExternals: {react: getPkgVersion('react')},
providedExternals: {react: process.env.REACT_VERSION as string},
featureServiceDefinitions: [
defineLogger((consumerId, consumerName) =>
logger.child({consumerId, consumerName})
Expand Down
10 changes: 10 additions & 0 deletions packages/demos/src/custom-logging/webpack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const {nodeIntegratorFilename} = require('../node-integrator');
const webpackBaseConfig = require('../webpack-base-config');

/**
Expand All @@ -15,6 +16,15 @@ const configs = [
publicPath: '/',
},
}),
merge.smart(webpackBaseConfig, {
entry: path.join(__dirname, './integrator.node.tsx'),
output: {
filename: nodeIntegratorFilename,
libraryTarget: 'commonjs2',
publicPath: '/',
},
target: 'node',
}),
];

module.exports = configs;
7 changes: 7 additions & 0 deletions packages/demos/src/feature-app-in-feature-app/externals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as FeatureHubReact from '@feature-hub/react';
import * as React from 'react';

export const externals = {
react: React,
'@feature-hub/react': FeatureHubReact,
};
3 changes: 1 addition & 2 deletions packages/demos/src/feature-app-in-feature-app/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {Server} from 'http';
import {AddressInfo} from 'net';
import {Browser} from '../browser';
import {startServer} from '../start-server';
import renderApp from './integrator.node';
import webpackConfigs from './webpack-config';

jest.setTimeout(120000);
Expand All @@ -18,7 +17,7 @@ describe('integration test: "Feature App in Feature App"', () => {
let url: string;

beforeAll(async () => {
server = await startServer(webpackConfigs, renderApp);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import {createFeatureHub} from '@feature-hub/core';
import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
import {createCommonJsModuleLoader} from '@feature-hub/module-loader-commonjs';
import {FeatureAppLoader, FeatureHubContextProvider} from '@feature-hub/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {getPkgVersion} from '../get-pkg-version';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {AppRendererOptions, AppRendererResult} from '../node-integrator';
import {externals} from './externals';

export default async function renderApp({
port,
}: AppRendererOptions): Promise<AppRendererResult> {
const featureAppNodeUrl = `http://localhost:${port}/feature-app.commonjs.js`;

const {featureAppManager} = createFeatureHub('test:integrator', {
moduleLoader: loadCommonJsModule,
moduleLoader: createCommonJsModuleLoader(externals),
providedExternals: {
react: getPkgVersion('react'),
'@feature-hub/react': getPkgVersion('@feature-hub/react'),
react: process.env.REACT_VERSION as string,
'@feature-hub/react': process.env.FEATURE_HUB_REACT_VERSION as string,
},
});

Expand Down
6 changes: 2 additions & 4 deletions packages/demos/src/feature-app-in-feature-app/integrator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import * as FeatureHubReact from '@feature-hub/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import '../blueprint-css';
import {externals} from './externals';

defineExternals({
react: React,
'@feature-hub/react': FeatureHubReact,
});
defineExternals(externals);

const {featureAppManager} = createFeatureHub('test:integrator', {
moduleLoader: loadAmdModule,
Expand Down
11 changes: 11 additions & 0 deletions packages/demos/src/feature-app-in-feature-app/webpack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const {nodeIntegratorFilename} = require('../node-integrator');
const webpackBaseConfig = require('../webpack-base-config');

/**
Expand Down Expand Up @@ -41,6 +42,16 @@ const configs = [
publicPath: '/',
},
}),

merge.smart(webpackBaseConfig, {
entry: path.join(__dirname, './integrator.node.tsx'),
output: {
filename: nodeIntegratorFilename,
libraryTarget: 'commonjs2',
publicPath: '/',
},
target: 'node',
}),
];

module.exports = configs;
3 changes: 1 addition & 2 deletions packages/demos/src/history-service/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {AddressInfo} from 'net';
import {ElementHandle} from 'puppeteer';
import {Browser} from '../browser';
import {startServer} from '../start-server';
import renderApp from './integrator.node';
import webpackConfigs from './webpack-config';

jest.setTimeout(120000);
Expand Down Expand Up @@ -70,7 +69,7 @@ describe('integration test: "history-service"', () => {
let url: string;

beforeAll(async () => {
server = await startServer(webpackConfigs, renderApp);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
2 changes: 1 addition & 1 deletion packages/demos/src/history-service/integrator.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {defineHistoryService} from '@feature-hub/history-service';
import {defineServerRequest} from '@feature-hub/server-request';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {AppRendererOptions, AppRendererResult} from '../node-integrator';
import {App} from './app';
import {rootLocationTransformer} from './root-location-transformer';

Expand Down
10 changes: 10 additions & 0 deletions packages/demos/src/history-service/webpack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const {nodeIntegratorFilename} = require('../node-integrator');
const webpackBaseConfig = require('../webpack-base-config');

/**
Expand All @@ -15,6 +16,15 @@ const configs = [
publicPath: '/',
},
}),
merge.smart(webpackBaseConfig, {
entry: path.join(__dirname, './integrator.node.tsx'),
output: {
filename: nodeIntegratorFilename,
libraryTarget: 'commonjs2',
publicPath: '/',
},
target: 'node',
}),
];

module.exports = configs;
2 changes: 1 addition & 1 deletion packages/demos/src/integrator-dom/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('integration test: "dom integrator"', () => {
let url: string;

beforeAll(async () => {
server = await startServer(webpackConfigs, undefined);
server = await startServer(webpackConfigs);
const {port} = server.address() as AddressInfo;
url = `http://localhost:${port}`;

Expand Down
2 changes: 1 addition & 1 deletion packages/demos/src/module-loader-amd/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('integration test: "amd module loader"', () => {
let server: Server;

beforeAll(async () => {
server = await startServer(webpackConfigs, undefined);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
3 changes: 1 addition & 2 deletions packages/demos/src/module-loader-commonjs/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {Server} from 'http';
import {AddressInfo} from 'net';
import {Browser} from '../browser';
import {startServer} from '../start-server';
import renderApp from './integrator.node';
import webpackConfigs from './webpack-config';

jest.setTimeout(120000);
Expand All @@ -17,7 +16,7 @@ describe('integration test: "commonjs module loader"', () => {
let server: Server;

beforeAll(async () => {
server = await startServer(webpackConfigs, renderApp);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
import {FeatureAppLoader, FeatureHubContextProvider} from '@feature-hub/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {AppRendererOptions, AppRendererResult} from '../node-integrator';

export default async function renderApp({
port,
Expand Down
10 changes: 10 additions & 0 deletions packages/demos/src/module-loader-commonjs/webpack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const {nodeIntegratorFilename} = require('../node-integrator');
const webpackBaseConfig = require('../webpack-base-config');

/**
Expand All @@ -24,6 +25,15 @@ const configs = [
publicPath: '/',
},
}),
merge.smart(webpackBaseConfig, {
entry: path.join(__dirname, './integrator.node.tsx'),
output: {
filename: nodeIntegratorFilename,
libraryTarget: 'commonjs2',
publicPath: '/',
},
target: 'node',
}),
];

module.exports = configs;
50 changes: 50 additions & 0 deletions packages/demos/src/node-integrator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {Css} from '@feature-hub/react';
import express from 'express';
import webpack from 'webpack';

export interface AppRendererOptions {
port: number;
req: express.Request;
}

export interface AppRendererResult {
html: string;
serializedStates?: string;
stylesheetsForSsr?: Map<string, Css>;
urlsForHydration?: Set<string>;
}

export type AppRenderer = (
options: AppRendererOptions
) => Promise<AppRendererResult>;

// tslint:disable-next-line:no-any
function evalNodeSource(source: string): any {
const mod = {exports: {}};

// tslint:disable-next-line:function-constructor
Function('module', 'exports', 'require', source)(mod, mod.exports, require);

return mod.exports;
}

export const nodeIntegratorFilename = 'integrator.node.js';

export function loadNodeIntegrator(
res: express.Response
): AppRenderer | undefined {
try {
const outputFileSystem: webpack.InputFileSystem & webpack.OutputFileSystem =
res.locals.webpack.devMiddleware.outputFileSystem;

const {outputPath} = res.locals.webpack.devMiddleware.stats.toJson();

const source = outputFileSystem
.readFileSync(outputFileSystem.join(outputPath, nodeIntegratorFilename))
.toString();

return evalNodeSource(source).default;
} catch {
return undefined;
}
}
3 changes: 1 addition & 2 deletions packages/demos/src/server-side-rendering/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {Server} from 'http';
import {AddressInfo} from 'net';
import {Browser} from '../browser';
import {startServer} from '../start-server';
import renderApp from './integrator.node';
import webpackConfigs from './webpack-config';

jest.setTimeout(120000);
Expand All @@ -18,7 +17,7 @@ describe('integration test: "server-side rendering"', () => {
let url: string;

beforeAll(async () => {
server = await startServer(webpackConfigs, renderApp);
server = await startServer(webpackConfigs);

const {port} = server.address() as AddressInfo;

Expand Down
9 changes: 4 additions & 5 deletions packages/demos/src/server-side-rendering/integrator.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
defineAsyncSsrManager,
} from '@feature-hub/async-ssr-manager';
import {createFeatureHub} from '@feature-hub/core';
import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
import {createCommonJsModuleLoader} from '@feature-hub/module-loader-commonjs';
import {
Css,
FeatureHubContextProvider,
Expand All @@ -15,8 +15,7 @@ import {
} from '@feature-hub/serialized-state-manager';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {getPkgVersion} from '../get-pkg-version';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {AppRendererOptions, AppRendererResult} from '../node-integrator';
import {App} from './app';

export default async function renderApp({
Expand All @@ -27,8 +26,8 @@ export default async function renderApp({
const {featureAppManager, featureServices} = createFeatureHub(
'test:integrator',
{
moduleLoader: loadCommonJsModule,
providedExternals: {react: getPkgVersion('react')},
moduleLoader: createCommonJsModuleLoader({react: React}),
providedExternals: {react: process.env.REACT_VERSION as string},
featureServiceDefinitions: [
asyncSsrManagerDefinition,
serializedStateManagerDefinition,
Expand Down
Loading

0 comments on commit ddb29bf

Please sign in to comment.