()
| 17 | import { perEnvironmentState } from '../environment' |
| 18 | |
| 19 | export function ssrManifestPlugin(): Plugin { |
| 20 | // module id => preload assets mapping |
| 21 | const getSsrManifest = perEnvironmentState(() => { |
| 22 | return {} as Record<string, string[]> |
| 23 | }) |
| 24 | |
| 25 | return { |
| 26 | name: 'vite:ssr-manifest', |
| 27 | |
| 28 | applyToEnvironment(environment) { |
| 29 | return !!environment.config.build.ssrManifest |
| 30 | }, |
| 31 | |
| 32 | generateBundle(_options, bundle) { |
| 33 | const config = this.environment.config |
| 34 | const ssrManifest = getSsrManifest(this) |
| 35 | const { base } = config |
| 36 | for (const file in bundle) { |
| 37 | const chunk = bundle[file] |
| 38 | if (chunk.type === 'chunk') { |
| 39 | for (const id in chunk.modules) { |
| 40 | const normalizedId = normalizePath(relative(config.root, id)) |
| 41 | const mappedChunks = |
| 42 | ssrManifest[normalizedId] ?? (ssrManifest[normalizedId] = []) |
| 43 | if (!chunk.isEntry) { |
| 44 | mappedChunks.push(joinUrlSegments(base, chunk.fileName)) |
| 45 | // <link> tags for entry chunks are already generated in static HTML, |
| 46 | // so we only need to record info for non-entry chunks. |
| 47 | chunk.viteMetadata!.importedCss.forEach((file) => { |
| 48 | mappedChunks.push(joinUrlSegments(base, file)) |
| 49 | }) |
| 50 | } |
| 51 | chunk.viteMetadata!.importedAssets.forEach((file) => { |
| 52 | mappedChunks.push(joinUrlSegments(base, file)) |
| 53 | }) |
| 54 | } |
| 55 | if (chunk.code.includes(preloadMethod)) { |
| 56 | // generate css deps map |
| 57 | const code = chunk.code |
| 58 | let imports: ImportSpecifier[] = [] |
| 59 | try { |
| 60 | imports = parseImports(code)[0].filter((i) => i.n && i.d > -1) |
| 61 | } catch (_e: unknown) { |
| 62 | const e = _e as EsModuleLexerParseError |
| 63 | const loc = numberToPos(code, e.idx) |
| 64 | this.error({ |
| 65 | name: e.name, |
| 66 | message: e.message, |
| 67 | stack: e.stack, |
| 68 | cause: e.cause, |
| 69 | pos: e.idx, |
| 70 | loc: { ...loc, file: chunk.fileName }, |
| 71 | frame: generateCodeFrame(code, loc), |
| 72 | }) |
| 73 | } |
| 74 | if (imports.length) { |
| 75 | for (let index = 0; index < imports.length; index++) { |
| 76 | const { s: start, e: end, n: name } = imports[index] |
no test coverage detected