Repository: vitejs/vite
File: packages/vite/src/node/plugins/css.ts (TypeScript)

Code before:
  map?: ExistingRawSourceMap | undefined
  additionalMap?: ExistingRawSourceMap | undefined
  error?: RollupError
  deps: string[]
}

const loadedPreprocessorPath: Partial<
  Record<
    PreprocessLang | PostCssDialectLang | 'sass-embedded',
    string | Promise<string>
  >
> = {}
let nodeResolveWithVite: NodeResolveWithViteFn | undefined

async function loadPreprocessorPath(
  lang: PreprocessLang | PostCssDialectLang | 'sass-embedded',
  root: string,
): Promise<string> {
  const cached = loadedPreprocessorPath[lang]
  if (cached) {
    return cached
  }
  loadedPreprocessorPath[lang] = (async () => {
    nodeResolveWithVite ??= await createNodeResolverWithVite(root)
    const resolved = nodeResolveWithVite(lang, path.join(root, '*'))
    if (resolved) return resolved

    const installCommand = getPackageManagerCommand('install')
    throw new Error(
      `Preprocessor dependency "${lang}" not found. Did you install it? Try \`${installCommand} -D ${lang}\`.`,
    )
  })()

  loadedPreprocessorPath[lang]
    // Set the result directly to avoid needing to resolve the promise again
    .then((p) => (loadedPreprocessorPath[lang] = p))
    // Set undefined so next retry work if the package is installed later
    .catch(() => (loadedPreprocessorPath[lang] = undefined))

  return loadedPreprocessorPath[lang]
}

async function loadSassPackage(root: string): Promise<{
  name: 'sass' | 'sass-embedded'
  path: string
}> {
  // try sass-embedded before sass
  try {
    const path = await loadPreprocessorPath('sass-embedded', root)
    return { name: 'sass-embedded', path }
  } catch (e1) {

Review comment (bug):
This only tries to resolve from `root`, but `requireResolveFromRootWithFallback` resolves from `__dirname` if failed. IIRC we need to keep the fallback for some cases covered by ecosystem-ci.

Code after:
  additionalMap?: ExistingRawSourceMap | undefined
  error?: RollupError
  deps: string[]
}

const loadedPreprocessorPath: Partial<
  Record<PreprocessLang | PostCssDialectLang | 'sass-embedded', string>
> = {}

function loadPreprocessorPath(
  lang: PreprocessLang | PostCssDialectLang | 'sass-embedded',
  root: string,
): string {
  const cached = loadedPreprocessorPath[lang]
  if (cached) {
    return cached
  }

  // Try resolve from project root first, then the current vite installation path
  const resolved =
    nodeResolveWithVite(lang, undefined, { root }) ??
    nodeResolveWithVite(lang, _dirname, { root })
  if (resolved) return (loadedPreprocessorPath[lang] = resolved)

  // Error if we can't find the preprocessor
  const installCommand = getPackageManagerCommand('install')
  throw new Error(
    `Preprocessor dependency "${lang}" not found. Did you install it? Try \`${installCommand} -D ${lang}\`.`,
  )
}

function loadSassPackage(root: string): {
  name: 'sass' | 'sass-embedded'
  path: string
} {
  // try sass-embedded before sass
  try {
    const path = loadPreprocessorPath('sass-embedded', root)
    return { name: 'sass-embedded', path }
  } catch (e1) {
    try {
      const path = loadPreprocessorPath(PreprocessLang.sass, root)
      return { name: 'sass', path }
    } catch {
      throw e1
    }
  }
}

let cachedSss: PostCSS.Syntax | Promise<PostCSS.Syntax>
async function loadSss(root: string): Promise<PostCSS.Syntax> {