@soda-gql/vite-plugin 0.11.10 → 0.11.12

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/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  let __soda_gql_builder_plugin_support = require("@soda-gql/builder/plugin-support");
2
+ let node_path = require("node:path");
2
3
  let __babel_core = require("@babel/core");
3
4
  let __soda_gql_babel_plugin = require("@soda-gql/babel/plugin");
4
5
  let __soda_gql_builder = require("@soda-gql/builder");
@@ -54,12 +55,28 @@ const sodaGqlPlugin = (options = {}) => {
54
55
  }
55
56
  };
56
57
  /**
58
+ * Convert an absolute file path to a relative path from baseDir.
59
+ * This is used to match against artifact sourcePaths which are relative.
60
+ */
61
+ const toRelativePath = (absolutePath) => {
62
+ if (!pluginSession) return (0, __soda_gql_common.normalizePath)(absolutePath);
63
+ return (0, __soda_gql_common.normalizePath)((0, node_path.relative)(pluginSession.config.baseDir, absolutePath));
64
+ };
65
+ /**
66
+ * Convert a relative file path to an absolute path using baseDir.
67
+ * This is used to convert artifact sourcePaths to absolute paths for Vite's module graph.
68
+ */
69
+ const toAbsolutePath = (relativePath) => {
70
+ if (!pluginSession) return relativePath;
71
+ return (0, __soda_gql_common.normalizePath)((0, node_path.resolve)(pluginSession.config.baseDir, relativePath));
72
+ };
73
+ /**
57
74
  * Check if a file path corresponds to a soda-gql source file.
58
75
  */
59
76
  const isSodaGqlFile = (filePath) => {
60
77
  if (!currentArtifact) return false;
61
- const normalized = (0, __soda_gql_common.normalizePath)(filePath);
62
- for (const element of Object.values(currentArtifact.elements)) if ((0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === normalized) return true;
78
+ const relativePath = toRelativePath(filePath);
79
+ for (const element of Object.values(currentArtifact.elements)) if ((0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === relativePath) return true;
63
80
  return false;
64
81
  };
65
82
  /**
@@ -122,9 +139,9 @@ const sodaGqlPlugin = (options = {}) => {
122
139
  if (!/\.[jt]sx?$/.test(id)) return null;
123
140
  if (id.includes("node_modules")) return null;
124
141
  if (!pluginSession || !currentArtifact) return null;
125
- const normalizedPath = (0, __soda_gql_common.normalizePath)(id);
126
- if (!Object.values(currentArtifact.elements).some((element) => (0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === normalizedPath)) return null;
127
- log(`Transforming: ${normalizedPath}`);
142
+ const relativePath = toRelativePath(id);
143
+ if (!Object.values(currentArtifact.elements).some((element) => (0, __soda_gql_common.normalizePath)(element.metadata.sourcePath) === relativePath)) return null;
144
+ log(`Transforming: ${relativePath}`);
128
145
  if (swcTransformer) {
129
146
  const swcResult = swcTransformer.transform({
130
147
  sourceCode: code,
@@ -140,6 +157,7 @@ const sodaGqlPlugin = (options = {}) => {
140
157
  filename: id,
141
158
  babelrc: false,
142
159
  configFile: false,
160
+ parserOpts: { plugins: id.endsWith(".tsx") ? ["typescript", "jsx"] : ["typescript"] },
143
161
  plugins: [(0, __soda_gql_babel_plugin.createPluginWithArtifact)({
144
162
  artifact: currentArtifact,
145
163
  config: pluginSession.config
@@ -188,7 +206,8 @@ const sodaGqlPlugin = (options = {}) => {
188
206
  log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);
189
207
  const affectedModules = /* @__PURE__ */ new Set();
190
208
  for (const affectedPath of affectedFiles) {
191
- const modulesByFile = server.moduleGraph.getModulesByFile(affectedPath);
209
+ const absolutePath = toAbsolutePath(affectedPath);
210
+ const modulesByFile = server.moduleGraph.getModulesByFile(absolutePath);
192
211
  if (modulesByFile) for (const mod of modulesByFile) affectedModules.add(mod);
193
212
  }
194
213
  for (const mod of modules) affectedModules.add(mod);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["pluginSession: PluginSession | null","currentArtifact: BuilderArtifact | null","previousArtifact: BuilderArtifact | null","swcTransformer: SwcTransformerInterface | null","_sodaGqlPlugin"],"sources":["../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { type TransformOptions, transformSync } from \"@babel/core\";\nimport { createPluginWithArtifact } from \"@soda-gql/babel/plugin\";\nimport { type BuilderArtifact, type BuilderArtifactElement, collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { HmrContext, ModuleNode, Plugin, ViteDevServer } from \"vite\";\nimport type { VitePluginOptions } from \"./types\";\n\n/**\n * Vite plugin for soda-gql that handles GraphQL code transformations\n * at build time with HMR support for development.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { sodaGqlPlugin } from \"@soda-gql/vite-plugin\";\n *\n * export default defineConfig({\n * plugins: [sodaGqlPlugin({ debug: true }), react()],\n * });\n * ```\n */\nexport const sodaGqlPlugin = (options: VitePluginOptions = {}): Plugin => {\n const stateKey = getStateKey(options.configPath);\n\n let pluginSession: PluginSession | null = null;\n let currentArtifact: BuilderArtifact | null = null;\n let previousArtifact: BuilderArtifact | null = null;\n let _viteServer: ViteDevServer | null = null;\n let isDevMode = false;\n let swcTransformer: SwcTransformerInterface | null = null;\n let swcInitialized = false;\n\n const log = (message: string): void => {\n if (options.debug) {\n console.log(`[@soda-gql/vite-plugin] ${message}`);\n }\n };\n\n /**\n * Initialize SWC transformer if configured.\n */\n const initializeSwcTransformer = async (): Promise<void> => {\n if (swcInitialized || options.transformer !== \"swc\") {\n return;\n }\n\n swcInitialized = true;\n\n if (!currentArtifact || !pluginSession) {\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n swcTransformer = await createTransformer({\n config: pluginSession.config,\n artifact: currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(stateKey, swcTransformer);\n log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/vite-plugin] Failed to initialize SWC transformer: ${error}. ` +\n \"Make sure @soda-gql/swc is installed. Falling back to Babel.\",\n );\n swcTransformer = null;\n }\n };\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n const isSodaGqlFile = (filePath: string): boolean => {\n if (!currentArtifact) return false;\n\n const normalized = normalizePath(filePath);\n for (const element of Object.values(currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === normalized) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n const hasArtifactChanged = (): boolean => {\n if (!previousArtifact || !currentArtifact) return true;\n\n const prevCount = Object.keys(previousArtifact.elements).length;\n const newCount = Object.keys(currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n };\n\n /**\n * Get files that changed between previous and current artifact.\n */\n const getChangedSodaGqlFiles = (): Set<string> => {\n const changed = new Set<string>();\n\n if (!previousArtifact || !currentArtifact) return changed;\n\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n };\n\n return {\n name: \"@soda-gql/vite-plugin\",\n enforce: \"pre\", // Run before other plugins to transform source early\n\n configResolved(config) {\n isDevMode = config.command === \"serve\";\n log(`Mode: ${isDevMode ? \"development\" : \"production\"}`);\n },\n\n async buildStart() {\n // Initialize plugin session\n pluginSession = createPluginSession(options, \"@soda-gql/vite-plugin\");\n if (!pluginSession) {\n log(\"Plugin disabled or config load failed\");\n return;\n }\n\n setSharedPluginSession(stateKey, pluginSession);\n\n // Build initial artifact\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n log(`Initial build: ${Object.keys(currentArtifact?.elements ?? {}).length} elements`);\n\n // Initialize SWC transformer if configured\n await initializeSwcTransformer();\n },\n\n configureServer(server) {\n _viteServer = server;\n log(\"Dev server configured\");\n },\n\n async transform(code, id) {\n // Skip non-JS/TS files\n if (!/\\.[jt]sx?$/.test(id)) {\n return null;\n }\n\n // Skip node_modules\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Skip if plugin is disabled or no artifact\n if (!pluginSession || !currentArtifact) {\n return null;\n }\n\n // Check if this file contains any soda-gql elements\n const normalizedPath = normalizePath(id);\n const hasElements = Object.values(currentArtifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === normalizedPath,\n );\n\n if (!hasElements) {\n return null; // Not a soda-gql file\n }\n\n log(`Transforming: ${normalizedPath}`);\n\n // Try SWC transformer first if available\n if (swcTransformer) {\n const swcResult = swcTransformer.transform({\n sourceCode: code,\n sourcePath: id,\n });\n\n if (swcResult.transformed) {\n return {\n code: swcResult.sourceCode,\n map: swcResult.sourceMap ? JSON.parse(swcResult.sourceMap) : undefined,\n };\n }\n // SWC didn't transform (no soda-gql code), return null to pass through\n return null;\n }\n\n // Fall back to Babel transformer\n const babelOptions: TransformOptions = {\n filename: id,\n babelrc: false,\n configFile: false,\n plugins: [createPluginWithArtifact({ artifact: currentArtifact, config: pluginSession.config })],\n sourceMaps: true,\n };\n\n const result = transformSync(code, babelOptions);\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n\n return null;\n },\n\n buildEnd() {\n if (!isDevMode) {\n // Cleanup for production builds\n log(\"Production build complete, cleaning up\");\n pluginSession = null;\n currentArtifact = null;\n previousArtifact = null;\n swcTransformer = null;\n setSharedPluginSession(stateKey, null);\n setSharedArtifact(stateKey, null);\n setSharedSwcTransformer(stateKey, null);\n }\n },\n\n async handleHotUpdate(ctx: HmrContext): Promise<ModuleNode[] | void> {\n const { file, server, modules } = ctx;\n const normalizedPath = normalizePath(file);\n\n if (!pluginSession || !currentArtifact) {\n return; // Let Vite handle normally\n }\n\n // Check if the changed file is a soda-gql source file\n if (!isSodaGqlFile(normalizedPath)) {\n return; // Not a soda-gql file, let Vite handle normally\n }\n\n log(`soda-gql file changed: ${normalizedPath}`);\n\n // Store previous artifact for change detection\n previousArtifact = currentArtifact;\n\n // Rebuild artifact to detect changes\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n if (!currentArtifact) {\n return;\n }\n\n // If artifact hasn't changed, just let normal HMR happen\n if (!hasArtifactChanged()) {\n log(\"Artifact unchanged, using normal HMR\");\n return;\n }\n\n // Compute affected files using module adjacency\n const sharedState = getSharedState(stateKey);\n const changedFiles = getChangedSodaGqlFiles();\n\n const affectedFiles = collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: sharedState.moduleAdjacency,\n });\n\n log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n\n // Convert affected file paths to Vite module nodes\n const affectedModules = new Set<ModuleNode>();\n\n for (const affectedPath of affectedFiles) {\n // Try to get module by file path\n const modulesByFile = server.moduleGraph.getModulesByFile(affectedPath);\n if (modulesByFile) {\n for (const mod of modulesByFile) {\n affectedModules.add(mod);\n }\n }\n }\n\n // Include original modules\n for (const mod of modules) {\n affectedModules.add(mod);\n }\n\n if (affectedModules.size > 0) {\n log(`Invalidating ${affectedModules.size} modules for HMR`);\n return [...affectedModules];\n }\n\n // Fall back to original modules\n return modules;\n },\n };\n};\n","// Re-export shared state utilities for advanced usage\nexport { getSharedArtifact, getSharedState, getStateKey } from \"@soda-gql/builder/plugin-support\";\nexport { sodaGqlPlugin } from \"./plugin\";\nexport type { TransformerType, VitePluginOptions } from \"./types\";\n\n// Re-import for convenience aliases\nimport { sodaGqlPlugin as _sodaGqlPlugin } from \"./plugin\";\n\n/**\n * Convenience alias for sodaGqlPlugin.\n * @see {@link sodaGqlPlugin}\n */\nexport const withSodaGql = _sodaGqlPlugin;\n\nexport default _sodaGqlPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["pluginSession: PluginSession | null","currentArtifact: BuilderArtifact | null","previousArtifact: BuilderArtifact | null","swcTransformer: SwcTransformerInterface | null","_sodaGqlPlugin"],"sources":["../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { relative, resolve } from \"node:path\";\nimport { type TransformOptions, transformSync } from \"@babel/core\";\nimport { createPluginWithArtifact } from \"@soda-gql/babel/plugin\";\nimport { type BuilderArtifact, type BuilderArtifactElement, collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { HmrContext, ModuleNode, Plugin, ViteDevServer } from \"vite\";\nimport type { VitePluginOptions } from \"./types\";\n\n/**\n * Vite plugin for soda-gql that handles GraphQL code transformations\n * at build time with HMR support for development.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { sodaGqlPlugin } from \"@soda-gql/vite-plugin\";\n *\n * export default defineConfig({\n * plugins: [sodaGqlPlugin({ debug: true }), react()],\n * });\n * ```\n */\nexport const sodaGqlPlugin = (options: VitePluginOptions = {}): Plugin => {\n const stateKey = getStateKey(options.configPath);\n\n let pluginSession: PluginSession | null = null;\n let currentArtifact: BuilderArtifact | null = null;\n let previousArtifact: BuilderArtifact | null = null;\n let _viteServer: ViteDevServer | null = null;\n let isDevMode = false;\n let swcTransformer: SwcTransformerInterface | null = null;\n let swcInitialized = false;\n\n const log = (message: string): void => {\n if (options.debug) {\n console.log(`[@soda-gql/vite-plugin] ${message}`);\n }\n };\n\n /**\n * Initialize SWC transformer if configured.\n */\n const initializeSwcTransformer = async (): Promise<void> => {\n if (swcInitialized || options.transformer !== \"swc\") {\n return;\n }\n\n swcInitialized = true;\n\n if (!currentArtifact || !pluginSession) {\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n swcTransformer = await createTransformer({\n config: pluginSession.config,\n artifact: currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(stateKey, swcTransformer);\n log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/vite-plugin] Failed to initialize SWC transformer: ${error}. ` +\n \"Make sure @soda-gql/swc is installed. Falling back to Babel.\",\n );\n swcTransformer = null;\n }\n };\n\n /**\n * Convert an absolute file path to a relative path from baseDir.\n * This is used to match against artifact sourcePaths which are relative.\n */\n const toRelativePath = (absolutePath: string): string => {\n if (!pluginSession) {\n return normalizePath(absolutePath);\n }\n return normalizePath(relative(pluginSession.config.baseDir, absolutePath));\n };\n\n /**\n * Convert a relative file path to an absolute path using baseDir.\n * This is used to convert artifact sourcePaths to absolute paths for Vite's module graph.\n */\n const toAbsolutePath = (relativePath: string): string => {\n if (!pluginSession) {\n return relativePath;\n }\n return normalizePath(resolve(pluginSession.config.baseDir, relativePath));\n };\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n const isSodaGqlFile = (filePath: string): boolean => {\n if (!currentArtifact) return false;\n\n const relativePath = toRelativePath(filePath);\n for (const element of Object.values(currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === relativePath) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n const hasArtifactChanged = (): boolean => {\n if (!previousArtifact || !currentArtifact) return true;\n\n const prevCount = Object.keys(previousArtifact.elements).length;\n const newCount = Object.keys(currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n };\n\n /**\n * Get files that changed between previous and current artifact.\n */\n const getChangedSodaGqlFiles = (): Set<string> => {\n const changed = new Set<string>();\n\n if (!previousArtifact || !currentArtifact) return changed;\n\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n };\n\n return {\n name: \"@soda-gql/vite-plugin\",\n enforce: \"pre\", // Run before other plugins to transform source early\n\n configResolved(config) {\n isDevMode = config.command === \"serve\";\n log(`Mode: ${isDevMode ? \"development\" : \"production\"}`);\n },\n\n async buildStart() {\n // Initialize plugin session\n pluginSession = createPluginSession(options, \"@soda-gql/vite-plugin\");\n if (!pluginSession) {\n log(\"Plugin disabled or config load failed\");\n return;\n }\n\n setSharedPluginSession(stateKey, pluginSession);\n\n // Build initial artifact\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n log(`Initial build: ${Object.keys(currentArtifact?.elements ?? {}).length} elements`);\n\n // Initialize SWC transformer if configured\n await initializeSwcTransformer();\n },\n\n configureServer(server) {\n _viteServer = server;\n log(\"Dev server configured\");\n },\n\n async transform(code, id) {\n // Skip non-JS/TS files\n if (!/\\.[jt]sx?$/.test(id)) {\n return null;\n }\n\n // Skip node_modules\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Skip if plugin is disabled or no artifact\n if (!pluginSession || !currentArtifact) {\n return null;\n }\n\n // Check if this file contains any soda-gql elements\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = toRelativePath(id);\n const hasElements = Object.values(currentArtifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === relativePath,\n );\n\n if (!hasElements) {\n return null; // Not a soda-gql file\n }\n\n log(`Transforming: ${relativePath}`);\n\n // Try SWC transformer first if available\n if (swcTransformer) {\n const swcResult = swcTransformer.transform({\n sourceCode: code,\n sourcePath: id,\n });\n\n if (swcResult.transformed) {\n return {\n code: swcResult.sourceCode,\n map: swcResult.sourceMap ? JSON.parse(swcResult.sourceMap) : undefined,\n };\n }\n // SWC didn't transform (no soda-gql code), return null to pass through\n return null;\n }\n\n // Fall back to Babel transformer\n const babelOptions: TransformOptions = {\n filename: id,\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: id.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n },\n plugins: [createPluginWithArtifact({ artifact: currentArtifact, config: pluginSession.config })],\n sourceMaps: true,\n };\n\n const result = transformSync(code, babelOptions);\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n\n return null;\n },\n\n buildEnd() {\n if (!isDevMode) {\n // Cleanup for production builds\n log(\"Production build complete, cleaning up\");\n pluginSession = null;\n currentArtifact = null;\n previousArtifact = null;\n swcTransformer = null;\n setSharedPluginSession(stateKey, null);\n setSharedArtifact(stateKey, null);\n setSharedSwcTransformer(stateKey, null);\n }\n },\n\n async handleHotUpdate(ctx: HmrContext): Promise<ModuleNode[] | void> {\n const { file, server, modules } = ctx;\n const normalizedPath = normalizePath(file);\n\n if (!pluginSession || !currentArtifact) {\n return; // Let Vite handle normally\n }\n\n // Check if the changed file is a soda-gql source file\n if (!isSodaGqlFile(normalizedPath)) {\n return; // Not a soda-gql file, let Vite handle normally\n }\n\n log(`soda-gql file changed: ${normalizedPath}`);\n\n // Store previous artifact for change detection\n previousArtifact = currentArtifact;\n\n // Rebuild artifact to detect changes\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n if (!currentArtifact) {\n return;\n }\n\n // If artifact hasn't changed, just let normal HMR happen\n if (!hasArtifactChanged()) {\n log(\"Artifact unchanged, using normal HMR\");\n return;\n }\n\n // Compute affected files using module adjacency\n const sharedState = getSharedState(stateKey);\n const changedFiles = getChangedSodaGqlFiles();\n\n const affectedFiles = collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: sharedState.moduleAdjacency,\n });\n\n log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n\n // Convert affected file paths to Vite module nodes\n // affectedFiles contains relative paths, convert to absolute for Vite's module graph\n const affectedModules = new Set<ModuleNode>();\n\n for (const affectedPath of affectedFiles) {\n // Convert relative path to absolute for Vite's module graph lookup\n const absolutePath = toAbsolutePath(affectedPath);\n const modulesByFile = server.moduleGraph.getModulesByFile(absolutePath);\n if (modulesByFile) {\n for (const mod of modulesByFile) {\n affectedModules.add(mod);\n }\n }\n }\n\n // Include original modules\n for (const mod of modules) {\n affectedModules.add(mod);\n }\n\n if (affectedModules.size > 0) {\n log(`Invalidating ${affectedModules.size} modules for HMR`);\n return [...affectedModules];\n }\n\n // Fall back to original modules\n return modules;\n },\n };\n};\n","// Re-export shared state utilities for advanced usage\nexport { getSharedArtifact, getSharedState, getStateKey } from \"@soda-gql/builder/plugin-support\";\nexport { sodaGqlPlugin } from \"./plugin\";\nexport type { TransformerType, VitePluginOptions } from \"./types\";\n\n// Re-import for convenience aliases\nimport { sodaGqlPlugin as _sodaGqlPlugin } from \"./plugin\";\n\n/**\n * Convenience alias for sodaGqlPlugin.\n * @see {@link sodaGqlPlugin}\n */\nexport const withSodaGql = _sodaGqlPlugin;\n\nexport default _sodaGqlPlugin;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAOY,KAAA,iBAAA,GAAoB,aAAH,GAAA;EAAG;EAEX,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAET,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAOL,SAAA,KAAA,CAAA,EAAA,OAAA;EAAe;;;;ECe3B,SAAA,WAkTZ,CAAA,EDjUwB,iBCec;;;;;;;AD1BvC;;;;;;;;;;;AC0BA;;cAAa,0BAA0B,sBAAyB;;;;AD1BhE;;;AAE8B,cEGjB,WFHiB,EAAA,CAAA,OAAA,CAAA,EEGW,iBFHX,EAAA,GEGN,KAAA,CAAA,MFHM"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAOY,KAAA,iBAAA,GAAoB,aAAH,GAAA;EAAG;EAEX,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAET,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAOL,SAAA,KAAA,CAAA,EAAA,OAAA;EAAe;;;;ECgB3B,SAAA,WA8UZ,CAAA,ED9VwB,iBCgBc;;;;;;;AD3BvC;;;;;;;;;;;AC2BA;;cAAa,0BAA0B,sBAAyB;;;;AD3BhE;;;AAE8B,cEGjB,WFHiB,EAAA,CAAA,OAAA,CAAA,EEGW,iBFHX,EAAA,GEGN,KAAA,CAAA,MFHM"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAOY,KAAA,iBAAA,GAAoB,aAAH,GAAA;EAAG;EAEX,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAET,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAOL,SAAA,KAAA,CAAA,EAAA,OAAA;EAAe;;;;ECe3B,SAAA,WAkTZ,CAAA,EDjUwB,iBCec;;;;;;;AD1BvC;;;;;;;;;;;AC0BA;;cAAa,0BAA0B,sBAAyB;;;;AD1BhE;;;AAE8B,cEGjB,WFHiB,EAAA,CAAA,OAAA,CAAA,EEGW,iBFHX,EAAA,GEGN,KAAA,CAAA,MFHM"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAOY,KAAA,iBAAA,GAAoB,aAAH,GAAA;EAAG;EAEX,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAET,SAAA,OAAA,CAAA,EAAA,MAAA,GAAS,MAAT,EAAA;EAAS;EAOL,SAAA,KAAA,CAAA,EAAA,OAAA;EAAe;;;;ECgB3B,SAAA,WA8UZ,CAAA,ED9VwB,iBCgBc;;;;;;;AD3BvC;;;;;;;;;;;AC2BA;;cAAa,0BAA0B,sBAAyB;;;;AD3BhE;;;AAE8B,cEGjB,WFHiB,EAAA,CAAA,OAAA,CAAA,EEGW,iBFHX,EAAA,GEGN,KAAA,CAAA,MFHM"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createPluginSession, getSharedArtifact, getSharedState, getSharedState as getSharedState$1, getStateKey, getStateKey as getStateKey$1, setSharedArtifact, setSharedPluginSession, setSharedSwcTransformer } from "@soda-gql/builder/plugin-support";
2
+ import { relative, resolve } from "node:path";
2
3
  import { transformSync } from "@babel/core";
3
4
  import { createPluginWithArtifact } from "@soda-gql/babel/plugin";
4
5
  import { collectAffectedFiles } from "@soda-gql/builder";
@@ -54,12 +55,28 @@ const sodaGqlPlugin = (options = {}) => {
54
55
  }
55
56
  };
56
57
  /**
58
+ * Convert an absolute file path to a relative path from baseDir.
59
+ * This is used to match against artifact sourcePaths which are relative.
60
+ */
61
+ const toRelativePath = (absolutePath) => {
62
+ if (!pluginSession) return normalizePath(absolutePath);
63
+ return normalizePath(relative(pluginSession.config.baseDir, absolutePath));
64
+ };
65
+ /**
66
+ * Convert a relative file path to an absolute path using baseDir.
67
+ * This is used to convert artifact sourcePaths to absolute paths for Vite's module graph.
68
+ */
69
+ const toAbsolutePath = (relativePath) => {
70
+ if (!pluginSession) return relativePath;
71
+ return normalizePath(resolve(pluginSession.config.baseDir, relativePath));
72
+ };
73
+ /**
57
74
  * Check if a file path corresponds to a soda-gql source file.
58
75
  */
59
76
  const isSodaGqlFile = (filePath) => {
60
77
  if (!currentArtifact) return false;
61
- const normalized = normalizePath(filePath);
62
- for (const element of Object.values(currentArtifact.elements)) if (normalizePath(element.metadata.sourcePath) === normalized) return true;
78
+ const relativePath = toRelativePath(filePath);
79
+ for (const element of Object.values(currentArtifact.elements)) if (normalizePath(element.metadata.sourcePath) === relativePath) return true;
63
80
  return false;
64
81
  };
65
82
  /**
@@ -122,9 +139,9 @@ const sodaGqlPlugin = (options = {}) => {
122
139
  if (!/\.[jt]sx?$/.test(id)) return null;
123
140
  if (id.includes("node_modules")) return null;
124
141
  if (!pluginSession || !currentArtifact) return null;
125
- const normalizedPath = normalizePath(id);
126
- if (!Object.values(currentArtifact.elements).some((element) => normalizePath(element.metadata.sourcePath) === normalizedPath)) return null;
127
- log(`Transforming: ${normalizedPath}`);
142
+ const relativePath = toRelativePath(id);
143
+ if (!Object.values(currentArtifact.elements).some((element) => normalizePath(element.metadata.sourcePath) === relativePath)) return null;
144
+ log(`Transforming: ${relativePath}`);
128
145
  if (swcTransformer) {
129
146
  const swcResult = swcTransformer.transform({
130
147
  sourceCode: code,
@@ -140,6 +157,7 @@ const sodaGqlPlugin = (options = {}) => {
140
157
  filename: id,
141
158
  babelrc: false,
142
159
  configFile: false,
160
+ parserOpts: { plugins: id.endsWith(".tsx") ? ["typescript", "jsx"] : ["typescript"] },
143
161
  plugins: [createPluginWithArtifact({
144
162
  artifact: currentArtifact,
145
163
  config: pluginSession.config
@@ -188,7 +206,8 @@ const sodaGqlPlugin = (options = {}) => {
188
206
  log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);
189
207
  const affectedModules = /* @__PURE__ */ new Set();
190
208
  for (const affectedPath of affectedFiles) {
191
- const modulesByFile = server.moduleGraph.getModulesByFile(affectedPath);
209
+ const absolutePath = toAbsolutePath(affectedPath);
210
+ const modulesByFile = server.moduleGraph.getModulesByFile(absolutePath);
192
211
  if (modulesByFile) for (const mod of modulesByFile) affectedModules.add(mod);
193
212
  }
194
213
  for (const mod of modules) affectedModules.add(mod);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["getStateKey","pluginSession: PluginSession | null","currentArtifact: BuilderArtifact | null","previousArtifact: BuilderArtifact | null","swcTransformer: SwcTransformerInterface | null","getSharedState","_sodaGqlPlugin"],"sources":["../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { type TransformOptions, transformSync } from \"@babel/core\";\nimport { createPluginWithArtifact } from \"@soda-gql/babel/plugin\";\nimport { type BuilderArtifact, type BuilderArtifactElement, collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { HmrContext, ModuleNode, Plugin, ViteDevServer } from \"vite\";\nimport type { VitePluginOptions } from \"./types\";\n\n/**\n * Vite plugin for soda-gql that handles GraphQL code transformations\n * at build time with HMR support for development.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { sodaGqlPlugin } from \"@soda-gql/vite-plugin\";\n *\n * export default defineConfig({\n * plugins: [sodaGqlPlugin({ debug: true }), react()],\n * });\n * ```\n */\nexport const sodaGqlPlugin = (options: VitePluginOptions = {}): Plugin => {\n const stateKey = getStateKey(options.configPath);\n\n let pluginSession: PluginSession | null = null;\n let currentArtifact: BuilderArtifact | null = null;\n let previousArtifact: BuilderArtifact | null = null;\n let _viteServer: ViteDevServer | null = null;\n let isDevMode = false;\n let swcTransformer: SwcTransformerInterface | null = null;\n let swcInitialized = false;\n\n const log = (message: string): void => {\n if (options.debug) {\n console.log(`[@soda-gql/vite-plugin] ${message}`);\n }\n };\n\n /**\n * Initialize SWC transformer if configured.\n */\n const initializeSwcTransformer = async (): Promise<void> => {\n if (swcInitialized || options.transformer !== \"swc\") {\n return;\n }\n\n swcInitialized = true;\n\n if (!currentArtifact || !pluginSession) {\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n swcTransformer = await createTransformer({\n config: pluginSession.config,\n artifact: currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(stateKey, swcTransformer);\n log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/vite-plugin] Failed to initialize SWC transformer: ${error}. ` +\n \"Make sure @soda-gql/swc is installed. Falling back to Babel.\",\n );\n swcTransformer = null;\n }\n };\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n const isSodaGqlFile = (filePath: string): boolean => {\n if (!currentArtifact) return false;\n\n const normalized = normalizePath(filePath);\n for (const element of Object.values(currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === normalized) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n const hasArtifactChanged = (): boolean => {\n if (!previousArtifact || !currentArtifact) return true;\n\n const prevCount = Object.keys(previousArtifact.elements).length;\n const newCount = Object.keys(currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n };\n\n /**\n * Get files that changed between previous and current artifact.\n */\n const getChangedSodaGqlFiles = (): Set<string> => {\n const changed = new Set<string>();\n\n if (!previousArtifact || !currentArtifact) return changed;\n\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n };\n\n return {\n name: \"@soda-gql/vite-plugin\",\n enforce: \"pre\", // Run before other plugins to transform source early\n\n configResolved(config) {\n isDevMode = config.command === \"serve\";\n log(`Mode: ${isDevMode ? \"development\" : \"production\"}`);\n },\n\n async buildStart() {\n // Initialize plugin session\n pluginSession = createPluginSession(options, \"@soda-gql/vite-plugin\");\n if (!pluginSession) {\n log(\"Plugin disabled or config load failed\");\n return;\n }\n\n setSharedPluginSession(stateKey, pluginSession);\n\n // Build initial artifact\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n log(`Initial build: ${Object.keys(currentArtifact?.elements ?? {}).length} elements`);\n\n // Initialize SWC transformer if configured\n await initializeSwcTransformer();\n },\n\n configureServer(server) {\n _viteServer = server;\n log(\"Dev server configured\");\n },\n\n async transform(code, id) {\n // Skip non-JS/TS files\n if (!/\\.[jt]sx?$/.test(id)) {\n return null;\n }\n\n // Skip node_modules\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Skip if plugin is disabled or no artifact\n if (!pluginSession || !currentArtifact) {\n return null;\n }\n\n // Check if this file contains any soda-gql elements\n const normalizedPath = normalizePath(id);\n const hasElements = Object.values(currentArtifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === normalizedPath,\n );\n\n if (!hasElements) {\n return null; // Not a soda-gql file\n }\n\n log(`Transforming: ${normalizedPath}`);\n\n // Try SWC transformer first if available\n if (swcTransformer) {\n const swcResult = swcTransformer.transform({\n sourceCode: code,\n sourcePath: id,\n });\n\n if (swcResult.transformed) {\n return {\n code: swcResult.sourceCode,\n map: swcResult.sourceMap ? JSON.parse(swcResult.sourceMap) : undefined,\n };\n }\n // SWC didn't transform (no soda-gql code), return null to pass through\n return null;\n }\n\n // Fall back to Babel transformer\n const babelOptions: TransformOptions = {\n filename: id,\n babelrc: false,\n configFile: false,\n plugins: [createPluginWithArtifact({ artifact: currentArtifact, config: pluginSession.config })],\n sourceMaps: true,\n };\n\n const result = transformSync(code, babelOptions);\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n\n return null;\n },\n\n buildEnd() {\n if (!isDevMode) {\n // Cleanup for production builds\n log(\"Production build complete, cleaning up\");\n pluginSession = null;\n currentArtifact = null;\n previousArtifact = null;\n swcTransformer = null;\n setSharedPluginSession(stateKey, null);\n setSharedArtifact(stateKey, null);\n setSharedSwcTransformer(stateKey, null);\n }\n },\n\n async handleHotUpdate(ctx: HmrContext): Promise<ModuleNode[] | void> {\n const { file, server, modules } = ctx;\n const normalizedPath = normalizePath(file);\n\n if (!pluginSession || !currentArtifact) {\n return; // Let Vite handle normally\n }\n\n // Check if the changed file is a soda-gql source file\n if (!isSodaGqlFile(normalizedPath)) {\n return; // Not a soda-gql file, let Vite handle normally\n }\n\n log(`soda-gql file changed: ${normalizedPath}`);\n\n // Store previous artifact for change detection\n previousArtifact = currentArtifact;\n\n // Rebuild artifact to detect changes\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n if (!currentArtifact) {\n return;\n }\n\n // If artifact hasn't changed, just let normal HMR happen\n if (!hasArtifactChanged()) {\n log(\"Artifact unchanged, using normal HMR\");\n return;\n }\n\n // Compute affected files using module adjacency\n const sharedState = getSharedState(stateKey);\n const changedFiles = getChangedSodaGqlFiles();\n\n const affectedFiles = collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: sharedState.moduleAdjacency,\n });\n\n log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n\n // Convert affected file paths to Vite module nodes\n const affectedModules = new Set<ModuleNode>();\n\n for (const affectedPath of affectedFiles) {\n // Try to get module by file path\n const modulesByFile = server.moduleGraph.getModulesByFile(affectedPath);\n if (modulesByFile) {\n for (const mod of modulesByFile) {\n affectedModules.add(mod);\n }\n }\n }\n\n // Include original modules\n for (const mod of modules) {\n affectedModules.add(mod);\n }\n\n if (affectedModules.size > 0) {\n log(`Invalidating ${affectedModules.size} modules for HMR`);\n return [...affectedModules];\n }\n\n // Fall back to original modules\n return modules;\n },\n };\n};\n","// Re-export shared state utilities for advanced usage\nexport { getSharedArtifact, getSharedState, getStateKey } from \"@soda-gql/builder/plugin-support\";\nexport { sodaGqlPlugin } from \"./plugin\";\nexport type { TransformerType, VitePluginOptions } from \"./types\";\n\n// Re-import for convenience aliases\nimport { sodaGqlPlugin as _sodaGqlPlugin } from \"./plugin\";\n\n/**\n * Convenience alias for sodaGqlPlugin.\n * @see {@link sodaGqlPlugin}\n */\nexport const withSodaGql = _sodaGqlPlugin;\n\nexport default _sodaGqlPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["getStateKey","pluginSession: PluginSession | null","currentArtifact: BuilderArtifact | null","previousArtifact: BuilderArtifact | null","swcTransformer: SwcTransformerInterface | null","getSharedState","_sodaGqlPlugin"],"sources":["../src/plugin.ts","../src/index.ts"],"sourcesContent":["import { relative, resolve } from \"node:path\";\nimport { type TransformOptions, transformSync } from \"@babel/core\";\nimport { createPluginWithArtifact } from \"@soda-gql/babel/plugin\";\nimport { type BuilderArtifact, type BuilderArtifactElement, collectAffectedFiles } from \"@soda-gql/builder\";\nimport {\n createPluginSession,\n getSharedState,\n getStateKey,\n type PluginSession,\n type SwcTransformerInterface,\n setSharedArtifact,\n setSharedPluginSession,\n setSharedSwcTransformer,\n} from \"@soda-gql/builder/plugin-support\";\nimport { normalizePath } from \"@soda-gql/common\";\nimport type { HmrContext, ModuleNode, Plugin, ViteDevServer } from \"vite\";\nimport type { VitePluginOptions } from \"./types\";\n\n/**\n * Vite plugin for soda-gql that handles GraphQL code transformations\n * at build time with HMR support for development.\n *\n * @example\n * ```typescript\n * // vite.config.ts\n * import { defineConfig } from \"vite\";\n * import react from \"@vitejs/plugin-react\";\n * import { sodaGqlPlugin } from \"@soda-gql/vite-plugin\";\n *\n * export default defineConfig({\n * plugins: [sodaGqlPlugin({ debug: true }), react()],\n * });\n * ```\n */\nexport const sodaGqlPlugin = (options: VitePluginOptions = {}): Plugin => {\n const stateKey = getStateKey(options.configPath);\n\n let pluginSession: PluginSession | null = null;\n let currentArtifact: BuilderArtifact | null = null;\n let previousArtifact: BuilderArtifact | null = null;\n let _viteServer: ViteDevServer | null = null;\n let isDevMode = false;\n let swcTransformer: SwcTransformerInterface | null = null;\n let swcInitialized = false;\n\n const log = (message: string): void => {\n if (options.debug) {\n console.log(`[@soda-gql/vite-plugin] ${message}`);\n }\n };\n\n /**\n * Initialize SWC transformer if configured.\n */\n const initializeSwcTransformer = async (): Promise<void> => {\n if (swcInitialized || options.transformer !== \"swc\") {\n return;\n }\n\n swcInitialized = true;\n\n if (!currentArtifact || !pluginSession) {\n return;\n }\n\n try {\n const { createTransformer } = await import(\"@soda-gql/swc\");\n swcTransformer = await createTransformer({\n config: pluginSession.config,\n artifact: currentArtifact,\n sourceMap: true,\n });\n setSharedSwcTransformer(stateKey, swcTransformer);\n log(\"SWC transformer initialized\");\n } catch (error) {\n console.warn(\n `[@soda-gql/vite-plugin] Failed to initialize SWC transformer: ${error}. ` +\n \"Make sure @soda-gql/swc is installed. Falling back to Babel.\",\n );\n swcTransformer = null;\n }\n };\n\n /**\n * Convert an absolute file path to a relative path from baseDir.\n * This is used to match against artifact sourcePaths which are relative.\n */\n const toRelativePath = (absolutePath: string): string => {\n if (!pluginSession) {\n return normalizePath(absolutePath);\n }\n return normalizePath(relative(pluginSession.config.baseDir, absolutePath));\n };\n\n /**\n * Convert a relative file path to an absolute path using baseDir.\n * This is used to convert artifact sourcePaths to absolute paths for Vite's module graph.\n */\n const toAbsolutePath = (relativePath: string): string => {\n if (!pluginSession) {\n return relativePath;\n }\n return normalizePath(resolve(pluginSession.config.baseDir, relativePath));\n };\n\n /**\n * Check if a file path corresponds to a soda-gql source file.\n */\n const isSodaGqlFile = (filePath: string): boolean => {\n if (!currentArtifact) return false;\n\n const relativePath = toRelativePath(filePath);\n for (const element of Object.values(currentArtifact.elements)) {\n if (normalizePath(element.metadata.sourcePath) === relativePath) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Check if artifact has changed by comparing element counts and hashes.\n */\n const hasArtifactChanged = (): boolean => {\n if (!previousArtifact || !currentArtifact) return true;\n\n const prevCount = Object.keys(previousArtifact.elements).length;\n const newCount = Object.keys(currentArtifact.elements).length;\n if (prevCount !== newCount) return true;\n\n // Compare individual elements by their content hash\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n if (!prevElement) return true;\n if (element.metadata.contentHash !== prevElement.metadata.contentHash) {\n return true;\n }\n }\n\n return false;\n };\n\n /**\n * Get files that changed between previous and current artifact.\n */\n const getChangedSodaGqlFiles = (): Set<string> => {\n const changed = new Set<string>();\n\n if (!previousArtifact || !currentArtifact) return changed;\n\n const prevElements = previousArtifact.elements as Record<string, BuilderArtifactElement>;\n const currElements = currentArtifact.elements as Record<string, BuilderArtifactElement>;\n\n // Compare elements by their source paths and content hashes\n for (const [id, element] of Object.entries(currElements)) {\n const prevElement = prevElements[id];\n const sourcePath = element.metadata.sourcePath;\n\n if (!prevElement || prevElement.metadata.contentHash !== element.metadata.contentHash) {\n changed.add(normalizePath(sourcePath));\n }\n }\n\n // Check for removed elements\n for (const [id, element] of Object.entries(prevElements)) {\n if (!currElements[id]) {\n const sourcePath = element.metadata.sourcePath;\n changed.add(normalizePath(sourcePath));\n }\n }\n\n return changed;\n };\n\n return {\n name: \"@soda-gql/vite-plugin\",\n enforce: \"pre\", // Run before other plugins to transform source early\n\n configResolved(config) {\n isDevMode = config.command === \"serve\";\n log(`Mode: ${isDevMode ? \"development\" : \"production\"}`);\n },\n\n async buildStart() {\n // Initialize plugin session\n pluginSession = createPluginSession(options, \"@soda-gql/vite-plugin\");\n if (!pluginSession) {\n log(\"Plugin disabled or config load failed\");\n return;\n }\n\n setSharedPluginSession(stateKey, pluginSession);\n\n // Build initial artifact\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n log(`Initial build: ${Object.keys(currentArtifact?.elements ?? {}).length} elements`);\n\n // Initialize SWC transformer if configured\n await initializeSwcTransformer();\n },\n\n configureServer(server) {\n _viteServer = server;\n log(\"Dev server configured\");\n },\n\n async transform(code, id) {\n // Skip non-JS/TS files\n if (!/\\.[jt]sx?$/.test(id)) {\n return null;\n }\n\n // Skip node_modules\n if (id.includes(\"node_modules\")) {\n return null;\n }\n\n // Skip if plugin is disabled or no artifact\n if (!pluginSession || !currentArtifact) {\n return null;\n }\n\n // Check if this file contains any soda-gql elements\n // Convert absolute path to relative for matching against artifact sourcePaths\n const relativePath = toRelativePath(id);\n const hasElements = Object.values(currentArtifact.elements).some(\n (element) => normalizePath(element.metadata.sourcePath) === relativePath,\n );\n\n if (!hasElements) {\n return null; // Not a soda-gql file\n }\n\n log(`Transforming: ${relativePath}`);\n\n // Try SWC transformer first if available\n if (swcTransformer) {\n const swcResult = swcTransformer.transform({\n sourceCode: code,\n sourcePath: id,\n });\n\n if (swcResult.transformed) {\n return {\n code: swcResult.sourceCode,\n map: swcResult.sourceMap ? JSON.parse(swcResult.sourceMap) : undefined,\n };\n }\n // SWC didn't transform (no soda-gql code), return null to pass through\n return null;\n }\n\n // Fall back to Babel transformer\n const babelOptions: TransformOptions = {\n filename: id,\n babelrc: false,\n configFile: false,\n parserOpts: {\n plugins: id.endsWith(\".tsx\") ? [\"typescript\", \"jsx\"] : [\"typescript\"],\n },\n plugins: [createPluginWithArtifact({ artifact: currentArtifact, config: pluginSession.config })],\n sourceMaps: true,\n };\n\n const result = transformSync(code, babelOptions);\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n\n return null;\n },\n\n buildEnd() {\n if (!isDevMode) {\n // Cleanup for production builds\n log(\"Production build complete, cleaning up\");\n pluginSession = null;\n currentArtifact = null;\n previousArtifact = null;\n swcTransformer = null;\n setSharedPluginSession(stateKey, null);\n setSharedArtifact(stateKey, null);\n setSharedSwcTransformer(stateKey, null);\n }\n },\n\n async handleHotUpdate(ctx: HmrContext): Promise<ModuleNode[] | void> {\n const { file, server, modules } = ctx;\n const normalizedPath = normalizePath(file);\n\n if (!pluginSession || !currentArtifact) {\n return; // Let Vite handle normally\n }\n\n // Check if the changed file is a soda-gql source file\n if (!isSodaGqlFile(normalizedPath)) {\n return; // Not a soda-gql file, let Vite handle normally\n }\n\n log(`soda-gql file changed: ${normalizedPath}`);\n\n // Store previous artifact for change detection\n previousArtifact = currentArtifact;\n\n // Rebuild artifact to detect changes\n currentArtifact = await pluginSession.getArtifactAsync();\n setSharedArtifact(stateKey, currentArtifact);\n\n if (!currentArtifact) {\n return;\n }\n\n // If artifact hasn't changed, just let normal HMR happen\n if (!hasArtifactChanged()) {\n log(\"Artifact unchanged, using normal HMR\");\n return;\n }\n\n // Compute affected files using module adjacency\n const sharedState = getSharedState(stateKey);\n const changedFiles = getChangedSodaGqlFiles();\n\n const affectedFiles = collectAffectedFiles({\n changedFiles,\n removedFiles: new Set(),\n previousModuleAdjacency: sharedState.moduleAdjacency,\n });\n\n log(`Changed files: ${changedFiles.size}, Affected files: ${affectedFiles.size}`);\n\n // Convert affected file paths to Vite module nodes\n // affectedFiles contains relative paths, convert to absolute for Vite's module graph\n const affectedModules = new Set<ModuleNode>();\n\n for (const affectedPath of affectedFiles) {\n // Convert relative path to absolute for Vite's module graph lookup\n const absolutePath = toAbsolutePath(affectedPath);\n const modulesByFile = server.moduleGraph.getModulesByFile(absolutePath);\n if (modulesByFile) {\n for (const mod of modulesByFile) {\n affectedModules.add(mod);\n }\n }\n }\n\n // Include original modules\n for (const mod of modules) {\n affectedModules.add(mod);\n }\n\n if (affectedModules.size > 0) {\n log(`Invalidating ${affectedModules.size} modules for HMR`);\n return [...affectedModules];\n }\n\n // Fall back to original modules\n return modules;\n },\n };\n};\n","// Re-export shared state utilities for advanced usage\nexport { getSharedArtifact, getSharedState, getStateKey } from \"@soda-gql/builder/plugin-support\";\nexport { sodaGqlPlugin } from \"./plugin\";\nexport type { TransformerType, VitePluginOptions } from \"./types\";\n\n// Re-import for convenience aliases\nimport { sodaGqlPlugin as _sodaGqlPlugin } from \"./plugin\";\n\n/**\n * Convenience alias for sodaGqlPlugin.\n * @see {@link sodaGqlPlugin}\n */\nexport const withSodaGql = _sodaGqlPlugin;\n\nexport default _sodaGqlPlugin;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soda-gql/vite-plugin",
3
- "version": "0.11.10",
3
+ "version": "0.11.12",
4
4
  "description": "Vite plugin for soda-gql",
5
5
  "type": "module",
6
6
  "private": false,
@@ -50,15 +50,15 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@babel/core": "^7.24.0",
53
- "@soda-gql/babel": "0.11.10",
54
- "@soda-gql/builder": "0.11.10",
55
- "@soda-gql/common": "0.11.10",
56
- "@soda-gql/config": "0.11.10"
53
+ "@soda-gql/babel": "0.11.12",
54
+ "@soda-gql/builder": "0.11.12",
55
+ "@soda-gql/common": "0.11.12",
56
+ "@soda-gql/config": "0.11.12"
57
57
  },
58
58
  "devDependencies": {},
59
59
  "peerDependencies": {
60
60
  "vite": "^5.0.0 || ^6.0.0",
61
- "@soda-gql/swc": "0.11.10"
61
+ "@soda-gql/swc": "0.11.12"
62
62
  },
63
63
  "optionalDependencies": {}
64
64
  }