rwsdk 0.1.12 → 0.1.14
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/vite/directivesPlugin.mjs +0 -1
- package/dist/vite/invalidateModule.d.mts +6 -2
- package/dist/vite/invalidateModule.mjs +23 -7
- package/dist/vite/isJsFile.d.mts +1 -0
- package/dist/vite/isJsFile.d.ts +1 -0
- package/dist/vite/isJsFile.js +3 -0
- package/dist/vite/isJsFile.mjs +3 -0
- package/dist/vite/miniflareHMRPlugin.d.mts +2 -0
- package/dist/vite/miniflareHMRPlugin.mjs +53 -59
- package/dist/vite/redwoodPlugin.mjs +2 -0
- package/dist/vite/ssrBridgePlugin.mjs +4 -13
- package/package.json +1 -1
|
@@ -47,7 +47,6 @@ export const directivesPlugin = ({ projectRootDir, clientFiles, serverFiles, })
|
|
|
47
47
|
devServer.environments[environment].depsOptimizer?.registerMissingImport(resolvedId, fullPath);
|
|
48
48
|
if (isAfterFirstResponse && !hadFile) {
|
|
49
49
|
log("Invalidating cache for lookup module %s after adding module id=%s", lookupModule, id);
|
|
50
|
-
//invalidateModule(devServer, environment, `virtual:use-${kind}-lookup`);
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
};
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
import type { ViteDevServer } from "vite";
|
|
2
|
-
|
|
1
|
+
import type { EnvironmentModuleNode, ViteDevServer } from "vite";
|
|
2
|
+
interface InvalidatableModuleOptions {
|
|
3
|
+
invalidateImportersRecursively?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare const invalidateModule: (devServer: ViteDevServer, environment: string, target: string | EnvironmentModuleNode, options?: InvalidatableModuleOptions, seen?: Set<EnvironmentModuleNode>) => void;
|
|
6
|
+
export {};
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import debug from "debug";
|
|
2
2
|
const log = debug("rwsdk:vite:invalidate-module");
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
export const invalidateModule = (devServer, environment, target, options = {}, seen = new Set()) => {
|
|
4
|
+
let moduleNode;
|
|
5
|
+
if (typeof target === "string") {
|
|
6
|
+
const id = target;
|
|
7
|
+
const [rawId, _query] = id.split("?");
|
|
8
|
+
moduleNode =
|
|
9
|
+
devServer?.environments[environment]?.moduleGraph.idToModuleMap.get(rawId);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
moduleNode = target;
|
|
13
|
+
}
|
|
8
14
|
if (moduleNode) {
|
|
9
|
-
|
|
15
|
+
if (seen.has(moduleNode)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
seen.add(moduleNode);
|
|
19
|
+
devServer.environments[environment]?.moduleGraph.invalidateModule(moduleNode, seen);
|
|
20
|
+
log("Invalidating module: id=%s, environment=%s", moduleNode.id, environment);
|
|
21
|
+
if (options.invalidateImportersRecursively) {
|
|
22
|
+
for (const importer of moduleNode.importers) {
|
|
23
|
+
invalidateModule(devServer, environment, importer, options, seen);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
10
26
|
}
|
|
11
27
|
else {
|
|
12
|
-
|
|
28
|
+
log("Module not found: id=%s, environment=%s", typeof target === "string" ? target : target.id, environment);
|
|
13
29
|
}
|
|
14
30
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isJsFile(filepath: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isJsFile(filepath: string): boolean;
|
|
@@ -4,13 +4,23 @@ import { readFile } from "node:fs/promises";
|
|
|
4
4
|
import debug from "debug";
|
|
5
5
|
import { VIRTUAL_SSR_PREFIX } from "./ssrBridgePlugin.mjs";
|
|
6
6
|
import { normalizeModulePath } from "./normalizeModulePath.mjs";
|
|
7
|
+
import { hasDirective as sourceHasDirective } from "./hasDirective.mjs";
|
|
8
|
+
import { isJsFile } from "./isJsFile.mjs";
|
|
9
|
+
import { invalidateModule } from "./invalidateModule.mjs";
|
|
7
10
|
import { getShortName } from "../lib/getShortName.mjs";
|
|
8
|
-
import { pathExists } from "fs-extra";
|
|
9
11
|
const verboseLog = debug("verbose:rwsdk:vite:hmr-plugin");
|
|
12
|
+
const hasDirective = async (filepath, directive) => {
|
|
13
|
+
if (!isJsFile(filepath)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const content = await readFile(filepath, "utf-8");
|
|
17
|
+
return sourceHasDirective(content, directive);
|
|
18
|
+
};
|
|
10
19
|
const hasEntryAsAncestor = (module, entryFile, seen = new Set()) => {
|
|
11
20
|
// Prevent infinite recursion
|
|
12
|
-
if (seen.has(module))
|
|
21
|
+
if (seen.has(module)) {
|
|
13
22
|
return false;
|
|
23
|
+
}
|
|
14
24
|
seen.add(module);
|
|
15
25
|
// Check direct importers
|
|
16
26
|
for (const importer of module.importers) {
|
|
@@ -22,62 +32,47 @@ const hasEntryAsAncestor = (module, entryFile, seen = new Set()) => {
|
|
|
22
32
|
}
|
|
23
33
|
return false;
|
|
24
34
|
};
|
|
25
|
-
// Cache for "use client" status results
|
|
26
|
-
const useClientCache = new Map();
|
|
27
|
-
// Function to invalidate cache for a file
|
|
28
|
-
const invalidateUseClientCache = (file) => {
|
|
29
|
-
useClientCache.delete(file);
|
|
30
|
-
};
|
|
31
|
-
const isUseClientModule = async (ctx, file, seen = new Set()) => {
|
|
32
|
-
// Prevent infinite recursion
|
|
33
|
-
if (seen.has(file))
|
|
34
|
-
return false;
|
|
35
|
-
seen.add(file);
|
|
36
|
-
try {
|
|
37
|
-
// Check cache first
|
|
38
|
-
if (useClientCache.has(file)) {
|
|
39
|
-
return useClientCache.get(file);
|
|
40
|
-
}
|
|
41
|
-
// Read and check the file
|
|
42
|
-
const content = (await pathExists(file))
|
|
43
|
-
? await readFile(file, "utf-8")
|
|
44
|
-
: "";
|
|
45
|
-
const hasUseClient = content.includes("'use client'") || content.includes('"use client"');
|
|
46
|
-
if (hasUseClient) {
|
|
47
|
-
useClientCache.set(file, true);
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
// Get the module from the module graph to find importers
|
|
51
|
-
const module = ctx.server.moduleGraph.getModuleById(file);
|
|
52
|
-
if (!module) {
|
|
53
|
-
useClientCache.set(file, false);
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
// Check all importers recursively
|
|
57
|
-
for (const importer of module.importers) {
|
|
58
|
-
if (await isUseClientModule(ctx, importer.url, seen)) {
|
|
59
|
-
useClientCache.set(file, true);
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
useClientCache.set(file, false);
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
useClientCache.set(file, false);
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
35
|
export const miniflareHMRPlugin = (givenOptions) => [
|
|
72
36
|
{
|
|
73
37
|
name: "rwsdk:miniflare-hmr",
|
|
74
38
|
async hotUpdate(ctx) {
|
|
39
|
+
const { clientFiles, serverFiles, viteEnvironment: { name: environment }, workerEntryPathname: entry, } = givenOptions;
|
|
75
40
|
verboseLog("Hot update: (env=%s) %s\nModule graph:\n\n%s", this.environment.name, ctx.file, dumpFullModuleGraph(ctx.server, this.environment.name));
|
|
76
|
-
const environment = givenOptions.viteEnvironment.name;
|
|
77
|
-
const entry = givenOptions.workerEntryPathname;
|
|
78
41
|
if (!["client", environment].includes(this.environment.name)) {
|
|
79
42
|
return [];
|
|
80
43
|
}
|
|
44
|
+
const hasClientDirective = await hasDirective(ctx.file, "use client");
|
|
45
|
+
const hasServerDirective = !hasClientDirective && (await hasDirective(ctx.file, "use server"));
|
|
46
|
+
let clientDirectiveChanged = false;
|
|
47
|
+
let serverDirectiveChanged = false;
|
|
48
|
+
if (!clientFiles.has(ctx.file) && hasClientDirective) {
|
|
49
|
+
clientFiles.add(ctx.file);
|
|
50
|
+
clientDirectiveChanged = true;
|
|
51
|
+
}
|
|
52
|
+
else if (clientFiles.has(ctx.file) && !hasClientDirective) {
|
|
53
|
+
clientFiles.delete(ctx.file);
|
|
54
|
+
clientDirectiveChanged = true;
|
|
55
|
+
}
|
|
56
|
+
if (!serverFiles.has(ctx.file) && hasServerDirective) {
|
|
57
|
+
serverFiles.add(ctx.file);
|
|
58
|
+
serverDirectiveChanged = true;
|
|
59
|
+
}
|
|
60
|
+
else if (serverFiles.has(ctx.file) && !hasServerDirective) {
|
|
61
|
+
serverFiles.delete(ctx.file);
|
|
62
|
+
serverDirectiveChanged = true;
|
|
63
|
+
}
|
|
64
|
+
if (clientDirectiveChanged) {
|
|
65
|
+
["client", "ssr", environment].forEach((environment) => {
|
|
66
|
+
invalidateModule(ctx.server, environment, "virtual:use-client-lookup.js");
|
|
67
|
+
});
|
|
68
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "/@id/virtual:use-client-lookup.js");
|
|
69
|
+
}
|
|
70
|
+
if (serverDirectiveChanged) {
|
|
71
|
+
["client", "ssr", environment].forEach((environment) => {
|
|
72
|
+
invalidateModule(ctx.server, environment, "virtual:use-server-lookup.js");
|
|
73
|
+
});
|
|
74
|
+
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX + "/@id/virtual:use-server-lookup.js");
|
|
75
|
+
}
|
|
81
76
|
// todo(justinvdm, 12 Dec 2024): Skip client references
|
|
82
77
|
const modules = Array.from(ctx.server.environments[environment].moduleGraph.getModulesByFile(ctx.file) ?? []);
|
|
83
78
|
const isWorkerUpdate = ctx.file === entry ||
|
|
@@ -91,7 +86,6 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
91
86
|
// => Notify for HMR update of any css files imported by in worker, that are also in the client module graph
|
|
92
87
|
// Why: There may have been changes to css classes referenced, which might css modules to change
|
|
93
88
|
if (this.environment.name === "client") {
|
|
94
|
-
const cssModules = [];
|
|
95
89
|
for (const [_, module] of ctx.server.environments[environment]
|
|
96
90
|
.moduleGraph.idToModuleMap) {
|
|
97
91
|
// todo(justinvdm, 13 Dec 2024): We check+update _all_ css files in worker module graph,
|
|
@@ -99,15 +93,15 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
99
93
|
// on the importers and imports of the changed file. We should be smarter about this.
|
|
100
94
|
if (module.file && module.file.endsWith(".css")) {
|
|
101
95
|
const clientModules = ctx.server.environments.client.moduleGraph.getModulesByFile(module.file);
|
|
102
|
-
|
|
103
|
-
|
|
96
|
+
for (const clientModule of clientModules ?? []) {
|
|
97
|
+
invalidateModule(ctx.server, "client", clientModule);
|
|
104
98
|
}
|
|
105
99
|
}
|
|
106
100
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
101
|
+
// context(justinvdm, 10 Jul 2025): If this isn't a file with a client
|
|
102
|
+
// directive or a css file, we shouldn't invalidate anything else to
|
|
103
|
+
// avoid full page reload
|
|
104
|
+
return hasClientDirective || ctx.file.endsWith(".css") ? undefined : [];
|
|
111
105
|
}
|
|
112
106
|
// The worker needs an update, and the hot check is for the worker environment
|
|
113
107
|
// => Notify for custom RSC-based HMR update, then short circuit HMR
|
|
@@ -122,12 +116,12 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
122
116
|
?.values()
|
|
123
117
|
.next().value;
|
|
124
118
|
if (m) {
|
|
125
|
-
ctx.server
|
|
119
|
+
invalidateModule(ctx.server, environment, m);
|
|
126
120
|
}
|
|
127
121
|
const virtualSSRModule = ctx.server.environments[environment].moduleGraph.idToModuleMap.get(VIRTUAL_SSR_PREFIX +
|
|
128
122
|
normalizeModulePath(givenOptions.rootDir, ctx.file));
|
|
129
123
|
if (virtualSSRModule) {
|
|
130
|
-
ctx.server
|
|
124
|
+
invalidateModule(ctx.server, environment, virtualSSRModule);
|
|
131
125
|
}
|
|
132
126
|
ctx.server.environments.client.hot.send({
|
|
133
127
|
type: "custom",
|
|
@@ -89,32 +89,23 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
|
|
|
89
89
|
log("Dev mode: fetching SSR module for realPath=%s", realId);
|
|
90
90
|
const result = await devServer?.environments.ssr.fetchModule(realId);
|
|
91
91
|
verboseLog("Fetch module result: id=%s, result=%O", realId, result);
|
|
92
|
-
if (!result) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
92
|
const code = "code" in result ? result.code : undefined;
|
|
96
93
|
log("Fetched SSR module code length: %d", code?.length || 0);
|
|
97
|
-
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
const { imports, dynamicImports } = findSsrImportSpecifiers(realId, code, verboseLog);
|
|
94
|
+
const { imports, dynamicImports } = findSsrImportSpecifiers(realId, code || "", verboseLog);
|
|
101
95
|
const allSpecifiers = [...new Set([...imports, ...dynamicImports])];
|
|
102
96
|
const switchCases = allSpecifiers
|
|
103
97
|
.map((specifier) => ` case "${specifier}": return import("${VIRTUAL_SSR_PREFIX}${specifier}");`)
|
|
104
98
|
.join("\n");
|
|
105
99
|
const transformedCode = `
|
|
106
100
|
await (async function(__vite_ssr_import__, __vite_ssr_dynamic_import__) {${code}})(
|
|
107
|
-
(id, ...args) => ssrImport(id
|
|
108
|
-
(id, ...args) => ssrImport(id
|
|
101
|
+
(id, ...args) => {ssrImport(id); return __vite_ssr_import__('/@id/${VIRTUAL_SSR_PREFIX}' + id, ...args);},
|
|
102
|
+
(id, ...args) => {ssrImport(id); return __vite_ssr_dynamic_import__('/@id/${VIRTUAL_SSR_PREFIX}' + id, ...args);}
|
|
109
103
|
);
|
|
110
104
|
|
|
111
|
-
function ssrImport(id
|
|
105
|
+
function ssrImport(id) {
|
|
112
106
|
switch (id) {
|
|
113
107
|
${switchCases}
|
|
114
108
|
}
|
|
115
|
-
|
|
116
|
-
const virtualId = '/@id/${VIRTUAL_SSR_PREFIX}' + id;
|
|
117
|
-
return isDynamic ? __vite_ssr_dynamic_import__(virtualId, ...args) : __vite_ssr_import__(virtualId, ...args);
|
|
118
109
|
}
|
|
119
110
|
`;
|
|
120
111
|
log("Transformed SSR module code length: %d", transformedCode.length);
|