rwsdk 1.0.0-alpha.3 → 1.0.0-alpha.5
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/getShortName.mjs +6 -1
- package/dist/lib/getShortName.test.mjs +25 -0
- package/dist/lib/hasPkgScript.d.mts +4 -1
- package/dist/lib/hasPkgScript.mjs +9 -6
- package/dist/lib/hasPkgScript.test.d.mts +1 -0
- package/dist/lib/hasPkgScript.test.mjs +33 -0
- package/dist/lib/jsonUtils.mjs +3 -0
- package/dist/lib/jsonUtils.test.d.mts +1 -0
- package/dist/lib/jsonUtils.test.mjs +90 -0
- package/dist/lib/normalizeModulePath.d.mts +5 -0
- package/dist/lib/normalizeModulePath.mjs +1 -1
- package/dist/lib/normalizeModulePath.test.d.mts +1 -0
- package/dist/lib/{normalizeModulePath.test.js → normalizeModulePath.test.mjs} +20 -1
- package/dist/runtime/lib/memoizeOnId.test.d.ts +1 -0
- package/dist/runtime/lib/memoizeOnId.test.js +49 -0
- package/dist/runtime/lib/realtime/protocol.test.d.ts +1 -0
- package/dist/runtime/lib/realtime/protocol.test.js +107 -0
- package/dist/runtime/lib/realtime/shared.test.d.ts +1 -0
- package/dist/runtime/lib/realtime/shared.test.js +18 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.test.d.ts +1 -0
- package/dist/runtime/lib/realtime/validateUpgradeRequest.test.js +66 -0
- package/dist/runtime/lib/router.test.js +1 -1
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.d.ts +2 -1
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.js +6 -6
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.d.ts +1 -0
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.js +49 -0
- package/dist/vite/checkIsUsingPrisma.d.mts +4 -0
- package/dist/vite/checkIsUsingPrisma.mjs +2 -2
- package/dist/vite/checkIsUsingPrisma.test.d.mts +1 -0
- package/dist/vite/checkIsUsingPrisma.test.mjs +30 -0
- package/dist/vite/configPlugin.mjs +22 -0
- package/dist/vite/createDirectiveLookupPlugin.d.mts +9 -0
- package/dist/vite/createDirectiveLookupPlugin.mjs +33 -29
- package/dist/vite/createDirectiveLookupPlugin.test.d.mts +1 -0
- package/dist/vite/createDirectiveLookupPlugin.test.mjs +40 -0
- package/dist/vite/directiveModulesDevPlugin.d.mts +2 -0
- package/dist/vite/directiveModulesDevPlugin.mjs +3 -3
- package/dist/vite/directiveModulesDevPlugin.test.d.mts +1 -0
- package/dist/vite/directiveModulesDevPlugin.test.mjs +59 -0
- package/dist/vite/directivesPlugin.d.mts +1 -0
- package/dist/vite/directivesPlugin.mjs +1 -1
- package/dist/vite/directivesPlugin.test.d.mts +1 -0
- package/dist/vite/directivesPlugin.test.mjs +24 -0
- package/dist/vite/ensureAliasArray.test.d.mts +1 -0
- package/dist/vite/ensureAliasArray.test.mjs +71 -0
- package/dist/vite/findSpecifiers.mjs +2 -1
- package/dist/vite/findSpecifiers.test.d.mts +1 -0
- package/dist/vite/findSpecifiers.test.mjs +202 -0
- package/dist/vite/findSsrSpecifiers.test.d.mts +1 -0
- package/dist/vite/findSsrSpecifiers.test.mjs +99 -0
- package/dist/vite/hasDirective.test.d.mts +1 -0
- package/dist/vite/hasDirective.test.mjs +109 -0
- package/dist/vite/isJsFile.test.d.mts +1 -0
- package/dist/vite/isJsFile.test.mjs +38 -0
- package/dist/vite/linkerPlugin.d.mts +8 -0
- package/dist/vite/linkerPlugin.mjs +30 -22
- package/dist/vite/linkerPlugin.test.d.mts +1 -0
- package/dist/vite/linkerPlugin.test.mjs +41 -0
- package/dist/vite/miniflareHMRPlugin.d.mts +5 -0
- package/dist/vite/miniflareHMRPlugin.mjs +2 -2
- package/dist/vite/miniflareHMRPlugin.test.d.mts +1 -0
- package/dist/vite/miniflareHMRPlugin.test.mjs +42 -0
- package/dist/vite/redwoodPlugin.d.mts +7 -0
- package/dist/vite/redwoodPlugin.mjs +7 -3
- package/dist/vite/redwoodPlugin.test.d.mts +1 -0
- package/dist/vite/redwoodPlugin.test.mjs +34 -0
- package/dist/vite/runDirectivesScan.d.mts +19 -0
- package/dist/vite/runDirectivesScan.mjs +52 -44
- package/dist/vite/runDirectivesScan.test.d.mts +1 -0
- package/dist/vite/runDirectivesScan.test.mjs +73 -0
- package/package.json +1 -1
- /package/dist/lib/{normalizeModulePath.test.d.ts → getShortName.test.d.mts} +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { findSsrImportCallSites } from "./findSsrSpecifiers.mjs";
|
|
3
|
+
describe("findSsrImportCallSites", () => {
|
|
4
|
+
it("should find __vite_ssr_import__ with double quotes", () => {
|
|
5
|
+
const code = `const a = __vite_ssr_import__("module-a");`;
|
|
6
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
7
|
+
expect(results).toHaveLength(1);
|
|
8
|
+
expect(results[0]).toEqual({
|
|
9
|
+
start: 10,
|
|
10
|
+
end: 41,
|
|
11
|
+
specifier: "module-a",
|
|
12
|
+
kind: "import",
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
it("should find __vite_ssr_import__ with single quotes", () => {
|
|
16
|
+
const code = `const a = __vite_ssr_import__('module-a');`;
|
|
17
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
18
|
+
expect(results).toHaveLength(1);
|
|
19
|
+
expect(results[0]).toEqual({
|
|
20
|
+
start: 10,
|
|
21
|
+
end: 41,
|
|
22
|
+
specifier: "module-a",
|
|
23
|
+
kind: "import",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
it("should find __vite_ssr_dynamic_import__ with double quotes", () => {
|
|
27
|
+
const code = `const a = __vite_ssr_dynamic_import__("module-a");`;
|
|
28
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
29
|
+
expect(results).toHaveLength(1);
|
|
30
|
+
expect(results[0]).toEqual({
|
|
31
|
+
start: 10,
|
|
32
|
+
end: 49,
|
|
33
|
+
specifier: "module-a",
|
|
34
|
+
kind: "dynamic_import",
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("should find __vite_ssr_dynamic_import__ with single quotes", () => {
|
|
38
|
+
const code = `const a = __vite_ssr_dynamic_import__('module-a');`;
|
|
39
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
40
|
+
expect(results).toHaveLength(1);
|
|
41
|
+
expect(results[0]).toEqual({
|
|
42
|
+
start: 10,
|
|
43
|
+
end: 49,
|
|
44
|
+
specifier: "module-a",
|
|
45
|
+
kind: "dynamic_import",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it("should find calls with additional arguments", () => {
|
|
49
|
+
const code = `const a = __vite_ssr_import__('module-a', { ssr: true });`;
|
|
50
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
51
|
+
expect(results).toHaveLength(1);
|
|
52
|
+
expect(results[0]).toEqual({
|
|
53
|
+
start: 10,
|
|
54
|
+
end: 56,
|
|
55
|
+
specifier: "module-a",
|
|
56
|
+
kind: "import",
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
it("should find a mix of different calls", () => {
|
|
60
|
+
const code = `
|
|
61
|
+
const a = __vite_ssr_import__("module-a");
|
|
62
|
+
const b = __vite_ssr_dynamic_import__('module-b');
|
|
63
|
+
`;
|
|
64
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
65
|
+
expect(results).toHaveLength(2);
|
|
66
|
+
expect(results).toEqual(expect.arrayContaining([
|
|
67
|
+
{
|
|
68
|
+
start: 17,
|
|
69
|
+
end: 48,
|
|
70
|
+
specifier: "module-a",
|
|
71
|
+
kind: "import",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
start: 66,
|
|
75
|
+
end: 105,
|
|
76
|
+
specifier: "module-b",
|
|
77
|
+
kind: "dynamic_import",
|
|
78
|
+
},
|
|
79
|
+
]));
|
|
80
|
+
});
|
|
81
|
+
it("should return correct ranges for replacement", () => {
|
|
82
|
+
const code = `__vite_ssr_import__("module-a")`;
|
|
83
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
84
|
+
expect(results).toHaveLength(1);
|
|
85
|
+
const { start, end } = results[0];
|
|
86
|
+
expect(code.substring(start, end)).toBe('__vite_ssr_import__("module-a")');
|
|
87
|
+
});
|
|
88
|
+
it("should return an empty array when no calls are found", () => {
|
|
89
|
+
const code = `import a from "module-a";`;
|
|
90
|
+
const results = findSsrImportCallSites("test.ts", code);
|
|
91
|
+
expect(results).toHaveLength(0);
|
|
92
|
+
});
|
|
93
|
+
it("should handle tsx files correctly", () => {
|
|
94
|
+
const code = `const a = () => <div>{__vite_ssr_import__("module-a")}</div>;`;
|
|
95
|
+
const results = findSsrImportCallSites("test.tsx", code);
|
|
96
|
+
expect(results).toHaveLength(1);
|
|
97
|
+
expect(results[0].specifier).toBe("module-a");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { hasDirective } from "./hasDirective.mjs";
|
|
3
|
+
describe("hasDirective", () => {
|
|
4
|
+
it('should find "use client" directive with double quotes', () => {
|
|
5
|
+
const code = `"use client";
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
|
|
9
|
+
const MyComponent = () => <div>Hello</div>;
|
|
10
|
+
export default MyComponent;`;
|
|
11
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
it("should find 'use server' directive with single quotes", () => {
|
|
14
|
+
const code = `'use server';
|
|
15
|
+
|
|
16
|
+
export async function myAction() {
|
|
17
|
+
// ...
|
|
18
|
+
}`;
|
|
19
|
+
expect(hasDirective(code, "use server")).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it("should find directive with leading whitespace", () => {
|
|
22
|
+
const code = ` "use client";
|
|
23
|
+
|
|
24
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
25
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it("should find directive after single-line comments", () => {
|
|
28
|
+
const code = `// This is a component
|
|
29
|
+
"use client";
|
|
30
|
+
|
|
31
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
32
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it("should find directive after multi-line comments", () => {
|
|
35
|
+
const code = `/* This is a component */
|
|
36
|
+
"use client";
|
|
37
|
+
|
|
38
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
39
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it("should find directive after empty lines", () => {
|
|
42
|
+
const code = `
|
|
43
|
+
|
|
44
|
+
"use client";
|
|
45
|
+
|
|
46
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
47
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it("should return false if no directive is present", () => {
|
|
50
|
+
const code = `import React from "react";
|
|
51
|
+
|
|
52
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
53
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
it("should return false if directive is not at the top", () => {
|
|
56
|
+
const code = `import React from "react";
|
|
57
|
+
"use client";
|
|
58
|
+
|
|
59
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
60
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
it("should return false if directive is inside a single-line comment", () => {
|
|
63
|
+
const code = `// "use client";
|
|
64
|
+
|
|
65
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
66
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
67
|
+
});
|
|
68
|
+
it("should return false if directive is inside a multi-line comment", () => {
|
|
69
|
+
const code = `/*
|
|
70
|
+
* "use client";
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
const MyComponent = () => <div>Hello</div>;`;
|
|
74
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
it("should return false if directive is a substring in other code", () => {
|
|
77
|
+
const code = `const message = 'please "use client" wisely';`;
|
|
78
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
it("should handle a file with only the directive", () => {
|
|
81
|
+
const code = `"use client"`;
|
|
82
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
it("should handle mixed comments, whitespace, and the directive", () => {
|
|
85
|
+
const code = `// A component
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
Another comment
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
'use client';
|
|
92
|
+
|
|
93
|
+
const MyComponent = () => <div>Hello</div>;
|
|
94
|
+
`;
|
|
95
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
it("should handle multi-line comment ending on same line", () => {
|
|
98
|
+
const code = `/* "use client" */
|
|
99
|
+
const MyComponent = () => <div>Hello</div>;
|
|
100
|
+
`;
|
|
101
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
102
|
+
});
|
|
103
|
+
it("should return false for code where directive appears after a valid line of code", () => {
|
|
104
|
+
const code = `const a = 1;
|
|
105
|
+
"use client";
|
|
106
|
+
`;
|
|
107
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { isJsFile } from "./isJsFile.mjs";
|
|
3
|
+
describe("isJsFile", () => {
|
|
4
|
+
const matchingExtensions = [
|
|
5
|
+
"file.js",
|
|
6
|
+
"file.jsx",
|
|
7
|
+
"file.ts",
|
|
8
|
+
"file.tsx",
|
|
9
|
+
"file.mjs",
|
|
10
|
+
"file.mts",
|
|
11
|
+
"file.cjs",
|
|
12
|
+
"file.cts",
|
|
13
|
+
"/path/to/component.js",
|
|
14
|
+
"../relative/path.tsx",
|
|
15
|
+
];
|
|
16
|
+
const nonMatchingExtensions = [
|
|
17
|
+
"file.css",
|
|
18
|
+
"file.html",
|
|
19
|
+
"file.json",
|
|
20
|
+
"file.txt",
|
|
21
|
+
"file.js.map",
|
|
22
|
+
"file_js",
|
|
23
|
+
"filejs",
|
|
24
|
+
"",
|
|
25
|
+
"no-extension",
|
|
26
|
+
"/path/to/image.png",
|
|
27
|
+
];
|
|
28
|
+
matchingExtensions.forEach((filepath) => {
|
|
29
|
+
it(`should return true for "${filepath}"`, () => {
|
|
30
|
+
expect(isJsFile(filepath)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
nonMatchingExtensions.forEach((filepath) => {
|
|
34
|
+
it(`should return false for "${filepath}"`, () => {
|
|
35
|
+
expect(isJsFile(filepath)).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { Plugin } from "vite";
|
|
2
|
+
export declare function linkWorkerBundle({ code, manifestContent, projectRootDir, }: {
|
|
3
|
+
code: string;
|
|
4
|
+
manifestContent: string;
|
|
5
|
+
projectRootDir: string;
|
|
6
|
+
}): {
|
|
7
|
+
code: string;
|
|
8
|
+
map: null;
|
|
9
|
+
};
|
|
2
10
|
export declare const linkerPlugin: ({ projectRootDir, }: {
|
|
3
11
|
projectRootDir: string;
|
|
4
12
|
}) => Plugin;
|
|
@@ -4,6 +4,29 @@ import { CLIENT_MANIFEST_RELATIVE_PATH } from "../lib/constants.mjs";
|
|
|
4
4
|
import debug from "debug";
|
|
5
5
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
6
6
|
const log = debug("rwsdk:vite:linker-plugin");
|
|
7
|
+
export function linkWorkerBundle({ code, manifestContent, projectRootDir, }) {
|
|
8
|
+
let newCode = code;
|
|
9
|
+
const manifest = JSON.parse(manifestContent);
|
|
10
|
+
// 1. Replace the manifest placeholder with the actual manifest content.
|
|
11
|
+
log("Injecting manifest into worker bundle");
|
|
12
|
+
newCode = newCode.replace('"__RWSDK_MANIFEST_PLACEHOLDER__"', manifestContent);
|
|
13
|
+
// 2. Replace asset placeholders with their final hashed paths.
|
|
14
|
+
log("Replacing asset placeholders in final worker bundle");
|
|
15
|
+
for (const [key, value] of Object.entries(manifest)) {
|
|
16
|
+
const normalizedKey = normalizeModulePath(key, projectRootDir, {
|
|
17
|
+
isViteStyle: false,
|
|
18
|
+
});
|
|
19
|
+
newCode = newCode.replaceAll(`rwsdk_asset:${normalizedKey}`, `/${value.file}`);
|
|
20
|
+
}
|
|
21
|
+
// 3. Deprefix any remaining placeholders that were not in the manifest.
|
|
22
|
+
// This handles public assets that don't go through the bundler.
|
|
23
|
+
log("Deprefixing remaining asset placeholders");
|
|
24
|
+
newCode = newCode.replaceAll("rwsdk_asset:", "");
|
|
25
|
+
return {
|
|
26
|
+
code: newCode,
|
|
27
|
+
map: null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
7
30
|
export const linkerPlugin = ({ projectRootDir, }) => {
|
|
8
31
|
return {
|
|
9
32
|
name: "rwsdk:linker",
|
|
@@ -13,29 +36,14 @@ export const linkerPlugin = ({ projectRootDir, }) => {
|
|
|
13
36
|
return null;
|
|
14
37
|
}
|
|
15
38
|
log("Rendering final worker chunk");
|
|
16
|
-
let newCode = code;
|
|
17
|
-
// Read the manifest from the filesystem.
|
|
18
39
|
const manifestContent = await fsp.readFile(path.resolve(projectRootDir, CLIENT_MANIFEST_RELATIVE_PATH), "utf-8");
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
log("
|
|
25
|
-
|
|
26
|
-
const normalizedKey = normalizeModulePath(key, projectRootDir, {
|
|
27
|
-
isViteStyle: false,
|
|
28
|
-
});
|
|
29
|
-
newCode = newCode.replaceAll(`rwsdk_asset:${normalizedKey}`, `/${value.file}`);
|
|
30
|
-
}
|
|
31
|
-
// 3. Deprefix any remaining placeholders that were not in the manifest.
|
|
32
|
-
// This handles public assets that don't go through the bundler.
|
|
33
|
-
log("Deprefixing remaining asset placeholders");
|
|
34
|
-
newCode = newCode.replaceAll("rwsdk_asset:", "");
|
|
35
|
-
return {
|
|
36
|
-
code: newCode,
|
|
37
|
-
map: null,
|
|
38
|
-
};
|
|
40
|
+
const result = linkWorkerBundle({
|
|
41
|
+
code,
|
|
42
|
+
manifestContent,
|
|
43
|
+
projectRootDir,
|
|
44
|
+
});
|
|
45
|
+
log("Final worker chunk rendered");
|
|
46
|
+
return result;
|
|
39
47
|
},
|
|
40
48
|
};
|
|
41
49
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { linkWorkerBundle } from "./linkerPlugin.mjs";
|
|
3
|
+
describe("linkWorkerBundle", () => {
|
|
4
|
+
const projectRootDir = "/test/project";
|
|
5
|
+
const manifest = {
|
|
6
|
+
"src/styles.css": { file: "assets/styles.123.css" },
|
|
7
|
+
"src/logo.svg": { file: "assets/logo.abc.svg" },
|
|
8
|
+
};
|
|
9
|
+
const manifestContent = JSON.stringify(manifest);
|
|
10
|
+
it("should replace the manifest placeholder", () => {
|
|
11
|
+
const code = `const manifest = "__RWSDK_MANIFEST_PLACEHOLDER__";`;
|
|
12
|
+
const result = linkWorkerBundle({
|
|
13
|
+
code,
|
|
14
|
+
manifestContent,
|
|
15
|
+
projectRootDir,
|
|
16
|
+
});
|
|
17
|
+
expect(result.code).toContain(`const manifest = ${manifestContent};`);
|
|
18
|
+
});
|
|
19
|
+
it("should replace asset placeholders with hashed paths from the manifest", () => {
|
|
20
|
+
const code = `
|
|
21
|
+
const stylesheet = "rwsdk_asset:/src/styles.css";
|
|
22
|
+
const logo = "rwsdk_asset:/src/logo.svg";
|
|
23
|
+
`;
|
|
24
|
+
const result = linkWorkerBundle({
|
|
25
|
+
code,
|
|
26
|
+
manifestContent,
|
|
27
|
+
projectRootDir,
|
|
28
|
+
});
|
|
29
|
+
expect(result.code).toContain(`const stylesheet = "/assets/styles.123.css";`);
|
|
30
|
+
expect(result.code).toContain(`const logo = "/assets/logo.abc.svg";`);
|
|
31
|
+
});
|
|
32
|
+
it("should deprefix remaining asset placeholders not in the manifest", () => {
|
|
33
|
+
const code = `const publicImg = "rwsdk_asset:/images/photo.jpg";`;
|
|
34
|
+
const result = linkWorkerBundle({
|
|
35
|
+
code,
|
|
36
|
+
manifestContent,
|
|
37
|
+
projectRootDir,
|
|
38
|
+
});
|
|
39
|
+
expect(result.code).toContain(`const publicImg = "/images/photo.jpg";`);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { Plugin } from "vite";
|
|
2
|
+
export declare const hasEntryAsAncestor: ({ module, entryFile, seen, }: {
|
|
3
|
+
module: any;
|
|
4
|
+
entryFile: string;
|
|
5
|
+
seen?: Set<any>;
|
|
6
|
+
}) => boolean;
|
|
2
7
|
export declare const miniflareHMRPlugin: (givenOptions: {
|
|
3
8
|
clientFiles: Set<string>;
|
|
4
9
|
serverFiles: Set<string>;
|
|
@@ -17,7 +17,7 @@ const hasDirective = async (filepath, directive) => {
|
|
|
17
17
|
const content = await readFile(filepath, "utf-8");
|
|
18
18
|
return sourceHasDirective(content, directive);
|
|
19
19
|
};
|
|
20
|
-
const hasEntryAsAncestor = (module, entryFile, seen = new Set()) => {
|
|
20
|
+
export const hasEntryAsAncestor = ({ module, entryFile, seen = new Set(), }) => {
|
|
21
21
|
// Prevent infinite recursion
|
|
22
22
|
if (seen.has(module)) {
|
|
23
23
|
return false;
|
|
@@ -28,7 +28,7 @@ const hasEntryAsAncestor = (module, entryFile, seen = new Set()) => {
|
|
|
28
28
|
if (importer.file === entryFile)
|
|
29
29
|
return true;
|
|
30
30
|
// Recursively check importers
|
|
31
|
-
if (hasEntryAsAncestor(importer, entryFile, seen))
|
|
31
|
+
if (hasEntryAsAncestor({ module: importer, entryFile, seen }))
|
|
32
32
|
return true;
|
|
33
33
|
}
|
|
34
34
|
return false;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { hasEntryAsAncestor } from "./miniflareHMRPlugin.mjs";
|
|
3
|
+
const createModule = (file) => ({
|
|
4
|
+
file,
|
|
5
|
+
importers: new Set(),
|
|
6
|
+
});
|
|
7
|
+
describe("hasEntryAsAncestor", () => {
|
|
8
|
+
it("should return true if the entry file is a direct importer", () => {
|
|
9
|
+
const entry = createModule("entry.js");
|
|
10
|
+
const mod = createModule("mod.js");
|
|
11
|
+
mod.importers.add(entry);
|
|
12
|
+
expect(hasEntryAsAncestor({ module: mod, entryFile: "entry.js" })).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it("should return true if the entry file is an indirect importer", () => {
|
|
15
|
+
const entry = createModule("entry.js");
|
|
16
|
+
const importer1 = createModule("importer1.js");
|
|
17
|
+
const mod = createModule("mod.js");
|
|
18
|
+
importer1.importers.add(entry);
|
|
19
|
+
mod.importers.add(importer1);
|
|
20
|
+
expect(hasEntryAsAncestor({ module: mod, entryFile: "entry.js" })).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
it("should return false if the entry file is not an importer", () => {
|
|
23
|
+
const entry = createModule("entry.js");
|
|
24
|
+
const other = createModule("other.js");
|
|
25
|
+
const mod = createModule("mod.js");
|
|
26
|
+
mod.importers.add(other);
|
|
27
|
+
expect(hasEntryAsAncestor({ module: mod, entryFile: "entry.js" })).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
it("should handle circular dependencies", () => {
|
|
30
|
+
const entry = createModule("entry.js");
|
|
31
|
+
const modA = createModule("modA.js");
|
|
32
|
+
const modB = createModule("modB.js");
|
|
33
|
+
modA.importers.add(entry);
|
|
34
|
+
modA.importers.add(modB);
|
|
35
|
+
modB.importers.add(modA);
|
|
36
|
+
expect(hasEntryAsAncestor({ module: modB, entryFile: "entry.js" })).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it("should return false for a module with no importers", () => {
|
|
39
|
+
const mod = createModule("mod.js");
|
|
40
|
+
expect(hasEntryAsAncestor({ module: mod, entryFile: "entry.js" })).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InlineConfig } from "vite";
|
|
2
|
+
import { unstable_readConfig } from "wrangler";
|
|
2
3
|
export type RedwoodPluginOptions = {
|
|
3
4
|
silent?: boolean;
|
|
4
5
|
rootDir?: string;
|
|
@@ -9,4 +10,10 @@ export type RedwoodPluginOptions = {
|
|
|
9
10
|
worker?: string;
|
|
10
11
|
};
|
|
11
12
|
};
|
|
13
|
+
export declare const determineWorkerEntryPathname: ({ projectRootDir, workerConfigPath, options, readConfig, }: {
|
|
14
|
+
projectRootDir: string;
|
|
15
|
+
workerConfigPath: string;
|
|
16
|
+
options: RedwoodPluginOptions;
|
|
17
|
+
readConfig?: typeof unstable_readConfig;
|
|
18
|
+
}) => Promise<string>;
|
|
12
19
|
export declare const redwoodPlugin: (options?: RedwoodPluginOptions) => Promise<InlineConfig["plugins"]>;
|
|
@@ -27,11 +27,11 @@ import { manifestPlugin } from "./manifestPlugin.mjs";
|
|
|
27
27
|
import { linkerPlugin } from "./linkerPlugin.mjs";
|
|
28
28
|
import { directiveModulesDevPlugin } from "./directiveModulesDevPlugin.mjs";
|
|
29
29
|
import { directivesFilteringPlugin } from "./directivesFilteringPlugin.mjs";
|
|
30
|
-
const determineWorkerEntryPathname = async (projectRootDir, workerConfigPath, options) => {
|
|
30
|
+
export const determineWorkerEntryPathname = async ({ projectRootDir, workerConfigPath, options, readConfig = unstable_readConfig, }) => {
|
|
31
31
|
if (options.entry?.worker) {
|
|
32
32
|
return resolve(projectRootDir, options.entry.worker);
|
|
33
33
|
}
|
|
34
|
-
const workerConfig =
|
|
34
|
+
const workerConfig = readConfig({ config: workerConfigPath });
|
|
35
35
|
return resolve(projectRootDir, workerConfig.main ?? "src/worker.tsx");
|
|
36
36
|
};
|
|
37
37
|
const clientFiles = new Set();
|
|
@@ -43,7 +43,11 @@ export const redwoodPlugin = async (options = {}) => {
|
|
|
43
43
|
(process.env.RWSDK_WRANGLER_CONFIG
|
|
44
44
|
? resolve(projectRootDir, process.env.RWSDK_WRANGLER_CONFIG)
|
|
45
45
|
: await findWranglerConfig(projectRootDir));
|
|
46
|
-
const workerEntryPathname = await determineWorkerEntryPathname(
|
|
46
|
+
const workerEntryPathname = await determineWorkerEntryPathname({
|
|
47
|
+
projectRootDir,
|
|
48
|
+
workerConfigPath,
|
|
49
|
+
options,
|
|
50
|
+
});
|
|
47
51
|
const shouldIncludeCloudflarePlugin = options.includeCloudflarePlugin ??
|
|
48
52
|
!(await hasOwnCloudflareVitePlugin({ rootProjectDir: projectRootDir }));
|
|
49
53
|
const shouldIncludeReactPlugin = options.includeReactPlugin ??
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { determineWorkerEntryPathname } from "./redwoodPlugin.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
describe("determineWorkerEntryPathname", () => {
|
|
5
|
+
const projectRootDir = "/test/project";
|
|
6
|
+
it("should use the entry path from options if provided", async () => {
|
|
7
|
+
const result = await determineWorkerEntryPathname({
|
|
8
|
+
projectRootDir,
|
|
9
|
+
workerConfigPath: "/test/project/wrangler.toml",
|
|
10
|
+
options: { entry: { worker: "src/custom-worker.ts" } },
|
|
11
|
+
});
|
|
12
|
+
expect(result).toBe(path.join(projectRootDir, "src/custom-worker.ts"));
|
|
13
|
+
});
|
|
14
|
+
it("should use the main path from wrangler config if no entry option is provided", async () => {
|
|
15
|
+
const readConfig = () => ({ main: "src/wrangler-worker.tsx" });
|
|
16
|
+
const result = await determineWorkerEntryPathname({
|
|
17
|
+
projectRootDir,
|
|
18
|
+
workerConfigPath: "/test/project/wrangler.toml",
|
|
19
|
+
options: {},
|
|
20
|
+
readConfig: readConfig,
|
|
21
|
+
});
|
|
22
|
+
expect(result).toBe(path.join(projectRootDir, "src/wrangler-worker.tsx"));
|
|
23
|
+
});
|
|
24
|
+
it("should use the default path if wrangler config has no main property", async () => {
|
|
25
|
+
const readConfig = () => ({});
|
|
26
|
+
const result = await determineWorkerEntryPathname({
|
|
27
|
+
projectRootDir,
|
|
28
|
+
workerConfigPath: "/test/project/wrangler.toml",
|
|
29
|
+
options: {},
|
|
30
|
+
readConfig: readConfig,
|
|
31
|
+
});
|
|
32
|
+
expect(result).toBe(path.join(projectRootDir, "src/worker.tsx"));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
import { Environment, ResolvedConfig } from "vite";
|
|
2
|
+
type Resolver = (context: {}, path: string, request: string, resolveContext: {}, callback: (err: Error | null, result?: string | false) => void) => void;
|
|
3
|
+
export declare function resolveModuleWithEnvironment({ path, importer, importerEnv, clientResolver, workerResolver, }: {
|
|
4
|
+
path: string;
|
|
5
|
+
importer?: string;
|
|
6
|
+
importerEnv: "client" | "worker";
|
|
7
|
+
clientResolver: Resolver;
|
|
8
|
+
workerResolver: Resolver;
|
|
9
|
+
}): Promise<{
|
|
10
|
+
id: string;
|
|
11
|
+
} | null>;
|
|
12
|
+
export declare function classifyModule({ contents, inheritedEnv, }: {
|
|
13
|
+
contents: string;
|
|
14
|
+
inheritedEnv: "client" | "worker";
|
|
15
|
+
}): {
|
|
16
|
+
moduleEnv: "client" | "worker";
|
|
17
|
+
isClient: boolean;
|
|
18
|
+
isServer: boolean;
|
|
19
|
+
};
|
|
2
20
|
export declare const runDirectivesScan: ({ rootConfig, environments, clientFiles, serverFiles, }: {
|
|
3
21
|
rootConfig: ResolvedConfig;
|
|
4
22
|
environments: Record<string, Environment>;
|
|
5
23
|
clientFiles: Set<string>;
|
|
6
24
|
serverFiles: Set<string>;
|
|
7
25
|
}) => Promise<void>;
|
|
26
|
+
export {};
|