mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-16 21:53:07 +00:00
feat: Batch dev server logs and fix React module resolution order
This commit is contained in:
@@ -74,6 +74,20 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
// Keep track of whether we've fetched initial logs
|
// Keep track of whether we've fetched initial logs
|
||||||
const hasFetchedInitialLogs = useRef(false);
|
const hasFetchedInitialLogs = useRef(false);
|
||||||
|
|
||||||
|
// Buffer for batching rapid output events into fewer setState calls.
|
||||||
|
// Content accumulates here and is flushed via requestAnimationFrame,
|
||||||
|
// ensuring at most one React re-render per animation frame (~60fps max).
|
||||||
|
const pendingOutputRef = useRef('');
|
||||||
|
const rafIdRef = useRef<number | null>(null);
|
||||||
|
|
||||||
|
const resetPendingOutput = useCallback(() => {
|
||||||
|
if (rafIdRef.current !== null) {
|
||||||
|
cancelAnimationFrame(rafIdRef.current);
|
||||||
|
rafIdRef.current = null;
|
||||||
|
}
|
||||||
|
pendingOutputRef.current = '';
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch buffered logs from the server
|
* Fetch buffered logs from the server
|
||||||
*/
|
*/
|
||||||
@@ -130,6 +144,7 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
* Clear logs and reset state
|
* Clear logs and reset state
|
||||||
*/
|
*/
|
||||||
const clearLogs = useCallback(() => {
|
const clearLogs = useCallback(() => {
|
||||||
|
resetPendingOutput();
|
||||||
setState({
|
setState({
|
||||||
logs: '',
|
logs: '',
|
||||||
logsVersion: 0,
|
logsVersion: 0,
|
||||||
@@ -144,13 +159,7 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
serverError: null,
|
serverError: null,
|
||||||
});
|
});
|
||||||
hasFetchedInitialLogs.current = false;
|
hasFetchedInitialLogs.current = false;
|
||||||
}, []);
|
}, [resetPendingOutput]);
|
||||||
|
|
||||||
// Buffer for batching rapid output events into fewer setState calls.
|
|
||||||
// Content accumulates here and is flushed via requestAnimationFrame,
|
|
||||||
// ensuring at most one React re-render per animation frame (~60fps max).
|
|
||||||
const pendingOutputRef = useRef('');
|
|
||||||
const rafIdRef = useRef<number | null>(null);
|
|
||||||
|
|
||||||
const flushPendingOutput = useCallback(() => {
|
const flushPendingOutput = useCallback(() => {
|
||||||
rafIdRef.current = null;
|
rafIdRef.current = null;
|
||||||
@@ -197,12 +206,9 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
// Clean up pending RAF on unmount to prevent state updates after unmount
|
// Clean up pending RAF on unmount to prevent state updates after unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (rafIdRef.current !== null) {
|
resetPendingOutput();
|
||||||
cancelAnimationFrame(rafIdRef.current);
|
|
||||||
rafIdRef.current = null;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}, []);
|
}, [resetPendingOutput]);
|
||||||
|
|
||||||
// Fetch initial logs when worktreePath changes
|
// Fetch initial logs when worktreePath changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -230,6 +236,7 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case 'dev-server:started': {
|
case 'dev-server:started': {
|
||||||
|
resetPendingOutput();
|
||||||
const { payload } = event;
|
const { payload } = event;
|
||||||
logger.info('Dev server started:', payload);
|
logger.info('Dev server started:', payload);
|
||||||
setState((prev) => ({
|
setState((prev) => ({
|
||||||
@@ -279,7 +286,7 @@ export function useDevServerLogs({ worktreePath, autoSubscribe = true }: UseDevS
|
|||||||
});
|
});
|
||||||
|
|
||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
}, [worktreePath, autoSubscribe, appendLogs]);
|
}, [worktreePath, autoSubscribe, appendLogs, resetPendingOutput]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -930,7 +930,8 @@ export class HttpApiClient implements ElectronAPI {
|
|||||||
const isHighFrequency =
|
const isHighFrequency =
|
||||||
data.type === 'dev-server:output' ||
|
data.type === 'dev-server:output' ||
|
||||||
data.type === 'test-runner:output' ||
|
data.type === 'test-runner:output' ||
|
||||||
data.type === 'auto_mode_progress';
|
data.type === 'feature:progress' ||
|
||||||
|
(data.type === 'auto-mode:event' && data.payload?.type === 'auto_mode_progress');
|
||||||
if (!isHighFrequency) {
|
if (!isHighFrequency) {
|
||||||
logger.info('WebSocket message:', data.type);
|
logger.info('WebSocket message:', data.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,16 +248,12 @@ export default defineConfig(({ command }) => {
|
|||||||
{ find: '@', replacement: path.resolve(__dirname, './src') },
|
{ find: '@', replacement: path.resolve(__dirname, './src') },
|
||||||
// Force ALL React imports (including from nested deps like zustand@4 inside
|
// Force ALL React imports (including from nested deps like zustand@4 inside
|
||||||
// @xyflow/react) to resolve to a single copy.
|
// @xyflow/react) to resolve to a single copy.
|
||||||
|
// Explicit subpath aliases must come BEFORE the broad regex so Vite's
|
||||||
|
// first-match-wins resolution applies the specific match first.
|
||||||
{
|
{
|
||||||
find: /^react-dom(\/|$)/,
|
find: /^react-dom(\/|$)/,
|
||||||
replacement: path.resolve(__dirname, '../../node_modules/react-dom') + '/',
|
replacement: path.resolve(__dirname, '../../node_modules/react-dom') + '/',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
find: /^react(\/|$)/,
|
|
||||||
replacement: path.resolve(__dirname, '../../node_modules/react') + '/',
|
|
||||||
},
|
|
||||||
// Explicit subpath aliases avoid mixed module IDs between bare imports and
|
|
||||||
// optimized deps (e.g. react/jsx-runtime), which can manifest as duplicate React.
|
|
||||||
{
|
{
|
||||||
find: 'react/jsx-runtime',
|
find: 'react/jsx-runtime',
|
||||||
replacement: path.resolve(__dirname, '../../node_modules/react/jsx-runtime.js'),
|
replacement: path.resolve(__dirname, '../../node_modules/react/jsx-runtime.js'),
|
||||||
@@ -266,6 +262,10 @@ export default defineConfig(({ command }) => {
|
|||||||
find: 'react/jsx-dev-runtime',
|
find: 'react/jsx-dev-runtime',
|
||||||
replacement: path.resolve(__dirname, '../../node_modules/react/jsx-dev-runtime.js'),
|
replacement: path.resolve(__dirname, '../../node_modules/react/jsx-dev-runtime.js'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
find: /^react(\/|$)/,
|
||||||
|
replacement: path.resolve(__dirname, '../../node_modules/react') + '/',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
dedupe: ['react', 'react-dom', 'zustand', 'use-sync-external-store', '@xyflow/react'],
|
dedupe: ['react', 'react-dom', 'zustand', 'use-sync-external-store', '@xyflow/react'],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user