UNPKG

@sveltejs/kit

Version:

SvelteKit is the fastest way to build Svelte apps

163 lines (135 loc) 4.52 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)); } /** * @param {import('types').ValidatedKitConfig} config * @returns {string} */ export function assets_base(config) { return (config.paths.assets || config.paths.base || '.') + '/'; } /** * Writes a function with arguments used by a template literal. * This helps us store strings in a module and inject values at runtime. * @param {string} name The name of the function * @param {string[]} placeholder_names The names of the placeholders in the string * @param {string} str A string with placeholders such as "Hello ${arg0}". * It must have backslashes, backticks and dollar signs already escaped. * @returns {string} The function written as a string */ export function create_function_as_string(name, placeholder_names, str) { const args = placeholder_names ? placeholder_names.join(', ') : ''; return `function ${name}(${args}) { return \`${str}\`; }`; } /** * Guarantees that the generated placeholder is not already present in the content. * @param {string} content * @param {string} key * @returns {string} */ export function generate_placeholder(content, key) { let id = 1; let placeholder = `__SVELTEKIT_${key}_${id}__`; while (content.includes(placeholder)) { placeholder = `__SVELTEKIT_${key}_${++id}__`; } return placeholder; }