rwsdk 0.2.0 → 0.3.1
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 -4
- package/dist/vite/configPlugin.mjs +70 -76
- package/dist/vite/constants.d.mts +2 -0
- package/dist/vite/constants.mjs +12 -0
- package/dist/vite/createDirectiveLookupPlugin.d.mts +0 -6
- package/dist/vite/createDirectiveLookupPlugin.mjs +69 -145
- package/dist/vite/createViteAwareResolver.d.mts +4 -0
- package/dist/vite/createViteAwareResolver.mjs +208 -0
- package/dist/vite/directiveModulesDevPlugin.d.mts +8 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +87 -0
- package/dist/vite/directivesFilteringPlugin.d.mts +6 -0
- package/dist/vite/directivesFilteringPlugin.mjs +31 -0
- package/dist/vite/directivesPlugin.mjs +32 -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 +8 -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 +20 -37
- package/dist/vite/moveStaticAssetsPlugin.mjs +2 -1
- package/dist/vite/prismaPlugin.mjs +1 -1
- package/dist/vite/reactConditionsResolverPlugin.mjs +15 -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 +156 -0
- package/dist/vite/ssrBridgePlugin.mjs +21 -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 +66 -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/dist/vite/virtualPlugin.mjs +8 -0
- package/package.json +7 -1
- package/dist/runtime/clientNavigation.d.ts +0 -9
- package/dist/runtime/clientNavigation.js +0 -88
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { Project, Node, SyntaxKind, } from "ts-morph";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { pathExists } from "fs-extra";
|
|
4
2
|
import debug from "debug";
|
|
3
|
+
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
5
4
|
const log = debug("rwsdk:vite:transform-jsx-script-tags");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const exists = await pathExists(manifestPath);
|
|
10
|
-
if (!exists) {
|
|
11
|
-
throw new Error(`RedwoodSDK expected client manifest to exist at ${manifestPath}. This is likely a bug. Please report it at https://github.com/redwoodjs/sdk/issues/new`);
|
|
12
|
-
}
|
|
13
|
-
manifestCache = JSON.parse(await readFile(manifestPath, "utf-8"));
|
|
5
|
+
function transformAssetPath(importPath, projectRootDir) {
|
|
6
|
+
if (process.env.VITE_IS_DEV_SERVER === "1") {
|
|
7
|
+
return importPath;
|
|
14
8
|
}
|
|
15
|
-
|
|
16
|
-
}
|
|
9
|
+
const normalizedImportPath = normalizeModulePath(importPath, projectRootDir);
|
|
10
|
+
return `rwsdk_asset:${normalizedImportPath}`;
|
|
11
|
+
}
|
|
12
|
+
// Note: This plugin only runs during discovery phase (Phase 1)
|
|
13
|
+
// Manifest reading and asset linking happens later in Phase 5
|
|
17
14
|
function hasJsxFunctions(text) {
|
|
18
15
|
return (text.includes('jsx("script"') ||
|
|
19
16
|
text.includes("jsx('script'") ||
|
|
@@ -28,7 +25,7 @@ function hasJsxFunctions(text) {
|
|
|
28
25
|
text.includes('jsxDEV("link"') ||
|
|
29
26
|
text.includes("jsxDEV('link'"));
|
|
30
27
|
}
|
|
31
|
-
function transformScriptImports(scriptContent, manifest) {
|
|
28
|
+
function transformScriptImports(scriptContent, clientEntryPoints, manifest, projectRootDir) {
|
|
32
29
|
const scriptProject = new Project({ useInMemoryFileSystem: true });
|
|
33
30
|
try {
|
|
34
31
|
const wrappedContent = `function __wrapper() {${scriptContent}}`;
|
|
@@ -49,12 +46,10 @@ function transformScriptImports(scriptContent, manifest) {
|
|
|
49
46
|
if (importPath.startsWith("/")) {
|
|
50
47
|
log("Found dynamic import with root-relative path: %s", importPath);
|
|
51
48
|
entryPoints.push(importPath);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
hasChanges = true;
|
|
57
|
-
}
|
|
49
|
+
clientEntryPoints.add(importPath);
|
|
50
|
+
const transformedImportPath = transformAssetPath(importPath, projectRootDir);
|
|
51
|
+
args[0].setLiteralValue(transformedImportPath);
|
|
52
|
+
hasChanges = true;
|
|
58
53
|
}
|
|
59
54
|
}
|
|
60
55
|
}
|
|
@@ -73,7 +68,7 @@ function transformScriptImports(scriptContent, manifest) {
|
|
|
73
68
|
return { content: undefined, hasChanges: false, entryPoints: [] };
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
|
-
export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
71
|
+
export async function transformJsxScriptTagsCode(code, clientEntryPoints, manifest = {}, projectRootDir) {
|
|
77
72
|
// context(justinvdm, 15 Jun 2025): Optimization to exit early
|
|
78
73
|
// to avoidunnecessary ts-morph parsing
|
|
79
74
|
if (!hasJsxFunctions(code)) {
|
|
@@ -124,7 +119,7 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
|
124
119
|
let hasStringLiteralChildren = false;
|
|
125
120
|
let hasSrc = false;
|
|
126
121
|
let isPreload = false;
|
|
127
|
-
let
|
|
122
|
+
let hrefProp;
|
|
128
123
|
for (const prop of properties) {
|
|
129
124
|
if (Node.isPropertyAssignment(prop)) {
|
|
130
125
|
const propName = prop.getName();
|
|
@@ -142,15 +137,13 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
|
142
137
|
const srcValue = initializer.getLiteralValue();
|
|
143
138
|
if (srcValue.startsWith("/")) {
|
|
144
139
|
entryPoints.push(srcValue);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
}
|
|
140
|
+
clientEntryPoints.add(srcValue);
|
|
141
|
+
const transformedSrc = transformAssetPath(srcValue, projectRootDir);
|
|
142
|
+
modifications.push({
|
|
143
|
+
type: "literalValue",
|
|
144
|
+
node: initializer,
|
|
145
|
+
value: transformedSrc,
|
|
146
|
+
});
|
|
154
147
|
}
|
|
155
148
|
}
|
|
156
149
|
}
|
|
@@ -160,7 +153,7 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
|
160
153
|
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
161
154
|
hasStringLiteralChildren = true;
|
|
162
155
|
const scriptContent = initializer.getLiteralValue();
|
|
163
|
-
const { content: transformedContent, hasChanges: contentHasChanges, entryPoints: dynamicEntryPoints, } = transformScriptImports(scriptContent, manifest);
|
|
156
|
+
const { content: transformedContent, hasChanges: contentHasChanges, entryPoints: dynamicEntryPoints, } = transformScriptImports(scriptContent, clientEntryPoints, manifest, projectRootDir);
|
|
164
157
|
entryPoints.push(...dynamicEntryPoints);
|
|
165
158
|
if (contentHasChanges && transformedContent) {
|
|
166
159
|
const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
|
|
@@ -174,21 +167,35 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
|
174
167
|
});
|
|
175
168
|
}
|
|
176
169
|
}
|
|
177
|
-
if (tagName === "link"
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
if (propName === "href" &&
|
|
187
|
-
(Node.isStringLiteral(initializer) ||
|
|
188
|
-
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
189
|
-
hrefValue = initializer.getLiteralValue();
|
|
170
|
+
if (tagName === "link" &&
|
|
171
|
+
propName === "rel" &&
|
|
172
|
+
initializer &&
|
|
173
|
+
(Node.isStringLiteral(initializer) ||
|
|
174
|
+
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
175
|
+
const relValue = initializer.getLiteralValue();
|
|
176
|
+
if (relValue === "preload" || relValue === "modulepreload") {
|
|
177
|
+
isPreload = true;
|
|
190
178
|
}
|
|
191
179
|
}
|
|
180
|
+
if (tagName === "link" && propName === "href") {
|
|
181
|
+
hrefProp = prop;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (isPreload && hrefProp) {
|
|
186
|
+
const initializer = hrefProp.getInitializer();
|
|
187
|
+
if (initializer &&
|
|
188
|
+
(Node.isStringLiteral(initializer) ||
|
|
189
|
+
Node.isNoSubstitutionTemplateLiteral(initializer))) {
|
|
190
|
+
const hrefValue = initializer.getLiteralValue();
|
|
191
|
+
if (hrefValue.startsWith("/")) {
|
|
192
|
+
const transformedHref = transformAssetPath(hrefValue, projectRootDir);
|
|
193
|
+
modifications.push({
|
|
194
|
+
type: "literalValue",
|
|
195
|
+
node: initializer,
|
|
196
|
+
value: transformedHref,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
192
199
|
}
|
|
193
200
|
}
|
|
194
201
|
if (tagName === "script" &&
|
|
@@ -205,43 +212,8 @@ export async function transformJsxScriptTagsCode(code, manifest = {}) {
|
|
|
205
212
|
needsRequestInfoImportRef.value = true;
|
|
206
213
|
}
|
|
207
214
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
hrefValue &&
|
|
211
|
-
hrefValue.startsWith("/") &&
|
|
212
|
-
manifest[hrefValue.slice(1)]) {
|
|
213
|
-
const path = hrefValue.slice(1);
|
|
214
|
-
for (const prop of properties) {
|
|
215
|
-
if (Node.isPropertyAssignment(prop) &&
|
|
216
|
-
prop.getName() === "href") {
|
|
217
|
-
const initializer = prop.getInitializer();
|
|
218
|
-
if (Node.isStringLiteral(initializer) ||
|
|
219
|
-
Node.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
220
|
-
const transformedHref = manifest[path].file;
|
|
221
|
-
const originalText = initializer.getText();
|
|
222
|
-
const isTemplateLiteral = Node.isNoSubstitutionTemplateLiteral(initializer);
|
|
223
|
-
const quote = isTemplateLiteral
|
|
224
|
-
? "`"
|
|
225
|
-
: originalText.charAt(0);
|
|
226
|
-
let replacementText;
|
|
227
|
-
if (isTemplateLiteral) {
|
|
228
|
-
replacementText = `\`/${transformedHref}\``;
|
|
229
|
-
}
|
|
230
|
-
else if (quote === '"') {
|
|
231
|
-
replacementText = `"/${transformedHref}"`;
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
replacementText = `'/${transformedHref}'`;
|
|
235
|
-
}
|
|
236
|
-
modifications.push({
|
|
237
|
-
type: "replaceText",
|
|
238
|
-
node: initializer,
|
|
239
|
-
text: replacementText,
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
215
|
+
// Note: Link preload href transformations happen in Phase 5 (Asset Linking)
|
|
216
|
+
// During discovery phase, we only transform script tags
|
|
245
217
|
}
|
|
246
218
|
}
|
|
247
219
|
if (entryPoints.length > 0) {
|
|
@@ -339,7 +311,7 @@ ${mod.callExprText}
|
|
|
339
311
|
}
|
|
340
312
|
return;
|
|
341
313
|
}
|
|
342
|
-
export const transformJsxScriptTagsPlugin = ({
|
|
314
|
+
export const transformJsxScriptTagsPlugin = ({ clientEntryPoints, projectRootDir, }) => {
|
|
343
315
|
let isBuild = false;
|
|
344
316
|
return {
|
|
345
317
|
name: "rwsdk:vite:transform-jsx-script-tags",
|
|
@@ -347,14 +319,24 @@ export const transformJsxScriptTagsPlugin = ({ manifestPath, }) => {
|
|
|
347
319
|
isBuild = config.command === "build";
|
|
348
320
|
},
|
|
349
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
|
+
}
|
|
326
|
+
if (isBuild &&
|
|
327
|
+
this.environment?.name === "worker" &&
|
|
328
|
+
process.env.RWSDK_BUILD_PASS !== "worker") {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
350
331
|
if (this.environment?.name === "worker" &&
|
|
351
332
|
id.endsWith(".tsx") &&
|
|
352
333
|
!id.includes("node_modules") &&
|
|
353
334
|
hasJsxFunctions(code)) {
|
|
354
335
|
log("Transforming JSX script tags in %s", id);
|
|
355
336
|
process.env.VERBOSE && log("Code:\n%s", code);
|
|
356
|
-
|
|
357
|
-
const result = await transformJsxScriptTagsCode(code, manifest
|
|
337
|
+
// During discovery phase, never use manifest - it doesn't exist yet
|
|
338
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, {}, // Empty manifest during discovery
|
|
339
|
+
projectRootDir);
|
|
358
340
|
if (result) {
|
|
359
341
|
log("Transformed JSX script tags in %s", id);
|
|
360
342
|
process.env.VERBOSE &&
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
2
|
import { transformJsxScriptTagsCode } from "./transformJsxScriptTagsPlugin.mjs";
|
|
3
3
|
import jsBeautify from "js-beautify";
|
|
4
|
+
import stubEnvVars from "../lib/testUtils/stubEnvVars.mjs";
|
|
4
5
|
// Helper function to normalize code formatting for test comparisons
|
|
5
6
|
function normalizeCode(code) {
|
|
6
7
|
return jsBeautify(code, { indent_size: 2 });
|
|
7
8
|
}
|
|
9
|
+
stubEnvVars();
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
process.env.RWSDK_BUILD_PASS = "worker";
|
|
12
|
+
});
|
|
8
13
|
describe("transformJsxScriptTagsCode", () => {
|
|
9
14
|
const mockManifest = {
|
|
10
15
|
"src/client.tsx": { file: "assets/client-a1b2c3d4.js" },
|
|
@@ -18,13 +23,14 @@ describe("transformJsxScriptTagsCode", () => {
|
|
|
18
23
|
type: "module"
|
|
19
24
|
})
|
|
20
25
|
`;
|
|
21
|
-
const
|
|
26
|
+
const clientEntryPoints = new Set();
|
|
27
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/Users/justin/rw/forks/workers-sdk/sdk/sdk");
|
|
22
28
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
23
29
|
|
|
24
30
|
(
|
|
25
31
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
26
32
|
jsx("script", {
|
|
27
|
-
src: "/
|
|
33
|
+
src: "rwsdk_asset:/src/client.tsx",
|
|
28
34
|
type: "module",
|
|
29
35
|
nonce: requestInfo.rw.nonce
|
|
30
36
|
})
|
|
@@ -38,14 +44,15 @@ nonce: requestInfo.rw.nonce
|
|
|
38
44
|
children: "import('/src/client.tsx').then(module => { console.log(module); })"
|
|
39
45
|
})
|
|
40
46
|
`;
|
|
41
|
-
const
|
|
47
|
+
const clientEntryPoints = new Set();
|
|
48
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
42
49
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
43
50
|
|
|
44
51
|
(
|
|
45
52
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
46
53
|
jsx("script", {
|
|
47
54
|
type: "module",
|
|
48
|
-
children: "import('/
|
|
55
|
+
children: "import('rwsdk_asset:/src/client.tsx').then(module => { console.log(module); })",
|
|
49
56
|
nonce: requestInfo.rw.nonce
|
|
50
57
|
})
|
|
51
58
|
)`;
|
|
@@ -55,12 +62,13 @@ nonce: requestInfo.rw.nonce
|
|
|
55
62
|
const code = `
|
|
56
63
|
jsx("script", { type: "module", children: "import('/src/client.tsx')" })
|
|
57
64
|
`;
|
|
58
|
-
const
|
|
65
|
+
const clientEntryPoints = new Set();
|
|
66
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
59
67
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
60
68
|
|
|
61
69
|
(
|
|
62
70
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
63
|
-
jsx("script", { type: "module", children: "import('/
|
|
71
|
+
jsx("script", { type: "module", children: "import('rwsdk_asset:/src/client.tsx')",
|
|
64
72
|
nonce: requestInfo.rw.nonce
|
|
65
73
|
})
|
|
66
74
|
)`;
|
|
@@ -80,7 +88,8 @@ nonce: requestInfo.rw.nonce
|
|
|
80
88
|
\`
|
|
81
89
|
})
|
|
82
90
|
`;
|
|
83
|
-
const
|
|
91
|
+
const clientEntryPoints = new Set();
|
|
92
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
84
93
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
85
94
|
|
|
86
95
|
(
|
|
@@ -90,7 +99,7 @@ type: "module",
|
|
|
90
99
|
children: \`
|
|
91
100
|
// Some comments here
|
|
92
101
|
const init = async () => {
|
|
93
|
-
await import('/
|
|
102
|
+
await import('rwsdk_asset:/src/entry.js');
|
|
94
103
|
console.log('initialized');
|
|
95
104
|
};
|
|
96
105
|
init();
|
|
@@ -110,7 +119,8 @@ import('/src/entry.js');
|
|
|
110
119
|
\`
|
|
111
120
|
})
|
|
112
121
|
`;
|
|
113
|
-
const
|
|
122
|
+
const clientEntryPoints = new Set();
|
|
123
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
114
124
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
115
125
|
|
|
116
126
|
(
|
|
@@ -119,8 +129,8 @@ import('/src/entry.js');
|
|
|
119
129
|
jsx("script", {
|
|
120
130
|
type: "module",
|
|
121
131
|
children: \`
|
|
122
|
-
import('/
|
|
123
|
-
import('/
|
|
132
|
+
import('rwsdk_asset:/src/client.tsx');
|
|
133
|
+
import('rwsdk_asset:/src/entry.js');
|
|
124
134
|
\`,
|
|
125
135
|
nonce: requestInfo.rw.nonce
|
|
126
136
|
})
|
|
@@ -135,14 +145,17 @@ nonce: requestInfo.rw.nonce
|
|
|
135
145
|
as: "script"
|
|
136
146
|
})
|
|
137
147
|
`;
|
|
138
|
-
const
|
|
139
|
-
|
|
148
|
+
const clientEntryPoints = new Set();
|
|
149
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
150
|
+
const expected = `
|
|
140
151
|
jsx("link", {
|
|
141
152
|
rel: "preload",
|
|
142
|
-
href: "/
|
|
153
|
+
href: "rwsdk_asset:/src/client.tsx",
|
|
143
154
|
as: "script"
|
|
144
155
|
})
|
|
145
|
-
|
|
156
|
+
`;
|
|
157
|
+
expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
|
|
158
|
+
expect(clientEntryPoints.size).toBe(0); // Make sure it doesn't incorrectly add to entry points
|
|
146
159
|
});
|
|
147
160
|
it("transforms link href attributes with modulepreload rel", async () => {
|
|
148
161
|
const code = `
|
|
@@ -151,13 +164,15 @@ nonce: requestInfo.rw.nonce
|
|
|
151
164
|
rel: "modulepreload"
|
|
152
165
|
})
|
|
153
166
|
`;
|
|
154
|
-
const
|
|
155
|
-
|
|
167
|
+
const clientEntryPoints = new Set();
|
|
168
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
169
|
+
const expected = `
|
|
156
170
|
jsx("link", {
|
|
157
|
-
href: "/
|
|
171
|
+
href: "rwsdk_asset:/src/client.tsx",
|
|
158
172
|
rel: "modulepreload"
|
|
159
173
|
})
|
|
160
|
-
|
|
174
|
+
`;
|
|
175
|
+
expect(normalizeCode(result?.code || "")).toEqual(normalizeCode(expected));
|
|
161
176
|
});
|
|
162
177
|
it("transforms real-world Document component example", async () => {
|
|
163
178
|
const code = `
|
|
@@ -169,7 +184,7 @@ nonce: requestInfo.rw.nonce
|
|
|
169
184
|
jsx("meta", { charSet: "utf-8" }),
|
|
170
185
|
jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
171
186
|
jsx("title", { children: "@redwoodjs/starter-standard" }),
|
|
172
|
-
jsx("link", { rel: "modulepreload", href: "
|
|
187
|
+
jsx("link", { rel: "modulepreload", href: "rwsdk_asset:/src/client.tsx", as: "script" })
|
|
173
188
|
]
|
|
174
189
|
}),
|
|
175
190
|
jsx("body", {
|
|
@@ -181,7 +196,8 @@ nonce: requestInfo.rw.nonce
|
|
|
181
196
|
]
|
|
182
197
|
})
|
|
183
198
|
`;
|
|
184
|
-
const
|
|
199
|
+
const clientEntryPoints = new Set();
|
|
200
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
185
201
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
186
202
|
|
|
187
203
|
jsx("html", {
|
|
@@ -192,7 +208,7 @@ children: [
|
|
|
192
208
|
jsx("meta", { charSet: "utf-8" }),
|
|
193
209
|
jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }),
|
|
194
210
|
jsx("title", { children: "@redwoodjs/starter-standard" }),
|
|
195
|
-
jsx("link", { rel: "modulepreload", href: "/
|
|
211
|
+
jsx("link", { rel: "modulepreload", href: "rwsdk_asset:/src/client.tsx", as: "script" })
|
|
196
212
|
]
|
|
197
213
|
}),
|
|
198
214
|
jsx("body", {
|
|
@@ -200,7 +216,7 @@ children: [
|
|
|
200
216
|
jsx("div", { id: "root", children: props.children }),
|
|
201
217
|
(
|
|
202
218
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
203
|
-
jsx("script", { children: "import(\\"/
|
|
219
|
+
jsx("script", { children: "import(\\"rwsdk_asset:/src/client.tsx\\")",
|
|
204
220
|
nonce: requestInfo.rw.nonce
|
|
205
221
|
})
|
|
206
222
|
)
|
|
@@ -214,7 +230,8 @@ nonce: requestInfo.rw.nonce
|
|
|
214
230
|
const code = `
|
|
215
231
|
jsx("div", { children: "No scripts or links here" })
|
|
216
232
|
`;
|
|
217
|
-
const
|
|
233
|
+
const clientEntryPoints = new Set();
|
|
234
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
218
235
|
expect(result).toBeUndefined();
|
|
219
236
|
});
|
|
220
237
|
it("handles paths not found in manifest", async () => {
|
|
@@ -224,13 +241,14 @@ nonce: requestInfo.rw.nonce
|
|
|
224
241
|
type: "module"
|
|
225
242
|
})
|
|
226
243
|
`;
|
|
227
|
-
const
|
|
244
|
+
const clientEntryPoints = new Set();
|
|
245
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
228
246
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
229
247
|
|
|
230
248
|
(
|
|
231
249
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/non-existent.js")),
|
|
232
250
|
jsx("script", {
|
|
233
|
-
src: "
|
|
251
|
+
src: "rwsdk_asset:/src/non-existent.js",
|
|
234
252
|
type: "module",
|
|
235
253
|
nonce: requestInfo.rw.nonce
|
|
236
254
|
})
|
|
@@ -244,13 +262,14 @@ nonce: requestInfo.rw.nonce
|
|
|
244
262
|
type: "module"
|
|
245
263
|
})
|
|
246
264
|
`;
|
|
247
|
-
const
|
|
265
|
+
const clientEntryPoints = new Set();
|
|
266
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
248
267
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
249
268
|
|
|
250
269
|
(
|
|
251
270
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
252
271
|
jsx("script", {
|
|
253
|
-
src: "/
|
|
272
|
+
src: "rwsdk_asset:/src/client.tsx",
|
|
254
273
|
type: "module",
|
|
255
274
|
nonce: requestInfo.rw.nonce
|
|
256
275
|
})
|
|
@@ -264,7 +283,8 @@ nonce: requestInfo.rw.nonce
|
|
|
264
283
|
children: "console.log('hello world')"
|
|
265
284
|
})
|
|
266
285
|
`;
|
|
267
|
-
const
|
|
286
|
+
const clientEntryPoints = new Set();
|
|
287
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
268
288
|
expect(result?.code).toEqual(`import { requestInfo } from "rwsdk/worker";
|
|
269
289
|
|
|
270
290
|
jsx("script", {
|
|
@@ -281,7 +301,8 @@ nonce: requestInfo.rw.nonce
|
|
|
281
301
|
dangerouslySetInnerHTML: { __html: "console.log('hello world')" }
|
|
282
302
|
})
|
|
283
303
|
`;
|
|
284
|
-
const
|
|
304
|
+
const clientEntryPoints = new Set();
|
|
305
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
285
306
|
expect(result?.code).toEqual(undefined);
|
|
286
307
|
});
|
|
287
308
|
it("does not add nonce to script tags that already have nonce", async () => {
|
|
@@ -292,7 +313,8 @@ nonce: requestInfo.rw.nonce
|
|
|
292
313
|
nonce: "existing-nonce"
|
|
293
314
|
})
|
|
294
315
|
`;
|
|
295
|
-
const
|
|
316
|
+
const clientEntryPoints = new Set();
|
|
317
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
296
318
|
expect(result?.code).toEqual(undefined);
|
|
297
319
|
});
|
|
298
320
|
it("uses existing requestInfo import if already present", async () => {
|
|
@@ -305,7 +327,8 @@ nonce: requestInfo.rw.nonce
|
|
|
305
327
|
children: "console.log('hello world')"
|
|
306
328
|
})
|
|
307
329
|
`;
|
|
308
|
-
const
|
|
330
|
+
const clientEntryPoints = new Set();
|
|
331
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
309
332
|
expect(result?.code).toEqual(`
|
|
310
333
|
import { foo } from 'bar';
|
|
311
334
|
import { requestInfo, someOtherThing } from "rwsdk/worker";
|
|
@@ -331,7 +354,8 @@ nonce: requestInfo.rw.nonce
|
|
|
331
354
|
children: "console.log('hello world')"
|
|
332
355
|
})
|
|
333
356
|
`;
|
|
334
|
-
const
|
|
357
|
+
const clientEntryPoints = new Set();
|
|
358
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
335
359
|
expect(result?.code).toEqual(`
|
|
336
360
|
import { foo } from 'bar';
|
|
337
361
|
import { someOtherThing, requestInfo } from "rwsdk/worker";
|
|
@@ -351,13 +375,14 @@ nonce: requestInfo.rw.nonce
|
|
|
351
375
|
})
|
|
352
376
|
`;
|
|
353
377
|
// Call without providing manifest (simulating dev mode)
|
|
354
|
-
const
|
|
378
|
+
const clientEntryPoints = new Set();
|
|
379
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
355
380
|
const expected = `import { requestInfo } from "rwsdk/worker";
|
|
356
381
|
|
|
357
382
|
(
|
|
358
383
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
359
384
|
jsx("script", {
|
|
360
|
-
src: "
|
|
385
|
+
src: "rwsdk_asset:/src/client.tsx",
|
|
361
386
|
type: "module",
|
|
362
387
|
nonce: requestInfo.rw.nonce
|
|
363
388
|
})
|
|
@@ -433,7 +458,7 @@ export const Document = ({
|
|
|
433
458
|
lineNumber: 22,
|
|
434
459
|
columnNumber: 4
|
|
435
460
|
}, this),
|
|
436
|
-
/* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "
|
|
461
|
+
/* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "rwsdk_asset:/src/client.tsx" }, void 0, false, {
|
|
437
462
|
fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
|
|
438
463
|
lineNumber: 23,
|
|
439
464
|
columnNumber: 4
|
|
@@ -470,7 +495,8 @@ export const Document = ({
|
|
|
470
495
|
columnNumber: 2
|
|
471
496
|
}, this);
|
|
472
497
|
`;
|
|
473
|
-
const
|
|
498
|
+
const clientEntryPoints = new Set();
|
|
499
|
+
const result = await transformJsxScriptTagsCode(code, clientEntryPoints, mockManifest, "/project/root/dir");
|
|
474
500
|
// For this complex test, we'll just verify the key transformations
|
|
475
501
|
const expected = `
|
|
476
502
|
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
@@ -534,7 +560,7 @@ children
|
|
|
534
560
|
),
|
|
535
561
|
(
|
|
536
562
|
(requestInfo.rw.scriptsToBeLoaded.add("/theme-script.js")),
|
|
537
|
-
/* @__PURE__ */ jsxDEV("script", { src: "
|
|
563
|
+
/* @__PURE__ */ jsxDEV("script", { src: "rwsdk_asset:/theme-script.js",
|
|
538
564
|
nonce: requestInfo.rw.nonce
|
|
539
565
|
}, void 0, false, {
|
|
540
566
|
fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
|
|
@@ -547,7 +573,7 @@ children
|
|
|
547
573
|
lineNumber: 22,
|
|
548
574
|
columnNumber: 4
|
|
549
575
|
}, this),
|
|
550
|
-
/* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "/
|
|
576
|
+
/* @__PURE__ */ jsxDEV("link", { rel: "modulepreload", href: "rwsdk_asset:/src/client.tsx" }, void 0, false, {
|
|
551
577
|
fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
|
|
552
578
|
lineNumber: 23,
|
|
553
579
|
columnNumber: 4
|
|
@@ -570,7 +596,7 @@ children
|
|
|
570
596
|
}, this),
|
|
571
597
|
(
|
|
572
598
|
(requestInfo.rw.scriptsToBeLoaded.add("/src/client.tsx")),
|
|
573
|
-
/* @__PURE__ */ jsxDEV("script", { children: "import(\\"/
|
|
599
|
+
/* @__PURE__ */ jsxDEV("script", { children: "import(\\"rwsdk_asset:/src/client.tsx\\")",
|
|
574
600
|
nonce: requestInfo.rw.nonce
|
|
575
601
|
}, void 0, false, {
|
|
576
602
|
fileName: "/Users/justin/rw/blotter/rwsdk-guestbook/src/app/document/Document.tsx",
|
|
@@ -12,5 +12,5 @@ type ExportInfoCompat = {
|
|
|
12
12
|
};
|
|
13
13
|
export declare const findExportedFunctions: (code: string, normalizedId?: string) => Set<string>;
|
|
14
14
|
export declare const findExportInfo: (code: string, normalizedId?: string) => ExportInfoCompat;
|
|
15
|
-
export declare const transformServerFunctions: (code: string, normalizedId: string, environment: "client" | "worker" | "ssr", serverFiles?: Set<string
|
|
15
|
+
export declare const transformServerFunctions: (code: string, normalizedId: string, environment: "client" | "worker" | "ssr", serverFiles?: Set<string>) => TransformResult | undefined;
|
|
16
16
|
export type { TransformResult };
|
|
@@ -84,19 +84,15 @@ function hasDefaultExport(code, normalizedId) {
|
|
|
84
84
|
}
|
|
85
85
|
return false;
|
|
86
86
|
}
|
|
87
|
-
export const transformServerFunctions = (code, normalizedId, environment, serverFiles
|
|
88
|
-
process.env.VERBOSE &&
|
|
89
|
-
log("Transform server functions called for normalizedId=%s, environment=%s", normalizedId, environment);
|
|
87
|
+
export const transformServerFunctions = (code, normalizedId, environment, serverFiles) => {
|
|
90
88
|
if (!hasDirective(code, "use server")) {
|
|
91
|
-
log("Skipping: no 'use server' directive in id=%s", normalizedId);
|
|
92
|
-
process.env.VERBOSE &&
|
|
93
|
-
log(":VERBOSE: Returning code unchanged for id=%s:\n%s", normalizedId, code);
|
|
94
89
|
return;
|
|
95
90
|
}
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
process.env.VERBOSE &&
|
|
92
|
+
log("Processing 'use server' module: normalizedId=%s, environment=%s", normalizedId, environment);
|
|
98
93
|
if (environment === "ssr" || environment === "client") {
|
|
99
|
-
|
|
94
|
+
process.env.VERBOSE &&
|
|
95
|
+
log(`Transforming for ${environment} environment: normalizedId=%s`, normalizedId);
|
|
100
96
|
const exportInfo = findExportInfo(code, normalizedId);
|
|
101
97
|
const allExports = new Set([
|
|
102
98
|
...exportInfo.localFunctions,
|
|
@@ -126,7 +122,8 @@ export const transformServerFunctions = (code, normalizedId, environment, server
|
|
|
126
122
|
s.append(`\nexport default createServerReference(${JSON.stringify(normalizedId)}, "default");\n`);
|
|
127
123
|
log(`Added ${environment} server reference for default export in normalizedId=%s`, normalizedId);
|
|
128
124
|
}
|
|
129
|
-
|
|
125
|
+
process.env.VERBOSE &&
|
|
126
|
+
log(`${environment} transformation complete for normalizedId=%s`, normalizedId);
|
|
130
127
|
return {
|
|
131
128
|
code: s.toString(),
|
|
132
129
|
map: s.generateMap({
|
|
@@ -137,7 +134,8 @@ export const transformServerFunctions = (code, normalizedId, environment, server
|
|
|
137
134
|
};
|
|
138
135
|
}
|
|
139
136
|
else if (environment === "worker") {
|
|
140
|
-
|
|
137
|
+
process.env.VERBOSE &&
|
|
138
|
+
log("Transforming for worker environment: normalizedId=%s", normalizedId);
|
|
141
139
|
const exportInfo = findExportInfo(code, normalizedId);
|
|
142
140
|
const s = new MagicString(code);
|
|
143
141
|
// Remove "use server" directive first
|
|
@@ -281,7 +279,8 @@ export const transformServerFunctions = (code, normalizedId, environment, server
|
|
|
281
279
|
if (registrationCalls.length > 0) {
|
|
282
280
|
s.append(registrationCalls.join("\n") + "\n");
|
|
283
281
|
}
|
|
284
|
-
|
|
282
|
+
process.env.VERBOSE &&
|
|
283
|
+
log("Worker transformation complete for normalizedId=%s", normalizedId);
|
|
285
284
|
return {
|
|
286
285
|
code: s.toString(),
|
|
287
286
|
map: s.generateMap({
|
|
@@ -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
|
}
|