Skip to content

Commit

Permalink
[Flight ESM] Wire up Source Maps in the flight-esm fixture
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed Aug 20, 2024
1 parent 52c9c43 commit 7f3783c
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 8 deletions.
39 changes: 39 additions & 0 deletions fixtures/flight-esm/server/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,45 @@ app.use(
express.static('node_modules/react-server-dom-esm/esm')
);

if (process.env.NODE_ENV === 'development') {
app.get('/source-maps', async function (req, res, next) {
// Proxy the request to the regional server.
const proxiedHeaders = {
'X-Forwarded-Host': req.hostname,
'X-Forwarded-For': req.ips,
'X-Forwarded-Port': 3000,
'X-Forwarded-Proto': req.protocol,
};

const promiseForData = request(
{
host: '127.0.0.1',
port: 3001,
method: req.method,
path: req.originalUrl,
headers: proxiedHeaders,
},
req
);

try {
const rscResponse = await promiseForData;
res.set('Content-type', 'application/json');
rscResponse.on('data', data => {
res.write(data);
res.flush();
});
rscResponse.on('end', data => {
res.end();
});
} catch (e) {
console.error(`Failed to proxy request: ${e.stack}`);
res.statusCode = 500;
res.end();
}
});
}

app.listen(3000, () => {
console.log('Global Fizz/Webpack Server listening on port 3000...');
});
Expand Down
65 changes: 65 additions & 0 deletions fixtures/flight-esm/server/region.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const app = express();
const compress = require('compression');
const {Readable} = require('node:stream');

const nodeModule = require('node:module');

app.use(compress());

// Application
Expand Down Expand Up @@ -116,6 +118,69 @@ app.get('/todos', function (req, res) {
]);
});

if (process.env.NODE_ENV === 'development') {
const rootDir = path.resolve(__dirname, '../');

app.get('/source-maps', async function (req, res, next) {
try {
res.set('Content-type', 'application/json');
let requestedFilePath = req.query.name;

if (requestedFilePath.startsWith('file://')) {
requestedFilePath = requestedFilePath.slice(7);
}

const relativePath = path.relative(rootDir, requestedFilePath);
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
// This is outside the root directory of the app. Forbid it to be served.
res.status = 403;
res.write('{}');
res.end();
return;
}

const sourceMap = nodeModule.findSourceMap(requestedFilePath);
let map;
// There are two ways to return a source map depending on what we observe in error.stack.
// A real app will have a similar choice to make for which strategy to pick.
if (!sourceMap || Error.prepareStackTrace === undefined) {
// When --enable-source-maps is enabled, the error.stack that we use to track
// stacks will have had the source map already applied so it's pointing to the
// original source. We return a blank source map that just maps everything to
// the original source in this case.
const sourceContent = await readFile(requestedFilePath, 'utf8');
const lines = sourceContent.split('\n').length;
map = {
version: 3,
sources: [requestedFilePath],
sourcesContent: [sourceContent],
// Note: This approach to mapping each line only lets you jump to each line
// not jump to a column within a line. To do that, you need a proper source map
// generated for each parsed segment or add a segment for each column.
mappings: 'AAAA' + ';AACA'.repeat(lines - 1),
sourceRoot: '',
};
} else {
// If something has overridden prepareStackTrace it is likely not getting the
// natively applied source mapping to error.stack and so the line will point to
// the compiled output similar to how a browser works.
// E.g. ironically this can happen with the source-map-support library that is
// auto-invoked by @babel/register if external source maps are generated.
// In this case we just use the source map that the native source mapping would
// have used.
map = sourceMap.payload;
}
res.write(JSON.stringify(map));
res.end();
} catch (x) {
res.status = 500;
res.write('{}');
res.end();
console.error(x);
}
});
}

app.listen(3001, () => {
console.log('Regional Flight Server listening on port 3001...');
});
Expand Down
11 changes: 11 additions & 0 deletions fixtures/flight-esm/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import ReactDOM from 'react-dom/client';
import {createFromFetch, encodeReply} from 'react-server-dom-esm/client';

const moduleBaseURL = '/src/';

function findSourceMapURL(fileName) {
return (
document.location.origin +
'/source-maps?name=' +
encodeURIComponent(fileName)
);
}

let updateRoot;
async function callServer(id, args) {
const response = fetch('/', {
Expand All @@ -17,6 +26,7 @@ async function callServer(id, args) {
const {returnValue, root} = await createFromFetch(response, {
callServer,
moduleBaseURL,
findSourceMapURL,
});
// Refresh the tree with the new RSC payload.
startTransition(() => {
Expand All @@ -34,6 +44,7 @@ let data = createFromFetch(
{
callServer,
moduleBaseURL,
findSourceMapURL,
}
);

Expand Down
21 changes: 13 additions & 8 deletions fixtures/flight/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ import {createFromFetch, encodeReply} from 'react-server-dom-webpack/client';
// TODO: This should be a dependency of the App but we haven't implemented CSS in Node yet.
import './style.css';

function findSourceMapURL(fileName) {
return (
document.location.origin +
'/source-maps?name=' +
encodeURIComponent(fileName)
);
}

let updateRoot;
async function callServer(id, args) {
const response = fetch('/', {
Expand All @@ -16,7 +24,10 @@ async function callServer(id, args) {
},
body: await encodeReply(args),
});
const {returnValue, root} = await createFromFetch(response, {callServer});
const {returnValue, root} = await createFromFetch(response, {
callServer,
findSourceMapURL,
});
// Refresh the tree with the new RSC payload.
startTransition(() => {
updateRoot(root);
Expand All @@ -39,13 +50,7 @@ async function hydrateApp() {
}),
{
callServer,
findSourceMapURL(fileName) {
return (
document.location.origin +
'/source-maps?name=' +
encodeURIComponent(fileName)
);
},
findSourceMapURL,
}
);

Expand Down

0 comments on commit 7f3783c

Please sign in to comment.