Skip to content

Commit 50ff949

Browse files
committed
progress
1 parent 479ea48 commit 50ff949

File tree

6 files changed

+25
-75
lines changed

6 files changed

+25
-75
lines changed

.worklogs/justin/2025-09-01-dev-server-dependency-optimization.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,21 @@ Finally, a guard was added to the plugin's `configResolved` hook to ensure this
107107

108108
The `createDirectiveLookupPlugin` was also updated to ensure its runtime `import()` statements pointed to the new physical dummy barrel files, fully removing the last reference to the old virtual module system.
109109

110+
## 9. A New Hurdle: Inter-Environment Dependency Timing
111+
112+
The "dummy file" solution is correct in principle, but its success depends on a critical assumption: that the `worker` environment completes its dependency scan and populates the `clientFiles` and `serverFiles` sets *before* the `client` and `ssr` environments run their own `optimizeDeps` pass.
113+
114+
It has become clear that this assumption is false. The environment optimizers appear to run in parallel, which means `directiveModulesDevPlugin` (running in the `client` and `ssr` environments) executes with empty `clientFiles` and `serverFiles` sets, rendering the optimization useless.
115+
116+
The next step is to investigate Vite's source code to answer a key question: how does Vite manage the `optimizeDeps` process for multiple environments? We need to determine if they are run concurrently or sequentially, and if there is any mechanism to enforce a specific order. The goal is to find a way to delay the `client` and `ssr` dependency optimization until after the `worker` environment has completed its initial scan.
117+
118+
### 9.1. Investigation Findings: Parallel Execution
119+
120+
A thorough investigation of Vite's source code (`packages/vite/src/node/server/index.ts`) has provided a definitive answer. During server startup, the `initServer` function calls the `listen` method on all configured environments wrapped in a `Promise.all`.
121+
122+
The `listen` method on each `DevEnvironment` instance is responsible for calling `depsOptimizer.init()`, which is the asynchronous function that starts the dependency scanning and optimization process.
123+
124+
Because they are called via `Promise.all`, **all environment dependency optimizers are explicitly run in parallel.** This confirms that our initial assumption was incorrect and explains why the `clientFiles` and `serverFiles` sets are empty. There is no built-in mechanism in Vite to enforce a sequential dependency optimization chain between environments.
125+
126+
Our next task is to devise a new strategy to manually create this synchronization.
127+

sdk/src/runtime/imports/ssr.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export const ssrLoadModule = memoizeOnId(async (id: string) => {
44
const { useClientLookup } = await import(
55
"virtual:use-client-lookup.js" as string
66
);
7-
87
const moduleFn = useClientLookup[id];
98

109
if (!moduleFn) {

sdk/src/vite/configPlugin.mts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import debug from "debug";
77
import { readFile, writeFile } from "node:fs/promises";
88
import { glob } from "glob";
99

10-
import {
11-
INTERMEDIATE_SSR_BRIDGE_PATH,
12-
INTERMEDIATES_OUTPUT_DIR,
13-
} from "../lib/constants.mjs";
10+
import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
1411
import { buildApp } from "./buildApp.mjs";
1512

1613
const log = debug("rwsdk:vite:config");

sdk/src/vite/createDirectiveLookupPlugin.mts

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,56 +77,6 @@ export const findFilesContainingDirective = async ({
7777
log("Found files for %s: %j", directive, Array.from(files));
7878
};
7979

80-
const resolveOptimizedDep = async (
81-
projectRootDir: string,
82-
id: string,
83-
environment: string,
84-
debugNamespace: string,
85-
): Promise<string | undefined> => {
86-
const log = debug(debugNamespace);
87-
88-
try {
89-
const depsDir = environment === "client" ? "deps" : `deps_${environment}`;
90-
const nodeModulesDepsDirPath = path.join("node_modules", ".vite", depsDir);
91-
const depsDirPath = path.join(projectRootDir, nodeModulesDepsDirPath);
92-
const manifestPath = path.join(depsDirPath, "_metadata.json");
93-
log("Checking for manifest at: %s", manifestPath);
94-
95-
const manifestExists = await pathExists(manifestPath);
96-
if (!manifestExists) {
97-
log("Manifest not found at %s", manifestPath);
98-
return undefined;
99-
}
100-
101-
const manifestContent = await readFile(manifestPath, "utf-8");
102-
const manifest = JSON.parse(manifestContent);
103-
104-
if (manifest.optimized && manifest.optimized[id]) {
105-
const optimizedFile = manifest.optimized[id].file;
106-
const optimizedPath = path.join(
107-
"/",
108-
nodeModulesDepsDirPath,
109-
optimizedFile,
110-
);
111-
112-
log(
113-
"Found optimized dependency: filePath=%s, optimizedPath=%s",
114-
id,
115-
optimizedPath,
116-
);
117-
return optimizedPath;
118-
}
119-
120-
process.env.VERBOSE &&
121-
log("File not found in optimized dependencies: id=%s", id);
122-
return undefined;
123-
} catch (error) {
124-
process.env.VERBOSE &&
125-
log("Error resolving optimized dependency for id=%s: %s", id, error);
126-
return undefined;
127-
}
128-
};
129-
13080
export const createDirectiveLookupPlugin = async ({
13181
projectRootDir,
13282
files,
@@ -238,8 +188,6 @@ export const createDirectiveLookupPlugin = async ({
238188
}
239189
},
240190
resolveId(source) {
241-
process.env.VERBOSE && log("Resolving id=%s", source);
242-
243191
if (source === `${config.virtualModuleName}.js`) {
244192
log("Resolving %s module", config.virtualModuleName);
245193
// context(justinvdm, 16 Jun 2025): Include .js extension

sdk/src/vite/directiveModulesDevPlugin.mts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,11 @@ export const directiveModulesDevPlugin = ({
6767
log("Created dummy barrel files at:", dummyFilePaths);
6868

6969
// This esbuild plugin hijacks the dummy files
70-
const esbuildPlugin = {
70+
const esbuildPlugin = (envName: string) => ({
7171
name: "rwsdk:directive-modules-dev-esbuild",
7272
setup(build: any) {
7373
build.onLoad({ filter: /rwsdk-.*-barrel\.js/ }, (args: any) => {
74+
console.log("############### onLoad", envName);
7475
log("ESBuild loading dummy file %s", args.path);
7576
const isClient = args.path.includes("client");
7677
const files = isClient ? clientFiles : serverFiles;
@@ -79,7 +80,7 @@ export const directiveModulesDevPlugin = ({
7980
return { contents, loader: "js" };
8081
});
8182
},
82-
};
83+
});
8384

8485
for (const envName of ["client", "ssr"]) {
8586
const envConfig = config.environments[envName];
@@ -97,7 +98,9 @@ export const directiveModulesDevPlugin = ({
9798
// 2. Add esbuild plugin for the dependency optimizer
9899
envConfig.optimizeDeps.esbuildOptions ??= {};
99100
envConfig.optimizeDeps.esbuildOptions.plugins ??= [];
100-
envConfig.optimizeDeps.esbuildOptions.plugins.push(esbuildPlugin);
101+
envConfig.optimizeDeps.esbuildOptions.plugins.push(
102+
esbuildPlugin(envName),
103+
);
101104
}
102105
}
103106
},

sdk/src/vite/reactConditionsResolverPlugin.mts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,6 @@ export const reactConditionsResolverPlugin = ({
181181
name: `rwsdk:react-conditions-resolver-esbuild-${envName}`,
182182
setup(build: any) {
183183
build.onResolve({ filter: /.*/ }, (args: any) => {
184-
process.env.VERBOSE &&
185-
log(
186-
"ESBuild resolving %s for env=%s, args=%O",
187-
args.path,
188-
envName,
189-
args,
190-
);
191-
192184
let resolved: string | undefined = mappings.get(args.path);
193185

194186
if (!resolved) {
@@ -200,13 +192,6 @@ export const reactConditionsResolverPlugin = ({
200192
}
201193

202194
if (resolved && args.importer !== "") {
203-
process.env.VERBOSE &&
204-
log(
205-
"ESBuild resolving %s -> %s for env=%s",
206-
args.path,
207-
resolved,
208-
envName,
209-
);
210195
if (args.path === "react-server-dom-webpack/client.edge") {
211196
return;
212197
}

0 commit comments

Comments
 (0)