fixtures/flight/server/global.js JAVASCRIPT 298 lines View on github.com → Search inside
1'use strict';23// This is a server to host CDN distributed resources like Webpack bundles and SSR45const path = require('path');67// Do this as the first thing so that any code reading it knows the right env.8process.env.BABEL_ENV = process.env.NODE_ENV;910const babelRegister = require('@babel/register');11babelRegister({12  babelrc: false,13  ignore: [14    /\/(build|node_modules)\//,15    function (file) {16      if ((path.dirname(file) + '/').startsWith(__dirname + '/')) {17        // Ignore everything in this folder18        // because it's a mix of CJS and ESM19        // and working with raw code is easier.20        return true;21      }22      return false;23    },24  ],25  presets: ['@babel/preset-react'],26});2728// Ensure environment variables are read.29require('../config/env');3031const fs = require('fs').promises;32const compress = require('compression');33const chalk = require('chalk');34const express = require('express');35const http = require('http');36const React = require('react');3738const {renderToPipeableStream} = require('react-dom/server');39const {createFromNodeStream} = require('react-server-dom-unbundled/client');40const {PassThrough} = require('stream');4142const app = express();4344app.use(compress());4546if (process.env.NODE_ENV === 'development') {47  // In development we host the Webpack server for live bundling.48  const webpack = require('webpack');49  const webpackMiddleware = require('webpack-dev-middleware');50  const webpackHotMiddleware = require('webpack-hot-middleware');51  const paths = require('../config/paths');52  const configFactory = require('../config/webpack.config');53  const getClientEnvironment = require('../config/env');5455  const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));5657  const config = configFactory('development');58  const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';59  const appName = require(paths.appPackageJson).name;6061  // Create a webpack compiler that is configured with custom messages.62  const compiler = webpack(config);63  app.use(64    webpackMiddleware(compiler, {65      publicPath: paths.publicUrlOrPath.slice(0, -1),66      serverSideRender: true,67      headers: () => {68        return {69          'Cache-Control': 'no-store, must-revalidate',70        };71      },72    })73  );74  app.use(webpackHotMiddleware(compiler));75}7677function request(options, body) {78  return new Promise((resolve, reject) => {79    const req = http.request(options, res => {80      resolve(res);81    });82    req.on('error', e => {83      reject(e);84    });85    body.pipe(req);86  });87}8889async function renderApp(req, res, next) {90  // Proxy the request to the regional server.91  const proxiedHeaders = {92    'X-Forwarded-Host': req.hostname,93    'X-Forwarded-For': req.ips,94    'X-Forwarded-Port': 3000,95    'X-Forwarded-Proto': req.protocol,96  };97  // Proxy other headers as desired.98  if (req.get('rsc-action')) {99    proxiedHeaders['Content-type'] = req.get('Content-type');100    proxiedHeaders['rsc-action'] = req.get('rsc-action');101  } else if (req.get('Content-type')) {102    proxiedHeaders['Content-type'] = req.get('Content-type');103  }104  if (req.headers['cache-control']) {105    proxiedHeaders['Cache-Control'] = req.get('cache-control');106  }107  if (req.get('rsc-request-id')) {108    proxiedHeaders['rsc-request-id'] = req.get('rsc-request-id');109  }110111  const requestsPrerender = req.path === '/prerender';112113  const promiseForData = request(114    {115      host: '127.0.0.1',116      port: 3001,117      method: req.method,118      path: requestsPrerender ? '/?prerender=1' : '/',119      headers: proxiedHeaders,120    },121    req122  );123124  if (req.accepts('text/html')) {125    try {126      const rscResponse = await promiseForData;127128      let virtualFs;129      let buildPath;130      if (process.env.NODE_ENV === 'development') {131        const {devMiddleware} = res.locals.webpack;132        virtualFs = devMiddleware.outputFileSystem.promises;133        buildPath = devMiddleware.stats.toJson().outputPath;134      } else {135        virtualFs = fs;136        buildPath = path.join(__dirname, '../build/');137      }138      // Read the module map from the virtual file system.139      const serverConsumerManifest = JSON.parse(140        await virtualFs.readFile(141          path.join(buildPath, 'react-ssr-manifest.json'),142          'utf8'143        )144      );145146      // Read the entrypoints containing the initial JS to bootstrap everything.147      // For other pages, the chunks in the RSC payload are enough.148      const mainJSChunks = JSON.parse(149        await virtualFs.readFile(150          path.join(buildPath, 'entrypoint-manifest.json'),151          'utf8'152        )153      ).main.js;154      // For HTML, we're a "client" emulator that runs the client code,155      // so we start by consuming the RSC payload. This needs a module156      // map that reverse engineers the client-side path to the SSR path.157158      // We need to get the formState before we start rendering but we also159      // need to run the Flight client inside the render to get all the preloads.160      // The API is ambivalent about what's the right one so we need two for now.161162      // Tee the response into two streams so that we can do both.163      const rscResponse1 = new PassThrough();164      const rscResponse2 = new PassThrough();165166      rscResponse.pipe(rscResponse1);167      rscResponse.pipe(rscResponse2);168169      const {formState} = await createFromNodeStream(170        rscResponse1,171        serverConsumerManifest172      );173      rscResponse1.end();174175      let cachedResult;176      let Root = () => {177        if (!cachedResult) {178          // Read this stream inside the render.179          cachedResult = createFromNodeStream(180            rscResponse2,181            serverConsumerManifest182          );183        }184        return React.use(cachedResult).root;185      };186      // Render it into HTML by resolving the client components187      res.set('Content-type', 'text/html');188      const {pipe} = renderToPipeableStream(React.createElement(Root), {189        bootstrapScripts: mainJSChunks,190        formState: formState,191        onShellReady() {192          pipe(res);193        },194        onShellError(error) {195          const {pipe: pipeError} = renderToPipeableStream(196            React.createElement('html', null, React.createElement('body')),197            {198              bootstrapScripts: mainJSChunks,199            }200          );201          pipeError(res);202        },203      });204    } catch (e) {205      console.error(`Failed to SSR: ${e.stack}`);206      res.statusCode = 500;207      res.end();208    }209  } else {210    try {211      const rscResponse = await promiseForData;212      // For other request, we pass-through the RSC payload.213      res.set('Content-type', 'text/x-component');214      rscResponse.on('data', data => {215        res.write(data);216        res.flush();217      });218      rscResponse.on('end', data => {219        res.end();220      });221    } catch (e) {222      console.error(`Failed to proxy request: ${e.stack}`);223      res.statusCode = 500;224      res.end();225    }226  }227}228229app.all('/', renderApp);230app.all('/prerender', renderApp);231232if (process.env.NODE_ENV === 'development') {233  app.use(express.static('public'));234235  app.get('/source-maps', async function (req, res, next) {236    // Proxy the request to the regional server.237    const proxiedHeaders = {238      'X-Forwarded-Host': req.hostname,239      'X-Forwarded-For': req.ips,240      'X-Forwarded-Port': 3000,241      'X-Forwarded-Proto': req.protocol,242    };243244    const promiseForData = request(245      {246        host: '127.0.0.1',247        port: 3001,248        method: req.method,249        path: req.originalUrl,250        headers: proxiedHeaders,251      },252      req253    );254255    try {256      const rscResponse = await promiseForData;257      res.set('Content-type', 'application/json');258      rscResponse.on('data', data => {259        res.write(data);260        res.flush();261      });262      rscResponse.on('end', data => {263        res.end();264      });265    } catch (e) {266      console.error(`Failed to proxy request: ${e.stack}`);267      res.statusCode = 500;268      res.end();269    }270  });271} else {272  // In production we host the static build output.273  app.use(express.static('build'));274}275276app.listen(3000, () => {277  console.log('Global Fizz/Webpack Server listening on port 3000...');278});279280app.on('error', function (error) {281  if (error.syscall !== 'listen') {282    throw error;283  }284285  switch (error.code) {286    case 'EACCES':287      console.error('port 3000 requires elevated privileges');288      process.exit(1);289      break;290    case 'EADDRINUSE':291      console.error('Port 3000 is already in use');292      process.exit(1);293      break;294    default:295      throw error;296  }297});

Code quality findings 10

Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (process.env.NODE_ENV === 'development') {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
Ensure all async functions handle errors properly
info correctness async-without-catch
async function renderApp(req, res, next) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const requestsPrerender = req.path === '/prerender';
Ensure try blocks have corresponding catch or finally blocks
info correctness try-without-catch
try {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (process.env.NODE_ENV === 'development') {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (process.env.NODE_ENV === 'development') {
Ensure all async functions handle errors properly
info correctness async-without-catch
app.get('/source-maps', async function (req, res, next) {
Remove debugging statements or use a logging library
info correctness console-log
console.log('Global Fizz/Webpack Server listening on port 3000...');
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (error.syscall !== 'listen') {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.