Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ImportAnalysisPluginAPI interface #19137

Closed
wants to merge 1 commit into from

Conversation

aleclarson
Copy link
Member

@aleclarson aleclarson commented Jan 5, 2025

Description

Add an api object to the vite:import-analysis internal plugin.

Motivation: Allow plugins to selectively inspect imports/exports of modules without requiring each plugin to repeat the same work that vite:import-analysis has already performed.

Example usage

import { ImportAnalysisCache, ImportAnalysisPluginAPI, Plugin } from 'vite'

export default function samplePlugin(): Plugin {
  let importAnalysisCache: ImportAnalysisCache

  return {
    name: 'sample-plugin',
    configResolved(config) {
      const importAnalysisAPI = config.plugins.find(
        p => p.name === 'vite:import-analysis'
      )?.api as ImportAnalysisPluginAPI

      if (!importAnalysisAPI) {
        throw new Error('vite:import-analysis plugin API is required')
      }

      importAnalysisCache =
        importAnalysisAPI.getImportAnalysisCache('**/*.tsx')
    },
    transform(code, id) {
      if (!id.endsWith('.tsx')) return

      const imports = importAnalysisCache.getImports(id)
      const exports = importAnalysisCache.getExports(id)

      console.log('transform:', {
        id,
        imports,
        exports,
      })
    },
  }
}

The API

export type ImportAnalysisListener = (
  id: string,
  imports: readonly Readonly<ImportSpecifier>[],
  exports: readonly Readonly<ExportSpecifier>[],
) => void


export interface ImportAnalysisPluginAPI {
  /**
   * Add a listener for import analysis events. Returns a function that can be used to remove the
   * listener. If no filter pattern is provided, the listener will be called for all modules capable
   * of having imports and exports.
   */
  addImportAnalysisListener(
    filter: FilterPattern | null | undefined,
    listener: ImportAnalysisListener,
  ): () => void
  addImportAnalysisListener(listener: ImportAnalysisListener): () => void
  /**
   * Get a cache of imports and exports for all modules that match the filter. If no filter is
   * provided, the cache will include all modules capable of having imports and exports.
   */
  getImportAnalysisCache(filter?: FilterPattern): ImportAnalysisCache
}


export interface ImportAnalysisCache {
  getImports(id: string): readonly Readonly<ImportSpecifier>[]
  getExports(id: string): readonly Readonly<ExportSpecifier>[]
  /**
   * Clear the cache. This is called automatically in the `buildStart` hook of the
   * `vite:import-analysis` plugin.
   */
  clear(): void
  /**
   * Stop listening to import analysis events and dispose of the cache.
   *
   * You can call this function to avoid memory leaks once you are done using the cache.
   * Alternatively, you can call `clear()` in the `buildEnd` hook of your plugin if you want to
   * reuse the cache instance in the next build. Calling `clear()` will release memory while Vite is
   * waiting to trigger the next build.
   */
  dispose(): void
}

Current status

As of now, this is just a proof of concept. No tests (though I manually tested it to ensure it works). Not sure if there are enough use cases to warrant adding it or not.

Downsides

The ImportSpecifier and ExportSpecifier types have "minified" property names, making them not very readable. Mapping those objects to ones with expanded property names would likely not be worth the GC/CPU cost?

@aleclarson
Copy link
Member Author

I'm gonna close this. Since other plugins may add/alter the imports/exports of a module, it's not particularly useful to have access to the vite:import-analysis parse results. There might be a use case in there somewhere, but not prominent enough to warrant this additional complexity.

@aleclarson aleclarson closed this Jan 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants