rwsdk 1.0.0-alpha.8 → 1.0.0-beta.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.mjs +1 -2
- package/dist/lib/e2e/browser.d.mts +1 -1
- package/dist/lib/e2e/browser.mjs +21 -5
- package/dist/lib/e2e/dev.mjs +62 -52
- package/dist/lib/e2e/environment.d.mts +2 -6
- package/dist/lib/e2e/environment.mjs +167 -158
- package/dist/lib/e2e/index.d.mts +5 -4
- package/dist/lib/e2e/index.mjs +5 -4
- package/dist/lib/e2e/poll.d.mts +8 -0
- package/dist/lib/e2e/poll.mjs +31 -0
- package/dist/lib/e2e/release.d.mts +1 -1
- package/dist/lib/e2e/release.mjs +56 -34
- package/dist/lib/e2e/retry.d.mts +4 -0
- package/dist/lib/e2e/retry.mjs +16 -0
- package/dist/lib/e2e/setup.d.mts +2 -0
- package/dist/lib/e2e/setup.mjs +1 -0
- package/dist/lib/e2e/tarball.d.mts +3 -3
- package/dist/lib/e2e/tarball.mjs +28 -118
- package/dist/lib/e2e/testHarness.d.mts +74 -40
- package/dist/lib/e2e/testHarness.mjs +320 -271
- package/dist/lib/e2e/types.d.mts +1 -0
- package/dist/lib/getShortName.mjs +1 -2
- package/dist/lib/getShortName.test.mjs +2 -2
- package/dist/lib/getSrcPaths.js +2 -2
- package/dist/lib/hasPkgScript.test.mjs +2 -2
- package/dist/lib/jsonUtils.test.mjs +2 -2
- package/dist/lib/normalizeModulePath.test.mjs +2 -2
- package/dist/lib/setupEnvFiles.mjs +2 -2
- package/dist/lib/smokeTests/artifacts.mjs +2 -2
- package/dist/lib/smokeTests/browser.d.mts +1 -1
- package/dist/lib/smokeTests/browser.mjs +6 -7
- package/dist/lib/smokeTests/cleanup.mjs +6 -9
- package/dist/lib/smokeTests/codeUpdates.mjs +5 -5
- package/dist/lib/smokeTests/development.mjs +2 -2
- package/dist/lib/smokeTests/environment.d.mts +2 -3
- package/dist/lib/smokeTests/environment.mjs +17 -3
- package/dist/lib/smokeTests/release.d.mts +2 -2
- package/dist/lib/smokeTests/release.mjs +3 -3
- package/dist/lib/smokeTests/reporting.mjs +2 -2
- package/dist/lib/smokeTests/runSmokeTests.mjs +4 -4
- package/dist/lib/smokeTests/utils.mjs +3 -3
- package/dist/lib/testUtils/stubEnvVars.mjs +1 -1
- package/dist/llms/rules/middleware.d.ts +1 -1
- package/dist/llms/rules/middleware.js +4 -4
- package/dist/runtime/client/client.d.ts +2 -2
- package/dist/runtime/client/client.js +2 -2
- package/dist/runtime/client/navigation.test.js +1 -1
- package/dist/runtime/client/types.d.ts +1 -1
- package/dist/runtime/entries/client.d.ts +2 -2
- package/dist/runtime/entries/client.js +2 -2
- package/dist/runtime/entries/router.d.ts +1 -1
- package/dist/runtime/entries/router.js +1 -1
- package/dist/runtime/entries/worker.d.ts +5 -6
- package/dist/runtime/entries/worker.js +5 -6
- package/dist/runtime/imports/worker.js +1 -1
- package/dist/runtime/lib/auth/session.d.ts +2 -2
- package/dist/runtime/lib/auth/session.js +5 -5
- package/dist/runtime/lib/db/DOWorkerDialect.d.ts +1 -1
- package/dist/runtime/lib/db/DOWorkerDialect.js +1 -1
- package/dist/runtime/lib/db/SqliteDurableObject.js +2 -2
- package/dist/runtime/lib/db/index.d.ts +2 -2
- package/dist/runtime/lib/db/index.js +2 -2
- package/dist/runtime/lib/db/migrations.d.ts +1 -1
- package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +3 -3
- package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +1 -1
- package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +2 -2
- package/dist/runtime/lib/db/typeInference/builders/createView.d.ts +1 -1
- package/dist/runtime/lib/db/typeInference/builders/dropTable.d.ts +1 -1
- package/dist/runtime/lib/db/typeInference/builders/dropView.d.ts +1 -1
- package/dist/runtime/lib/db/typeInference/builders/schema.d.ts +3 -3
- package/dist/runtime/lib/db/typeInference/database.d.ts +2 -2
- package/dist/runtime/lib/memoizeOnId.test.js +1 -1
- package/dist/runtime/lib/realtime/client.js +2 -2
- package/dist/runtime/lib/realtime/durableObject.js +1 -1
- package/dist/runtime/lib/realtime/protocol.test.js +1 -1
- package/dist/runtime/lib/realtime/shared.test.js +1 -1
- package/dist/runtime/lib/realtime/validateUpgradeRequest.test.js +1 -1
- package/dist/runtime/lib/realtime/worker.js +2 -2
- package/dist/runtime/lib/router.d.ts +1 -1
- package/dist/runtime/lib/router.test.js +2 -3
- package/dist/runtime/lib/rwContext.d.ts +1 -1
- package/dist/runtime/lib/stitchDocumentAndAppStreams.d.ts +18 -0
- package/dist/runtime/lib/stitchDocumentAndAppStreams.js +143 -0
- package/dist/runtime/lib/turnstile/useTurnstile.js +1 -1
- package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.js +1 -1
- package/dist/runtime/register/worker.d.ts +1 -1
- package/dist/runtime/register/worker.js +34 -22
- package/dist/runtime/render/assembleDocument.d.ts +1 -1
- package/dist/runtime/render/createThenableFromReadableStream.js +1 -1
- package/dist/runtime/render/preloads.d.ts +2 -2
- package/dist/runtime/render/renderDocumentHtmlStream.js +6 -6
- package/dist/runtime/render/renderHtmlStream.d.ts +1 -1
- package/dist/runtime/render/renderToRscStream.d.ts +4 -1
- package/dist/runtime/render/renderToRscStream.js +11 -1
- package/dist/runtime/render/renderToStream.d.ts +1 -1
- package/dist/runtime/render/renderToStream.js +2 -2
- package/dist/runtime/render/stylesheets.d.ts +1 -1
- package/dist/runtime/requestInfo/types.d.ts +0 -2
- package/dist/runtime/requestInfo/worker.d.ts +1 -1
- package/dist/runtime/requestInfo/worker.js +1 -9
- package/dist/runtime/script.js +1 -1
- package/dist/runtime/ssrBridge.d.ts +2 -2
- package/dist/runtime/ssrBridge.js +2 -2
- package/dist/runtime/worker.d.ts +1 -1
- package/dist/runtime/worker.js +3 -11
- package/dist/scripts/addon.d.mts +1 -0
- package/dist/scripts/addon.mjs +70 -0
- package/dist/scripts/debug-sync.mjs +106 -137
- package/dist/scripts/ensure-deploy-env.mjs +6 -6
- package/dist/scripts/migrate-new.mjs +3 -4
- package/dist/scripts/smoke-test.mjs +2 -2
- package/dist/scripts/worker-run.mjs +7 -9
- package/dist/vite/buildApp.d.mts +2 -1
- package/dist/vite/buildApp.mjs +10 -6
- package/dist/vite/checkIsUsingPrisma.test.mjs +1 -1
- package/dist/vite/configPlugin.mjs +35 -17
- package/dist/vite/createDirectiveLookupPlugin.mjs +1 -1
- package/dist/vite/createDirectiveLookupPlugin.test.mjs +2 -2
- package/dist/vite/createViteAwareResolver.d.mts +1 -2
- package/dist/vite/createViteAwareResolver.mjs +1 -1
- package/dist/vite/directiveModulesDevPlugin.d.mts +2 -1
- package/dist/vite/directiveModulesDevPlugin.mjs +6 -5
- package/dist/vite/directiveModulesDevPlugin.test.mjs +2 -2
- package/dist/vite/directivesPlugin.mjs +3 -3
- package/dist/vite/directivesPlugin.test.mjs +1 -1
- package/dist/vite/ensureAliasArray.test.mjs +1 -1
- package/dist/vite/findSpecifiers.mjs +1 -1
- package/dist/vite/findSpecifiers.test.mjs +2 -2
- package/dist/vite/findSsrSpecifiers.mjs +1 -1
- package/dist/vite/findSsrSpecifiers.test.mjs +1 -1
- package/dist/vite/getViteEsbuild.mjs +1 -1
- package/dist/vite/hasDirective.d.mts +6 -3
- package/dist/vite/hasDirective.mjs +43 -27
- package/dist/vite/hasDirective.test.mjs +73 -75
- package/dist/vite/index.d.mts +1 -1
- package/dist/vite/invalidateCacheIfPrismaClientChanged.mjs +2 -2
- package/dist/vite/isJsFile.test.mjs +1 -1
- package/dist/vite/{reactConditionsResolverPlugin.d.mts → knownDepsResolverPlugin.d.mts} +3 -3
- package/dist/vite/{reactConditionsResolverPlugin.mjs → knownDepsResolverPlugin.mjs} +29 -24
- package/dist/vite/linkerPlugin.mjs +2 -2
- package/dist/vite/linkerPlugin.test.mjs +1 -1
- package/dist/vite/miniflareHMRPlugin.mjs +5 -5
- package/dist/vite/miniflareHMRPlugin.test.mjs +1 -1
- package/dist/vite/prismaPlugin.mjs +1 -1
- package/dist/vite/redwoodPlugin.d.mts +2 -0
- package/dist/vite/redwoodPlugin.mjs +37 -17
- package/dist/vite/redwoodPlugin.test.mjs +2 -2
- package/dist/vite/resolveForcedPaths.d.mts +4 -0
- package/dist/vite/resolveForcedPaths.mjs +9 -0
- package/dist/vite/runDirectivesScan.d.mts +3 -1
- package/dist/vite/runDirectivesScan.mjs +60 -20
- package/dist/vite/runDirectivesScan.test.mjs +2 -2
- package/dist/vite/ssrBridgePlugin.mjs +10 -3
- package/dist/vite/transformClientComponents.mjs +8 -6
- package/dist/vite/transformClientComponents.test.mjs +117 -59
- package/dist/vite/transformJsxScriptTagsPlugin.mjs +1 -1
- package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +2 -2
- package/dist/vite/transformServerFunctions.d.mts +1 -1
- package/dist/vite/transformServerFunctions.mjs +5 -5
- package/dist/vite/transformServerFunctions.test.mjs +3 -3
- package/package.json +60 -50
- package/dist/runtime/imports/resolveSSRValue.d.ts +0 -1
- package/dist/runtime/imports/resolveSSRValue.js +0 -8
- package/dist/runtime/lib/injectHtmlAtMarker.d.ts +0 -11
- package/dist/runtime/lib/injectHtmlAtMarker.js +0 -90
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
2
2
|
import os from "os";
|
|
3
|
-
import
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_CLIENT_BARREL_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_PATH, } from "../lib/constants.mjs";
|
|
4
5
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
5
|
-
import { VENDOR_CLIENT_BARREL_PATH, VENDOR_SERVER_BARREL_PATH, VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
|
|
6
6
|
import { runDirectivesScan } from "./runDirectivesScan.mjs";
|
|
7
7
|
export const generateVendorBarrelContent = (files, projectRootDir) => {
|
|
8
8
|
const imports = [...files]
|
|
@@ -30,7 +30,7 @@ export const generateAppBarrelContent = (files, projectRootDir) => {
|
|
|
30
30
|
})
|
|
31
31
|
.join("\n");
|
|
32
32
|
};
|
|
33
|
-
export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
|
|
33
|
+
export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, workerEntryPathname, }) => {
|
|
34
34
|
const { promise: scanPromise, resolve: resolveScanPromise } = Promise.withResolvers();
|
|
35
35
|
const tempDir = mkdtempSync(path.join(os.tmpdir(), "rwsdk-"));
|
|
36
36
|
const APP_CLIENT_BARREL_PATH = path.join(tempDir, "app-client-barrel.js");
|
|
@@ -47,6 +47,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
47
47
|
environments: server.environments,
|
|
48
48
|
clientFiles,
|
|
49
49
|
serverFiles,
|
|
50
|
+
entries: [workerEntryPathname],
|
|
50
51
|
}).then(() => {
|
|
51
52
|
// context(justinvdm, 11 Sep 2025): For vendor barrels, we write the
|
|
52
53
|
// files directly to disk after the scan. For app barrels, we use a
|
|
@@ -83,7 +84,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
|
|
|
83
84
|
env.optimizeDeps.include ??= [];
|
|
84
85
|
const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
|
|
85
86
|
env.optimizeDeps.include.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
|
|
86
|
-
if (envName === "client") {
|
|
87
|
+
if (envName === "client" || envName === "ssr") {
|
|
87
88
|
entries.push(APP_CLIENT_BARREL_PATH);
|
|
88
89
|
}
|
|
89
90
|
else if (envName === "worker") {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { generateAppBarrelContent, generateVendorBarrelContent, } from "./directiveModulesDevPlugin.mjs";
|
|
3
3
|
describe("directiveModulesDevPlugin helpers", () => {
|
|
4
4
|
const projectRootDir = "/Users/test/project";
|
|
5
5
|
describe("generateVendorBarrelContent", () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "node:fs/promises";
|
|
3
1
|
import debug from "debug";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
4
5
|
import { transformClientComponents } from "./transformClientComponents.mjs";
|
|
5
6
|
import { transformServerFunctions } from "./transformServerFunctions.mjs";
|
|
6
|
-
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
7
7
|
const log = debug("rwsdk:vite:rsc-directives-plugin");
|
|
8
8
|
export const getLoader = (filePath) => {
|
|
9
9
|
const ext = path.extname(filePath).slice(1);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { ensureAliasArray } from "./ensureAliasArray.mjs";
|
|
3
3
|
describe("ensureAliasArray", () => {
|
|
4
4
|
it("should create resolve and alias array if resolve is undefined", () => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Lang, Lang as SgLang, parse as sgParse } from "@ast-grep/napi";
|
|
2
2
|
import path from "path";
|
|
3
3
|
// These patterns are used to match import statements in code for SSR transformations.
|
|
4
4
|
export const IMPORT_PATTERNS = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { describe,
|
|
2
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { findExports, findImportSpecifiers } from "./findSpecifiers.mjs";
|
|
3
3
|
function dedupeImports(imports) {
|
|
4
4
|
const seen = new Set();
|
|
5
5
|
return imports.filter((imp) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Lang, Lang as SgLang, parse as sgParse } from "@ast-grep/napi";
|
|
2
2
|
import path from "path";
|
|
3
3
|
/**
|
|
4
4
|
* Finds callsites for __vite_ssr_import__ and __vite_ssr_dynamic_import__ with their ranges.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { findSsrImportCallSites } from "./findSsrSpecifiers.mjs";
|
|
3
3
|
describe("findSsrImportCallSites", () => {
|
|
4
4
|
it("should find __vite_ssr_import__ with double quotes", () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
3
|
const require = createRequire(import.meta.url);
|
|
4
4
|
export async function getViteEsbuild(projectRootDir) {
|
|
5
5
|
const vitePath = require.resolve("vite/package.json", {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Efficiently checks if a React directive (e.g., "use server", "use client")
|
|
3
|
-
* is present in the code.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* is present in the code.
|
|
4
|
+
*
|
|
5
|
+
* This function is optimized for performance by only checking the first few
|
|
6
|
+
* lines of the code, as directives must appear at the very top of a file.
|
|
7
|
+
* It handles comments, whitespace, and any valid directive prologue
|
|
8
|
+
* (e.g., "use strict").
|
|
6
9
|
*/
|
|
7
10
|
export declare function hasDirective(code: string, directive: string): boolean;
|
|
@@ -1,54 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Efficiently checks if a React directive (e.g., "use server", "use client")
|
|
3
|
-
* is present in the code.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* is present in the code.
|
|
4
|
+
*
|
|
5
|
+
* This function is optimized for performance by only checking the first few
|
|
6
|
+
* lines of the code, as directives must appear at the very top of a file.
|
|
7
|
+
* It handles comments, whitespace, and any valid directive prologue
|
|
8
|
+
* (e.g., "use strict").
|
|
6
9
|
*/
|
|
7
10
|
export function hasDirective(code, directive) {
|
|
8
|
-
|
|
9
|
-
const singleQuoteDirective = `'${directive}'`;
|
|
10
|
-
const doubleQuoteDirective = `"${directive}"`;
|
|
11
|
-
if (!code.includes(singleQuoteDirective) &&
|
|
12
|
-
!code.includes(doubleQuoteDirective)) {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
// Split into lines and check each one
|
|
16
|
-
const lines = code.split("\n");
|
|
11
|
+
const lines = code.slice(0, 512).split("\n"); // Check first ~512 chars
|
|
17
12
|
let inMultiLineComment = false;
|
|
13
|
+
let foundUseClient = false;
|
|
14
|
+
let foundTargetDirective = false;
|
|
15
|
+
const doubleQuoteDirective = `"${directive}"`;
|
|
16
|
+
const singleQuoteDirective = `'${directive}'`;
|
|
17
|
+
const doubleQuoteUseClient = `"use client"`;
|
|
18
|
+
const singleQuoteUseClient = `'use client'`;
|
|
18
19
|
for (const line of lines) {
|
|
19
20
|
const trimmedLine = line.trim();
|
|
20
|
-
// Skip empty lines
|
|
21
21
|
if (trimmedLine.length === 0) {
|
|
22
22
|
continue;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
if (trimmedLine.startsWith("/*")) {
|
|
26
|
-
inMultiLineComment = true;
|
|
27
|
-
// Check if the comment ends on the same line
|
|
24
|
+
if (inMultiLineComment) {
|
|
28
25
|
if (trimmedLine.includes("*/")) {
|
|
29
26
|
inMultiLineComment = false;
|
|
30
27
|
}
|
|
31
28
|
continue;
|
|
32
29
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
inMultiLineComment = false;
|
|
30
|
+
if (trimmedLine.startsWith("/*")) {
|
|
31
|
+
if (!trimmedLine.includes("*/")) {
|
|
32
|
+
inMultiLineComment = true;
|
|
37
33
|
}
|
|
38
34
|
continue;
|
|
39
35
|
}
|
|
40
|
-
// Skip single-line comments
|
|
41
36
|
if (trimmedLine.startsWith("//")) {
|
|
42
37
|
continue;
|
|
43
38
|
}
|
|
44
|
-
|
|
39
|
+
const cleanedLine = trimmedLine.endsWith(";")
|
|
40
|
+
? trimmedLine.slice(0, -1)
|
|
41
|
+
: trimmedLine;
|
|
42
|
+
if (trimmedLine.startsWith(doubleQuoteUseClient) ||
|
|
43
|
+
trimmedLine.startsWith(singleQuoteUseClient)) {
|
|
44
|
+
foundUseClient = true;
|
|
45
|
+
if (directive === "use client") {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
45
49
|
if (trimmedLine.startsWith(doubleQuoteDirective) ||
|
|
46
50
|
trimmedLine.startsWith(singleQuoteDirective)) {
|
|
47
|
-
|
|
51
|
+
foundTargetDirective = true;
|
|
52
|
+
if (directive !== "use server") {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
48
55
|
}
|
|
49
|
-
//
|
|
50
|
-
//
|
|
56
|
+
// Any other string literal is part of a valid directive prologue.
|
|
57
|
+
// We can continue searching.
|
|
58
|
+
if (trimmedLine.startsWith('"') || trimmedLine.startsWith("'")) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// If we encounter any other non-directive, non-comment, non-string-literal
|
|
62
|
+
// line of code, the directive prologue is over. Stop.
|
|
51
63
|
break;
|
|
52
64
|
}
|
|
53
|
-
return false
|
|
65
|
+
// If looking for 'use server' and 'use client' was found, return false (client takes priority)
|
|
66
|
+
if (directive === "use server" && foundUseClient) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return foundTargetDirective;
|
|
54
70
|
}
|
|
@@ -1,109 +1,107 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { hasDirective } from "./hasDirective.mjs";
|
|
3
3
|
describe("hasDirective", () => {
|
|
4
|
-
it('should find "use client" directive
|
|
5
|
-
const code = `"use client";
|
|
6
|
-
|
|
7
|
-
import React from "react";
|
|
8
|
-
|
|
9
|
-
const MyComponent = () => <div>Hello</div>;
|
|
10
|
-
export default MyComponent;`;
|
|
4
|
+
it('should find "use client" directive', () => {
|
|
5
|
+
const code = `"use client"; import React from "react";`;
|
|
11
6
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
12
7
|
});
|
|
13
|
-
it(
|
|
14
|
-
const code = `'use server';
|
|
15
|
-
|
|
16
|
-
export async function myAction() {
|
|
17
|
-
// ...
|
|
18
|
-
}`;
|
|
8
|
+
it('should find "use server" directive', () => {
|
|
9
|
+
const code = `'use server'; export async function myAction() {}`;
|
|
19
10
|
expect(hasDirective(code, "use server")).toBe(true);
|
|
20
11
|
});
|
|
21
|
-
it("should find directive
|
|
22
|
-
const code = `
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
it("should not find a directive that is not there", () => {
|
|
13
|
+
const code = `import React from "react";`;
|
|
14
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
it('should find "use client" directive with single quotes', () => {
|
|
17
|
+
const code = `'use client'; import React from "react";`;
|
|
25
18
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
26
19
|
});
|
|
27
|
-
it("should find directive
|
|
28
|
-
const code =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
it("should find directive when preceded by comments and whitespace", () => {
|
|
21
|
+
const code = `
|
|
22
|
+
// This is a client component
|
|
23
|
+
/* And here is another comment */
|
|
24
|
+
|
|
25
|
+
"use client";
|
|
26
|
+
import React from 'react';
|
|
27
|
+
export default () => <div>Hello</div>;
|
|
28
|
+
`;
|
|
32
29
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
33
30
|
});
|
|
34
|
-
it(
|
|
35
|
-
const code =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
it('should find "use client" directive when preceded by "use strict"', () => {
|
|
32
|
+
const code = `
|
|
33
|
+
"use strict";
|
|
34
|
+
"use client";
|
|
35
|
+
import React from 'react';
|
|
36
|
+
export default () => <div>Hello</div>;
|
|
37
|
+
`;
|
|
39
38
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
40
39
|
});
|
|
41
|
-
it(
|
|
40
|
+
it('should find "use server" directive when preceded by "use strict" and comments', () => {
|
|
42
41
|
const code = `
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
// server stuff
|
|
43
|
+
"use strict";
|
|
44
|
+
/* another comment */
|
|
45
|
+
"use server";
|
|
46
|
+
export async function myAction() {}
|
|
47
|
+
`;
|
|
48
|
+
expect(hasDirective(code, "use server")).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
it("should find directive when preceded by another string literal directive", () => {
|
|
51
|
+
const code = `
|
|
52
|
+
"use awesome"; // Some other directive
|
|
53
|
+
"use client";
|
|
54
|
+
import React from 'react';
|
|
55
|
+
export default () => <div>Hello</div>;
|
|
56
|
+
`;
|
|
47
57
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
48
58
|
});
|
|
49
59
|
it("should return false if no directive is present", () => {
|
|
50
60
|
const code = `import React from "react";
|
|
51
|
-
|
|
52
|
-
const MyComponent = () => <div>Hello</div>;`;
|
|
61
|
+
export default () => <div>Hello</div>;`;
|
|
53
62
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
54
63
|
});
|
|
55
|
-
it("should return false if directive is
|
|
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", () => {
|
|
64
|
+
it("should return false if the directive is commented out", () => {
|
|
63
65
|
const code = `// "use client";
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
import React from "react";
|
|
67
|
+
export default () => <div>Hello</div>;`;
|
|
66
68
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
67
69
|
});
|
|
68
|
-
it("should return false if directive
|
|
69
|
-
const code =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const MyComponent = () => <div>Hello</div>;`;
|
|
70
|
+
it("should return false if the directive appears after code", () => {
|
|
71
|
+
const code = `import React from "react";
|
|
72
|
+
"use client";
|
|
73
|
+
export default () => <div>Hello</div>;`;
|
|
74
74
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
75
75
|
});
|
|
76
|
-
it("should
|
|
77
|
-
const code = `
|
|
76
|
+
it("should handle multi-line comments correctly", () => {
|
|
77
|
+
const code = `
|
|
78
|
+
/*
|
|
79
|
+
* "use client";
|
|
80
|
+
*/
|
|
81
|
+
import React from "react";
|
|
82
|
+
`;
|
|
78
83
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
79
84
|
});
|
|
80
|
-
it("should handle
|
|
81
|
-
const code = `"use client"
|
|
85
|
+
it("should handle code with no whitespace", () => {
|
|
86
|
+
const code = `"use client";import React from "react";`;
|
|
82
87
|
expect(hasDirective(code, "use client")).toBe(true);
|
|
83
88
|
});
|
|
84
|
-
it("should handle
|
|
85
|
-
const code =
|
|
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);
|
|
89
|
+
it("should handle empty code", () => {
|
|
90
|
+
const code = "";
|
|
91
|
+
expect(hasDirective(code, "use client")).toBe(false);
|
|
96
92
|
});
|
|
97
|
-
it("should handle
|
|
98
|
-
const code =
|
|
99
|
-
const MyComponent = () => <div>Hello</div>;
|
|
100
|
-
`;
|
|
93
|
+
it("should handle code with only whitespace", () => {
|
|
94
|
+
const code = " \n\t ";
|
|
101
95
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
102
96
|
});
|
|
103
|
-
it("should
|
|
104
|
-
const code =
|
|
105
|
-
|
|
106
|
-
`;
|
|
97
|
+
it("should handle files with only comments", () => {
|
|
98
|
+
const code = `// comment 1
|
|
99
|
+
/* comment 2 */`;
|
|
107
100
|
expect(hasDirective(code, "use client")).toBe(false);
|
|
108
101
|
});
|
|
102
|
+
it("should prioritize 'use client' over 'use server'", () => {
|
|
103
|
+
const code = `'use client';\n'use server';\nconsole.log('hello');`;
|
|
104
|
+
expect(hasDirective(code, "use client")).toBe(true);
|
|
105
|
+
expect(hasDirective(code, "use server")).toBe(false);
|
|
106
|
+
});
|
|
109
107
|
});
|
package/dist/vite/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { redwoodPlugin as redwood, type RedwoodPluginOptions, } from "./redwoodPlugin.mjs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { remove, pathExists } from "fs-extra";
|
|
1
|
+
import { pathExists, remove } from "fs-extra";
|
|
3
2
|
import { stat } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
4
|
export const invalidateCacheIfPrismaClientChanged = async ({ projectRootDir, }) => {
|
|
5
5
|
const viteDepsCachePath = resolve(projectRootDir, "node_modules", ".vite", `deps_worker`, `@prisma_client.js`);
|
|
6
6
|
// Get mtimes for comparison
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Plugin } from "vite";
|
|
2
1
|
import enhancedResolve from "enhanced-resolve";
|
|
3
|
-
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
export declare const ENV_PREDEFINED_IMPORTS: {
|
|
4
4
|
worker: string[];
|
|
5
5
|
ssr: string[];
|
|
6
6
|
client: string[];
|
|
@@ -10,6 +10,6 @@ export declare const ENV_RESOLVERS: {
|
|
|
10
10
|
worker: enhancedResolve.ResolveFunction;
|
|
11
11
|
client: enhancedResolve.ResolveFunction;
|
|
12
12
|
};
|
|
13
|
-
export declare const
|
|
13
|
+
export declare const knownDepsResolverPlugin: ({ projectRootDir, }: {
|
|
14
14
|
projectRootDir: string;
|
|
15
15
|
}) => Plugin[];
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
|
-
import { ROOT_DIR } from "../lib/constants.mjs";
|
|
3
2
|
import enhancedResolve from "enhanced-resolve";
|
|
3
|
+
import { ROOT_DIR } from "../lib/constants.mjs";
|
|
4
4
|
import { ensureAliasArray } from "./ensureAliasArray.mjs";
|
|
5
|
-
const log = debug("rwsdk:vite:
|
|
6
|
-
const
|
|
7
|
-
|
|
5
|
+
const log = debug("rwsdk:vite:known-deps-resolver-plugin");
|
|
6
|
+
const KNOWN_PREFIXES = [
|
|
7
|
+
"react",
|
|
8
|
+
"react-dom",
|
|
9
|
+
"react-server-dom-webpack",
|
|
10
|
+
"rwsdk",
|
|
11
|
+
];
|
|
12
|
+
export const ENV_PREDEFINED_IMPORTS = {
|
|
8
13
|
worker: [
|
|
9
14
|
"react",
|
|
10
15
|
"react-dom",
|
|
@@ -42,10 +47,10 @@ export const ENV_RESOLVERS = {
|
|
|
42
47
|
conditionNames: ["browser", "default"],
|
|
43
48
|
}),
|
|
44
49
|
};
|
|
45
|
-
function
|
|
46
|
-
if (!
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
50
|
+
function resolveKnownImport(id, envName, projectRootDir, isPrefixedImport = false) {
|
|
51
|
+
if (!isPrefixedImport) {
|
|
52
|
+
const isKnownImport = KNOWN_PREFIXES.some((prefix) => id === prefix || id.startsWith(`${prefix}/`));
|
|
53
|
+
if (!isKnownImport) {
|
|
49
54
|
return undefined;
|
|
50
55
|
}
|
|
51
56
|
}
|
|
@@ -70,13 +75,13 @@ function resolveReactImport(id, envName, projectRootDir, isReactImportKnown = fa
|
|
|
70
75
|
}
|
|
71
76
|
return resolved;
|
|
72
77
|
}
|
|
73
|
-
function
|
|
78
|
+
function resolvePredefinedEnvImportMappings(env, projectRootDir) {
|
|
74
79
|
process.env.VERBOSE &&
|
|
75
80
|
log("Resolving environment import mappings for env=%s", env);
|
|
76
81
|
const mappings = new Map();
|
|
77
|
-
const
|
|
78
|
-
for (const importRequest of
|
|
79
|
-
const resolved =
|
|
82
|
+
const predefinedImports = ENV_PREDEFINED_IMPORTS[env];
|
|
83
|
+
for (const importRequest of predefinedImports) {
|
|
84
|
+
const resolved = resolveKnownImport(importRequest, env, projectRootDir, true);
|
|
80
85
|
if (resolved) {
|
|
81
86
|
mappings.set(importRequest, resolved);
|
|
82
87
|
process.env.VERBOSE &&
|
|
@@ -87,27 +92,27 @@ function resolveEnvImportMappings(env, projectRootDir) {
|
|
|
87
92
|
log("Environment import mappings complete for env=%s: %d mappings", env, mappings.size);
|
|
88
93
|
return mappings;
|
|
89
94
|
}
|
|
90
|
-
export const
|
|
91
|
-
log("Initializing
|
|
95
|
+
export const knownDepsResolverPlugin = ({ projectRootDir, }) => {
|
|
96
|
+
log("Initializing known dependencies resolver plugin");
|
|
92
97
|
let isBuild = false;
|
|
93
98
|
const ENV_IMPORT_MAPPINGS = Object.fromEntries(Object.keys(ENV_RESOLVERS).map((env) => [
|
|
94
99
|
env,
|
|
95
|
-
|
|
100
|
+
resolvePredefinedEnvImportMappings(env, projectRootDir),
|
|
96
101
|
]));
|
|
97
102
|
// Log a clean summary instead of all the individual mappings
|
|
98
103
|
const totalMappings = Object.values(ENV_IMPORT_MAPPINGS).reduce((sum, mappings) => sum + mappings.size, 0);
|
|
99
|
-
log("
|
|
104
|
+
log("Known dependencies resolver configured with %d total mappings across %d environments", totalMappings, Object.keys(ENV_IMPORT_MAPPINGS).length);
|
|
100
105
|
function createEsbuildResolverPlugin(envName, mappings) {
|
|
101
106
|
if (!mappings) {
|
|
102
107
|
return null;
|
|
103
108
|
}
|
|
104
109
|
return {
|
|
105
|
-
name: `rwsdk:
|
|
110
|
+
name: `rwsdk:known-dependencies-resolver-esbuild-${envName}`,
|
|
106
111
|
setup(build) {
|
|
107
112
|
build.onResolve({ filter: /.*/ }, (args) => {
|
|
108
113
|
let resolved = mappings.get(args.path);
|
|
109
114
|
if (!resolved) {
|
|
110
|
-
resolved =
|
|
115
|
+
resolved = resolveKnownImport(args.path, envName, projectRootDir);
|
|
111
116
|
}
|
|
112
117
|
if (resolved && args.importer !== "") {
|
|
113
118
|
if (args.path === "react-server-dom-webpack/client.edge") {
|
|
@@ -123,7 +128,7 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
123
128
|
}
|
|
124
129
|
return [
|
|
125
130
|
{
|
|
126
|
-
name: "rwsdk:
|
|
131
|
+
name: "rwsdk:known-dependencies-resolver:config",
|
|
127
132
|
enforce: "post",
|
|
128
133
|
config(config, { command }) {
|
|
129
134
|
isBuild = command === "build";
|
|
@@ -133,7 +138,7 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
133
138
|
log("Setting up resolve aliases and optimizeDeps for each environment");
|
|
134
139
|
// Set up aliases and optimizeDeps for each environment
|
|
135
140
|
for (const [envName, mappings] of Object.entries(ENV_IMPORT_MAPPINGS)) {
|
|
136
|
-
const
|
|
141
|
+
const predefinedImports = ENV_PREDEFINED_IMPORTS[envName];
|
|
137
142
|
// Ensure environment config exists
|
|
138
143
|
if (!config.environments) {
|
|
139
144
|
config.environments = {};
|
|
@@ -151,7 +156,7 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
151
156
|
envConfig.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
152
157
|
envConfig.optimizeDeps.esbuildOptions.plugins.push(esbuildPlugin);
|
|
153
158
|
envConfig.optimizeDeps.include ??= [];
|
|
154
|
-
envConfig.optimizeDeps.include.push(...
|
|
159
|
+
envConfig.optimizeDeps.include.push(...predefinedImports);
|
|
155
160
|
log("Added esbuild plugin and optimizeDeps includes for environment: %s", envName);
|
|
156
161
|
}
|
|
157
162
|
const aliases = ensureAliasArray(envConfig);
|
|
@@ -161,12 +166,12 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
161
166
|
process.env.VERBOSE &&
|
|
162
167
|
log("Added alias for env=%s: %s -> %s", envName, find, replacement);
|
|
163
168
|
}
|
|
164
|
-
log("Environment %s configured with %d aliases and %d optimizeDeps includes", envName, mappings.size,
|
|
169
|
+
log("Environment %s configured with %d aliases and %d optimizeDeps includes", envName, mappings.size, predefinedImports.length);
|
|
165
170
|
}
|
|
166
171
|
},
|
|
167
172
|
},
|
|
168
173
|
{
|
|
169
|
-
name: "rwsdk:
|
|
174
|
+
name: "rwsdk:known-dependencies-resolver:resolveId",
|
|
170
175
|
enforce: "pre",
|
|
171
176
|
async resolveId(id, importer) {
|
|
172
177
|
// Skip during directive scanning to avoid performance issues
|
|
@@ -188,7 +193,7 @@ export const reactConditionsResolverPlugin = ({ projectRootDir, }) => {
|
|
|
188
193
|
}
|
|
189
194
|
let resolved = mappings.get(id);
|
|
190
195
|
if (!resolved) {
|
|
191
|
-
resolved =
|
|
196
|
+
resolved = resolveKnownImport(id, envName, projectRootDir);
|
|
192
197
|
}
|
|
193
198
|
if (resolved) {
|
|
194
199
|
process.env.VERBOSE &&
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import debug from "debug";
|
|
2
2
|
import fsp from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
3
4
|
import { CLIENT_MANIFEST_RELATIVE_PATH } from "../lib/constants.mjs";
|
|
4
|
-
import debug from "debug";
|
|
5
5
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
6
6
|
const log = debug("rwsdk:vite:linker-plugin");
|
|
7
7
|
export function linkWorkerBundle({ code, manifestContent, projectRootDir, }) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
1
3
|
import { resolve } from "node:path";
|
|
2
4
|
import colors from "picocolors";
|
|
3
|
-
import {
|
|
4
|
-
import debug from "debug";
|
|
5
|
-
import { VIRTUAL_SSR_PREFIX } from "./ssrBridgePlugin.mjs";
|
|
5
|
+
import { getShortName } from "../lib/getShortName.mjs";
|
|
6
6
|
import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
|
|
7
7
|
import { hasDirective as sourceHasDirective } from "./hasDirective.mjs";
|
|
8
|
-
import { isJsFile } from "./isJsFile.mjs";
|
|
9
8
|
import { invalidateModule } from "./invalidateModule.mjs";
|
|
10
|
-
import {
|
|
9
|
+
import { isJsFile } from "./isJsFile.mjs";
|
|
10
|
+
import { VIRTUAL_SSR_PREFIX } from "./ssrBridgePlugin.mjs";
|
|
11
11
|
const log = debug("rwsdk:vite:hmr-plugin");
|
|
12
12
|
let hasErrored = false;
|
|
13
13
|
const hasDirective = async (filepath, directive) => {
|