vite-plugin-config-loader.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { Plugin } from 'vite';
  2. import { compile, CompileResult, CompilerOptions } from './utils/compiler.js';
  3. import { debugLogger } from './utils/logger.js';
  4. export interface ConfigLoaderApi {
  5. getVendureConfig(): Promise<CompileResult>;
  6. }
  7. export const configLoaderName = 'vendure:config-loader';
  8. /**
  9. * This Vite plugin loads the VendureConfig from the specified file path, and
  10. * makes it available to other plugins via the `ConfigLoaderApi`.
  11. */
  12. export function configLoaderPlugin(options: CompilerOptions): Plugin {
  13. let result: CompileResult;
  14. const onConfigLoaded: Array<() => void> = [];
  15. return {
  16. name: configLoaderName,
  17. async buildStart() {
  18. this.info(
  19. `Loading Vendure config. This can take a short while depending on the size of your project...`,
  20. );
  21. try {
  22. const startTime = Date.now();
  23. result = await compile({
  24. ...options,
  25. logger: process.env.LOG
  26. ? debugLogger
  27. : {
  28. info: (message: string) => this.info(message),
  29. warn: (message: string) => this.warn(message),
  30. debug: (message: string) => this.debug(message),
  31. error: (message: string) => this.error(message),
  32. },
  33. });
  34. const endTime = Date.now();
  35. const duration = endTime - startTime;
  36. const pluginNames = result.pluginInfo
  37. .map(p => `${p.name} ${p.sourcePluginPath ? '(local)' : '(npm)'}`)
  38. .join(', ');
  39. this.info(`Found ${result.pluginInfo.length} plugins: ${pluginNames}`);
  40. this.info(
  41. `Vendure config loaded (using export "${result.exportedSymbolName}") in ${duration}ms`,
  42. );
  43. } catch (e: unknown) {
  44. if (e instanceof Error) {
  45. const message = [
  46. e.message,
  47. `If you are using a monorepo, you may need to provide a custom pathAdapter to resolve the paths correctly.`,
  48. ].join('\n');
  49. this.error(`Error loading Vendure config: ${message}`);
  50. }
  51. }
  52. onConfigLoaded.forEach(fn => fn());
  53. },
  54. api: {
  55. getVendureConfig(): Promise<CompileResult> {
  56. if (result) {
  57. return Promise.resolve(result);
  58. } else {
  59. return new Promise<CompileResult>(resolve => {
  60. onConfigLoaded.push(() => {
  61. resolve(result);
  62. });
  63. });
  64. }
  65. },
  66. } satisfies ConfigLoaderApi,
  67. };
  68. }
  69. /**
  70. * Inter-plugin dependencies implemented following the pattern given here:
  71. * https://rollupjs.org/plugin-development/#direct-plugin-communication
  72. */
  73. export function getConfigLoaderApi(plugins: readonly Plugin[]): ConfigLoaderApi {
  74. const parentPlugin = plugins.find(plugin => plugin.name === configLoaderName);
  75. if (!parentPlugin) {
  76. throw new Error(`This plugin depends on the "${configLoaderName}" plugin.`);
  77. }
  78. return parentPlugin.api as ConfigLoaderApi;
  79. }