rwsdk 1.4.1 → 1.5.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/e2e/environment.d.mts +1 -1
- package/dist/lib/e2e/environment.mjs +28 -1
- package/dist/lib/e2e/tarball.d.mts +2 -1
- package/dist/lib/e2e/tarball.mjs +2 -2
- package/dist/lib/e2e/testHarness.d.mts +5 -0
- package/dist/lib/e2e/testHarness.mjs +7 -1
- package/dist/lib/smokeTests/environment.mjs +1 -0
- package/dist/lib/smokeTests/types.d.mts +1 -0
- package/dist/runtime/render/assembleDocument.js +1 -1
- package/dist/runtime/render/renderDocumentHtmlStream.js +1 -1
- package/dist/runtime/render/stylesheets.js +22 -0
- package/dist/scripts/smoke-test.mjs +8 -0
- package/dist/vite/addOptimizeDepsPlugin.d.mts +10 -0
- package/dist/vite/addOptimizeDepsPlugin.mjs +6 -0
- package/dist/vite/buildApp.mjs +54 -15
- package/dist/vite/configPlugin.mjs +27 -20
- package/dist/vite/createDirectiveLookupPlugin.mjs +11 -15
- package/dist/vite/directiveModulesDevPlugin.mjs +86 -103
- package/dist/vite/directivesFilteringPlugin.mjs +55 -14
- package/dist/vite/directivesPlugin.mjs +44 -87
- package/dist/vite/knownDepsResolverPlugin.mjs +29 -36
- package/dist/vite/linkerPlugin.mjs +1 -1
- package/dist/vite/prismaPlugin.mjs +7 -10
- package/dist/vite/redwoodPlugin.mjs +5 -4
- package/dist/vite/runDirectivesScan.mjs +1 -1
- package/dist/vite/ssrBridgePlugin.mjs +11 -21
- package/dist/vite/statePlugin.mjs +8 -15
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +3 -3
- package/dist/vite/viteCompat.d.mts +5 -0
- package/dist/vite/viteCompat.mjs +378 -0
- package/dist/vite/viteCompat.test.d.mts +1 -0
- package/dist/vite/viteCompat.test.mjs +72 -0
- package/dist/vite/vitePreamblePlugin.d.mts +2 -153
- package/package.json +8 -7
|
@@ -42,6 +42,91 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
42
42
|
client: VENDOR_CLIENT_BARREL_PATH,
|
|
43
43
|
server: VENDOR_SERVER_BARREL_PATH,
|
|
44
44
|
});
|
|
45
|
+
const appBarrelPaths = [APP_CLIENT_BARREL_PATH, APP_SERVER_BARREL_PATH];
|
|
46
|
+
const slugifyOptimizeEntry = (id) => id.replaceAll("/", "_").replaceAll(".", "__");
|
|
47
|
+
const VENDOR_CLIENT_BARREL_OPTIMIZED_ID = slugifyOptimizeEntry(VENDOR_CLIENT_BARREL_EXPORT_PATH);
|
|
48
|
+
const VENDOR_SERVER_BARREL_OPTIMIZED_ID = slugifyOptimizeEntry(VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
49
|
+
const escapeRegExp = (s) => s.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
50
|
+
const appBarrelFilter = new RegExp(`(${appBarrelPaths.map(escapeRegExp).join("|")})$`);
|
|
51
|
+
const BARREL_PREFIX = "\0rwsdk-app-barrel:";
|
|
52
|
+
const createAppBarrelBlockerPlugin = () => ({
|
|
53
|
+
name: "rwsdk:app-barrel-blocker",
|
|
54
|
+
async resolveId(id) {
|
|
55
|
+
await scanPromise;
|
|
56
|
+
// Handle stable vendor barrel specifiers by redirecting them to
|
|
57
|
+
// the in-memory temp barrel files. This lets Vite rewrite the
|
|
58
|
+
// specifier to its optimized dependency bundle while still serving
|
|
59
|
+
// our generated content.
|
|
60
|
+
const isClientBarrelPath = id === VENDOR_CLIENT_BARREL_EXPORT_PATH ||
|
|
61
|
+
id === VENDOR_CLIENT_BARREL_OPTIMIZED_ID ||
|
|
62
|
+
id === SDK_VENDOR_CLIENT_BARREL_PATH ||
|
|
63
|
+
id.endsWith("/__vendor_client_barrel.dev-virtual.js");
|
|
64
|
+
const isServerBarrelPath = id === VENDOR_SERVER_BARREL_EXPORT_PATH ||
|
|
65
|
+
id === VENDOR_SERVER_BARREL_OPTIMIZED_ID ||
|
|
66
|
+
id === SDK_VENDOR_SERVER_BARREL_PATH ||
|
|
67
|
+
id.endsWith("/__vendor_server_barrel.dev-virtual.js");
|
|
68
|
+
if (isClientBarrelPath) {
|
|
69
|
+
return VENDOR_CLIENT_BARREL_PATH;
|
|
70
|
+
}
|
|
71
|
+
if (isServerBarrelPath) {
|
|
72
|
+
return VENDOR_SERVER_BARREL_PATH;
|
|
73
|
+
}
|
|
74
|
+
// Handle app barrel files
|
|
75
|
+
if (appBarrelFilter.test(id)) {
|
|
76
|
+
return `${BARREL_PREFIX}${id}`;
|
|
77
|
+
}
|
|
78
|
+
// context(justinvdm, 11 Sep 2025): Prevent Vite from
|
|
79
|
+
// externalizing our application files. If we don't, paths
|
|
80
|
+
// imported in our application barrel files will be marked as
|
|
81
|
+
// external, and thus not scanned for dependencies.
|
|
82
|
+
if (id.startsWith("/") &&
|
|
83
|
+
(id.includes("/src/") || id.includes("/generated/")) &&
|
|
84
|
+
!id.includes("node_modules")) {
|
|
85
|
+
return id;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
load(id) {
|
|
89
|
+
// Handle vendor barrels
|
|
90
|
+
if (id === VENDOR_CLIENT_BARREL_PATH ||
|
|
91
|
+
id === VENDOR_SERVER_BARREL_PATH) {
|
|
92
|
+
const isServerBarrel = id.includes("server-barrel");
|
|
93
|
+
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
94
|
+
return generateVendorBarrelContent(files, projectRootDir);
|
|
95
|
+
}
|
|
96
|
+
// Handle app barrels
|
|
97
|
+
if (id.startsWith(BARREL_PREFIX)) {
|
|
98
|
+
const barrelPath = id.slice(BARREL_PREFIX.length);
|
|
99
|
+
const isServerBarrel = barrelPath.includes("app-server-barrel");
|
|
100
|
+
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
101
|
+
return generateAppBarrelContent(files, projectRootDir);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
const addUnique = (items, value) => {
|
|
106
|
+
if (!items.includes(value)) {
|
|
107
|
+
items.push(value);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const configureOptimizeDeps = (envName, env) => {
|
|
111
|
+
env.optimizeDeps ??= {};
|
|
112
|
+
env.optimizeDeps.include ??= [];
|
|
113
|
+
addUnique(env.optimizeDeps.include, VENDOR_CLIENT_BARREL_EXPORT_PATH);
|
|
114
|
+
addUnique(env.optimizeDeps.include, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
115
|
+
const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
|
|
116
|
+
addUnique(entries, VENDOR_CLIENT_BARREL_EXPORT_PATH);
|
|
117
|
+
addUnique(entries, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
118
|
+
if (envName === "client" || envName === "ssr") {
|
|
119
|
+
addUnique(entries, APP_CLIENT_BARREL_PATH);
|
|
120
|
+
}
|
|
121
|
+
else if (envName === "worker") {
|
|
122
|
+
addUnique(entries, APP_SERVER_BARREL_PATH);
|
|
123
|
+
}
|
|
124
|
+
env.optimizeDeps.rolldownOptions ??= {};
|
|
125
|
+
env.optimizeDeps.rolldownOptions.plugins ??= [];
|
|
126
|
+
if (!env.optimizeDeps.rolldownOptions.plugins.some((plugin) => plugin.name === "rwsdk:app-barrel-blocker")) {
|
|
127
|
+
env.optimizeDeps.rolldownOptions.plugins.unshift(createAppBarrelBlockerPlugin());
|
|
128
|
+
}
|
|
129
|
+
};
|
|
45
130
|
return {
|
|
46
131
|
name: "rwsdk:directive-modules-dev",
|
|
47
132
|
enforce: "pre",
|
|
@@ -105,109 +190,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
105
190
|
mkdirSync(path.dirname(VENDOR_SERVER_BARREL_PATH), { recursive: true });
|
|
106
191
|
writeFileSync(VENDOR_SERVER_BARREL_PATH, "");
|
|
107
192
|
for (const [envName, env] of Object.entries(config.environments || {})) {
|
|
108
|
-
env
|
|
109
|
-
env.optimizeDeps.include ??= [];
|
|
110
|
-
env.optimizeDeps.include.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
111
|
-
const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
|
|
112
|
-
entries.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
113
|
-
if (envName === "client" || envName === "ssr") {
|
|
114
|
-
entries.push(APP_CLIENT_BARREL_PATH);
|
|
115
|
-
}
|
|
116
|
-
else if (envName === "worker") {
|
|
117
|
-
entries.push(APP_SERVER_BARREL_PATH);
|
|
118
|
-
}
|
|
119
|
-
env.optimizeDeps.esbuildOptions ??= {};
|
|
120
|
-
env.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
121
|
-
env.optimizeDeps.esbuildOptions.plugins.unshift({
|
|
122
|
-
name: "rwsdk:app-barrel-blocker",
|
|
123
|
-
setup(build) {
|
|
124
|
-
const appBarrelPaths = [
|
|
125
|
-
APP_CLIENT_BARREL_PATH,
|
|
126
|
-
APP_SERVER_BARREL_PATH,
|
|
127
|
-
];
|
|
128
|
-
const vendorBarrelPaths = [
|
|
129
|
-
VENDOR_CLIENT_BARREL_PATH,
|
|
130
|
-
VENDOR_SERVER_BARREL_PATH,
|
|
131
|
-
];
|
|
132
|
-
const barrelPaths = [...appBarrelPaths, ...vendorBarrelPaths];
|
|
133
|
-
const escapeRegExp = (s) => s.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
134
|
-
const barrelFilter = new RegExp(`(${barrelPaths.map(escapeRegExp).join("|")})$`);
|
|
135
|
-
build.onResolve({ filter: /.*/ }, async (args) => {
|
|
136
|
-
// Block all resolutions until the scan is complete.
|
|
137
|
-
await scanPromise;
|
|
138
|
-
// Handle stable vendor barrel specifiers by redirecting them to
|
|
139
|
-
// the in-memory temp barrel files. This lets Vite rewrite the
|
|
140
|
-
// specifier to its optimized dependency bundle while still serving
|
|
141
|
-
// our generated content.
|
|
142
|
-
const isClientBarrelPath = args.path === VENDOR_CLIENT_BARREL_EXPORT_PATH ||
|
|
143
|
-
args.path === SDK_VENDOR_CLIENT_BARREL_PATH ||
|
|
144
|
-
args.path.endsWith("/__vendor_client_barrel.dev-virtual.js");
|
|
145
|
-
const isServerBarrelPath = args.path === VENDOR_SERVER_BARREL_EXPORT_PATH ||
|
|
146
|
-
args.path === SDK_VENDOR_SERVER_BARREL_PATH ||
|
|
147
|
-
args.path.endsWith("/__vendor_server_barrel.dev-virtual.js");
|
|
148
|
-
if (isClientBarrelPath) {
|
|
149
|
-
return {
|
|
150
|
-
path: VENDOR_CLIENT_BARREL_PATH,
|
|
151
|
-
namespace: "rwsdk-barrel-ns",
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
if (isServerBarrelPath) {
|
|
155
|
-
return {
|
|
156
|
-
path: VENDOR_SERVER_BARREL_PATH,
|
|
157
|
-
namespace: "rwsdk-barrel-ns",
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
// Handle barrel files (app + vendor)
|
|
161
|
-
if (barrelFilter.test(args.path)) {
|
|
162
|
-
return {
|
|
163
|
-
path: args.path,
|
|
164
|
-
namespace: "rwsdk-barrel-ns",
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
// context(justinvdm, 11 Sep 2025): Prevent Vite from
|
|
168
|
-
// externalizing our application files. If we don't, paths
|
|
169
|
-
// imported in our application barrel files will be marked as
|
|
170
|
-
// external, and thus not scanned for dependencies.
|
|
171
|
-
if (args.path.startsWith("/") &&
|
|
172
|
-
(args.path.includes("/src/") ||
|
|
173
|
-
args.path.includes("/generated/")) &&
|
|
174
|
-
!args.path.includes("node_modules")) {
|
|
175
|
-
// By returning a result, we claim the module and prevent vite:dep-scan
|
|
176
|
-
// from marking it as external.
|
|
177
|
-
return {
|
|
178
|
-
path: args.path,
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
build.onLoad({ filter: /__vendor_(client|server)_barrel\.dev-virtual\.js$/ }, async (args) => {
|
|
183
|
-
await scanPromise;
|
|
184
|
-
const isServerBarrel = args.path.includes("server-barrel");
|
|
185
|
-
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
186
|
-
return {
|
|
187
|
-
contents: generateVendorBarrelContent(files, projectRootDir),
|
|
188
|
-
loader: "js",
|
|
189
|
-
};
|
|
190
|
-
});
|
|
191
|
-
build.onLoad({ filter: /.*/, namespace: "rwsdk-barrel-ns" }, (args) => {
|
|
192
|
-
const isServerBarrel = args.path.includes("server-barrel");
|
|
193
|
-
const isVendorBarrel = args.path.includes("vendor");
|
|
194
|
-
if (isVendorBarrel) {
|
|
195
|
-
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
196
|
-
const content = generateVendorBarrelContent(files, projectRootDir);
|
|
197
|
-
return {
|
|
198
|
-
contents: content,
|
|
199
|
-
loader: "js",
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const files = isServerBarrel ? serverFiles : clientFiles;
|
|
203
|
-
const content = generateAppBarrelContent(files, projectRootDir);
|
|
204
|
-
return {
|
|
205
|
-
contents: content,
|
|
206
|
-
loader: "js",
|
|
207
|
-
};
|
|
208
|
-
});
|
|
209
|
-
},
|
|
210
|
-
});
|
|
193
|
+
configureOptimizeDeps(envName, env);
|
|
211
194
|
}
|
|
212
195
|
},
|
|
213
196
|
};
|
|
@@ -1,32 +1,73 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
2
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
3
3
|
const log = debug("rwsdk:vite:directives-filtering-plugin");
|
|
4
|
+
function filterDirectiveModules({ clientFiles, serverFiles, projectRootDir, includedModules, }) {
|
|
5
|
+
process.env.VERBOSE &&
|
|
6
|
+
log("Directive modules before filtering: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
|
|
7
|
+
for (const files of [clientFiles, serverFiles]) {
|
|
8
|
+
for (const id of files) {
|
|
9
|
+
const absoluteId = normalizeModulePath(id, projectRootDir, {
|
|
10
|
+
absolute: true,
|
|
11
|
+
});
|
|
12
|
+
if (!includedModules.has(absoluteId)) {
|
|
13
|
+
files.delete(id);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
process.env.VERBOSE &&
|
|
18
|
+
log("Client/server files after filtering: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
|
|
19
|
+
}
|
|
4
20
|
export const directivesFilteringPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
|
|
5
21
|
return {
|
|
6
22
|
name: "rwsdk:directives-filtering",
|
|
7
23
|
enforce: "post",
|
|
8
|
-
|
|
24
|
+
buildEnd() {
|
|
9
25
|
if (this.environment.name !== "worker" ||
|
|
10
26
|
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
11
27
|
return;
|
|
12
28
|
}
|
|
13
29
|
log("Filtering directive modules after worker build...");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
const includedModules = new Set();
|
|
31
|
+
for (const id of this.getModuleIds()) {
|
|
32
|
+
const info = this.getModuleInfo(id);
|
|
33
|
+
if (info && info.isIncluded !== false) {
|
|
34
|
+
includedModules.add(id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
filterDirectiveModules({
|
|
38
|
+
clientFiles,
|
|
39
|
+
serverFiles,
|
|
40
|
+
projectRootDir,
|
|
41
|
+
includedModules,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
generateBundle(_options, bundle) {
|
|
45
|
+
if (this.environment.name !== "worker" ||
|
|
46
|
+
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
log("Filtering directive modules from bundle output...");
|
|
50
|
+
// context(justinvdm, 2026-05-13): Rolldown (Vite 8+) does not expose
|
|
51
|
+
// ModuleInfo.isIncluded. Instead, we inspect the final output chunks.
|
|
52
|
+
// A module whose renderedLength is 0 (or missing) was tree-shaken to
|
|
53
|
+
// empty and should be removed from the directive sets.
|
|
54
|
+
const includedModules = new Set();
|
|
55
|
+
for (const output of Object.values(bundle)) {
|
|
56
|
+
if (output.type !== "chunk") {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
for (const [moduleId, renderedModule] of Object.entries(output.modules)) {
|
|
60
|
+
if (renderedModule.renderedLength > 0) {
|
|
61
|
+
includedModules.add(moduleId);
|
|
25
62
|
}
|
|
26
63
|
}
|
|
64
|
+
}
|
|
65
|
+
filterDirectiveModules({
|
|
66
|
+
clientFiles,
|
|
67
|
+
serverFiles,
|
|
68
|
+
projectRootDir,
|
|
69
|
+
includedModules,
|
|
27
70
|
});
|
|
28
|
-
process.env.VERBOSE &&
|
|
29
|
-
log("Client/server files after filtering: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
|
|
30
71
|
},
|
|
31
72
|
};
|
|
32
73
|
};
|
|
@@ -2,6 +2,7 @@ import debug from "debug";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
5
|
+
import { addOptimizeDepsPlugin } from "./addOptimizeDepsPlugin.mjs";
|
|
5
6
|
import { transformClientComponents } from "./transformClientComponents.mjs";
|
|
6
7
|
import { transformServerFunctions } from "./transformServerFunctions.mjs";
|
|
7
8
|
const log = debug("rwsdk:vite:rsc-directives-plugin");
|
|
@@ -92,100 +93,56 @@ export const directivesPlugin = ({ projectRootDir, clientFiles, serverFiles, })
|
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
94
95
|
process.env.VERBOSE && log("Configuring environment: env=%s", env);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
build.onLoad({ filter: /\.(js|ts|jsx|tsx|mts|mjs|cjs)$/ }, async (args) => {
|
|
103
|
-
process.env.VERBOSE &&
|
|
104
|
-
log("Esbuild onLoad called for environment=%s, path=%s", env, args.path);
|
|
105
|
-
const normalizedPath = normalizeModulePath(args.path, projectRootDir);
|
|
106
|
-
// context(justinvdm,2025-06-15): If we're in app code,
|
|
107
|
-
// we will be doing the transform work in the vite plugin hooks,
|
|
108
|
-
// the only reason we're in esbuild land for app code is for
|
|
109
|
-
// dependency discovery, so we can skip transform work
|
|
110
|
-
// and use heuristics instead - see below inside if block
|
|
111
|
-
if (!args.path.includes("node_modules")) {
|
|
112
|
-
if (clientFiles.has(normalizedPath)) {
|
|
113
|
-
// context(justinvdm,2025-06-15): If this is a client file:
|
|
114
|
-
// * for ssr and client envs we can skip so esbuild looks at the
|
|
115
|
-
// original source code to discovery dependencies
|
|
116
|
-
// * for worker env, the transform would have just created
|
|
117
|
-
// references and dropped all imports, so we can just return empty code
|
|
118
|
-
if (env === "client" || env === "ssr") {
|
|
119
|
-
log("Esbuild onLoad skipping client module in app code for client or ssr env, path=%s", args.path);
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
log("Esbuild onLoad returning empty code for server module in app code for worker env, path=%s to bypass esbuild dependency discovery", args.path);
|
|
124
|
-
return {
|
|
125
|
-
contents: "",
|
|
126
|
-
loader: "js",
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else if (serverFiles.has(normalizedPath)) {
|
|
131
|
-
// context(justinvdm,2025-06-15): If this is a server file:
|
|
132
|
-
// * for worker env, we can skip so esbuild looks at the
|
|
133
|
-
// original source code to discovery dependencies
|
|
134
|
-
// * for ssr and client envs, the transform would have just created
|
|
135
|
-
// references and dropped all imports, so we can just return empty code
|
|
136
|
-
if (env === "worker") {
|
|
137
|
-
log("Esbuild onLoad skipping server module in app code for worker env, path=%s", args.path);
|
|
138
|
-
return undefined;
|
|
139
|
-
}
|
|
140
|
-
else if (env === "ssr" || env === "client") {
|
|
141
|
-
log("Esbuild onLoad returning empty code for server module in app code for ssr or client env, path=%s", args.path);
|
|
142
|
-
return {
|
|
143
|
-
contents: "",
|
|
144
|
-
loader: "js",
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
96
|
+
const directivesFileFilter = /\.(js|ts|jsx|tsx|mts|mjs|cjs)$/;
|
|
97
|
+
async function handleDirectivesLoad(filePath) {
|
|
98
|
+
const normalizedPath = normalizeModulePath(filePath, projectRootDir);
|
|
99
|
+
if (!filePath.includes("node_modules")) {
|
|
100
|
+
if (clientFiles.has(normalizedPath)) {
|
|
101
|
+
if (env === "client" || env === "ssr") {
|
|
102
|
+
return undefined;
|
|
148
103
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
code = await fs.readFile(args.path, "utf-8");
|
|
104
|
+
else {
|
|
105
|
+
return { code: "", moduleType: "js" };
|
|
152
106
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
107
|
+
}
|
|
108
|
+
else if (serverFiles.has(normalizedPath)) {
|
|
109
|
+
if (env === "worker") {
|
|
156
110
|
return undefined;
|
|
157
111
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
clientFiles,
|
|
161
|
-
isEsbuild: true,
|
|
162
|
-
});
|
|
163
|
-
if (clientResult) {
|
|
164
|
-
process.env.VERBOSE &&
|
|
165
|
-
log("Esbuild client component transformation successful for environment=%s, path=%s", env, args.path);
|
|
166
|
-
process.env.VERBOSE &&
|
|
167
|
-
log("Esbuild client component transformation for environment=%s, path=%s, code: %j", env, args.path, clientResult.code);
|
|
168
|
-
return {
|
|
169
|
-
contents: clientResult.code,
|
|
170
|
-
loader: getLoader(args.path),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
const serverResult = transformServerFunctions(code, normalizedPath, env, serverFiles);
|
|
174
|
-
if (serverResult) {
|
|
175
|
-
process.env.VERBOSE &&
|
|
176
|
-
log("Esbuild server function transformation successful for environment=%s, path=%s", env, args.path);
|
|
177
|
-
return {
|
|
178
|
-
contents: serverResult.code,
|
|
179
|
-
loader: getLoader(args.path),
|
|
180
|
-
};
|
|
112
|
+
else if (env === "ssr" || env === "client") {
|
|
113
|
+
return { code: "", moduleType: "js" };
|
|
181
114
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
let code;
|
|
118
|
+
try {
|
|
119
|
+
code = await fs.readFile(filePath, "utf-8");
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const clientResult = await transformClientComponents(code, normalizedPath, { environmentName: env, clientFiles, isEsbuild: true });
|
|
125
|
+
if (clientResult) {
|
|
126
|
+
return { code: clientResult.code, moduleType: getLoader(filePath) };
|
|
127
|
+
}
|
|
128
|
+
const serverResult = transformServerFunctions(code, normalizedPath, env, serverFiles);
|
|
129
|
+
if (serverResult) {
|
|
130
|
+
return { code: serverResult.code, moduleType: getLoader(filePath) };
|
|
131
|
+
}
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
addOptimizeDepsPlugin(config, {
|
|
135
|
+
name: "rsc-directives-transform",
|
|
136
|
+
async load(id) {
|
|
137
|
+
if (!directivesFileFilter.test(id)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const result = await handleDirectivesLoad(id);
|
|
141
|
+
if (result) {
|
|
142
|
+
return { code: result.code, moduleType: result.moduleType };
|
|
143
|
+
}
|
|
185
144
|
},
|
|
186
145
|
});
|
|
187
|
-
process.env.VERBOSE &&
|
|
188
|
-
log("Environment configuration complete for env=%s", env);
|
|
189
146
|
},
|
|
190
147
|
};
|
|
191
148
|
};
|
|
@@ -91,44 +91,34 @@ export const knownDepsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
91
91
|
// Log a clean summary instead of all the individual mappings
|
|
92
92
|
const totalMappings = Object.values(ENV_IMPORT_MAPPINGS).reduce((sum, mappings) => sum + mappings.size, 0);
|
|
93
93
|
log("Known dependencies resolver configured with %d total mappings across %d environments", totalMappings, Object.keys(ENV_IMPORT_MAPPINGS).length);
|
|
94
|
-
function
|
|
94
|
+
function createResolverPlugin(envName, mappings) {
|
|
95
95
|
if (!mappings) {
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
-
// Create reverse mapping from slugified names to original imports
|
|
99
|
-
// Vite converts "react-dom/server.edge" -> "react-dom_server__edge"
|
|
100
|
-
// Pattern: / becomes _, . becomes __
|
|
101
98
|
const slugifiedToOriginal = new Map();
|
|
102
|
-
for (const [original
|
|
99
|
+
for (const [original] of mappings) {
|
|
103
100
|
const slugified = original.replace(/\//g, "_").replace(/\./g, "__");
|
|
104
101
|
slugifiedToOriginal.set(slugified, original);
|
|
105
102
|
}
|
|
106
103
|
return {
|
|
107
|
-
name: `rwsdk:known-dependencies-resolver
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
if (originalImport) {
|
|
115
|
-
resolved = mappings.get(originalImport);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (!resolved) {
|
|
119
|
-
resolved = resolveKnownImport(args.path, envName, projectRootDir);
|
|
104
|
+
name: `rwsdk:known-dependencies-resolver-${envName}`,
|
|
105
|
+
resolveId(id) {
|
|
106
|
+
let resolved = mappings.get(id);
|
|
107
|
+
if (!resolved) {
|
|
108
|
+
const originalImport = slugifiedToOriginal.get(id);
|
|
109
|
+
if (originalImport) {
|
|
110
|
+
resolved = mappings.get(originalImport);
|
|
120
111
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return
|
|
128
|
-
path: resolved,
|
|
129
|
-
};
|
|
112
|
+
}
|
|
113
|
+
if (!resolved) {
|
|
114
|
+
resolved = resolveKnownImport(id, envName, projectRootDir);
|
|
115
|
+
}
|
|
116
|
+
if (resolved) {
|
|
117
|
+
if (id === "react-server-dom-webpack/client.edge") {
|
|
118
|
+
return;
|
|
130
119
|
}
|
|
131
|
-
|
|
120
|
+
return resolved;
|
|
121
|
+
}
|
|
132
122
|
},
|
|
133
123
|
};
|
|
134
124
|
}
|
|
@@ -152,17 +142,20 @@ export const knownDepsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
152
142
|
config.environments[envName] = {};
|
|
153
143
|
}
|
|
154
144
|
const envConfig = config.environments[envName];
|
|
155
|
-
|
|
156
|
-
if (esbuildPlugin && mappings) {
|
|
145
|
+
if (mappings) {
|
|
157
146
|
envConfig.optimizeDeps ??= {};
|
|
158
|
-
envConfig.optimizeDeps.
|
|
159
|
-
envConfig.optimizeDeps.
|
|
160
|
-
envConfig.optimizeDeps.
|
|
161
|
-
envConfig.optimizeDeps.
|
|
162
|
-
envConfig.optimizeDeps.
|
|
147
|
+
envConfig.optimizeDeps.rolldownOptions ??= {};
|
|
148
|
+
envConfig.optimizeDeps.rolldownOptions.transform ??= {};
|
|
149
|
+
envConfig.optimizeDeps.rolldownOptions.transform.define ??= {};
|
|
150
|
+
envConfig.optimizeDeps.rolldownOptions.transform.define["process.env.NODE_ENV"] = JSON.stringify(process.env.NODE_ENV);
|
|
151
|
+
envConfig.optimizeDeps.rolldownOptions.plugins ??= [];
|
|
152
|
+
const plugin = createResolverPlugin(envName, mappings);
|
|
153
|
+
if (plugin) {
|
|
154
|
+
envConfig.optimizeDeps.rolldownOptions.plugins.push(plugin);
|
|
155
|
+
}
|
|
163
156
|
envConfig.optimizeDeps.include ??= [];
|
|
164
157
|
envConfig.optimizeDeps.include.push(...predefinedImports);
|
|
165
|
-
log("Added
|
|
158
|
+
log("Added optimizeDeps plugin and includes for environment: %s", envName);
|
|
166
159
|
}
|
|
167
160
|
const aliases = ensureAliasArray(envConfig);
|
|
168
161
|
for (const [find, replacement] of mappings) {
|
|
@@ -9,7 +9,7 @@ export function linkWorkerBundle({ code, manifestContent, projectRootDir, base,
|
|
|
9
9
|
const manifest = JSON.parse(manifestContent);
|
|
10
10
|
// 1. Replace the manifest placeholder with the actual manifest content.
|
|
11
11
|
log("Injecting manifest into worker bundle");
|
|
12
|
-
newCode = newCode.replace(/['"]__RWSDK_MANIFEST_PLACEHOLDER__['"]/, manifestContent);
|
|
12
|
+
newCode = newCode.replace(/['"`]__RWSDK_MANIFEST_PLACEHOLDER__['"`]/, manifestContent);
|
|
13
13
|
// 2. Replace asset placeholders with their final hashed paths.
|
|
14
14
|
log("Replacing asset placeholders in final worker bundle");
|
|
15
15
|
for (const [key, value] of Object.entries(manifest)) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import { addOptimizeDepsPlugin } from "./addOptimizeDepsPlugin.mjs";
|
|
2
3
|
import { checkPrismaStatus } from "./checkIsUsingPrisma.mjs";
|
|
3
4
|
import { ensureAliasArray } from "./ensureAliasArray.mjs";
|
|
4
5
|
import { invalidateCacheIfPrismaClientChanged } from "./invalidateCacheIfPrismaClientChanged.mjs";
|
|
@@ -21,17 +22,13 @@ export const prismaPlugin = async ({ projectRootDir, }) => {
|
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
const wasmPath = resolve(projectRootDir, "node_modules/.prisma/client/wasm.js");
|
|
24
|
-
|
|
25
|
-
config
|
|
26
|
-
config.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
27
|
-
config.optimizeDeps.esbuildOptions.plugins.push({
|
|
25
|
+
const prismaFilter = /^.prisma\/client\/default/;
|
|
26
|
+
addOptimizeDepsPlugin(config, {
|
|
28
27
|
name: "rwsdk:prisma",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
});
|
|
28
|
+
resolveId(id) {
|
|
29
|
+
if (prismaFilter.test(id)) {
|
|
30
|
+
return wasmPath;
|
|
31
|
+
}
|
|
35
32
|
},
|
|
36
33
|
});
|
|
37
34
|
ensureAliasArray(config).push({
|
|
@@ -6,12 +6,12 @@ import { devServerConstantPlugin } from "./devServerConstant.mjs";
|
|
|
6
6
|
import { hasOwnCloudflareVitePlugin } from "./hasOwnCloudflareVitePlugin.mjs";
|
|
7
7
|
import { hasOwnReactVitePlugin } from "./hasOwnReactVitePlugin.mjs";
|
|
8
8
|
import reactPlugin from "@vitejs/plugin-react";
|
|
9
|
-
import tsconfigPaths from "vite-tsconfig-paths";
|
|
10
9
|
import { pathExists } from "fs-extra";
|
|
11
10
|
import { $ } from "../lib/$.mjs";
|
|
12
11
|
import { findWranglerConfig } from "../lib/findWranglerConfig.mjs";
|
|
13
12
|
import { hasPkgScript } from "../lib/hasPkgScript.mjs";
|
|
14
13
|
import { cloudflarePreInitPlugin } from "./cloudflarePreInitPlugin.mjs";
|
|
14
|
+
import { compatTransform } from "./viteCompat.mjs";
|
|
15
15
|
import { configPlugin } from "./configPlugin.mjs";
|
|
16
16
|
import { devServerTimingPlugin } from "./devServerTimingPlugin.mjs";
|
|
17
17
|
import { directiveModulesDevPlugin } from "./directiveModulesDevPlugin.mjs";
|
|
@@ -84,7 +84,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
84
84
|
console.log("🚀 Project has no .wrangler directory yet, assuming fresh install: running `npm run dev:init`...");
|
|
85
85
|
await $ `npm run dev:init`;
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
const pluginResults = await Promise.all([
|
|
88
88
|
staleDepRetryPlugin(),
|
|
89
89
|
statePlugin({ projectRootDir }),
|
|
90
90
|
devServerTimingPlugin(),
|
|
@@ -112,7 +112,6 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
112
112
|
}),
|
|
113
113
|
knownDepsResolverPlugin({ projectRootDir }),
|
|
114
114
|
cloudflarePreInitPlugin(),
|
|
115
|
-
tsconfigPaths({ root: projectRootDir }),
|
|
116
115
|
shouldIncludeCloudflarePlugin
|
|
117
116
|
? cloudflare({
|
|
118
117
|
viteEnvironment: { name: "worker" },
|
|
@@ -158,5 +157,7 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
158
157
|
serverFiles,
|
|
159
158
|
projectRootDir,
|
|
160
159
|
}),
|
|
161
|
-
];
|
|
160
|
+
]);
|
|
161
|
+
const flattenedPlugins = pluginResults.flat().filter((plugin) => plugin != null);
|
|
162
|
+
return compatTransform(flattenedPlugins);
|
|
162
163
|
};
|
|
@@ -99,7 +99,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
|
|
|
99
99
|
return contents;
|
|
100
100
|
};
|
|
101
101
|
const esbuild = await getViteEsbuild(rootConfig.root);
|
|
102
|
-
const input = initialEntries ?? environments.worker.config.build.
|
|
102
|
+
const input = initialEntries ?? environments.worker.config.build.rolldownOptions?.input;
|
|
103
103
|
let entries;
|
|
104
104
|
if (Array.isArray(input)) {
|
|
105
105
|
entries = input;
|