rwsdk 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,8 @@ import debug from "debug";
5
5
  import { getViteEsbuild } from "./getViteEsbuild.mjs";
6
6
  import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
7
7
  import { externalModules } from "./constants.mjs";
8
- import { createViteAwareResolver } from "./createViteAwareResolver.mjs";
8
+ import { createViteAwareResolver, mapViteResolveToEnhancedResolveOptions, } from "./createViteAwareResolver.mjs";
9
+ import resolve from "enhanced-resolve";
9
10
  const log = debug("rwsdk:vite:run-directives-scan");
10
11
  // Copied from Vite's source code.
11
12
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/shared/utils.ts
@@ -41,28 +42,23 @@ export const runDirectivesScan = async ({ rootConfig, environment, clientFiles,
41
42
  const absoluteEntries = entries.map((entry) => path.resolve(rootConfig.root, entry));
42
43
  log("Starting directives scan for environment '%s' with entries:", environment.name, absoluteEntries);
43
44
  // Use enhanced-resolve with Vite plugin integration for full compatibility
44
- const resolver = createViteAwareResolver(rootConfig, environment.name, environment);
45
- const resolveId = async (id, importer) => {
46
- return new Promise((resolve) => {
47
- resolver({}, importer || rootConfig.root, id, {}, (err, result) => {
48
- if (!err && result) {
49
- resolve({ id: result });
50
- }
51
- else {
52
- if (err) {
53
- // Handle specific enhanced-resolve errors gracefully
54
- const errorMessage = err.message || String(err);
55
- if (errorMessage.includes("Package path . is not exported")) {
56
- log("Package exports error for %s, marking as external", id);
57
- }
58
- else {
59
- log("Resolution failed for %s: %s", id, errorMessage);
60
- }
61
- }
62
- resolve(null);
63
- }
64
- });
65
- });
45
+ const workerResolver = createViteAwareResolver(rootConfig, environment.name, environment);
46
+ // Create a client resolver with browser conditions
47
+ // We'll use the mapViteResolveToEnhancedResolveOptions function directly
48
+ // to create a resolver with browser conditions
49
+ const clientResolveOptions = mapViteResolveToEnhancedResolveOptions(rootConfig, environment.name);
50
+ // Override the conditions to use browser conditions for client resolution
51
+ clientResolveOptions.conditionNames = ["browser", "module"];
52
+ const clientResolver = resolve.create(clientResolveOptions);
53
+ const moduleEnvironments = new Map();
54
+ const fileContentCache = new Map();
55
+ const readFileWithCache = async (path) => {
56
+ if (fileContentCache.has(path)) {
57
+ return fileContentCache.get(path);
58
+ }
59
+ const contents = await fsp.readFile(path, "utf-8");
60
+ fileContentCache.set(path, contents);
61
+ return contents;
66
62
  };
67
63
  const esbuildScanPlugin = {
68
64
  name: "rwsdk:esbuild-scan-plugin",
@@ -92,14 +88,65 @@ export const runDirectivesScan = async ({ rootConfig, environment, clientFiles,
92
88
  return { external: true };
93
89
  }
94
90
  log("onResolve called for:", args.path, "from:", args.importer);
95
- const resolved = await resolveId(args.path, args.importer);
91
+ let importerEnv = moduleEnvironments.get(args.importer);
92
+ // If we don't know the importer's environment yet, check its content
93
+ if (!importerEnv &&
94
+ args.importer &&
95
+ /\.(m|c)?[jt]sx?$/.test(args.importer)) {
96
+ try {
97
+ const importerContents = await readFileWithCache(args.importer);
98
+ if (hasDirective(importerContents, "use client")) {
99
+ importerEnv = "client";
100
+ log("Pre-detected importer 'use client' in:", args.importer);
101
+ }
102
+ else if (hasDirective(importerContents, "use server")) {
103
+ importerEnv = "worker";
104
+ log("Pre-detected importer 'use server' in:", args.importer);
105
+ }
106
+ else {
107
+ importerEnv = "worker"; // Default for entry points
108
+ }
109
+ moduleEnvironments.set(args.importer, importerEnv);
110
+ }
111
+ catch (e) {
112
+ importerEnv = "worker"; // Default fallback
113
+ log("Could not pre-read importer, using worker environment:", args.importer);
114
+ }
115
+ }
116
+ else if (!importerEnv) {
117
+ importerEnv = "worker"; // Default for entry points or non-script files
118
+ }
119
+ log("Importer:", args.importer, "environment:", importerEnv);
120
+ const resolver = importerEnv === "client" ? clientResolver : workerResolver;
121
+ const resolved = await new Promise((resolve) => {
122
+ resolver({}, args.importer || rootConfig.root, args.path, {}, (err, result) => {
123
+ if (!err && result) {
124
+ resolve({ id: result });
125
+ }
126
+ else {
127
+ if (err) {
128
+ const errorMessage = err.message || String(err);
129
+ if (errorMessage.includes("Package path . is not exported")) {
130
+ log("Package exports error for %s, marking as external", args.path);
131
+ }
132
+ else {
133
+ log("Resolution failed for %s: %s", args.path, errorMessage);
134
+ }
135
+ }
136
+ resolve(null);
137
+ }
138
+ });
139
+ });
96
140
  log("Resolution result:", resolved);
97
141
  const resolvedPath = resolved?.id;
98
142
  if (resolvedPath && path.isAbsolute(resolvedPath)) {
99
143
  // Normalize the path for esbuild compatibility
100
144
  const normalizedPath = normalizeModulePath(resolvedPath, rootConfig.root, { absolute: true });
101
145
  log("Normalized path:", normalizedPath);
102
- return { path: normalizedPath };
146
+ return {
147
+ path: normalizedPath,
148
+ pluginData: { inheritedEnv: importerEnv },
149
+ };
103
150
  }
104
151
  log("Marking as external:", args.path, "resolved to:", resolvedPath);
105
152
  return { external: true };
@@ -117,12 +164,29 @@ export const runDirectivesScan = async ({ rootConfig, environment, clientFiles,
117
164
  return null;
118
165
  }
119
166
  try {
120
- const contents = await fsp.readFile(args.path, "utf-8");
121
- if (hasDirective(contents, "use client")) {
167
+ const contents = await readFileWithCache(args.path);
168
+ const inheritedEnv = args.pluginData?.inheritedEnv || "worker";
169
+ let currentEnv = inheritedEnv;
170
+ const isClient = hasDirective(contents, "use client");
171
+ const isServer = hasDirective(contents, "use server");
172
+ // A file's own directive takes precedence over the inherited environment.
173
+ if (isClient) {
174
+ currentEnv = "client";
175
+ }
176
+ else if (isServer) {
177
+ // `else if` handles cases where a file might have both directives.
178
+ // "use client" takes precedence.
179
+ currentEnv = "worker";
180
+ }
181
+ // Store the definitive environment for this module, so it can be used when it becomes an importer.
182
+ moduleEnvironments.set(args.path, currentEnv);
183
+ log("Set environment for", args.path, "to", currentEnv);
184
+ // Finally, populate the output sets if the file has a directive.
185
+ if (isClient) {
122
186
  log("Discovered 'use client' in:", args.path);
123
187
  clientFiles.add(normalizeModulePath(args.path, rootConfig.root));
124
188
  }
125
- if (hasDirective(contents, "use server")) {
189
+ if (isServer) {
126
190
  log("Discovered 'use server' in:", args.path);
127
191
  serverFiles.add(normalizeModulePath(args.path, rootConfig.root));
128
192
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {