mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 00:20:04 +01:00
[Flight Parcel] Implement findSourceMapURL (#32294)
This implements `findSourceMapURL` in react-server-dom-parcel, enabling source maps for replayed server errors on the client. It utilizes a new endpoint in the Parcel dev server that returns the source map for a given bundle/file. The error overlay UI has also been updated to handle these stacks. See https://github.com/parcel-bundler/parcel/pull/10082 Also updated the fixture to the latest Parcel canary. A few APIs have changed. We do have a higher level library wrapper now (`@parcel/rsc` added in https://github.com/parcel-bundler/parcel/pull/10074) but I left the fixture using the lower level APIs directly here since it is easier to see how react-server-dom-parcel is used.
This commit is contained in:
parent
0a82580bfc
commit
f82c662b8d
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"extends": "@parcel/config-default",
|
||||
"runtimes": ["...", "@parcel/runtime-rsc"]
|
||||
}
|
||||
|
|
@ -1,15 +1,11 @@
|
|||
{
|
||||
"name": "flight-parcel",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"examples/*"
|
||||
],
|
||||
"source": "src/server.tsx",
|
||||
"server": "dist/server.js",
|
||||
"targets": {
|
||||
"server": {
|
||||
"source": "src/server.tsx",
|
||||
"context": "react-server",
|
||||
"outputFormat": "commonjs",
|
||||
"includeNodeModules": {
|
||||
"express": false
|
||||
}
|
||||
|
|
@ -18,18 +14,11 @@
|
|||
"scripts": {
|
||||
"predev": "cp -r ../../build/oss-experimental/* ./node_modules/",
|
||||
"prebuild": "cp -r ../../build/oss-experimental/* ./node_modules/",
|
||||
"dev": "concurrently \"npm run dev:watch\" \"sleep 2 && npm run dev:start\"",
|
||||
"dev:watch": "NODE_ENV=development parcel watch",
|
||||
"dev:start": "NODE_ENV=development node dist/server.js",
|
||||
"dev": "parcel",
|
||||
"build": "parcel build",
|
||||
"start": "node dist/server.js"
|
||||
},
|
||||
"@parcel/resolver-default": {
|
||||
"packageExports": true
|
||||
},
|
||||
"dependencies": {
|
||||
"@parcel/config-default": "2.0.0-dev.1795",
|
||||
"@parcel/runtime-rsc": "2.13.3-dev.3418",
|
||||
"@types/parcel-env": "^0.0.6",
|
||||
"@types/express": "*",
|
||||
"@types/node": "^22.10.1",
|
||||
|
|
@ -37,15 +26,11 @@
|
|||
"@types/react-dom": "^19",
|
||||
"concurrently": "^7.3.0",
|
||||
"express": "^4.18.2",
|
||||
"parcel": "2.0.0-dev.1793",
|
||||
"parcel": "canary",
|
||||
"process": "^0.11.10",
|
||||
"react": "experimental",
|
||||
"react-dom": "experimental",
|
||||
"react-server-dom-parcel": "experimental",
|
||||
"rsc-html-stream": "^0.0.4",
|
||||
"ws": "^8.8.1"
|
||||
},
|
||||
"@parcel/bundler-default": {
|
||||
"minBundleSize": 0
|
||||
"rsc-html-stream": "^0.0.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import './client';
|
||||
import './Todos.css';
|
||||
import {Resources} from '@parcel/runtime-rsc';
|
||||
import {Dialog} from './Dialog';
|
||||
import {TodoDetail} from './TodoDetail';
|
||||
import {TodoCreate} from './TodoCreate';
|
||||
|
|
@ -13,7 +12,6 @@ export async function Todos({id}: {id?: number}) {
|
|||
<html style={{colorScheme: 'dark light'}}>
|
||||
<head>
|
||||
<title>Todos</title>
|
||||
<Resources />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ async function render(
|
|||
return ReactClient.use(data);
|
||||
}
|
||||
|
||||
let htmlStream = await renderHTMLToReadableStream(<Content />);
|
||||
let htmlStream = await renderHTMLToReadableStream(<Content />, {
|
||||
bootstrapScriptContent: (Todos as any).bootstrapScript,
|
||||
});
|
||||
let response = htmlStream.pipeThrough(injectRSCPayload(s2));
|
||||
Readable.fromWeb(response as NodeReadableStream).pipe(res);
|
||||
} else {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -31,6 +31,17 @@ import type {TemporaryReferenceSet} from 'react-client/src/ReactFlightTemporaryR
|
|||
export {createTemporaryReferenceSet} from 'react-client/src/ReactFlightTemporaryReferences';
|
||||
export type {TemporaryReferenceSet};
|
||||
|
||||
function findSourceMapURL(filename: string, environmentName: string) {
|
||||
const devServer = parcelRequire.meta.devServer;
|
||||
if (devServer != null) {
|
||||
const qs = new URLSearchParams();
|
||||
qs.set('filename', filename);
|
||||
qs.set('env', environmentName);
|
||||
return devServer + '/__parcel_source_map?' + qs.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
type CallServerCallback = <A, T>(id: string, args: A) => Promise<T>;
|
||||
|
||||
let callServer: CallServerCallback | null = null;
|
||||
|
|
@ -57,6 +68,9 @@ export function createServerReference<A: Iterable<any>, T>(
|
|||
return createServerReferenceImpl(
|
||||
id + '#' + exportName,
|
||||
callCurrentServerCallback,
|
||||
undefined,
|
||||
findSourceMapURL,
|
||||
exportName,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +121,7 @@ export function createFromReadableStream<T>(
|
|||
options && options.temporaryReferences
|
||||
? options.temporaryReferences
|
||||
: undefined,
|
||||
undefined, // TODO: findSourceMapUrl
|
||||
__DEV__ ? findSourceMapURL : undefined,
|
||||
__DEV__ ? (options ? options.replayConsoleLogs !== false : true) : false, // defaults to true
|
||||
__DEV__ && options && options.environmentName
|
||||
? options.environmentName
|
||||
|
|
@ -131,7 +145,7 @@ export function createFromFetch<T>(
|
|||
options && options.temporaryReferences
|
||||
? options.temporaryReferences
|
||||
: undefined,
|
||||
undefined, // TODO: findSourceMapUrl
|
||||
__DEV__ ? findSourceMapURL : undefined,
|
||||
__DEV__ ? (options ? options.replayConsoleLogs !== false : true) : false, // defaults to true
|
||||
__DEV__ && options && options.environmentName
|
||||
? options.environmentName
|
||||
|
|
|
|||
|
|
@ -30,6 +30,17 @@ import type {TemporaryReferenceSet} from 'react-client/src/ReactFlightTemporaryR
|
|||
export {createTemporaryReferenceSet} from 'react-client/src/ReactFlightTemporaryReferences';
|
||||
export type {TemporaryReferenceSet};
|
||||
|
||||
function findSourceMapURL(filename: string, environmentName: string) {
|
||||
const devServer = parcelRequire.meta.devServer;
|
||||
if (devServer != null) {
|
||||
const qs = new URLSearchParams();
|
||||
qs.set('filename', filename);
|
||||
qs.set('env', environmentName);
|
||||
return devServer + '/__parcel_source_map?' + qs.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function noServerCall() {
|
||||
throw new Error(
|
||||
'Server Functions cannot be called during initial render. ' +
|
||||
|
|
@ -42,7 +53,13 @@ export function createServerReference<A: Iterable<any>, T>(
|
|||
id: string,
|
||||
exportName: string,
|
||||
): (...A) => Promise<T> {
|
||||
return createServerReferenceImpl(id + '#' + exportName, noServerCall);
|
||||
return createServerReferenceImpl(
|
||||
id + '#' + exportName,
|
||||
noServerCall,
|
||||
undefined,
|
||||
findSourceMapURL,
|
||||
exportName,
|
||||
);
|
||||
}
|
||||
|
||||
type EncodeFormActionCallback = <A>(
|
||||
|
|
@ -69,7 +86,7 @@ function createResponseFromOptions(options?: Options) {
|
|||
options && options.temporaryReferences
|
||||
? options.temporaryReferences
|
||||
: undefined,
|
||||
undefined, // TODO: findSourceMapUrl
|
||||
__DEV__ ? findSourceMapURL : undefined,
|
||||
__DEV__ && options ? options.replayConsoleLogs === true : false, // defaults to false
|
||||
__DEV__ && options && options.environmentName
|
||||
? options.environmentName
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@ import {
|
|||
|
||||
import {createServerReference as createServerReferenceImpl} from 'react-client/src/ReactFlightReplyClient';
|
||||
|
||||
function findSourceMapURL(filename: string, environmentName: string) {
|
||||
const devServer = parcelRequire.meta.devServer;
|
||||
if (devServer != null) {
|
||||
const qs = new URLSearchParams();
|
||||
qs.set('filename', filename);
|
||||
qs.set('env', environmentName);
|
||||
return devServer + '/__parcel_source_map?' + qs.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function noServerCall() {
|
||||
throw new Error(
|
||||
'Server Functions cannot be called during initial render. ' +
|
||||
|
|
@ -33,7 +44,13 @@ export function createServerReference<A: Iterable<any>, T>(
|
|||
id: string,
|
||||
exportName: string,
|
||||
): (...A) => Promise<T> {
|
||||
return createServerReferenceImpl(id + '#' + exportName, noServerCall);
|
||||
return createServerReferenceImpl(
|
||||
id + '#' + exportName,
|
||||
noServerCall,
|
||||
undefined,
|
||||
findSourceMapURL,
|
||||
exportName,
|
||||
);
|
||||
}
|
||||
|
||||
type EncodeFormActionCallback = <A>(
|
||||
|
|
@ -60,7 +77,7 @@ export function createFromNodeStream<T>(
|
|||
options ? options.encodeFormAction : undefined,
|
||||
options && typeof options.nonce === 'string' ? options.nonce : undefined,
|
||||
undefined, // TODO: If encodeReply is supported, this should support temporaryReferences
|
||||
undefined, // TODO: findSourceMapUrl
|
||||
__DEV__ ? findSourceMapURL : undefined,
|
||||
__DEV__ && options ? options.replayConsoleLogs === true : false, // defaults to false
|
||||
__DEV__ && options && options.environmentName
|
||||
? options.environmentName
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ declare var parcelRequire: {
|
|||
extendImportMap: (importMap: {[string]: string}) => void,
|
||||
meta: {
|
||||
publicUrl: string,
|
||||
devServer: string | null,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user