rwsdk 0.2.0 → 0.3.0
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/lib/constants.d.mts +6 -1
- package/dist/lib/constants.mjs +6 -1
- package/dist/lib/smokeTests/browser.mjs +5 -21
- package/dist/lib/smokeTests/codeUpdates.d.mts +1 -1
- package/dist/lib/smokeTests/codeUpdates.mjs +41 -5
- package/dist/lib/smokeTests/development.d.mts +1 -1
- package/dist/lib/smokeTests/development.mjs +4 -10
- package/dist/lib/smokeTests/release.d.mts +1 -1
- package/dist/lib/smokeTests/release.mjs +4 -9
- package/dist/lib/smokeTests/runSmokeTests.mjs +2 -2
- package/dist/lib/smokeTests/templates/SmokeTest.template.js +3 -2
- package/dist/lib/testUtils/stubEnvVars.d.mts +2 -0
- package/dist/lib/testUtils/stubEnvVars.mjs +11 -0
- package/dist/runtime/imports/client.js +4 -9
- package/dist/runtime/imports/worker.js +2 -1
- package/dist/runtime/register/ssr.js +2 -1
- package/dist/runtime/requestInfo/worker.js +9 -1
- package/dist/runtime/worker.d.ts +0 -3
- package/dist/runtime/worker.js +1 -10
- package/dist/scripts/debug-sync.mjs +0 -23
- package/dist/scripts/smoke-test.mjs +0 -10
- package/dist/vite/buildApp.d.mts +15 -0
- package/dist/vite/buildApp.mjs +53 -0
- package/dist/vite/configPlugin.d.mts +4 -2
- package/dist/vite/configPlugin.mjs +69 -62
- package/dist/vite/createDirectiveLookupPlugin.d.mts +0 -6
- package/dist/vite/createDirectiveLookupPlugin.mjs +61 -145
- package/dist/vite/directiveModulesDevPlugin.d.mts +8 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +62 -0
- package/dist/vite/directivesFilteringPlugin.d.mts +6 -0
- package/dist/vite/directivesFilteringPlugin.mjs +31 -0
- package/dist/vite/directivesPlugin.mjs +28 -42
- package/dist/vite/getViteEsbuild.d.mts +1 -0
- package/dist/vite/getViteEsbuild.mjs +12 -0
- package/dist/vite/injectVitePreamblePlugin.d.mts +3 -2
- package/dist/vite/injectVitePreamblePlugin.mjs +4 -2
- package/dist/vite/linkerPlugin.d.mts +4 -0
- package/dist/vite/linkerPlugin.mjs +41 -0
- package/dist/vite/manifestPlugin.d.mts +2 -2
- package/dist/vite/manifestPlugin.mjs +12 -37
- package/dist/vite/moveStaticAssetsPlugin.mjs +2 -1
- package/dist/vite/prismaPlugin.mjs +1 -1
- package/dist/vite/reactConditionsResolverPlugin.mjs +11 -16
- package/dist/vite/redwoodPlugin.d.mts +0 -1
- package/dist/vite/redwoodPlugin.mjs +27 -9
- package/dist/vite/runDirectivesScan.d.mts +7 -0
- package/dist/vite/runDirectivesScan.mjs +152 -0
- package/dist/vite/ssrBridgePlugin.mjs +13 -14
- package/dist/vite/transformClientComponents.d.mts +0 -1
- package/dist/vite/transformClientComponents.mjs +1 -9
- package/dist/vite/transformJsxScriptTagsPlugin.d.mts +4 -3
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +62 -84
- package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +67 -41
- package/dist/vite/transformServerFunctions.d.mts +1 -1
- package/dist/vite/transformServerFunctions.mjs +11 -12
- package/package.json +7 -1
- package/dist/runtime/clientNavigation.d.ts +0 -9
- package/dist/runtime/clientNavigation.js +0 -88
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import path, { resolve } from "node:path";
|
|
2
2
|
import { builtinModules } from "node:module";
|
|
3
3
|
import enhancedResolve from "enhanced-resolve";
|
|
4
|
-
import
|
|
4
|
+
import debug from "debug";
|
|
5
|
+
import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
|
|
6
|
+
import { buildApp } from "./buildApp.mjs";
|
|
7
|
+
const log = debug("rwsdk:vite:config");
|
|
5
8
|
// port(justinvdm, 09 Jun 2025):
|
|
6
9
|
// https://github.com/cloudflare/workers-sdk/blob/d533f5ee7da69c205d8d5e2a5f264d2370fc612b/packages/vite-plugin-cloudflare/src/cloudflare-environment.ts#L123-L128
|
|
7
10
|
export const cloudflareBuiltInModules = [
|
|
@@ -15,10 +18,60 @@ export const externalModules = [
|
|
|
15
18
|
...builtinModules,
|
|
16
19
|
...builtinModules.map((m) => `node:${m}`),
|
|
17
20
|
];
|
|
18
|
-
export const configPlugin = ({ silent, projectRootDir,
|
|
21
|
+
export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }) => ({
|
|
19
22
|
name: "rwsdk:config",
|
|
20
23
|
config: async (_) => {
|
|
21
24
|
const mode = process.env.NODE_ENV;
|
|
25
|
+
const workerConfig = {
|
|
26
|
+
resolve: {
|
|
27
|
+
conditions: [
|
|
28
|
+
"workerd",
|
|
29
|
+
"react-server",
|
|
30
|
+
"module",
|
|
31
|
+
// context(justinvdm, 11 Jun 2025): Some packages meant for cloudflare workers, yet
|
|
32
|
+
// their deps have only node import conditions, e.g. `agents` package (meant for CF),
|
|
33
|
+
// has `pkce-challenge` package as a dep, which has only node import conditions.
|
|
34
|
+
// https://github.com/crouchcd/pkce-challenge/blob/master/package.json#L17
|
|
35
|
+
//
|
|
36
|
+
// @cloudflare/vite-plugin should take care of any relevant polyfills for deps with
|
|
37
|
+
// node builtins imports that can be polyfilled though, so it is worth us including this condition here.
|
|
38
|
+
// However, it does mean we will try to run packages meant for node that cannot be run on cloudflare workers.
|
|
39
|
+
// That's the trade-off, but arguably worth it.
|
|
40
|
+
"node",
|
|
41
|
+
],
|
|
42
|
+
noExternal: true,
|
|
43
|
+
},
|
|
44
|
+
define: {
|
|
45
|
+
"import.meta.env.RWSDK_ENV": JSON.stringify("worker"),
|
|
46
|
+
},
|
|
47
|
+
optimizeDeps: {
|
|
48
|
+
noDiscovery: false,
|
|
49
|
+
include: ["rwsdk/worker"],
|
|
50
|
+
exclude: [],
|
|
51
|
+
entries: [workerEntryPathname],
|
|
52
|
+
esbuildOptions: {
|
|
53
|
+
jsx: "automatic",
|
|
54
|
+
jsxImportSource: "react",
|
|
55
|
+
define: {
|
|
56
|
+
"process.env.NODE_ENV": JSON.stringify(mode),
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
build: {
|
|
61
|
+
outDir: resolve(projectRootDir, "dist", "worker"),
|
|
62
|
+
emitAssets: true,
|
|
63
|
+
emptyOutDir: false,
|
|
64
|
+
ssr: true,
|
|
65
|
+
rollupOptions: {
|
|
66
|
+
output: {
|
|
67
|
+
inlineDynamicImports: true,
|
|
68
|
+
},
|
|
69
|
+
input: {
|
|
70
|
+
worker: workerEntryPathname,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
22
75
|
const baseConfig = {
|
|
23
76
|
appType: "custom",
|
|
24
77
|
mode,
|
|
@@ -40,7 +93,7 @@ export const configPlugin = ({ silent, projectRootDir, clientEntryPathnames, wor
|
|
|
40
93
|
outDir: resolve(projectRootDir, "dist", "client"),
|
|
41
94
|
manifest: true,
|
|
42
95
|
rollupOptions: {
|
|
43
|
-
input:
|
|
96
|
+
input: [],
|
|
44
97
|
},
|
|
45
98
|
},
|
|
46
99
|
define: {
|
|
@@ -49,6 +102,7 @@ export const configPlugin = ({ silent, projectRootDir, clientEntryPathnames, wor
|
|
|
49
102
|
optimizeDeps: {
|
|
50
103
|
noDiscovery: false,
|
|
51
104
|
include: ["rwsdk/client"],
|
|
105
|
+
entries: [],
|
|
52
106
|
esbuildOptions: {
|
|
53
107
|
jsx: "automatic",
|
|
54
108
|
jsxImportSource: "react",
|
|
@@ -87,80 +141,33 @@ export const configPlugin = ({ silent, projectRootDir, clientEntryPathnames, wor
|
|
|
87
141
|
build: {
|
|
88
142
|
lib: {
|
|
89
143
|
entry: {
|
|
90
|
-
[path.basename(
|
|
144
|
+
[path.basename(INTERMEDIATE_SSR_BRIDGE_PATH, ".js")]: enhancedResolve.sync(projectRootDir, "rwsdk/__ssr_bridge"),
|
|
91
145
|
},
|
|
92
146
|
formats: ["es"],
|
|
93
|
-
fileName: () => path.basename(
|
|
147
|
+
fileName: () => path.basename(INTERMEDIATE_SSR_BRIDGE_PATH),
|
|
94
148
|
},
|
|
95
|
-
outDir: path.dirname(
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
worker: {
|
|
99
|
-
resolve: {
|
|
100
|
-
conditions: [
|
|
101
|
-
"workerd",
|
|
102
|
-
"react-server",
|
|
103
|
-
"module",
|
|
104
|
-
// context(justinvdm, 11 Jun 2025): Some packages meant for cloudflare workers, yet
|
|
105
|
-
// their deps have only node import conditions, e.g. `agents` package (meant for CF),
|
|
106
|
-
// has `pkce-challenge` package as a dep, which has only node import conditions.
|
|
107
|
-
// https://github.com/crouchcd/pkce-challenge/blob/master/package.json#L17
|
|
108
|
-
//
|
|
109
|
-
// @cloudflare/vite-plugin should take care of any relevant polyfills for deps with
|
|
110
|
-
// node builtins imports that can be polyfilled though, so it is worth us including this condition here.
|
|
111
|
-
// However, it does mean we will try to run packages meant for node that cannot be run on cloudflare workers.
|
|
112
|
-
// That's the trade-off, but arguably worth it.
|
|
113
|
-
"node",
|
|
114
|
-
],
|
|
115
|
-
noExternal: true,
|
|
116
|
-
},
|
|
117
|
-
define: {
|
|
118
|
-
"import.meta.env.RWSDK_ENV": JSON.stringify("worker"),
|
|
119
|
-
},
|
|
120
|
-
optimizeDeps: {
|
|
121
|
-
noDiscovery: false,
|
|
122
|
-
include: ["rwsdk/worker"],
|
|
123
|
-
exclude: [],
|
|
124
|
-
entries: [workerEntryPathname],
|
|
125
|
-
esbuildOptions: {
|
|
126
|
-
jsx: "automatic",
|
|
127
|
-
jsxImportSource: "react",
|
|
128
|
-
define: {
|
|
129
|
-
"process.env.NODE_ENV": JSON.stringify(mode),
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
build: {
|
|
134
|
-
outDir: resolve(projectRootDir, "dist", "worker"),
|
|
135
|
-
emitAssets: true,
|
|
136
|
-
ssr: true,
|
|
149
|
+
outDir: path.dirname(INTERMEDIATE_SSR_BRIDGE_PATH),
|
|
137
150
|
rollupOptions: {
|
|
138
151
|
output: {
|
|
139
152
|
inlineDynamicImports: true,
|
|
140
153
|
},
|
|
141
|
-
input: {
|
|
142
|
-
worker: workerEntryPathname,
|
|
143
|
-
},
|
|
144
154
|
},
|
|
145
155
|
},
|
|
146
156
|
},
|
|
157
|
+
worker: workerConfig,
|
|
147
158
|
},
|
|
148
159
|
server: {
|
|
149
160
|
hmr: true,
|
|
150
161
|
},
|
|
151
162
|
builder: {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
// through the processing done by `@cloudflare/vite-plugin`
|
|
161
|
-
await builder.build(builder.environments["client"]);
|
|
162
|
-
await builder.build(builder.environments["ssr"]);
|
|
163
|
-
await builder.build(builder.environments["worker"]);
|
|
163
|
+
async buildApp(builder) {
|
|
164
|
+
await buildApp({
|
|
165
|
+
builder,
|
|
166
|
+
projectRootDir,
|
|
167
|
+
clientEntryPoints,
|
|
168
|
+
clientFiles,
|
|
169
|
+
serverFiles,
|
|
170
|
+
});
|
|
164
171
|
},
|
|
165
172
|
},
|
|
166
173
|
};
|
|
@@ -7,12 +7,6 @@ interface DirectiveLookupConfig {
|
|
|
7
7
|
pluginName: string;
|
|
8
8
|
optimizeForEnvironments?: string[];
|
|
9
9
|
}
|
|
10
|
-
export declare const findFilesContainingDirective: ({ projectRootDir, files, directive, debugNamespace, }: {
|
|
11
|
-
projectRootDir: string;
|
|
12
|
-
files: Set<string>;
|
|
13
|
-
directive: string;
|
|
14
|
-
debugNamespace: string;
|
|
15
|
-
}) => Promise<void>;
|
|
16
10
|
export declare const createDirectiveLookupPlugin: ({ projectRootDir, files, config, }: {
|
|
17
11
|
projectRootDir: string;
|
|
18
12
|
files: Set<string>;
|
|
@@ -1,125 +1,12 @@
|
|
|
1
1
|
import MagicString from "magic-string";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { readFile } from "fs/promises";
|
|
4
3
|
import debug from "debug";
|
|
5
|
-
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
6
|
-
import { pathExists } from "fs-extra";
|
|
7
|
-
import { stat } from "fs/promises";
|
|
8
|
-
import { getSrcPaths } from "../lib/getSrcPaths.js";
|
|
9
|
-
import { hasDirective } from "./hasDirective.mjs";
|
|
10
|
-
export const findFilesContainingDirective = async ({ projectRootDir, files, directive, debugNamespace, }) => {
|
|
11
|
-
const log = debug(debugNamespace);
|
|
12
|
-
log("Starting search for '%s' files in projectRootDir=%s", directive, projectRootDir);
|
|
13
|
-
const filesToScan = await getSrcPaths(projectRootDir);
|
|
14
|
-
log("Found %d files to scan for '%s' directive", filesToScan.length, directive);
|
|
15
|
-
for (const file of filesToScan) {
|
|
16
|
-
try {
|
|
17
|
-
const stats = await stat(file);
|
|
18
|
-
if (!stats.isFile()) {
|
|
19
|
-
process.env.VERBOSE && log("Skipping %s (not a file)", file);
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
process.env.VERBOSE && log("Scanning file: %s", file);
|
|
23
|
-
const content = await readFile(file, "utf-8");
|
|
24
|
-
if (hasDirective(content, directive)) {
|
|
25
|
-
const normalizedPath = normalizeModulePath(file, projectRootDir);
|
|
26
|
-
log("Found '%s' directive in file: %s -> %s", directive, file, normalizedPath);
|
|
27
|
-
files.add(normalizedPath);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
console.error(`Error reading file ${file}:`, error);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
log("Completed scan. Found %d %s files total", files.size, directive);
|
|
35
|
-
process.env.VERBOSE &&
|
|
36
|
-
log("Found files for %s: %j", directive, Array.from(files));
|
|
37
|
-
};
|
|
38
|
-
const resolveOptimizedDep = async (projectRootDir, id, environment, debugNamespace) => {
|
|
39
|
-
const log = debug(debugNamespace);
|
|
40
|
-
try {
|
|
41
|
-
const depsDir = environment === "client" ? "deps" : `deps_${environment}`;
|
|
42
|
-
const nodeModulesDepsDirPath = path.join("node_modules", ".vite", depsDir);
|
|
43
|
-
const depsDirPath = path.join(projectRootDir, nodeModulesDepsDirPath);
|
|
44
|
-
const manifestPath = path.join(depsDirPath, "_metadata.json");
|
|
45
|
-
log("Checking for manifest at: %s", manifestPath);
|
|
46
|
-
const manifestExists = await pathExists(manifestPath);
|
|
47
|
-
if (!manifestExists) {
|
|
48
|
-
log("Manifest not found at %s", manifestPath);
|
|
49
|
-
return undefined;
|
|
50
|
-
}
|
|
51
|
-
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
52
|
-
const manifest = JSON.parse(manifestContent);
|
|
53
|
-
if (manifest.optimized && manifest.optimized[id]) {
|
|
54
|
-
const optimizedFile = manifest.optimized[id].file;
|
|
55
|
-
const optimizedPath = path.join("/", nodeModulesDepsDirPath, optimizedFile);
|
|
56
|
-
log("Found optimized dependency: filePath=%s, optimizedPath=%s", id, optimizedPath);
|
|
57
|
-
return optimizedPath;
|
|
58
|
-
}
|
|
59
|
-
process.env.VERBOSE &&
|
|
60
|
-
log("File not found in optimized dependencies: id=%s", id);
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
process.env.VERBOSE &&
|
|
65
|
-
log("Error resolving optimized dependency for id=%s: %s", id, error);
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
const addOptimizedDepsEntries = async ({ projectRootDir, directive, environment, debugNamespace, files, }) => {
|
|
70
|
-
const log = debug(debugNamespace);
|
|
71
|
-
try {
|
|
72
|
-
const depsDir = environment === "client" ? "deps" : `deps_${environment}`;
|
|
73
|
-
const depsDirPath = path.join(projectRootDir, "node_modules", ".vite", depsDir);
|
|
74
|
-
const manifestPath = path.join(depsDirPath, "_metadata.json");
|
|
75
|
-
process.env.VERBOSE && log("Checking for manifest at: %s", manifestPath);
|
|
76
|
-
const manifestExists = await pathExists(manifestPath);
|
|
77
|
-
if (!manifestExists) {
|
|
78
|
-
process.env.VERBOSE && log("Manifest not found at %s", manifestPath);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const manifestContent = await readFile(manifestPath, "utf-8");
|
|
82
|
-
const manifest = JSON.parse(manifestContent);
|
|
83
|
-
for (const entryId of Object.keys(manifest.optimized)) {
|
|
84
|
-
if (entryId.startsWith("/node_modules/")) {
|
|
85
|
-
const srcPath = manifest.optimized[entryId].src;
|
|
86
|
-
const resolvedSrcPath = path.resolve(projectRootDir, "node_modules", ".vite", "deps", srcPath);
|
|
87
|
-
let contents;
|
|
88
|
-
try {
|
|
89
|
-
contents = await readFile(resolvedSrcPath, "utf-8");
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
process.env.VERBOSE &&
|
|
93
|
-
log("Error reading file %s: %s", resolvedSrcPath, error);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (hasDirective(contents, directive)) {
|
|
97
|
-
log("Adding optimized entry to files: %s", entryId);
|
|
98
|
-
files.add(entryId);
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
log("Skipping optimized entry %s because it does not contain the '%s' directive", entryId, directive);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
process.env.VERBOSE &&
|
|
108
|
-
log("Error adding optimized deps entries: %s", error);
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
4
|
export const createDirectiveLookupPlugin = async ({ projectRootDir, files, config, }) => {
|
|
112
5
|
const debugNamespace = `rwsdk:vite:${config.pluginName}`;
|
|
113
6
|
const log = debug(debugNamespace);
|
|
114
7
|
let isDev = false;
|
|
115
|
-
log("Initializing %s plugin with projectRootDir=%s", config.pluginName, projectRootDir);
|
|
116
|
-
await findFilesContainingDirective({
|
|
117
|
-
projectRootDir,
|
|
118
|
-
files,
|
|
119
|
-
directive: config.directive,
|
|
120
|
-
debugNamespace,
|
|
121
|
-
});
|
|
122
8
|
let devServer;
|
|
9
|
+
log("Initializing %s plugin with projectRootDir=%s", config.pluginName, projectRootDir);
|
|
123
10
|
return {
|
|
124
11
|
name: `rwsdk:${config.pluginName}`,
|
|
125
12
|
config(_, { command, isPreview }) {
|
|
@@ -129,16 +16,13 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
129
16
|
configureServer(server) {
|
|
130
17
|
devServer = server;
|
|
131
18
|
},
|
|
132
|
-
|
|
19
|
+
configEnvironment(env, viteConfig) {
|
|
20
|
+
if (!isDev &&
|
|
21
|
+
process.env.RWSDK_BUILD_PASS &&
|
|
22
|
+
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
133
25
|
log("Configuring environment: env=%s", env);
|
|
134
|
-
// Add optimized deps entries that match our pattern
|
|
135
|
-
await addOptimizedDepsEntries({
|
|
136
|
-
projectRootDir,
|
|
137
|
-
files,
|
|
138
|
-
directive: config.directive,
|
|
139
|
-
environment: env,
|
|
140
|
-
debugNamespace,
|
|
141
|
-
});
|
|
142
26
|
viteConfig.optimizeDeps ??= {};
|
|
143
27
|
viteConfig.optimizeDeps.esbuildOptions ??= {};
|
|
144
28
|
viteConfig.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
@@ -150,7 +34,7 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
150
34
|
const escapedVirtualModuleName = config.virtualModuleName.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
151
35
|
const escapedPrefixedModuleName = `/@id/${config.virtualModuleName}`.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
152
36
|
build.onResolve({
|
|
153
|
-
filter: new RegExp(`^(${escapedVirtualModuleName}|${escapedPrefixedModuleName})
|
|
37
|
+
filter: new RegExp(`^(${escapedVirtualModuleName}|${escapedPrefixedModuleName})\\.js$`),
|
|
154
38
|
}, () => {
|
|
155
39
|
process.env.VERBOSE &&
|
|
156
40
|
log("Esbuild onResolve: marking %s as external", config.virtualModuleName);
|
|
@@ -167,6 +51,9 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
167
51
|
log("Applying optimizeDeps and aliasing for environment: %s", env);
|
|
168
52
|
viteConfig.optimizeDeps.include ??= [];
|
|
169
53
|
for (const file of files) {
|
|
54
|
+
if (file.includes("node_modules")) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
170
57
|
const actualFilePath = path.join(projectRootDir, file);
|
|
171
58
|
process.env.VERBOSE &&
|
|
172
59
|
log("Adding to optimizeDeps.entries: %s", actualFilePath);
|
|
@@ -183,36 +70,66 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
183
70
|
}
|
|
184
71
|
},
|
|
185
72
|
resolveId(source) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
log("Resolving %s module", config.virtualModuleName);
|
|
189
|
-
// context(justinvdm, 16 Jun 2025): Include .js extension
|
|
190
|
-
// so it goes through vite processing chain
|
|
191
|
-
return source;
|
|
73
|
+
if (source !== `${config.virtualModuleName}.js`) {
|
|
74
|
+
return null;
|
|
192
75
|
}
|
|
193
|
-
|
|
76
|
+
// context(justinvdm, 3 Sep 2025): This logic determines *when* to
|
|
77
|
+
// generate and bundle the lookup map. By conditionally externalizing it,
|
|
78
|
+
// we ensure the map is only created after tree-shaking is complete and
|
|
79
|
+
// that it's correctly shared between the SSR and final worker builds.
|
|
80
|
+
log("Resolving %s module", config.virtualModuleName);
|
|
81
|
+
const envName = this.environment?.name;
|
|
82
|
+
// 1. Worker Pass -> externalize
|
|
83
|
+
if (isDev &&
|
|
84
|
+
envName === "worker" &&
|
|
85
|
+
process.env.RWSDK_BUILD_PASS === "worker") {
|
|
86
|
+
// context(justinvdm, 3 Sep 2025): We externalize the lookup during the
|
|
87
|
+
// first worker pass. This defers its bundling until after the
|
|
88
|
+
// directivesFilteringPlugin has had a chance to run and tree-shake
|
|
89
|
+
// the list of client/server files.
|
|
90
|
+
log("Marking as external for worker pass");
|
|
91
|
+
return { id: source, external: true };
|
|
92
|
+
}
|
|
93
|
+
// 2. SSR Pass -> externalize
|
|
94
|
+
if (isDev && envName === "ssr") {
|
|
95
|
+
// context(justinvdm, 3 Sep 2025): We also externalize during the SSR
|
|
96
|
+
// build. This ensures that both the worker and SSR artifacts refer to
|
|
97
|
+
// the same virtual module, which will be resolved into a single, shared
|
|
98
|
+
// lookup map during the final linker pass.
|
|
99
|
+
log("Marking as external for ssr pass");
|
|
100
|
+
return { id: source, external: true };
|
|
101
|
+
}
|
|
102
|
+
// 3. Client Pass & 4. Linker Pass -> resolve and bundle
|
|
103
|
+
// context(justinvdm, 3 Sep 2025): For the client build, the dev server,
|
|
104
|
+
// and the final linker pass, we resolve the module ID with a null-byte
|
|
105
|
+
// prefix. This signals to Vite/Rollup that this is a virtual module
|
|
106
|
+
// whose content should be provided by the `load` hook, bundling it in.
|
|
107
|
+
log("Resolving for bundling");
|
|
108
|
+
return source;
|
|
194
109
|
},
|
|
195
110
|
async load(id) {
|
|
196
|
-
process.env.VERBOSE && log("Loading id=%s", id);
|
|
197
111
|
if (id === config.virtualModuleName + ".js") {
|
|
198
112
|
log("Loading %s module with %d files", config.virtualModuleName, files.size);
|
|
199
113
|
const environment = this.environment?.name || "client";
|
|
200
114
|
log("Current environment: %s, isDev: %s", environment, isDev);
|
|
201
|
-
const optimizedDeps = {};
|
|
202
|
-
if (isDev && devServer) {
|
|
203
|
-
for (const file of files) {
|
|
204
|
-
const resolvedPath = await resolveOptimizedDep(projectRootDir, file, environment, debugNamespace);
|
|
205
|
-
if (resolvedPath) {
|
|
206
|
-
optimizedDeps[file] = resolvedPath;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
115
|
const s = new MagicString(`
|
|
211
116
|
export const ${config.exportName} = {
|
|
212
117
|
${Array.from(files)
|
|
213
|
-
.map((file) =>
|
|
214
|
-
|
|
215
|
-
|
|
118
|
+
.map((file) => {
|
|
119
|
+
if (file.includes("node_modules") && isDev) {
|
|
120
|
+
const barrelPath = config.kind === "client"
|
|
121
|
+
? "rwsdk/__client_barrel"
|
|
122
|
+
: "rwsdk/__server_barrel";
|
|
123
|
+
return `
|
|
124
|
+
"${file}": () => import("${barrelPath}").then(m => m.default["${file}"]),
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
return `
|
|
129
|
+
"${file}": () => import("${file}"),
|
|
130
|
+
`;
|
|
131
|
+
}
|
|
132
|
+
})
|
|
216
133
|
.join("")}
|
|
217
134
|
};
|
|
218
135
|
`);
|
|
@@ -225,7 +142,6 @@ export const ${config.exportName} = {
|
|
|
225
142
|
map,
|
|
226
143
|
};
|
|
227
144
|
}
|
|
228
|
-
process.env.VERBOSE && log("No load handling for id=%s", id);
|
|
229
145
|
},
|
|
230
146
|
};
|
|
231
147
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
export declare const VIRTUAL_CLIENT_BARREL_ID = "virtual:rwsdk:client-module-barrel";
|
|
3
|
+
export declare const VIRTUAL_SERVER_BARREL_ID = "virtual:rwsdk:server-module-barrel";
|
|
4
|
+
export declare const directiveModulesDevPlugin: ({ clientFiles, serverFiles, projectRootDir, }: {
|
|
5
|
+
clientFiles: Set<string>;
|
|
6
|
+
serverFiles: Set<string>;
|
|
7
|
+
projectRootDir: string;
|
|
8
|
+
}) => Plugin;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { writeFileSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
4
|
+
import { runDirectivesScan } from "./runDirectivesScan.mjs";
|
|
5
|
+
import { CLIENT_BARREL_PATH } from "../lib/constants.mjs";
|
|
6
|
+
import { SERVER_BARREL_PATH } from "../lib/constants.mjs";
|
|
7
|
+
export const VIRTUAL_CLIENT_BARREL_ID = "virtual:rwsdk:client-module-barrel";
|
|
8
|
+
export const VIRTUAL_SERVER_BARREL_ID = "virtual:rwsdk:server-module-barrel";
|
|
9
|
+
const CLIENT_BARREL_EXPORT_PATH = "rwsdk/__client_barrel";
|
|
10
|
+
const SERVER_BARREL_EXPORT_PATH = "rwsdk/__server_barrel";
|
|
11
|
+
const generateBarrelContent = (files, projectRootDir) => {
|
|
12
|
+
const imports = [...files]
|
|
13
|
+
.filter((file) => file.includes("node_modules"))
|
|
14
|
+
.map((file, i) => `import * as M${i} from '${normalizeModulePath(file, projectRootDir, {
|
|
15
|
+
absolute: true,
|
|
16
|
+
})}';`)
|
|
17
|
+
.join("\n");
|
|
18
|
+
const exports = "export default {\n" +
|
|
19
|
+
[...files]
|
|
20
|
+
.filter((file) => file.includes("node_modules"))
|
|
21
|
+
.map((file, i) => ` '${normalizeModulePath(file, projectRootDir)}': M${i},`)
|
|
22
|
+
.join("\n") +
|
|
23
|
+
"\n};";
|
|
24
|
+
return `${imports}\n\n${exports}`;
|
|
25
|
+
};
|
|
26
|
+
export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
|
|
27
|
+
return {
|
|
28
|
+
name: "rwsdk:directive-modules-dev",
|
|
29
|
+
enforce: "pre",
|
|
30
|
+
async configResolved(config) {
|
|
31
|
+
if (config.command !== "serve") {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const workerEnv = config.environments["worker"];
|
|
35
|
+
if (workerEnv) {
|
|
36
|
+
await runDirectivesScan({
|
|
37
|
+
rootConfig: config,
|
|
38
|
+
envName: "worker",
|
|
39
|
+
clientFiles,
|
|
40
|
+
serverFiles,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Generate the barrel content and write it to the dummy files.
|
|
44
|
+
// We can do this now because our scan is complete.
|
|
45
|
+
const clientBarrelContent = generateBarrelContent(clientFiles, projectRootDir);
|
|
46
|
+
const serverBarrelContent = generateBarrelContent(serverFiles, projectRootDir);
|
|
47
|
+
mkdirSync(path.dirname(CLIENT_BARREL_PATH), { recursive: true });
|
|
48
|
+
writeFileSync(CLIENT_BARREL_PATH, clientBarrelContent);
|
|
49
|
+
mkdirSync(path.dirname(SERVER_BARREL_PATH), { recursive: true });
|
|
50
|
+
writeFileSync(SERVER_BARREL_PATH, serverBarrelContent);
|
|
51
|
+
for (const [envName, env] of Object.entries(config.environments)) {
|
|
52
|
+
if (envName === "client" || envName === "ssr") {
|
|
53
|
+
env.optimizeDeps.include = [
|
|
54
|
+
...(env.optimizeDeps.include || []),
|
|
55
|
+
CLIENT_BARREL_EXPORT_PATH,
|
|
56
|
+
SERVER_BARREL_EXPORT_PATH,
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
3
|
+
const log = debug("rwsdk:vite:directives-filtering-plugin");
|
|
4
|
+
export const directivesFilteringPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
|
|
5
|
+
return {
|
|
6
|
+
name: "rwsdk:directives-filtering",
|
|
7
|
+
enforce: "post",
|
|
8
|
+
async buildEnd() {
|
|
9
|
+
if (this.environment.name !== "worker" ||
|
|
10
|
+
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
log("Filtering directive modules after worker build...");
|
|
14
|
+
process.env.VERBOSE &&
|
|
15
|
+
log("Directive modules before filtering: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
|
|
16
|
+
[clientFiles, serverFiles].forEach((files) => {
|
|
17
|
+
for (const id of files) {
|
|
18
|
+
const absoluteId = normalizeModulePath(id, projectRootDir, {
|
|
19
|
+
absolute: true,
|
|
20
|
+
});
|
|
21
|
+
const info = this.getModuleInfo(absoluteId);
|
|
22
|
+
if (!info?.isIncluded) {
|
|
23
|
+
files.delete(id);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
process.env.VERBOSE &&
|
|
28
|
+
log("Client/server files after filtering: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|