rwsdk 0.3.0 → 0.3.2
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.
- package/dist/vite/buildApp.mjs +2 -2
- package/dist/vite/configPlugin.d.mts +0 -2
- package/dist/vite/configPlugin.mjs +1 -14
- package/dist/vite/constants.d.mts +2 -0
- package/dist/vite/constants.mjs +12 -0
- package/dist/vite/createDirectiveLookupPlugin.mjs +8 -0
- package/dist/vite/createViteAwareResolver.d.mts +4 -0
- package/dist/vite/createViteAwareResolver.mjs +257 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +53 -28
- package/dist/vite/directivesPlugin.mjs +4 -0
- package/dist/vite/injectVitePreamblePlugin.mjs +4 -0
- package/dist/vite/manifestPlugin.mjs +8 -0
- package/dist/vite/reactConditionsResolverPlugin.mjs +4 -0
- package/dist/vite/redwoodPlugin.mjs +1 -1
- package/dist/vite/runDirectivesScan.d.mts +4 -4
- package/dist/vite/runDirectivesScan.mjs +124 -120
- package/dist/vite/ssrBridgePlugin.mjs +8 -0
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +4 -0
- package/dist/vite/virtualPlugin.mjs +8 -0
- package/package.json +1 -1
package/dist/vite/buildApp.mjs
CHANGED
|
@@ -10,14 +10,14 @@ const log = debug("rwsdk:vite:build-app");
|
|
|
10
10
|
* @see docs/architecture/productionBuildProcess.md
|
|
11
11
|
*/
|
|
12
12
|
export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }) {
|
|
13
|
+
const workerEnv = builder.environments.worker;
|
|
13
14
|
await runDirectivesScan({
|
|
14
15
|
rootConfig: builder.config,
|
|
15
|
-
|
|
16
|
+
environment: workerEnv,
|
|
16
17
|
clientFiles,
|
|
17
18
|
serverFiles,
|
|
18
19
|
});
|
|
19
20
|
console.log("Building worker to discover used client components...");
|
|
20
|
-
const workerEnv = builder.environments.worker;
|
|
21
21
|
process.env.RWSDK_BUILD_PASS = "worker";
|
|
22
22
|
await builder.build(workerEnv);
|
|
23
23
|
log("Used client files after worker build & filtering: %O", Array.from(clientFiles));
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
|
-
export declare const cloudflareBuiltInModules: string[];
|
|
3
|
-
export declare const externalModules: string[];
|
|
4
2
|
export declare const configPlugin: ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }: {
|
|
5
3
|
silent: boolean;
|
|
6
4
|
projectRootDir: string;
|
|
@@ -1,23 +1,10 @@
|
|
|
1
1
|
import path, { resolve } from "node:path";
|
|
2
|
-
import { builtinModules } from "node:module";
|
|
3
2
|
import enhancedResolve from "enhanced-resolve";
|
|
4
3
|
import debug from "debug";
|
|
5
4
|
import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
|
|
6
5
|
import { buildApp } from "./buildApp.mjs";
|
|
6
|
+
import { externalModules } from "./constants.mjs";
|
|
7
7
|
const log = debug("rwsdk:vite:config");
|
|
8
|
-
// port(justinvdm, 09 Jun 2025):
|
|
9
|
-
// https://github.com/cloudflare/workers-sdk/blob/d533f5ee7da69c205d8d5e2a5f264d2370fc612b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts#L123-L128
|
|
10
|
-
export const cloudflareBuiltInModules = [
|
|
11
|
-
"cloudflare:email",
|
|
12
|
-
"cloudflare:sockets",
|
|
13
|
-
"cloudflare:workers",
|
|
14
|
-
"cloudflare:workflows",
|
|
15
|
-
];
|
|
16
|
-
export const externalModules = [
|
|
17
|
-
...cloudflareBuiltInModules,
|
|
18
|
-
...builtinModules,
|
|
19
|
-
...builtinModules.map((m) => `node:${m}`),
|
|
20
|
-
];
|
|
21
8
|
export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }) => ({
|
|
22
9
|
name: "rwsdk:config",
|
|
23
10
|
config: async (_) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { builtinModules } from "node:module";
|
|
2
|
+
export const cloudflareBuiltInModules = [
|
|
3
|
+
"cloudflare:email",
|
|
4
|
+
"cloudflare:sockets",
|
|
5
|
+
"cloudflare:workers",
|
|
6
|
+
"cloudflare:workflows",
|
|
7
|
+
];
|
|
8
|
+
export const externalModules = [
|
|
9
|
+
...cloudflareBuiltInModules,
|
|
10
|
+
...builtinModules,
|
|
11
|
+
...builtinModules.map((m) => `node:${m}`),
|
|
12
|
+
];
|
|
@@ -70,6 +70,10 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
resolveId(source) {
|
|
73
|
+
// Skip during directive scanning to avoid performance issues
|
|
74
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
73
77
|
if (source !== `${config.virtualModuleName}.js`) {
|
|
74
78
|
return null;
|
|
75
79
|
}
|
|
@@ -108,6 +112,10 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
108
112
|
return source;
|
|
109
113
|
},
|
|
110
114
|
async load(id) {
|
|
115
|
+
// Skip during directive scanning to avoid performance issues
|
|
116
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
111
119
|
if (id === config.virtualModuleName + ".js") {
|
|
112
120
|
log("Loading %s module with %d files", config.virtualModuleName, files.size);
|
|
113
121
|
const environment = this.environment?.name || "client";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import resolve, { ResolveOptions } from "enhanced-resolve";
|
|
2
|
+
import { ResolvedConfig } from "vite";
|
|
3
|
+
export declare const mapViteResolveToEnhancedResolveOptions: (viteConfig: ResolvedConfig, envName: string) => ResolveOptions;
|
|
4
|
+
export declare const createViteAwareResolver: (viteConfig: ResolvedConfig, envName: string, environment?: any) => resolve.ResolveFunctionAsync;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import resolve from "enhanced-resolve";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import createDebug from "debug";
|
|
5
|
+
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
6
|
+
const debug = createDebug("rwsdk:vite:enhanced-resolve-plugin");
|
|
7
|
+
// Enhanced-resolve plugin that wraps Vite plugin resolution
|
|
8
|
+
class VitePluginResolverPlugin {
|
|
9
|
+
constructor(environment, source = "resolve", target = "resolved") {
|
|
10
|
+
this.environment = environment;
|
|
11
|
+
this.source = source;
|
|
12
|
+
this.target = target;
|
|
13
|
+
// Create an enhanced-resolve instance for the plugin context
|
|
14
|
+
const baseOptions = mapViteResolveToEnhancedResolveOptions(this.environment.config, this.environment.name);
|
|
15
|
+
this.enhancedResolver = resolve.create(baseOptions);
|
|
16
|
+
}
|
|
17
|
+
apply(resolver) {
|
|
18
|
+
const target = resolver.ensureHook(this.target);
|
|
19
|
+
resolver
|
|
20
|
+
.getHook(this.source)
|
|
21
|
+
.tapAsync("VitePluginResolverPlugin", (request, resolveContext, callback) => {
|
|
22
|
+
const plugins = this.environment?.plugins;
|
|
23
|
+
if (!plugins) {
|
|
24
|
+
return callback();
|
|
25
|
+
}
|
|
26
|
+
// Create a plugin context with enhanced-resolve-based resolve method
|
|
27
|
+
const pluginContext = {
|
|
28
|
+
environment: this.environment,
|
|
29
|
+
resolve: async (id, importer) => {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
this.enhancedResolver({}, importer || this.environment.config.root, id, {}, (err, result) => {
|
|
32
|
+
if (!err && result) {
|
|
33
|
+
debug("Context resolve: %s -> %s", id, result);
|
|
34
|
+
resolve({ id: result });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
debug("Context resolve failed for %s: %s", id, err?.message || "not found");
|
|
38
|
+
resolve(null);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
debug("Trying to resolve %s from %s", request.request, request.path);
|
|
45
|
+
// This function encapsulates the logic to process Vite plugins for a given request.
|
|
46
|
+
const runPluginProcessing = async (currentRequest) => {
|
|
47
|
+
debug("Available plugins:", plugins.map((p) => p.name));
|
|
48
|
+
for (const plugin of plugins) {
|
|
49
|
+
const resolveIdHandler = plugin.resolveId;
|
|
50
|
+
if (!resolveIdHandler)
|
|
51
|
+
continue;
|
|
52
|
+
let handlerFn;
|
|
53
|
+
let shouldApplyFilter = false;
|
|
54
|
+
let filter = null;
|
|
55
|
+
if (typeof resolveIdHandler === "function") {
|
|
56
|
+
handlerFn = resolveIdHandler;
|
|
57
|
+
}
|
|
58
|
+
else if (typeof resolveIdHandler === "object" &&
|
|
59
|
+
typeof resolveIdHandler.handler === "function") {
|
|
60
|
+
handlerFn = resolveIdHandler.handler;
|
|
61
|
+
shouldApplyFilter = true;
|
|
62
|
+
filter = resolveIdHandler.filter;
|
|
63
|
+
}
|
|
64
|
+
if (!handlerFn)
|
|
65
|
+
continue;
|
|
66
|
+
if (shouldApplyFilter && filter?.id) {
|
|
67
|
+
const idFilter = filter.id;
|
|
68
|
+
let shouldSkip = false;
|
|
69
|
+
if (idFilter instanceof RegExp) {
|
|
70
|
+
shouldSkip = !idFilter.test(currentRequest.request);
|
|
71
|
+
}
|
|
72
|
+
else if (Array.isArray(idFilter)) {
|
|
73
|
+
// Handle array of filters - matches if ANY filter matches
|
|
74
|
+
shouldSkip = !idFilter.some((f) => f instanceof RegExp
|
|
75
|
+
? f.test(currentRequest.request)
|
|
76
|
+
: f === currentRequest.request);
|
|
77
|
+
}
|
|
78
|
+
else if (typeof idFilter === "string") {
|
|
79
|
+
shouldSkip = idFilter !== currentRequest.request;
|
|
80
|
+
}
|
|
81
|
+
else if (typeof idFilter === "object" && idFilter !== null) {
|
|
82
|
+
// Handle include/exclude object pattern
|
|
83
|
+
const { include, exclude } = idFilter;
|
|
84
|
+
let matches = true;
|
|
85
|
+
// Check include patterns (if any)
|
|
86
|
+
if (include) {
|
|
87
|
+
const includePatterns = Array.isArray(include)
|
|
88
|
+
? include
|
|
89
|
+
: [include];
|
|
90
|
+
matches = includePatterns.some((pattern) => pattern instanceof RegExp
|
|
91
|
+
? pattern.test(currentRequest.request)
|
|
92
|
+
: pattern === currentRequest.request);
|
|
93
|
+
}
|
|
94
|
+
// Check exclude patterns (if any) - exclude overrides include
|
|
95
|
+
if (matches && exclude) {
|
|
96
|
+
const excludePatterns = Array.isArray(exclude)
|
|
97
|
+
? exclude
|
|
98
|
+
: [exclude];
|
|
99
|
+
const isExcluded = excludePatterns.some((pattern) => pattern instanceof RegExp
|
|
100
|
+
? pattern.test(currentRequest.request)
|
|
101
|
+
: pattern === currentRequest.request);
|
|
102
|
+
matches = !isExcluded;
|
|
103
|
+
}
|
|
104
|
+
shouldSkip = !matches;
|
|
105
|
+
}
|
|
106
|
+
if (shouldSkip) {
|
|
107
|
+
debug("Skipping plugin '%s' due to filter mismatch for '%s'", plugin.name, currentRequest.request);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
debug("Calling plugin '%s' for '%s'", plugin.name, currentRequest.request);
|
|
113
|
+
const result = await handlerFn.call(pluginContext, currentRequest.request, currentRequest.path, { scan: true });
|
|
114
|
+
debug("Plugin '%s' returned:", plugin.name, result);
|
|
115
|
+
if (!result)
|
|
116
|
+
continue;
|
|
117
|
+
const resolvedId = typeof result === "string" ? result : result.id;
|
|
118
|
+
if (resolvedId && resolvedId !== currentRequest.request) {
|
|
119
|
+
debug("Plugin '%s' resolved '%s' -> '%s'", plugin.name, currentRequest.request, resolvedId);
|
|
120
|
+
return callback(null, {
|
|
121
|
+
...currentRequest,
|
|
122
|
+
path: resolvedId,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (resolvedId === currentRequest.request) {
|
|
126
|
+
debug("Plugin '%s' returned unchanged ID, continuing to next plugin", plugin.name);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
debug("Plugin '%s' failed while resolving '%s': %s", plugin.name, currentRequest.request, e.message);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// If no plugin resolves, fall back to enhanced-resolve's default behavior
|
|
134
|
+
debug("No Vite plugin resolved '%s', falling back.", currentRequest.request);
|
|
135
|
+
// For absolute paths, check if the file exists
|
|
136
|
+
if (path.isAbsolute(currentRequest.request)) {
|
|
137
|
+
try {
|
|
138
|
+
if (fs.existsSync(currentRequest.request)) {
|
|
139
|
+
debug("File exists, resolving to: %s", currentRequest.request);
|
|
140
|
+
return callback(null, {
|
|
141
|
+
...currentRequest,
|
|
142
|
+
path: currentRequest.request,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
debug("Error checking file existence: %s", e.message);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
callback();
|
|
151
|
+
};
|
|
152
|
+
// For relative imports, normalize them to absolute paths first
|
|
153
|
+
if (request.request.startsWith("../") ||
|
|
154
|
+
request.request.startsWith("./")) {
|
|
155
|
+
try {
|
|
156
|
+
// Use path.dirname to get the directory of the importer file
|
|
157
|
+
const importerDir = path.dirname(request.path);
|
|
158
|
+
const absolutePath = normalizeModulePath(request.request, importerDir, { absolute: true });
|
|
159
|
+
debug("Absolutified %s -> %s", request.request, absolutePath);
|
|
160
|
+
const absoluteRequest = { ...request, request: absolutePath };
|
|
161
|
+
runPluginProcessing(absoluteRequest).catch((e) => {
|
|
162
|
+
debug("Error in plugin processing: %s", e.message);
|
|
163
|
+
callback();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
debug("Failed to absolutify %s: %s", request.request, e.message);
|
|
168
|
+
callback();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// For non-relative imports, process them directly
|
|
173
|
+
runPluginProcessing(request).catch((e) => {
|
|
174
|
+
debug("Error in plugin processing: %s", e.message);
|
|
175
|
+
callback();
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const mapAlias = (alias) => {
|
|
182
|
+
const mappedAlias = {};
|
|
183
|
+
if (Array.isArray(alias)) {
|
|
184
|
+
// Handle array format: { find: string | RegExp, replacement: string }
|
|
185
|
+
for (const { find, replacement } of alias) {
|
|
186
|
+
if (find instanceof RegExp) {
|
|
187
|
+
// For RegExp, use the source as-is
|
|
188
|
+
mappedAlias[find.source] = replacement;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// For string aliases, use them as-is without modification
|
|
192
|
+
mappedAlias[find] = replacement;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Handle object format: { [find: string]: replacement }
|
|
198
|
+
for (const [find, replacement] of Object.entries(alias)) {
|
|
199
|
+
// Use the alias key as-is without modification
|
|
200
|
+
mappedAlias[find] = replacement;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return mappedAlias;
|
|
204
|
+
};
|
|
205
|
+
export const mapViteResolveToEnhancedResolveOptions = (viteConfig, envName) => {
|
|
206
|
+
const env = viteConfig.environments[envName];
|
|
207
|
+
if (!env) {
|
|
208
|
+
throw new Error(`Could not find environment configuration for "${envName}".`);
|
|
209
|
+
}
|
|
210
|
+
const envResolveOptions = (env.resolve || {});
|
|
211
|
+
// Merge root config aliases with environment-specific aliases
|
|
212
|
+
const mergedAlias = {
|
|
213
|
+
...(viteConfig.resolve?.alias ? mapAlias(viteConfig.resolve.alias) : {}),
|
|
214
|
+
...(envResolveOptions.alias ? mapAlias(envResolveOptions.alias) : {}),
|
|
215
|
+
};
|
|
216
|
+
// Use comprehensive extensions list similar to Vite's defaults
|
|
217
|
+
const extensions = envResolveOptions.extensions || [
|
|
218
|
+
".mjs",
|
|
219
|
+
".js",
|
|
220
|
+
".mts",
|
|
221
|
+
".ts",
|
|
222
|
+
".jsx",
|
|
223
|
+
".tsx",
|
|
224
|
+
".json",
|
|
225
|
+
];
|
|
226
|
+
const baseOptions = {
|
|
227
|
+
// File system is required by enhanced-resolve.
|
|
228
|
+
fileSystem: fs,
|
|
229
|
+
// Map Vite's resolve options to enhanced-resolve's options.
|
|
230
|
+
alias: Object.keys(mergedAlias).length > 0 ? mergedAlias : undefined,
|
|
231
|
+
conditionNames: envResolveOptions.conditions,
|
|
232
|
+
mainFields: envResolveOptions.mainFields,
|
|
233
|
+
extensions,
|
|
234
|
+
symlinks: envResolveOptions.preserveSymlinks,
|
|
235
|
+
// Add default node modules resolution.
|
|
236
|
+
modules: ["node_modules"],
|
|
237
|
+
roots: [viteConfig.root],
|
|
238
|
+
};
|
|
239
|
+
return baseOptions;
|
|
240
|
+
};
|
|
241
|
+
export const createViteAwareResolver = (viteConfig, envName, environment) => {
|
|
242
|
+
const baseOptions = mapViteResolveToEnhancedResolveOptions(viteConfig, envName);
|
|
243
|
+
// Add Vite plugin resolver if environment is provided
|
|
244
|
+
const plugins = environment
|
|
245
|
+
? [new VitePluginResolverPlugin(environment)]
|
|
246
|
+
: [];
|
|
247
|
+
const enhancedResolveOptions = {
|
|
248
|
+
...baseOptions,
|
|
249
|
+
plugins,
|
|
250
|
+
};
|
|
251
|
+
debug("Creating enhanced-resolve with options:", {
|
|
252
|
+
extensions: enhancedResolveOptions.extensions,
|
|
253
|
+
alias: enhancedResolveOptions.alias,
|
|
254
|
+
roots: enhancedResolveOptions.roots,
|
|
255
|
+
});
|
|
256
|
+
return resolve.create(enhancedResolveOptions);
|
|
257
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import path from "
|
|
1
|
+
import path from "path";
|
|
2
2
|
import { writeFileSync, mkdirSync } from "node:fs";
|
|
3
3
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
4
|
+
import { CLIENT_BARREL_PATH, SERVER_BARREL_PATH } from "../lib/constants.mjs";
|
|
4
5
|
import { runDirectivesScan } from "./runDirectivesScan.mjs";
|
|
5
|
-
import { CLIENT_BARREL_PATH } from "../lib/constants.mjs";
|
|
6
|
-
import { SERVER_BARREL_PATH } from "../lib/constants.mjs";
|
|
7
6
|
export const VIRTUAL_CLIENT_BARREL_ID = "virtual:rwsdk:client-module-barrel";
|
|
8
7
|
export const VIRTUAL_SERVER_BARREL_ID = "virtual:rwsdk:server-module-barrel";
|
|
9
8
|
const CLIENT_BARREL_EXPORT_PATH = "rwsdk/__client_barrel";
|
|
@@ -24,38 +23,64 @@ const generateBarrelContent = (files, projectRootDir) => {
|
|
|
24
23
|
return `${imports}\n\n${exports}`;
|
|
25
24
|
};
|
|
26
25
|
export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
|
|
26
|
+
let scanPromise = null;
|
|
27
27
|
return {
|
|
28
28
|
name: "rwsdk:directive-modules-dev",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (config.command !== "serve") {
|
|
29
|
+
configureServer(server) {
|
|
30
|
+
if (!process.env.VITE_IS_DEV_SERVER || process.env.RWSDK_WORKER_RUN) {
|
|
32
31
|
return;
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
// Start the directive scan as soon as the server is configured.
|
|
34
|
+
// We don't await it here, allowing Vite to continue its startup.
|
|
35
|
+
scanPromise = runDirectivesScan({
|
|
36
|
+
rootConfig: server.config,
|
|
37
|
+
environment: server.environments.worker,
|
|
38
|
+
clientFiles,
|
|
39
|
+
serverFiles,
|
|
40
|
+
}).then(() => {
|
|
41
|
+
// After the scan is complete, write the barrel files.
|
|
42
|
+
const clientBarrelContent = generateBarrelContent(clientFiles, projectRootDir);
|
|
43
|
+
writeFileSync(CLIENT_BARREL_PATH, clientBarrelContent);
|
|
44
|
+
const serverBarrelContent = generateBarrelContent(serverFiles, projectRootDir);
|
|
45
|
+
writeFileSync(SERVER_BARREL_PATH, serverBarrelContent);
|
|
46
|
+
});
|
|
47
|
+
// context(justinvdm, 4 Sep 2025): Add middleware to block incoming
|
|
48
|
+
// requests until the scan is complete. This gives us a single hook for
|
|
49
|
+
// preventing app code being processed by vite until the scan is complete.
|
|
50
|
+
// This improves perceived startup time by not blocking Vite's optimizer.
|
|
51
|
+
server.middlewares.use(async (_req, _res, next) => {
|
|
52
|
+
if (scanPromise) {
|
|
53
|
+
await scanPromise;
|
|
54
|
+
}
|
|
55
|
+
next();
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
configResolved(config) {
|
|
59
|
+
if (config.command !== "serve") {
|
|
60
|
+
return;
|
|
42
61
|
}
|
|
43
|
-
//
|
|
44
|
-
// We can do this now because our scan is complete.
|
|
45
|
-
const clientBarrelContent = generateBarrelContent(clientFiles, projectRootDir);
|
|
46
|
-
const serverBarrelContent = generateBarrelContent(serverFiles, projectRootDir);
|
|
62
|
+
// Create dummy files to give esbuild a real path to resolve.
|
|
47
63
|
mkdirSync(path.dirname(CLIENT_BARREL_PATH), { recursive: true });
|
|
48
|
-
writeFileSync(CLIENT_BARREL_PATH,
|
|
64
|
+
writeFileSync(CLIENT_BARREL_PATH, "");
|
|
49
65
|
mkdirSync(path.dirname(SERVER_BARREL_PATH), { recursive: true });
|
|
50
|
-
writeFileSync(SERVER_BARREL_PATH,
|
|
51
|
-
for (const [envName, env] of Object.entries(config.environments)) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
writeFileSync(SERVER_BARREL_PATH, "");
|
|
67
|
+
for (const [envName, env] of Object.entries(config.environments || {})) {
|
|
68
|
+
env.optimizeDeps ??= {};
|
|
69
|
+
env.optimizeDeps.include ??= [];
|
|
70
|
+
env.optimizeDeps.include.push(CLIENT_BARREL_EXPORT_PATH, SERVER_BARREL_EXPORT_PATH);
|
|
71
|
+
env.optimizeDeps.esbuildOptions ??= {};
|
|
72
|
+
env.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
73
|
+
env.optimizeDeps.esbuildOptions.plugins.push({
|
|
74
|
+
name: "rwsdk:block-optimizer-for-scan",
|
|
75
|
+
setup(build) {
|
|
76
|
+
build.onStart(async () => {
|
|
77
|
+
// context(justinvdm, 4 Sep 2025): We await the scan promise
|
|
78
|
+
// here because we want to block the optimizer until the scan is
|
|
79
|
+
// complete.
|
|
80
|
+
await scanPromise;
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
});
|
|
59
84
|
}
|
|
60
85
|
},
|
|
61
86
|
};
|
|
@@ -52,6 +52,10 @@ export const directivesPlugin = ({ projectRootDir, clientFiles, serverFiles, })
|
|
|
52
52
|
});
|
|
53
53
|
},
|
|
54
54
|
async transform(code, id) {
|
|
55
|
+
// Skip during directive scanning to avoid performance issues
|
|
56
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
55
59
|
if (isBuild &&
|
|
56
60
|
this.environment?.name === "worker" &&
|
|
57
61
|
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
@@ -4,6 +4,10 @@ export const injectVitePreamble = ({ clientEntryPoints, projectRootDir, }) => ({
|
|
|
4
4
|
name: "rwsdk:inject-vite-preamble",
|
|
5
5
|
apply: "serve",
|
|
6
6
|
transform(code, id) {
|
|
7
|
+
// Skip during directive scanning to avoid performance issues
|
|
8
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
7
11
|
if (this.environment.name !== "client") {
|
|
8
12
|
return;
|
|
9
13
|
}
|
|
@@ -11,11 +11,19 @@ export const manifestPlugin = ({ projectRootDir, }) => {
|
|
|
11
11
|
isBuild = config.command === "build";
|
|
12
12
|
},
|
|
13
13
|
resolveId(id) {
|
|
14
|
+
// Skip during directive scanning to avoid performance issues
|
|
15
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
14
18
|
if (id === virtualModuleId) {
|
|
15
19
|
return resolvedVirtualModuleId;
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
async load(id) {
|
|
23
|
+
// Skip during directive scanning to avoid performance issues
|
|
24
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
19
27
|
if (id === resolvedVirtualModuleId) {
|
|
20
28
|
if (isBuild) {
|
|
21
29
|
// context(justinvdm, 28 Aug 2025): During the build, we don't have
|
|
@@ -169,6 +169,10 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
169
169
|
name: "rwsdk:react-conditions-resolver:resolveId",
|
|
170
170
|
enforce: "pre",
|
|
171
171
|
async resolveId(id, importer) {
|
|
172
|
+
// Skip during directive scanning to avoid performance issues
|
|
173
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
172
176
|
if (!isBuild) {
|
|
173
177
|
return;
|
|
174
178
|
}
|
|
@@ -63,12 +63,12 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
63
63
|
}
|
|
64
64
|
return [
|
|
65
65
|
devServerTimingPlugin(),
|
|
66
|
+
devServerConstantPlugin(),
|
|
66
67
|
directiveModulesDevPlugin({
|
|
67
68
|
clientFiles,
|
|
68
69
|
serverFiles,
|
|
69
70
|
projectRootDir,
|
|
70
71
|
}),
|
|
71
|
-
devServerConstantPlugin(),
|
|
72
72
|
configPlugin({
|
|
73
73
|
silent: options.silent ?? false,
|
|
74
74
|
projectRootDir,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ResolvedConfig } from "vite";
|
|
2
|
-
export declare
|
|
1
|
+
import { Environment, ResolvedConfig } from "vite";
|
|
2
|
+
export declare const runDirectivesScan: ({ rootConfig, environment, clientFiles, serverFiles, }: {
|
|
3
3
|
rootConfig: ResolvedConfig;
|
|
4
|
-
|
|
4
|
+
environment: Environment;
|
|
5
5
|
clientFiles: Set<string>;
|
|
6
6
|
serverFiles: Set<string>;
|
|
7
|
-
})
|
|
7
|
+
}) => Promise<void>;
|
|
@@ -2,9 +2,10 @@ import fsp from "node:fs/promises";
|
|
|
2
2
|
import { hasDirective } from "./hasDirective.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import debug from "debug";
|
|
5
|
-
import { ensureAliasArray } from "./ensureAliasArray.mjs";
|
|
6
5
|
import { getViteEsbuild } from "./getViteEsbuild.mjs";
|
|
7
6
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
7
|
+
import { externalModules } from "./constants.mjs";
|
|
8
|
+
import { createViteAwareResolver } from "./createViteAwareResolver.mjs";
|
|
8
9
|
const log = debug("rwsdk:vite:run-directives-scan");
|
|
9
10
|
// Copied from Vite's source code.
|
|
10
11
|
// https://github.com/vitejs/vite/blob/main/packages/vite/src/shared/utils.ts
|
|
@@ -13,140 +14,143 @@ const isObject = (value) => Object.prototype.toString.call(value) === "[object O
|
|
|
13
14
|
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts
|
|
14
15
|
const externalRE = /^(https?:)?\/\//;
|
|
15
16
|
const isExternalUrl = (url) => externalRE.test(url);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
export const runDirectivesScan = async ({ rootConfig, environment, clientFiles, serverFiles, }) => {
|
|
18
|
+
console.log("\n🔍 Scanning for 'use client' and 'use server' directives...");
|
|
19
|
+
// Set environment variable to indicate scanning is in progress
|
|
20
|
+
process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE = "true";
|
|
21
|
+
try {
|
|
22
|
+
const esbuild = await getViteEsbuild(rootConfig.root);
|
|
23
|
+
const input = environment.config.build.rollupOptions?.input;
|
|
24
|
+
let entries;
|
|
25
|
+
if (Array.isArray(input)) {
|
|
26
|
+
entries = input;
|
|
27
|
+
}
|
|
28
|
+
else if (typeof input === "string") {
|
|
29
|
+
entries = [input];
|
|
30
|
+
}
|
|
31
|
+
else if (isObject(input)) {
|
|
32
|
+
entries = Object.values(input);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
entries = [];
|
|
36
|
+
}
|
|
37
|
+
if (entries.length === 0) {
|
|
38
|
+
log("No entries found for directives scan in environment '%s', skipping.", environment.name);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const absoluteEntries = entries.map((entry) => path.resolve(rootConfig.root, entry));
|
|
42
|
+
log("Starting directives scan for environment '%s' with entries:", environment.name, absoluteEntries);
|
|
43
|
+
// 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
|
+
});
|
|
29
65
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
};
|
|
67
|
+
const esbuildScanPlugin = {
|
|
68
|
+
name: "rwsdk:esbuild-scan-plugin",
|
|
69
|
+
setup(build) {
|
|
70
|
+
// Match Vite's behavior by externalizing assets and special queries.
|
|
71
|
+
// This prevents esbuild from trying to bundle them, which would fail.
|
|
72
|
+
const scriptFilter = /\.(c|m)?[jt]sx?$/;
|
|
73
|
+
const specialQueryFilter = /[?&](?:url|raw|worker|sharedworker|inline)\b/;
|
|
74
|
+
// This regex is used to identify if a path has any file extension.
|
|
75
|
+
const hasExtensionRegex = /\.[^/]+$/;
|
|
76
|
+
build.onResolve({ filter: specialQueryFilter }, (args) => {
|
|
77
|
+
log("Externalizing special query:", args.path);
|
|
37
78
|
return { external: true };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
for (const { find, replacement } of aliases) {
|
|
47
|
-
const findPattern = find instanceof RegExp ? find : new RegExp(`^${find}(\\/.*)?$`);
|
|
48
|
-
if (findPattern.test(args.path)) {
|
|
49
|
-
const newPath = args.path.replace(findPattern, (_match, rest) => {
|
|
50
|
-
// `rest` is the captured group `(\\/.*)?` from the regex.
|
|
51
|
-
return replacement + (rest || "");
|
|
52
|
-
});
|
|
53
|
-
const resolved = await build.resolve(newPath, {
|
|
54
|
-
importer: args.importer,
|
|
55
|
-
resolveDir: args.resolveDir,
|
|
56
|
-
kind: args.kind,
|
|
57
|
-
pluginData: { rwsdkScanResolver: true },
|
|
58
|
-
});
|
|
59
|
-
if (resolved.errors.length === 0) {
|
|
60
|
-
return resolved;
|
|
61
|
-
}
|
|
62
|
-
log("Could not resolve aliased path '%s' (from '%s'). Marking as external. Errors: %s", newPath, args.path, resolved.errors.map((e) => e.text).join(", "));
|
|
79
|
+
});
|
|
80
|
+
build.onResolve({ filter: /.*/, namespace: "file" }, (args) => {
|
|
81
|
+
// Externalize if the path has an extension AND that extension is not a
|
|
82
|
+
// script extension. Extensionless paths are assumed to be scripts and
|
|
83
|
+
// are allowed to pass through for resolution.
|
|
84
|
+
if (hasExtensionRegex.test(args.path) &&
|
|
85
|
+
!scriptFilter.test(args.path)) {
|
|
86
|
+
log("Externalizing non-script import:", args.path);
|
|
63
87
|
return { external: true };
|
|
64
88
|
}
|
|
65
|
-
}
|
|
66
|
-
// 2. If no alias matches, try esbuild's default resolver.
|
|
67
|
-
const resolved = await build.resolve(args.path, {
|
|
68
|
-
importer: args.importer,
|
|
69
|
-
resolveDir: args.resolveDir,
|
|
70
|
-
kind: args.kind,
|
|
71
|
-
pluginData: { rwsdkScanResolver: true },
|
|
72
89
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
90
|
+
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
91
|
+
if (externalModules.includes(args.path)) {
|
|
92
|
+
return { external: true };
|
|
93
|
+
}
|
|
94
|
+
log("onResolve called for:", args.path, "from:", args.importer);
|
|
95
|
+
const resolved = await resolveId(args.path, args.importer);
|
|
96
|
+
log("Resolution result:", resolved);
|
|
97
|
+
const resolvedPath = resolved?.id;
|
|
98
|
+
if (resolvedPath && path.isAbsolute(resolvedPath)) {
|
|
99
|
+
// Normalize the path for esbuild compatibility
|
|
100
|
+
const normalizedPath = normalizeModulePath(resolvedPath, rootConfig.root, { absolute: true });
|
|
101
|
+
log("Normalized path:", normalizedPath);
|
|
102
|
+
return { path: normalizedPath };
|
|
103
|
+
}
|
|
104
|
+
log("Marking as external:", args.path, "resolved to:", resolvedPath);
|
|
76
105
|
return { external: true };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
log("Discovered 'use client' in:", args.path);
|
|
90
|
-
clientFiles.add(normalizeModulePath(args.path, projectRootDir));
|
|
106
|
+
});
|
|
107
|
+
build.onLoad({ filter: /\.(m|c)?[jt]sx?$/ }, async (args) => {
|
|
108
|
+
log("onLoad called for:", args.path);
|
|
109
|
+
if (!args.path.startsWith("/") ||
|
|
110
|
+
args.path.includes("virtual:") ||
|
|
111
|
+
isExternalUrl(args.path)) {
|
|
112
|
+
log("Skipping file due to filter:", args.path, {
|
|
113
|
+
startsWithSlash: args.path.startsWith("/"),
|
|
114
|
+
hasVirtual: args.path.includes("virtual:"),
|
|
115
|
+
isExternal: isExternalUrl(args.path),
|
|
116
|
+
});
|
|
117
|
+
return null;
|
|
91
118
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
try {
|
|
120
|
+
const contents = await fsp.readFile(args.path, "utf-8");
|
|
121
|
+
if (hasDirective(contents, "use client")) {
|
|
122
|
+
log("Discovered 'use client' in:", args.path);
|
|
123
|
+
clientFiles.add(normalizeModulePath(args.path, rootConfig.root));
|
|
124
|
+
}
|
|
125
|
+
if (hasDirective(contents, "use server")) {
|
|
126
|
+
log("Discovered 'use server' in:", args.path);
|
|
127
|
+
serverFiles.add(normalizeModulePath(args.path, rootConfig.root));
|
|
128
|
+
}
|
|
129
|
+
return { contents, loader: "default" };
|
|
95
130
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
export async function runDirectivesScan({ rootConfig, envName, clientFiles, serverFiles, }) {
|
|
107
|
-
const esbuild = await getViteEsbuild(rootConfig.root);
|
|
108
|
-
const env = rootConfig.environments[envName];
|
|
109
|
-
const input = env.build.rollupOptions?.input;
|
|
110
|
-
let entries;
|
|
111
|
-
if (Array.isArray(input)) {
|
|
112
|
-
entries = input;
|
|
113
|
-
}
|
|
114
|
-
else if (typeof input === "string") {
|
|
115
|
-
entries = [input];
|
|
116
|
-
}
|
|
117
|
-
else if (isObject(input)) {
|
|
118
|
-
entries = Object.values(input);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
entries = [];
|
|
122
|
-
}
|
|
123
|
-
if (entries.length === 0) {
|
|
124
|
-
log("No entries found for directives scan in environment '%s', skipping.", envName);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
const absoluteEntries = entries.map((entry) => path.resolve(rootConfig.root, entry));
|
|
128
|
-
log("Starting directives scan for environment '%s' with entries:", envName, absoluteEntries);
|
|
129
|
-
try {
|
|
130
|
-
const result = await esbuild.build({
|
|
131
|
+
catch (e) {
|
|
132
|
+
log("Could not read file during scan, skipping:", args.path, e);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
await esbuild.build({
|
|
131
139
|
entryPoints: absoluteEntries,
|
|
132
140
|
bundle: true,
|
|
133
141
|
write: false,
|
|
134
142
|
platform: "node",
|
|
135
143
|
format: "esm",
|
|
136
144
|
logLevel: "silent",
|
|
137
|
-
|
|
138
|
-
plugins: [
|
|
139
|
-
createEsbuildScanPlugin({
|
|
140
|
-
clientFiles,
|
|
141
|
-
serverFiles,
|
|
142
|
-
aliases: ensureAliasArray(env),
|
|
143
|
-
projectRootDir: rootConfig.root,
|
|
144
|
-
}),
|
|
145
|
-
],
|
|
145
|
+
plugins: [esbuildScanPlugin],
|
|
146
146
|
});
|
|
147
|
-
return result.metafile;
|
|
148
147
|
}
|
|
149
148
|
catch (e) {
|
|
150
|
-
throw new Error(`RWSDK directive scan failed:\n${e.
|
|
149
|
+
throw new Error(`RWSDK directive scan failed:\n${e.stack}`);
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
// Always clear the scanning flag when done
|
|
153
|
+
delete process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE;
|
|
154
|
+
console.log("✅ Scan complete.");
|
|
151
155
|
}
|
|
152
|
-
}
|
|
156
|
+
};
|
|
@@ -48,6 +48,10 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
async resolveId(id) {
|
|
51
|
+
// Skip during directive scanning to avoid performance issues
|
|
52
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
51
55
|
if (isDev) {
|
|
52
56
|
// context(justinvdm, 27 May 2025): In dev, we need to dynamically load
|
|
53
57
|
// SSR modules, so we return the virtual id so that the dynamic loading
|
|
@@ -89,6 +93,10 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
|
|
|
89
93
|
}
|
|
90
94
|
},
|
|
91
95
|
async load(id) {
|
|
96
|
+
// Skip during directive scanning to avoid performance issues
|
|
97
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
92
100
|
if (id.startsWith(VIRTUAL_SSR_PREFIX) &&
|
|
93
101
|
this.environment.name === "worker") {
|
|
94
102
|
const realId = id.slice(VIRTUAL_SSR_PREFIX.length);
|
|
@@ -319,6 +319,10 @@ export const transformJsxScriptTagsPlugin = ({ clientEntryPoints, projectRootDir
|
|
|
319
319
|
isBuild = config.command === "build";
|
|
320
320
|
},
|
|
321
321
|
async transform(code, id) {
|
|
322
|
+
// Skip during directive scanning to avoid performance issues
|
|
323
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
322
326
|
if (isBuild &&
|
|
323
327
|
this.environment?.name === "worker" &&
|
|
324
328
|
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
@@ -4,12 +4,20 @@ export const virtualPlugin = (name, load) => {
|
|
|
4
4
|
return {
|
|
5
5
|
name: `rwsdk:virtual-${name}`,
|
|
6
6
|
resolveId(source, _importer, _options) {
|
|
7
|
+
// Skip during directive scanning to avoid performance issues
|
|
8
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
7
11
|
if (source === name || source.startsWith(`${name}?`)) {
|
|
8
12
|
return `\0${source}`;
|
|
9
13
|
}
|
|
10
14
|
return;
|
|
11
15
|
},
|
|
12
16
|
load(id, options) {
|
|
17
|
+
// Skip during directive scanning to avoid performance issues
|
|
18
|
+
if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
13
21
|
if (id === `\0${name}` || id.startsWith(`\0${name}?`)) {
|
|
14
22
|
return load.apply(this, [id, options]);
|
|
15
23
|
}
|