@vendure/dashboard 3.3.6-master-202507120238 → 3.3.6

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.
Files changed (54) hide show
  1. package/dist/plugin/types.d.ts +40 -0
  2. package/dist/plugin/utils/ast-utils.d.ts +0 -5
  3. package/dist/plugin/utils/ast-utils.js +0 -67
  4. package/dist/plugin/utils/ast-utils.spec.js +1 -76
  5. package/dist/plugin/utils/compiler.d.ts +22 -0
  6. package/dist/plugin/utils/compiler.js +162 -0
  7. package/dist/plugin/utils/config-loader.d.ts +0 -120
  8. package/dist/plugin/utils/config-loader.js +1 -367
  9. package/dist/plugin/utils/logger.d.ts +3 -0
  10. package/dist/plugin/utils/logger.js +39 -0
  11. package/dist/plugin/utils/plugin-discovery.d.ts +27 -0
  12. package/dist/plugin/utils/plugin-discovery.js +343 -0
  13. package/dist/plugin/utils/tsconfig-utils.d.ts +9 -0
  14. package/dist/plugin/utils/tsconfig-utils.js +50 -0
  15. package/dist/plugin/vite-plugin-config-loader.d.ts +3 -3
  16. package/dist/plugin/vite-plugin-config-loader.js +13 -13
  17. package/dist/plugin/vite-plugin-dashboard-metadata.js +19 -2
  18. package/dist/plugin/vite-plugin-vendure-dashboard.d.ts +7 -7
  19. package/dist/plugin/vite-plugin-vendure-dashboard.js +2 -2
  20. package/package.json +134 -131
  21. package/vite/tests/barrel-exports.spec.ts +13 -4
  22. package/{dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.js → vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/index.js} +6 -6
  23. package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/package.json +8 -0
  24. package/vite/tests/fixtures-npm-plugin/package.json +6 -0
  25. package/{dist/plugin/tests/barrel-exports/vendure-config.js → vite/tests/fixtures-npm-plugin/vendure-config.ts} +5 -6
  26. package/vite/tests/fixtures-path-alias/aliased-plugin/index.ts +1 -0
  27. package/vite/tests/fixtures-path-alias/aliased-plugin/src/aliased.plugin.ts +8 -0
  28. package/vite/tests/fixtures-path-alias/package.json +6 -0
  29. package/vite/tests/fixtures-path-alias/vendure-config.ts +19 -0
  30. package/vite/tests/npm-plugin.spec.ts +46 -0
  31. package/vite/tests/path-alias.spec.ts +33 -0
  32. package/vite/tests/tsconfig.json +11 -0
  33. package/vite/types.ts +44 -0
  34. package/vite/utils/ast-utils.spec.ts +1 -80
  35. package/vite/utils/ast-utils.ts +0 -86
  36. package/vite/utils/compiler.ts +244 -0
  37. package/vite/utils/config-loader.ts +0 -555
  38. package/vite/utils/logger.ts +43 -0
  39. package/vite/utils/plugin-discovery.ts +442 -0
  40. package/vite/utils/tsconfig-utils.ts +79 -0
  41. package/vite/vite-plugin-config-loader.ts +20 -17
  42. package/vite/vite-plugin-dashboard-metadata.ts +26 -7
  43. package/vite/vite-plugin-tailwind-source.ts +2 -2
  44. package/vite/vite-plugin-vendure-dashboard.ts +9 -9
  45. package/dist/plugin/tests/barrel-exports/my-plugin/index.d.ts +0 -1
  46. package/dist/plugin/tests/barrel-exports/my-plugin/index.js +0 -17
  47. package/dist/plugin/tests/barrel-exports/my-plugin/src/my.plugin.d.ts +0 -2
  48. package/dist/plugin/tests/barrel-exports/vendure-config.d.ts +0 -2
  49. package/dist/plugin/tests/barrel-exports.spec.js +0 -14
  50. /package/dist/plugin/{tests/barrel-exports.spec.d.ts → types.js} +0 -0
  51. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/my-plugin/index.ts +0 -0
  52. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/my-plugin/src/my.plugin.ts +0 -0
  53. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/package.json +0 -0
  54. /package/vite/tests/{barrel-exports → fixtures-barrel-exports}/vendure-config.ts +0 -0
@@ -0,0 +1,343 @@
1
+ import { parse } from 'acorn';
2
+ import { simple as walkSimple } from 'acorn-walk';
3
+ import glob from 'fast-glob';
4
+ import fs from 'fs-extra';
5
+ import { open } from 'fs/promises';
6
+ import path from 'path';
7
+ import * as ts from 'typescript';
8
+ import { fileURLToPath } from 'url';
9
+ import { findTsConfigPaths } from './tsconfig-utils.js';
10
+ export async function discoverPlugins({ vendureConfigPath, transformTsConfigPathMappings, logger, outputPath, pluginPackageScanner, }) {
11
+ const plugins = [];
12
+ // Analyze source files to find local plugins and package imports
13
+ const { localPluginLocations, packageImports } = await analyzeSourceFiles(vendureConfigPath, logger, transformTsConfigPathMappings);
14
+ logger.debug(`[discoverPlugins] Found ${localPluginLocations.size} local plugins: ${JSON.stringify([...localPluginLocations.entries()], null, 2)}`);
15
+ logger.debug(`[discoverPlugins] Found ${packageImports.length} package imports: ${JSON.stringify(packageImports, null, 2)}`);
16
+ const filePaths = await findVendurePluginFiles({
17
+ logger,
18
+ nodeModulesRoot: pluginPackageScanner === null || pluginPackageScanner === void 0 ? void 0 : pluginPackageScanner.nodeModulesRoot,
19
+ packageGlobs: packageImports.map(pkg => pkg + '/**/*.js'),
20
+ outputPath,
21
+ vendureConfigPath,
22
+ });
23
+ for (const filePath of filePaths) {
24
+ const content = await fs.readFile(filePath, 'utf-8');
25
+ logger.debug(`[discoverPlugins] Checking file ${filePath}`);
26
+ // First check if this file imports from @vendure/core
27
+ if (!content.includes('@vendure/core')) {
28
+ continue;
29
+ }
30
+ try {
31
+ const ast = parse(content, {
32
+ ecmaVersion: 'latest',
33
+ sourceType: 'module',
34
+ });
35
+ let hasVendurePlugin = false;
36
+ let pluginName;
37
+ let dashboardPath;
38
+ // Walk the AST to find the plugin class and its decorator
39
+ walkSimple(ast, {
40
+ CallExpression(node) {
41
+ // Look for __decorate calls
42
+ const calleeName = node.callee.name;
43
+ const nodeArgs = node.arguments;
44
+ const isDecoratorWithArgs = calleeName === '__decorate' && nodeArgs.length >= 2;
45
+ if (isDecoratorWithArgs) {
46
+ // Check the decorators array (first argument)
47
+ const decorators = nodeArgs[0];
48
+ if (decorators.type === 'ArrayExpression') {
49
+ for (const decorator of decorators.elements) {
50
+ const props = getDecoratorObjectProps(decorator);
51
+ for (const prop of props) {
52
+ const isDashboardProd = prop.key.name === 'dashboard' && prop.value.type === 'Literal';
53
+ if (isDashboardProd) {
54
+ dashboardPath = prop.value.value;
55
+ hasVendurePlugin = true;
56
+ }
57
+ }
58
+ }
59
+ }
60
+ // Get the plugin class name (second argument)
61
+ const targetClass = nodeArgs[1];
62
+ if (targetClass.type === 'Identifier') {
63
+ pluginName = targetClass.name;
64
+ }
65
+ }
66
+ },
67
+ });
68
+ if (hasVendurePlugin && pluginName && dashboardPath) {
69
+ logger.debug(`[discoverPlugins] Found plugin "${pluginName}" in file: ${filePath}`);
70
+ // Keep the dashboard path relative to the plugin file
71
+ const resolvedDashboardPath = dashboardPath.startsWith('.')
72
+ ? dashboardPath // Keep the relative path as-is
73
+ : './' + path.relative(path.dirname(filePath), dashboardPath); // Make absolute path relative
74
+ // Check if this is a local plugin we found earlier
75
+ const sourcePluginPath = localPluginLocations.get(pluginName);
76
+ plugins.push(Object.assign({ name: pluginName, pluginPath: filePath, dashboardEntryPath: resolvedDashboardPath }, (sourcePluginPath && { sourcePluginPath })));
77
+ }
78
+ }
79
+ catch (e) {
80
+ logger.error(`Failed to parse ${filePath}: ${e instanceof Error ? e.message : String(e)}`);
81
+ }
82
+ }
83
+ return plugins;
84
+ }
85
+ function getDecoratorObjectProps(decorator) {
86
+ var _a;
87
+ if (decorator.type === 'CallExpression' &&
88
+ decorator.arguments.length === 1 &&
89
+ decorator.arguments[0].type === 'ObjectExpression') {
90
+ // Look for the dashboard property in the decorator config
91
+ return (_a = decorator.arguments[0].properties) !== null && _a !== void 0 ? _a : [];
92
+ }
93
+ return [];
94
+ }
95
+ /**
96
+ * Analyzes TypeScript source files starting from the config file to discover:
97
+ * 1. Local Vendure plugins
98
+ * 2. All non-local package imports that could contain plugins
99
+ */
100
+ export async function analyzeSourceFiles(vendureConfigPath, logger, transformTsConfigPathMappings) {
101
+ const localPluginLocations = new Map();
102
+ const visitedFiles = new Set();
103
+ const packageImportsSet = new Set();
104
+ // Get tsconfig paths for resolving aliases
105
+ const tsConfigInfo = await findTsConfigPaths(vendureConfigPath, logger, 'compiling', transformTsConfigPathMappings);
106
+ async function processFile(filePath) {
107
+ if (visitedFiles.has(filePath)) {
108
+ return;
109
+ }
110
+ visitedFiles.add(filePath);
111
+ try {
112
+ // First check if this is a directory
113
+ const stat = await fs.stat(filePath);
114
+ if (stat.isDirectory()) {
115
+ // If it's a directory, try to find the plugin file
116
+ const indexFilePath = path.join(filePath, 'index.ts');
117
+ if (await fs.pathExists(indexFilePath)) {
118
+ await processFile(indexFilePath);
119
+ }
120
+ return;
121
+ }
122
+ const content = await fs.readFile(filePath, 'utf-8');
123
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
124
+ // Track imports to follow
125
+ const importsToFollow = [];
126
+ function visit(node) {
127
+ // Look for VendurePlugin decorator
128
+ const vendurePluginClassName = getVendurePluginClassName(node);
129
+ if (vendurePluginClassName) {
130
+ localPluginLocations.set(vendurePluginClassName, filePath);
131
+ logger.debug(`Found plugin "${vendurePluginClassName}" at ${filePath}`);
132
+ }
133
+ // Handle both imports and exports
134
+ const isImportOrExport = ts.isImportDeclaration(node) || ts.isExportDeclaration(node);
135
+ if (isImportOrExport) {
136
+ const moduleSpecifier = node.moduleSpecifier;
137
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
138
+ const importPath = moduleSpecifier.text;
139
+ // Track non-local imports (packages)
140
+ const npmPackageName = getNpmPackageNameFromImport(importPath);
141
+ if (npmPackageName) {
142
+ packageImportsSet.add(npmPackageName);
143
+ }
144
+ // Handle path aliases and local imports
145
+ const pathAliasImports = getPotentialPathAliasImportPaths(importPath, tsConfigInfo);
146
+ if (pathAliasImports.length) {
147
+ importsToFollow.push(...pathAliasImports);
148
+ }
149
+ // Also handle local imports
150
+ if (importPath.startsWith('.')) {
151
+ const resolvedPath = path.resolve(path.dirname(filePath), importPath);
152
+ importsToFollow.push(resolvedPath);
153
+ }
154
+ }
155
+ }
156
+ ts.forEachChild(node, visit);
157
+ }
158
+ visit(sourceFile);
159
+ // Follow imports
160
+ for (const importPath of importsToFollow) {
161
+ // Try all possible file paths
162
+ const possiblePaths = [
163
+ importPath + '.ts',
164
+ importPath + '.js',
165
+ path.join(importPath, 'index.ts'),
166
+ path.join(importPath, 'index.js'),
167
+ ];
168
+ // Try each possible path
169
+ let found = false;
170
+ for (const possiblePath of possiblePaths) {
171
+ const possiblePathExists = await fs.pathExists(possiblePath);
172
+ if (possiblePathExists) {
173
+ await processFile(possiblePath);
174
+ found = true;
175
+ break;
176
+ }
177
+ }
178
+ // If none of the file paths worked, try the raw import path
179
+ // (it might be a directory)
180
+ const tryRawPath = !found && (await fs.pathExists(importPath));
181
+ if (tryRawPath) {
182
+ await processFile(importPath);
183
+ }
184
+ }
185
+ }
186
+ catch (e) {
187
+ const message = e instanceof Error ? e.message : String(e);
188
+ logger.error(`Failed to process ${filePath}: ${message}`);
189
+ }
190
+ }
191
+ await processFile(vendureConfigPath);
192
+ return {
193
+ localPluginLocations,
194
+ packageImports: Array.from(packageImportsSet),
195
+ };
196
+ }
197
+ /**
198
+ * If this is a class declaration that is decorated with the `VendurePlugin` decorator,
199
+ * we want to return that class name, as we have found a local Vendure plugin.
200
+ */
201
+ function getVendurePluginClassName(node) {
202
+ var _a;
203
+ if (ts.isClassDeclaration(node)) {
204
+ const decorators = ts.canHaveDecorators(node) ? ts.getDecorators(node) : undefined;
205
+ if (decorators === null || decorators === void 0 ? void 0 : decorators.length) {
206
+ for (const decorator of decorators) {
207
+ const decoratorName = getDecoratorName(decorator);
208
+ if (decoratorName === 'VendurePlugin') {
209
+ const className = (_a = node.name) === null || _a === void 0 ? void 0 : _a.text;
210
+ if (className) {
211
+ return className;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ function getNpmPackageNameFromImport(importPath) {
219
+ if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
220
+ // Get the root package name (e.g. '@scope/package/subpath' -> '@scope/package')
221
+ const packageName = importPath.startsWith('@')
222
+ ? importPath.split('/').slice(0, 2).join('/')
223
+ : importPath.split('/')[0];
224
+ return packageName;
225
+ }
226
+ }
227
+ function getPotentialPathAliasImportPaths(importPath, tsConfigInfo) {
228
+ const importsToFollow = [];
229
+ if (!tsConfigInfo) {
230
+ return importsToFollow;
231
+ }
232
+ for (const [alias, patterns] of Object.entries(tsConfigInfo.paths)) {
233
+ const aliasPattern = alias.replace(/\*$/, '');
234
+ if (importPath.startsWith(aliasPattern)) {
235
+ const relativePart = importPath.slice(aliasPattern.length);
236
+ // Try each pattern
237
+ for (const pattern of patterns) {
238
+ const resolvedPattern = pattern.replace(/\*$/, '');
239
+ const resolvedPath = path.resolve(tsConfigInfo.baseUrl, resolvedPattern, relativePart);
240
+ importsToFollow.push(resolvedPath);
241
+ }
242
+ }
243
+ }
244
+ return importsToFollow;
245
+ }
246
+ function getDecoratorName(decorator) {
247
+ if (ts.isCallExpression(decorator.expression)) {
248
+ const expression = decorator.expression.expression;
249
+ // Handle both direct usage and imported usage
250
+ if (ts.isIdentifier(expression)) {
251
+ return expression.text;
252
+ }
253
+ // Handle property access like `Decorators.VendurePlugin`
254
+ if (ts.isPropertyAccessExpression(expression)) {
255
+ return expression.name.text;
256
+ }
257
+ }
258
+ return undefined;
259
+ }
260
+ export async function findVendurePluginFiles({ outputPath, vendureConfigPath, logger, nodeModulesRoot: providedNodeModulesRoot, packageGlobs, }) {
261
+ let nodeModulesRoot = providedNodeModulesRoot;
262
+ const readStart = Date.now();
263
+ if (!nodeModulesRoot) {
264
+ // If the node_modules root path has not been explicitly
265
+ // specified, we will try to guess it by resolving the
266
+ // `@vendure/core` package.
267
+ try {
268
+ const coreUrl = import.meta.resolve('@vendure/core');
269
+ logger.debug(`Found core URL: ${coreUrl}`);
270
+ const corePath = fileURLToPath(coreUrl);
271
+ logger.debug(`Found core path: ${corePath}`);
272
+ nodeModulesRoot = path.join(path.dirname(corePath), '..', '..');
273
+ }
274
+ catch (e) {
275
+ logger.warn(`Failed to resolve @vendure/core: ${e instanceof Error ? e.message : String(e)}`);
276
+ nodeModulesRoot = path.dirname(vendureConfigPath);
277
+ }
278
+ }
279
+ const patterns = [
280
+ // Local compiled plugins in temp dir
281
+ path.join(outputPath, '**/*.js'),
282
+ // Node modules patterns
283
+ ...packageGlobs.map(pattern => path.join(nodeModulesRoot, pattern)),
284
+ ];
285
+ logger.debug(`Finding Vendure plugins using patterns: ${patterns.join('\n')}`);
286
+ const globStart = Date.now();
287
+ const files = await glob(patterns, {
288
+ ignore: [
289
+ // Standard test & doc files
290
+ '**/node_modules/**/node_modules/**',
291
+ '**/*.spec.js',
292
+ '**/*.test.js',
293
+ ],
294
+ onlyFiles: true,
295
+ absolute: true,
296
+ followSymbolicLinks: false,
297
+ stats: false,
298
+ });
299
+ logger.debug(`Glob found ${files.length} files in ${Date.now() - globStart}ms`);
300
+ // Read files in larger parallel batches
301
+ const batchSize = 100; // Increased batch size
302
+ const potentialPluginFiles = [];
303
+ for (let i = 0; i < files.length; i += batchSize) {
304
+ const batch = files.slice(i, i + batchSize);
305
+ const results = await Promise.all(batch.map(async (file) => {
306
+ try {
307
+ // Try reading just first 3000 bytes first - most imports are at the top
308
+ const fileHandle = await open(file, 'r');
309
+ try {
310
+ const buffer = Buffer.alloc(3000);
311
+ const { bytesRead } = await fileHandle.read(buffer, 0, 3000, 0);
312
+ let content = buffer.toString('utf8', 0, bytesRead);
313
+ // Quick check for common indicators
314
+ if (content.includes('@vendure/core')) {
315
+ return file;
316
+ }
317
+ // If we find a promising indicator but no definitive match,
318
+ // read more of the file
319
+ if (content.includes('@vendure') || content.includes('VendurePlugin')) {
320
+ const largerBuffer = Buffer.alloc(5000);
321
+ const { bytesRead: moreBytes } = await fileHandle.read(largerBuffer, 0, 5000, 0);
322
+ content = largerBuffer.toString('utf8', 0, moreBytes);
323
+ if (content.includes('@vendure/core')) {
324
+ return file;
325
+ }
326
+ }
327
+ }
328
+ finally {
329
+ await fileHandle.close();
330
+ }
331
+ }
332
+ catch (e) {
333
+ logger.warn(`Failed to read file ${file}: ${e instanceof Error ? e.message : String(e)}`);
334
+ }
335
+ return null;
336
+ }));
337
+ const validResults = results.filter((f) => f !== null);
338
+ potentialPluginFiles.push(...validResults);
339
+ }
340
+ logger.info(`Found ${potentialPluginFiles.length} potential plugin files in ${Date.now() - readStart}ms ` +
341
+ `(scanned ${files.length} files)`);
342
+ return potentialPluginFiles;
343
+ }
@@ -0,0 +1,9 @@
1
+ import { Logger, TransformTsConfigPathMappingsFn } from '../types.js';
2
+ export interface TsConfigPathsConfig {
3
+ baseUrl: string;
4
+ paths: Record<string, string[]>;
5
+ }
6
+ /**
7
+ * Finds and parses tsconfig files in the given directory and its parent directories.
8
+ */
9
+ export declare function findTsConfigPaths(configPath: string, logger: Logger, phase: 'compiling' | 'loading', transformTsConfigPathMappings: TransformTsConfigPathMappingsFn): Promise<TsConfigPathsConfig | undefined>;
@@ -0,0 +1,50 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ /**
4
+ * Finds and parses tsconfig files in the given directory and its parent directories.
5
+ */
6
+ export async function findTsConfigPaths(configPath, logger, phase, transformTsConfigPathMappings) {
7
+ let currentDir = path.dirname(configPath);
8
+ while (currentDir !== path.parse(currentDir).root) {
9
+ try {
10
+ const files = await fs.readdir(currentDir);
11
+ const tsConfigFiles = files.filter(file => /^tsconfig(\..*)?\.json$/.test(file));
12
+ for (const fileName of tsConfigFiles) {
13
+ const tsConfigFilePath = path.join(currentDir, fileName);
14
+ try {
15
+ const { paths, baseUrl } = await getCompilerOptionsFromFile(tsConfigFilePath);
16
+ if (paths) {
17
+ const tsConfigBaseUrl = path.resolve(currentDir, baseUrl || '.');
18
+ const pathMappings = getTransformedPathMappings(paths, phase, transformTsConfigPathMappings);
19
+ return { baseUrl: tsConfigBaseUrl, paths: pathMappings };
20
+ }
21
+ }
22
+ catch (e) {
23
+ logger.warn(`Could not read or parse tsconfig file ${tsConfigFilePath}: ${e instanceof Error ? e.message : String(e)}`);
24
+ }
25
+ }
26
+ }
27
+ catch (e) {
28
+ logger.warn(`Could not read directory ${currentDir}: ${e instanceof Error ? e.message : String(e)}`);
29
+ }
30
+ currentDir = path.dirname(currentDir);
31
+ }
32
+ return undefined;
33
+ }
34
+ async function getCompilerOptionsFromFile(tsConfigFilePath) {
35
+ const tsConfigContent = await fs.readFile(tsConfigFilePath, 'utf-8');
36
+ const tsConfig = JSON.parse(tsConfigContent);
37
+ return tsConfig.compilerOptions || {};
38
+ }
39
+ function getTransformedPathMappings(paths, phase, transformTsConfigPathMappings) {
40
+ const pathMappings = {};
41
+ for (const [alias, patterns] of Object.entries(paths)) {
42
+ const normalizedPatterns = patterns.map(pattern => pattern.replace(/\\/g, '/'));
43
+ pathMappings[alias] = transformTsConfigPathMappings({
44
+ phase,
45
+ alias,
46
+ patterns: normalizedPatterns,
47
+ });
48
+ }
49
+ return pathMappings;
50
+ }
@@ -1,14 +1,14 @@
1
1
  import { Plugin } from 'vite';
2
- import { ConfigLoaderOptions, LoadVendureConfigResult } from './utils/config-loader.js';
2
+ import { CompileResult, CompilerOptions } from './utils/compiler.js';
3
3
  export interface ConfigLoaderApi {
4
- getVendureConfig(): Promise<LoadVendureConfigResult>;
4
+ getVendureConfig(): Promise<CompileResult>;
5
5
  }
6
6
  export declare const configLoaderName = "vendure:config-loader";
7
7
  /**
8
8
  * This Vite plugin loads the VendureConfig from the specified file path, and
9
9
  * makes it available to other plugins via the `ConfigLoaderApi`.
10
10
  */
11
- export declare function configLoaderPlugin(options: ConfigLoaderOptions): Plugin;
11
+ export declare function configLoaderPlugin(options: CompilerOptions): Plugin;
12
12
  /**
13
13
  * Inter-plugin dependencies implemented following the pattern given here:
14
14
  * https://rollupjs.org/plugin-development/#direct-plugin-communication
@@ -1,4 +1,5 @@
1
- import { loadVendureConfig } from './utils/config-loader.js';
1
+ import { compile } from './utils/compiler.js';
2
+ import { debugLogger } from './utils/logger.js';
2
3
  export const configLoaderName = 'vendure:config-loader';
3
4
  /**
4
5
  * This Vite plugin loads the VendureConfig from the specified file path, and
@@ -13,20 +14,19 @@ export function configLoaderPlugin(options) {
13
14
  this.info(`Loading Vendure config. This can take a short while depending on the size of your project...`);
14
15
  try {
15
16
  const startTime = Date.now();
16
- result = await loadVendureConfig({
17
- pathAdapter: options.pathAdapter,
18
- tempDir: options.tempDir,
19
- vendureConfigPath: options.vendureConfigPath,
20
- vendureConfigExport: options.vendureConfigExport,
21
- logger: {
22
- info: (message) => this.info(message),
23
- warn: (message) => this.warn(message),
24
- debug: (message) => this.debug(message),
25
- },
26
- });
17
+ result = await compile(Object.assign(Object.assign({}, options), { logger: process.env.LOG
18
+ ? debugLogger
19
+ : {
20
+ info: (message) => this.info(message),
21
+ warn: (message) => this.warn(message),
22
+ debug: (message) => this.debug(message),
23
+ error: (message) => this.error(message),
24
+ } }));
27
25
  const endTime = Date.now();
28
26
  const duration = endTime - startTime;
29
- const pluginNames = result.pluginInfo.map(p => p.name).join(', ');
27
+ const pluginNames = result.pluginInfo
28
+ .map(p => `${p.name} ${p.sourcePluginPath ? '(local)' : '(npm)'}`)
29
+ .join(', ');
30
30
  this.info(`Found ${result.pluginInfo.length} plugins: ${pluginNames}`);
31
31
  this.info(`Vendure config loaded (using export "${result.exportedSymbolName}") in ${duration}ms`);
32
32
  }
@@ -23,12 +23,29 @@ export function dashboardMetadataPlugin() {
23
23
  async load(id) {
24
24
  var _a;
25
25
  if (id === resolvedVirtualModuleId) {
26
+ const startTime = Date.now();
27
+ this.debug('Loading dashboard extensions...');
26
28
  if (!loadVendureConfigResult) {
29
+ const configStart = Date.now();
27
30
  loadVendureConfigResult = await configLoaderApi.getVendureConfig();
31
+ this.debug(`Loaded Vendure config in ${Date.now() - configStart}ms`);
28
32
  }
29
33
  const { pluginInfo } = loadVendureConfigResult;
30
- const pluginsWithExtensions = (_a = pluginInfo === null || pluginInfo === void 0 ? void 0 : pluginInfo.map(({ dashboardEntryPath, pluginPath }) => dashboardEntryPath && path.join(pluginPath, dashboardEntryPath)).filter(x => x != null)) !== null && _a !== void 0 ? _a : [];
31
- this.info(`Found ${pluginsWithExtensions.length} Dashboard extensions`);
34
+ const resolveStart = Date.now();
35
+ const pluginsWithExtensions = (_a = pluginInfo === null || pluginInfo === void 0 ? void 0 : pluginInfo.map(({ dashboardEntryPath, pluginPath, sourcePluginPath }) => {
36
+ if (!dashboardEntryPath) {
37
+ return null;
38
+ }
39
+ // For local plugins, use the sourcePluginPath to resolve the dashboard extension
40
+ const basePath = sourcePluginPath
41
+ ? path.dirname(sourcePluginPath)
42
+ : path.dirname(pluginPath);
43
+ const resolved = path.resolve(basePath, dashboardEntryPath);
44
+ this.debug(`Resolved extension path: ${resolved}`);
45
+ return resolved;
46
+ }).filter(x => x != null)) !== null && _a !== void 0 ? _a : [];
47
+ this.info(`Found ${pluginsWithExtensions.length} Dashboard extensions in ${Date.now() - resolveStart}ms`);
48
+ this.debug(`Total dashboard extension loading completed in ${Date.now() - startTime}ms`);
32
49
  return `
33
50
  export async function runDashboardExtensions() {
34
51
  ${pluginsWithExtensions
@@ -1,5 +1,6 @@
1
1
  import { PluginOption } from 'vite';
2
- import { PathAdapter } from './utils/config-loader.js';
2
+ import { PathAdapter } from './types.js';
3
+ import { PackageScannerConfig } from './utils/compiler.js';
3
4
  import { ThemeVariablesPluginOptions } from './vite-plugin-theme.js';
4
5
  import { UiConfigPluginOptions } from './vite-plugin-ui-config.js';
5
6
  /**
@@ -54,7 +55,7 @@ export type VitePluginVendureDashboardOptions = {
54
55
  pathAdapter?: PathAdapter;
55
56
  /**
56
57
  * @description
57
- * The name of the exported variable from the Vendure server configuration file.
58
+ * The name of the exported variable from the Vendure server configuration file, e.g. `config`.
58
59
  * This is only required if the plugin is unable to auto-detect the name of the exported variable.
59
60
  */
60
61
  vendureConfigExport?: string;
@@ -67,12 +68,11 @@ export type VitePluginVendureDashboardOptions = {
67
68
  disableTansStackRouterPlugin?: boolean;
68
69
  /**
69
70
  * @description
70
- * If set to `true`, compilation errors during the build process will be reported and
71
- * the build will fail.
72
- *
73
- * @default false
71
+ * Allows you to customize the location of node_modules & glob patterns used to scan for potential
72
+ * Vendure plugins installed as npm packages. If not provided, the compiler will attempt to guess
73
+ * the location based on the location of the `@vendure/core` package.
74
74
  */
75
- reportCompilationErrors?: boolean;
75
+ pluginPackageScanner?: PackageScannerConfig;
76
76
  } & UiConfigPluginOptions & ThemeVariablesPluginOptions;
77
77
  /**
78
78
  * @description
@@ -47,9 +47,9 @@ export function vendureDashboardPlugin(options) {
47
47
  tailwindcss(),
48
48
  configLoaderPlugin({
49
49
  vendureConfigPath: normalizedVendureConfigPath,
50
- tempDir,
51
- reportCompilationErrors: options.reportCompilationErrors,
50
+ outputPath: tempDir,
52
51
  pathAdapter: options.pathAdapter,
52
+ pluginPackageScanner: options.pluginPackageScanner,
53
53
  }),
54
54
  viteConfigPlugin({ packageRoot }),
55
55
  adminApiSchemaPlugin(),