UNPKG

@sveltejs/kit

Version:

SvelteKit is the fastest way to build Svelte apps

139 lines (113 loc) 3.71 kB
import fs from 'node:fs'; import path from 'node:path'; import { normalizePath } from 'vite'; /** * Adds transitive JS and CSS dependencies to the js and css inputs. * @param {import('vite').Manifest} manifest * @param {string} entry * @param {boolean} add_dynamic_css * @returns {import('types').AssetDependencies} */ export function find_deps(manifest, entry, add_dynamic_css) { /** @type {Set<string>} */ const seen = new Set(); /** @type {Set<string>} */ const imports = new Set(); /** @type {Set<string>} */ const stylesheets = new Set(); /** @type {Set<string>} */ const imported_assets = new Set(); /** @type {Map<string, { css: Set<string>; assets: Set<string> }>} */ const stylesheet_map = new Map(); /** * @param {string} current * @param {boolean} add_js * @param {string} initial_importer * @param {number} dynamic_import_depth */ function traverse(current, add_js, initial_importer, dynamic_import_depth) { if (seen.has(current)) return; seen.add(current); const { chunk } = resolve_symlinks(manifest, current); if (add_js) imports.add(chunk.file); if (chunk.assets) { chunk.assets.forEach(asset => imported_assets.add(asset)); } if (chunk.css) { chunk.css.forEach((file) => stylesheets.add(file)); } if (chunk.imports) { chunk.imports.forEach((file) => traverse(file, add_js, initial_importer, dynamic_import_depth)); } if (!add_dynamic_css) return; if ((chunk.css || chunk.assets) && dynamic_import_depth <= 1) { // group files based on the initial importer because if a file is only ever // a transitive dependency, it doesn't have a suitable name we can map back to // the server manifest if (stylesheet_map.has(initial_importer)) { const { css, assets } = /** @type {{ css: Set<string>; assets: Set<string> }} */ (stylesheet_map.get(initial_importer)); if (chunk.css) chunk.css.forEach((file) => css.add(file)); if (chunk.assets) chunk.assets.forEach((file) => assets.add(file)); } else { stylesheet_map.set(initial_importer, { css: new Set(chunk.css), assets: new Set(chunk.assets) }); } } if (chunk.dynamicImports) { dynamic_import_depth++; chunk.dynamicImports.forEach((file) => { traverse(file, false, file, dynamic_import_depth); }); } } const { chunk, file } = resolve_symlinks(manifest, entry); traverse(file, true, entry, 0); const assets = Array.from(imported_assets); return { assets, file: chunk.file, imports: Array.from(imports), stylesheets: Array.from(stylesheets), // TODO do we need this separately? fonts: filter_fonts(assets), stylesheet_map }; } /** * @param {import('vite').Manifest} manifest * @param {string} file */ export function resolve_symlinks(manifest, file) { while (!manifest[file]) { const next = normalizePath(path.relative('.', fs.realpathSync(file))); if (next === file) throw new Error(`Could not find file "${file}" in Vite manifest`); file = next; } const chunk = manifest[file]; return { chunk, file }; } /** * @param {string[]} assets * @returns {string[]} */ export function filter_fonts(assets) { return assets.filter((asset) => /\.(woff2?|ttf|otf)$/.test(asset)); } const method_names = new Set((['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH', 'OPTIONS'])); // If we'd written this in TypeScript, it could be easy... /** * @param {string} str * @returns {str is import('types').HttpMethod} */ export function is_http_method(str) { return method_names.has(str); } /** * @param {import('types').ValidatedKitConfig} config * @returns {string} */ export function assets_base(config) { return (config.paths.assets || config.paths.base || '.') + '/'; }