what-compiler 0.11.6 → 0.11.8

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.
@@ -16,6 +16,18 @@ import { setupErrorOverlay } from './error-overlay.js';
16
16
 
17
17
  const VIRTUAL_ROUTES_ID = 'virtual:what-routes';
18
18
  const RESOLVED_VIRTUAL_ID = '\0' + VIRTUAL_ROUTES_ID;
19
+ const SERVER_ACTION_MODULE_RE = /(?:from\s*['"](?:what-framework\/server|what-server(?:\/actions)?)['"]|import\s*['"](?:what-framework\/server|what-server(?:\/actions)?)['"])/;
20
+ const SCRIPT_MODULE_RE = /\.[cm]?[jt]sx?$/;
21
+
22
+ function patternMatches(pattern, value) {
23
+ if (!pattern) return false;
24
+ if (Array.isArray(pattern)) return pattern.some((entry) => patternMatches(entry, value));
25
+ if (pattern instanceof RegExp) {
26
+ pattern.lastIndex = 0;
27
+ return pattern.test(value);
28
+ }
29
+ return typeof pattern === 'function' ? pattern(value) : false;
30
+ }
19
31
 
20
32
  /**
21
33
  * Shape the "preserve JSX" transform config for the running Vite version.
@@ -82,6 +94,32 @@ export default function whatVitePlugin(options = {}) {
82
94
  let pagesDir = '';
83
95
  let server = null;
84
96
  let isDevMode = false;
97
+ const actionIdRegistry = new Map();
98
+
99
+ function registerActionId(metadata) {
100
+ const existing = actionIdRegistry.get(metadata.id);
101
+ if (existing && existing.key !== metadata.key) {
102
+ throw new Error(
103
+ `Duplicate server action ID "${metadata.id}". ` +
104
+ `First declared by "${existing.bindingName}" at ${existing.source}; ` +
105
+ `conflicts with "${metadata.bindingName}" at ${metadata.source}.`
106
+ );
107
+ }
108
+ actionIdRegistry.set(metadata.id, metadata);
109
+ }
110
+
111
+ function clearActionIdsForFile(filename) {
112
+ for (const [id, metadata] of actionIdRegistry) {
113
+ if (metadata.filename === filename) actionIdRegistry.delete(id);
114
+ }
115
+ }
116
+
117
+ function actionFilenameForFile(filename) {
118
+ const cleanFilename = filename.replace(/[?#].*$/, '');
119
+ return rootDir
120
+ ? path.relative(rootDir, cleanFilename).split(path.sep).join('/')
121
+ : cleanFilename;
122
+ }
85
123
 
86
124
  return {
87
125
  name: 'vite-plugin-what',
@@ -111,6 +149,9 @@ export default function whatVitePlugin(options = {}) {
111
149
  });
112
150
 
113
151
  devServer.watcher.on('unlink', (file) => {
152
+ // Vite will never transform an unlinked module again, so explicitly
153
+ // release its IDs before handling the narrower pages refresh path.
154
+ clearActionIdsForFile(actionFilenameForFile(file));
114
155
  if (file.startsWith(pagesDir)) {
115
156
  const mod = devServer.moduleGraph.getModuleById(RESOLVED_VIRTUAL_ID);
116
157
  if (mod) {
@@ -137,9 +178,20 @@ export default function whatVitePlugin(options = {}) {
137
178
 
138
179
  // Transform JSX files
139
180
  transform(code, id) {
140
- // Check if we should process this file
141
- if (!include.test(id)) return null;
142
- if (exclude && exclude.test(id)) return null;
181
+ const cleanId = id.replace(/[?#].*$/, '');
182
+ const hasJsx = patternMatches(include, cleanId);
183
+ const isScriptModule = SCRIPT_MODULE_RE.test(cleanId);
184
+ const hasServerActions = isScriptModule && SERVER_ACTION_MODULE_RE.test(code);
185
+ if (exclude && patternMatches(exclude, cleanId)) return null;
186
+
187
+ // Clear before either transforming the replacement or returning early.
188
+ // Otherwise a .ts/.js module that removes its final action import leaves
189
+ // an ID reserved forever and produces false duplicate-ID failures.
190
+ if (isScriptModule) clearActionIdsForFile(actionFilenameForFile(cleanId));
191
+ // Server action metadata is required in plain .js/.ts modules too, so
192
+ // those modules pass through the same hermetic Babel transform even when
193
+ // they contain no JSX.
194
+ if (!hasJsx && !hasServerActions) return null;
143
195
 
144
196
  try {
145
197
  const result = transformSync(code, {
@@ -153,7 +205,11 @@ export default function whatVitePlugin(options = {}) {
153
205
  configFile: false,
154
206
  babelrc: false,
155
207
  plugins: [
156
- [whatBabelPlugin, { production }]
208
+ [whatBabelPlugin, {
209
+ production,
210
+ projectRoot: rootDir || process.cwd(),
211
+ onActionId: registerActionId,
212
+ }]
157
213
  ],
158
214
  parserOpts: {
159
215
  plugins: ['jsx', 'typescript']