Urara-Blog/node_modules/.pnpm-store/v3/files/4d/81fac9b1c35d3b237a5d2072f62077ea7493df4c83a4a89470a54c833442df35bd654f11940845d78cd71ecbd0b6013e5d3a64aecde06229db04d938ead53c
2022-08-14 01:14:53 +08:00

241 lines
6.6 KiB
Text

import { log } from './log';
import path from 'path';
import fs from 'fs';
import { createRequire } from 'module';
export function findRootSvelteDependencies(root: string, cwdFallback = true): SvelteDependency[] {
log.debug(`findSvelteDependencies: searching svelte dependencies in ${root}`);
const pkgFile = path.join(root, 'package.json');
if (!fs.existsSync(pkgFile)) {
if (cwdFallback) {
const cwd = process.cwd();
if (root !== cwd) {
log.debug(`no package.json found in vite root ${root}`);
return findRootSvelteDependencies(cwd, false);
}
}
log.warn(`no package.json found, findRootSvelteDependencies failed`);
return [];
}
const pkg = parsePkg(root);
if (!pkg) {
return [];
}
const deps = [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.devDependencies || {})
].filter((dep) => !is_common_without_svelte_field(dep));
return getSvelteDependencies(deps, root);
}
function getSvelteDependencies(
deps: string[],
pkgDir: string,
path: string[] = []
): SvelteDependency[] {
const result = [];
const localRequire = createRequire(`${pkgDir}/package.json`);
const resolvedDeps = deps
.map((dep) => resolveDependencyData(dep, localRequire))
.filter(Boolean) as DependencyData[];
for (const { pkg, dir } of resolvedDeps) {
const type = getSvelteDependencyType(pkg);
if (!type) continue;
result.push({ name: pkg.name, type, pkg, dir, path });
// continue crawling for component libraries so we can optimize them, js libraries are fine
if (type === 'component-library' && pkg.dependencies) {
let dependencyNames = Object.keys(pkg.dependencies);
const circular = dependencyNames.filter((name) => path.includes(name));
if (circular.length > 0) {
log.warn.enabled &&
log.warn(
`skipping circular svelte dependencies in automated vite optimizeDeps handling`,
circular.map((x) => path.concat(x).join('>'))
);
dependencyNames = dependencyNames.filter((name) => !path.includes(name));
}
if (path.length === 3) {
log.debug.once(`encountered deep svelte dependency tree: ${path.join('>')}`);
}
result.push(...getSvelteDependencies(dependencyNames, dir, path.concat(pkg.name)));
}
}
return result;
}
export function resolveDependencyData(
dep: string,
localRequire: NodeRequire
): DependencyData | void {
try {
const pkgJson = `${dep}/package.json`;
const pkg = localRequire(pkgJson);
const dir = path.dirname(localRequire.resolve(pkgJson));
return { dir, pkg };
} catch (e) {
log.debug.once(`dependency ${dep} does not export package.json`, e);
// walk up from default export until we find package.json with name=dep
try {
let dir = path.dirname(localRequire.resolve(dep));
while (dir) {
const pkg = parsePkg(dir, true);
if (pkg && pkg.name === dep) {
return { dir, pkg };
}
const parent = path.dirname(dir);
if (parent === dir) {
break;
}
dir = parent;
}
} catch (e) {
log.debug.once(`error while trying to find package.json of ${dep}`, e);
}
}
log.debug.once(`failed to resolve ${dep}`);
}
function parsePkg(dir: string, silent = false): Pkg | void {
const pkgFile = path.join(dir, 'package.json');
try {
return JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
} catch (e) {
!silent && log.warn.enabled && log.warn(`failed to parse ${pkgFile}`, e);
}
}
function getSvelteDependencyType(pkg: Pkg): SvelteDependencyType | undefined {
if (isSvelteComponentLib(pkg)) {
return 'component-library';
} else if (isSvelteLib(pkg)) {
return 'js-library';
} else {
return undefined;
}
}
function isSvelteComponentLib(pkg: Pkg) {
return !!pkg.svelte;
}
function isSvelteLib(pkg: Pkg) {
return !!pkg.dependencies?.svelte || !!pkg.peerDependencies?.svelte;
}
const COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD = [
'@lukeed/uuid',
'@playwright/test',
'@sveltejs/vite-plugin-svelte',
'@sveltejs/kit',
'autoprefixer',
'cookie',
'dotenv',
'esbuild',
'eslint',
'jest',
'mdsvex',
'playwright',
'postcss',
'prettier',
'svelte',
'svelte-check',
'svelte-hmr',
'svelte-preprocess',
'tslib',
'typescript',
'vite',
'vitest',
'__vite-browser-external' // see https://github.com/sveltejs/vite-plugin-svelte/issues/362
];
const COMMON_PREFIXES_WITHOUT_SVELTE_FIELD = [
'@fontsource/',
'@postcss-plugins/',
'@rollup/',
'@sveltejs/adapter-',
'@types/',
'@typescript-eslint/',
'eslint-',
'jest-',
'postcss-plugin-',
'prettier-plugin-',
'rollup-plugin-',
'vite-plugin-'
];
/**
* Test for common dependency names that tell us it is not a package including a svelte field, eg. eslint + plugins.
*
* This speeds up the find process as we don't have to try and require the package.json for all of them
*
* @param dependency {string}
* @returns {boolean} true if it is a dependency without a svelte field
*/
export function is_common_without_svelte_field(dependency: string): boolean {
return (
COMMON_DEPENDENCIES_WITHOUT_SVELTE_FIELD.includes(dependency) ||
COMMON_PREFIXES_WITHOUT_SVELTE_FIELD.some(
(prefix) =>
prefix.startsWith('@')
? dependency.startsWith(prefix)
: dependency.substring(dependency.lastIndexOf('/') + 1).startsWith(prefix) // check prefix omitting @scope/
)
);
}
export function needsOptimization(dep: string, localRequire: NodeRequire): boolean {
const depData = resolveDependencyData(dep, localRequire);
if (!depData) return false;
const pkg = depData.pkg;
// only optimize if is cjs, using the below as heuristic
// see https://github.com/sveltejs/vite-plugin-svelte/issues/162
const hasEsmFields = pkg.module || pkg.exports;
if (hasEsmFields) return false;
if (pkg.main) {
// ensure entry is js so vite can prebundle it
// see https://github.com/sveltejs/vite-plugin-svelte/issues/233
const entryExt = path.extname(pkg.main);
return !entryExt || entryExt === '.js' || entryExt === '.cjs';
} else {
// check if has implicit index.js entrypoint
// https://github.com/sveltejs/vite-plugin-svelte/issues/281
try {
localRequire.resolve(`${dep}/index.js`);
return true;
} catch {
return false;
}
}
}
interface DependencyData {
dir: string;
pkg: Pkg;
}
export interface SvelteDependency {
name: string;
type: SvelteDependencyType;
dir: string;
pkg: Pkg;
path: string[];
}
// component-library => exports svelte components
// js-library => only uses svelte api, no components
export type SvelteDependencyType = 'component-library' | 'js-library';
export interface Pkg {
name: string;
svelte?: string;
dependencies?: DependencyList;
devDependencies?: DependencyList;
peerDependencies?: DependencyList;
[key: string]: any;
}
export interface DependencyList {
[key: string]: string;
}