Răsfoiți Sursa

refactor(dashboard): Rename gqlTadaOutputPath option (#3686)

Michael Bromley 5 luni în urmă
părinte
comite
ad9f2c5565

+ 1 - 1
.github/workflows/scripts/vite.config.mts

@@ -11,7 +11,7 @@ export default defineConfig({
         vendureDashboardPlugin({
             vendureConfigPath: pathToFileURL('./src/vendure-config.ts'),
             adminUiConfig: { apiHost: 'http://localhost', apiPort: 3000 },
-            gqlTadaOutputPath: './src/gql',
+            gqlOutputPath: './src/gql',
         }),
     ],
     resolve: {

+ 5 - 1
.vscode/settings.json

@@ -20,5 +20,9 @@
     ],
     "conventionalCommits.gitmoji": false,
     "typescript.tsdk": "node_modules/typescript/lib",
-    "angular.enable-strict-mode-prompt": false
+    "angular.enable-strict-mode-prompt": false,
+    "sonarlint.connectedMode.project": {
+        "connectionId": "vendure-ecommerce",
+        "projectKey": "vendure-ecommerce_vendure"
+    }
 }

+ 1 - 1
docs/docs/guides/extending-the-dashboard/getting-started/index.md

@@ -59,7 +59,7 @@ export default defineConfig({
             // be introspected and the types will be generated in this location.
             // These types can be used in your dashboard extensions to provide
             // type safety when writing queries and mutations.
-            gqlTadaOutputPath: './src/gql',
+            gqlOutputPath: './src/gql',
         }),
     ],
     resolve: {

+ 1 - 0
package-lock.json

@@ -5095,6 +5095,7 @@
     },
     "node_modules/@clack/prompts/node_modules/is-unicode-supported": {
       "version": "1.3.0",
+      "extraneous": true,
       "inBundle": true,
       "license": "MIT",
       "engines": {

+ 1 - 1
packages/dashboard/vite.config.mts

@@ -36,7 +36,7 @@ export default ({ mode }: { mode: string }) => {
             vendureDashboardPlugin({
                 vendureConfigPath: pathToFileURL(vendureConfigPath),
                 adminUiConfig: { apiHost: adminApiHost, apiPort: adminApiPort },
-                // gqlTadaOutputPath: path.resolve(__dirname, './graphql/'),
+                // gqlOutputPath: path.resolve(__dirname, './graphql/'),
                 tempCompilationDir: path.resolve(__dirname, './.temp'),
             }) as any,
         ],

+ 66 - 17
packages/dashboard/vite/utils/plugin-discovery.ts

@@ -30,6 +30,7 @@ export async function discoverPlugins({
     // Analyze source files to find local plugins and package imports
     const { localPluginLocations, packageImports } = await analyzeSourceFiles(
         vendureConfigPath,
+        pluginPackageScanner?.nodeModulesRoot ?? guessNodeModulesRoot(vendureConfigPath, logger),
         logger,
         transformTsConfigPathMappings,
     );
@@ -137,6 +138,29 @@ function getDecoratorObjectProps(decorator: any): any[] {
     return [];
 }
 
+async function isSymlinkedLocalPackage(
+    packageName: string,
+    nodeModulesRoot: string,
+): Promise<string | undefined> {
+    try {
+        const packagePath = path.join(nodeModulesRoot, packageName);
+        const stats = await fs.lstat(packagePath);
+        if (stats.isSymbolicLink()) {
+            // Get the real path that the symlink points to
+            const realPath = await fs.realpath(packagePath);
+            // If the real path is within the project directory (i.e. not in some other node_modules),
+            // then it's a local package
+            if (!realPath.includes('node_modules')) {
+                return realPath;
+            }
+        }
+    } catch (e) {
+        // Package doesn't exist or other error - not a local package
+        return undefined;
+    }
+    return undefined;
+}
+
 /**
  * Analyzes TypeScript source files starting from the config file to discover:
  * 1. Local Vendure plugins
@@ -144,6 +168,7 @@ function getDecoratorObjectProps(decorator: any): any[] {
  */
 export async function analyzeSourceFiles(
     vendureConfigPath: string,
+    nodeModulesRoot: string,
     logger: Logger,
     transformTsConfigPathMappings: TransformTsConfigPathMappingsFn,
 ): Promise<{
@@ -186,7 +211,7 @@ export async function analyzeSourceFiles(
             // Track imports to follow
             const importsToFollow: string[] = [];
 
-            function visit(node: ts.Node) {
+            async function visit(node: ts.Node) {
                 // Look for VendurePlugin decorator
                 const vendurePluginClassName = getVendurePluginClassName(node);
                 if (vendurePluginClassName) {
@@ -204,7 +229,20 @@ export async function analyzeSourceFiles(
                         // Track non-local imports (packages)
                         const npmPackageName = getNpmPackageNameFromImport(importPath);
                         if (npmPackageName) {
-                            packageImportsSet.add(npmPackageName);
+                            // Check if this is actually a symlinked local package
+                            const localPackagePath = await isSymlinkedLocalPackage(
+                                npmPackageName,
+                                nodeModulesRoot,
+                            );
+                            if (localPackagePath) {
+                                // If it is local, follow it like a local import
+                                importsToFollow.push(localPackagePath);
+                                logger.debug(
+                                    `Found symlinked local package "${npmPackageName}" at ${localPackagePath}`,
+                                );
+                            } else {
+                                packageImportsSet.add(npmPackageName);
+                            }
                         }
                         // Handle path aliases and local imports
                         const pathAliasImports = getPotentialPathAliasImportPaths(importPath, tsConfigInfo);
@@ -219,10 +257,15 @@ export async function analyzeSourceFiles(
                     }
                 }
 
-                ts.forEachChild(node, visit);
+                // Visit children
+                const promises: Array<Promise<void>> = [];
+                ts.forEachChild(node, child => {
+                    promises.push(visit(child));
+                });
+                await Promise.all(promises);
             }
 
-            visit(sourceFile);
+            await visit(sourceFile);
 
             // Follow imports
             for (const importPath of importsToFollow) {
@@ -352,19 +395,7 @@ export async function findVendurePluginFiles({
     let nodeModulesRoot = providedNodeModulesRoot;
     const readStart = Date.now();
     if (!nodeModulesRoot) {
-        // If the node_modules root path has not been explicitly
-        // specified, we will try to guess it by resolving the
-        // `@vendure/core` package.
-        try {
-            const coreUrl = import.meta.resolve('@vendure/core');
-            logger.debug(`Found core URL: ${coreUrl}`);
-            const corePath = fileURLToPath(coreUrl);
-            logger.debug(`Found core path: ${corePath}`);
-            nodeModulesRoot = path.join(path.dirname(corePath), '..', '..');
-        } catch (e) {
-            logger.warn(`Failed to resolve @vendure/core: ${e instanceof Error ? e.message : String(e)}`);
-            nodeModulesRoot = path.dirname(vendureConfigPath);
-        }
+        nodeModulesRoot = guessNodeModulesRoot(vendureConfigPath, logger);
     }
 
     const patterns = [
@@ -443,3 +474,21 @@ export async function findVendurePluginFiles({
 
     return potentialPluginFiles;
 }
+
+function guessNodeModulesRoot(vendureConfigPath: string, logger: Logger): string {
+    let nodeModulesRoot: string;
+    // If the node_modules root path has not been explicitly
+    // specified, we will try to guess it by resolving the
+    // `@vendure/core` package.
+    try {
+        const coreUrl = import.meta.resolve('@vendure/core');
+        logger.debug(`Found core URL: ${coreUrl}`);
+        const corePath = fileURLToPath(coreUrl);
+        logger.debug(`Found core path: ${corePath}`);
+        nodeModulesRoot = path.join(path.dirname(corePath), '..', '..');
+    } catch (e) {
+        logger.warn(`Failed to resolve @vendure/core: ${e instanceof Error ? e.message : String(e)}`);
+        nodeModulesRoot = path.dirname(vendureConfigPath);
+    }
+    return nodeModulesRoot;
+}

+ 3 - 3
packages/dashboard/vite/vite-plugin-vendure-dashboard.ts

@@ -76,7 +76,7 @@ export type VitePluginVendureDashboardOptions = {
      * @description
      * The path to the directory where the generated GraphQL Tada files will be output.
      */
-    gqlTadaOutputPath?: string;
+    gqlOutputPath?: string;
     tempCompilationDir?: string;
     disableTansStackRouterPlugin?: boolean;
     /**
@@ -134,8 +134,8 @@ export function vendureDashboardPlugin(options: VitePluginVendureDashboardOption
         adminApiSchemaPlugin(),
         dashboardMetadataPlugin(),
         uiConfigPlugin({ adminUiConfig: options.adminUiConfig }),
-        ...(options.gqlTadaOutputPath
-            ? [gqlTadaPlugin({ gqlTadaOutputPath: options.gqlTadaOutputPath, tempDir, packageRoot })]
+        ...(options.gqlOutputPath
+            ? [gqlTadaPlugin({ gqlTadaOutputPath: options.gqlOutputPath, tempDir, packageRoot })]
             : []),
         transformIndexHtmlPlugin(),
     ];

+ 1 - 2
packages/dev-server/vite.config.mts

@@ -9,8 +9,7 @@ export default defineConfig({
         vendureDashboardPlugin({
             vendureConfigPath: pathToFileURL('./dev-config.ts'),
             adminUiConfig: { apiHost: 'http://localhost', apiPort: 3000 },
-            gqlTadaOutputPath: path.resolve(__dirname, './graphql/'),
-            pluginScanPatterns: ['*vendure*'],
+            gqlOutputPath: path.resolve(__dirname, './graphql/'),
         }) as any,
     ],
 });