{"version":3,"file":"admin-vite-optimize-exclude.mjs","sources":["../../../../src/node/core/admin-vite-optimize-exclude.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport readPkgUp from 'read-pkg-up';\n\nimport { ADMIN_VITE_ALIAS_MODULES, ADMIN_VITE_SINGLETON_MODULES } from './admin-vite-alias-modules';\nimport { getModule, type PackageJson } from './dependencies';\nimport type { PluginMeta } from './plugins';\n\nconst REACT_PEER_DEPENDENCIES = new Set(['react', 'react-dom']);\n\n/**\n * Packages explicitly pre-bundled or aliased for the admin singleton contract.\n * Never auto-exclude these — they must stay on the optimizeDeps.include / dedupe path.\n *\n * The admin entry host (@strapi/strapi) must never land in optimizeDeps.exclude (#26944, #27014).\n * CJS-only deps imported by @strapi/admin (e.g. invariant, lodash) belong in optimizeDeps.include\n * (see vite/config.ts — #26964, #26944, #27014).\n * The CodeMirror singletons (e.g. @uiw/react-codemirror — ESM with a React peer) match the\n * exclude heuristic but must stay pre-bundled so the admin keeps a single instance\n */\nconst PINNED_OPTIMIZE_MODULES = new Set<string>([\n  ...ADMIN_VITE_ALIAS_MODULES,\n  ...ADMIN_VITE_SINGLETON_MODULES,\n  '@strapi/strapi',\n]);\n\n/**\n * Thin shared plugin UI kits that are known to break when Vite re-optimizes their pre-built\n * dist (original #26944 victims). Only these names — plus packages that opt in via package.json —\n * may be auto-excluded. Broad heuristic matching alone was too aggressive for large plugins\n * (e.g. CKEditor) and orphaned their transitive CJS/UMD deps (#27136).\n *\n * @internal exported for tests\n */\nexport const ADMIN_VITE_OPTIMIZE_DEPS_EXCLUDE_ALLOWLIST = new Set<string>([\n  'strapi-design-extended',\n]);\n\nconst isOfficialStrapiPackage = (name: string): boolean => name.startsWith('@strapi/');\n\ntype PackageExportEntry =\n  | string\n  | {\n      import?: string;\n      require?: string;\n      default?: string;\n    };\n\nconst getRootPackageExport = (pkg: PackageJson): PackageExportEntry | undefined => {\n  const exportsField = pkg.exports as Record<string, PackageExportEntry> | string | undefined;\n\n  if (!exportsField || typeof exportsField === 'string') {\n    return undefined;\n  }\n\n  return exportsField['.'];\n};\n\n/**\n * @internal exported for tests\n */\nexport const isEsmPackage = (pkg: PackageJson): boolean => {\n  if (pkg.type === 'module') {\n    return true;\n  }\n\n  const rootExport = getRootPackageExport(pkg);\n\n  return (\n    typeof rootExport === 'object' &&\n    rootExport !== null &&\n    'import' in rootExport &&\n    typeof rootExport.import === 'string'\n  );\n};\n\n/**\n * @internal exported for tests\n */\nexport const hasReactPeerDependency = (pkg: PackageJson): boolean =>\n  Object.keys(pkg.peerDependencies ?? {}).some((name) => REACT_PEER_DEPENDENCIES.has(name));\n\n/**\n * Targets libraries that ship a pre-built dist bundle (e.g. plugin UI kits) rather than\n * source packages like react-intl that still benefit from Vite's dep optimizer.\n *\n * @internal exported for tests\n */\nexport const shipsPreBuiltDist = (pkg: PackageJson): boolean => {\n  const rootExport = getRootPackageExport(pkg);\n  const exportImport =\n    typeof rootExport === 'object' && rootExport !== null && 'import' in rootExport\n      ? rootExport.import\n      : undefined;\n\n  const entryPaths = [pkg.module, pkg.main, exportImport].filter(\n    (entry): entry is string => typeof entry === 'string'\n  );\n\n  if (\n    entryPaths.some(\n      (entry) =>\n        entry.includes('/dist/') || entry.startsWith('./dist/') || entry.startsWith('dist/')\n    )\n  ) {\n    return true;\n  }\n\n  return (\n    Array.isArray(pkg.files) &&\n    pkg.files.some((file) => file === 'dist' || file.startsWith('dist/'))\n  );\n};\n\n/**\n * Shape check for packages that *could* be excluded (pre-built ESM + React peer + dist).\n * Matching alone is not enough to exclude — see {@link isEligibleForOptimizeDepsExclude}.\n *\n * @internal exported for tests\n */\nexport const shouldExcludeFromOptimizeDeps = (pkg: PackageJson): boolean =>\n  hasReactPeerDependency(pkg) && isEsmPackage(pkg) && shipsPreBuiltDist(pkg);\n\ntype StrapiAdminViteMeta = {\n  optimizeDepsExclude?: unknown;\n};\n\ntype StrapiPackageMeta = {\n  admin?: {\n    vite?: StrapiAdminViteMeta;\n  };\n};\n\n/**\n * Packages may opt into optimizeDeps.exclude via package.json:\n * `{ \"strapi\": { \"admin\": { \"vite\": { \"optimizeDepsExclude\": true } } } }`\n *\n * @internal exported for tests\n */\nexport const packageOptsIntoOptimizeDepsExclude = (pkg: PackageJson): boolean => {\n  const strapi = (pkg as PackageJson & { strapi?: StrapiPackageMeta }).strapi;\n\n  return strapi?.admin?.vite?.optimizeDepsExclude === true;\n};\n\n/**\n * A candidate is excluded only when it matches the UI-kit shape AND is either on the\n * known-safe allowlist or explicitly opts in. This keeps #26944 working for thin kits\n * without auto-excluding large editor/chart plugins (#27136).\n *\n * @internal exported for tests\n */\nexport const isEligibleForOptimizeDepsExclude = (name: string, pkg: PackageJson): boolean => {\n  if (!shouldExcludeFromOptimizeDeps(pkg)) {\n    return false;\n  }\n\n  return (\n    ADMIN_VITE_OPTIMIZE_DEPS_EXCLUDE_ALLOWLIST.has(name) || packageOptsIntoOptimizeDepsExclude(pkg)\n  );\n};\n\n/**\n * @internal exported for tests\n */\nexport const getPluginPackageName = (modulePath: string): string => {\n  if (modulePath.startsWith('@')) {\n    const [scope, name] = modulePath.split('/');\n\n    return `${scope}/${name}`;\n  }\n\n  return modulePath.split('/')[0] ?? modulePath;\n};\n\nconst collectDependencyNames = (pkg: PackageJson): string[] => {\n  const names = new Set<string>();\n\n  for (const section of [pkg.dependencies, pkg.devDependencies] as const) {\n    if (section) {\n      for (const name of Object.keys(section)) {\n        names.add(name);\n      }\n    }\n  }\n\n  return [...names];\n};\n\nconst getPluginPackageJson = async (\n  plugin: PluginMeta,\n  cwd: string\n): Promise<PackageJson | null> => {\n  if (plugin.type === 'local' && plugin.path) {\n    try {\n      const content = await fs.readFile(path.join(plugin.path, 'package.json'), 'utf8');\n\n      return JSON.parse(content) as PackageJson;\n    } catch {\n      return null;\n    }\n  }\n\n  return getModule(getPluginPackageName(plugin.modulePath), cwd);\n};\n\nconst loadAppPackageJson = async (cwd: string): Promise<PackageJson | null> => {\n  const result = await readPkgUp({ cwd });\n\n  return result?.packageJson ?? null;\n};\n\n/**\n * Pre-built ESM libraries with React peers (shared plugin UI kits) are incompatible with\n * Strapi's React/design-system pre-bundling. Skip dep optimization so they resolve through\n * the admin resolve aliases instead of being re-bundled by Vite.\n *\n * Scans app and plugin dependency trees (#26944). Only allowlisted or opt-in packages that\n * also match the UI-kit shape are excluded (#27136). Official @strapi/* packages and pinned\n * singletons are never auto-excluded — @strapi/strapi matches the heuristic but must stay on\n * the optimizeDeps.include path (#26944, #27014).\n *\n * Apps can still exclude additional packages via `src/admin/vite.config` optimizeDeps.exclude.\n *\n * @internal\n */\nexport const collectAdminOptimizeDepsExclude = async (\n  cwd: string,\n  plugins: PluginMeta[]\n): Promise<string[]> => {\n  const candidateNames = new Set<string>();\n  const appPkg = await loadAppPackageJson(cwd);\n\n  if (appPkg) {\n    for (const name of collectDependencyNames(appPkg)) {\n      candidateNames.add(name);\n    }\n  }\n\n  for (const plugin of plugins) {\n    const pluginPkg = await getPluginPackageJson(plugin, cwd);\n\n    if (pluginPkg) {\n      for (const name of collectDependencyNames(pluginPkg)) {\n        candidateNames.add(name);\n      }\n    }\n  }\n\n  const exclude: string[] = [];\n\n  for (const name of candidateNames) {\n    if (PINNED_OPTIMIZE_MODULES.has(name) || isOfficialStrapiPackage(name)) {\n      continue;\n    }\n\n    const pkg = await getModule(name, cwd);\n\n    if (pkg && isEligibleForOptimizeDepsExclude(name, pkg)) {\n      exclude.push(name);\n    }\n  }\n\n  return exclude.sort();\n};\n"],"names":["REACT_PEER_DEPENDENCIES","Set","PINNED_OPTIMIZE_MODULES","ADMIN_VITE_ALIAS_MODULES","ADMIN_VITE_SINGLETON_MODULES","ADMIN_VITE_OPTIMIZE_DEPS_EXCLUDE_ALLOWLIST","isOfficialStrapiPackage","name","startsWith","getRootPackageExport","pkg","exportsField","exports","undefined","isEsmPackage","type","rootExport","import","hasReactPeerDependency","Object","keys","peerDependencies","some","has","shipsPreBuiltDist","exportImport","entryPaths","module","main","filter","entry","includes","Array","isArray","files","file","shouldExcludeFromOptimizeDeps","packageOptsIntoOptimizeDepsExclude","strapi","admin","vite","optimizeDepsExclude","isEligibleForOptimizeDepsExclude","getPluginPackageName","modulePath","scope","split","collectDependencyNames","names","section","dependencies","devDependencies","add","getPluginPackageJson","plugin","cwd","path","content","fs","readFile","join","JSON","parse","getModule","loadAppPackageJson","result","readPkgUp","packageJson","collectAdminOptimizeDepsExclude","plugins","candidateNames","appPkg","pluginPkg","exclude","push","sort"],"mappings":"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"}