first commit
This commit is contained in:
268
node_modules/vitefu/src/index.js
generated
vendored
Normal file
268
node_modules/vitefu/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import fsSync from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import {
|
||||
isDepIncluded,
|
||||
isDepExcluded,
|
||||
isDepNoExternaled,
|
||||
isDepExternaled
|
||||
} from './sync.cjs'
|
||||
|
||||
/** @type {import('pnpapi')} */
|
||||
let pnp
|
||||
if (process.versions.pnp) {
|
||||
try {
|
||||
pnp = createRequire(import.meta.url)('pnpapi')
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export { isDepIncluded, isDepExcluded, isDepNoExternaled, isDepExternaled }
|
||||
|
||||
/** @type {import('./index.d.ts').crawlFrameworkPkgs} */
|
||||
export async function crawlFrameworkPkgs(options) {
|
||||
const pkgJsonPath = await findClosestPkgJsonPath(options.root)
|
||||
if (!pkgJsonPath) {
|
||||
// don't throw as package.json is not required
|
||||
return {
|
||||
optimizeDeps: { include: [], exclude: [] },
|
||||
ssr: { noExternal: [], external: [] }
|
||||
}
|
||||
}
|
||||
const pkgJson = await readJson(pkgJsonPath).catch((e) => {
|
||||
throw new Error(`Unable to read ${pkgJsonPath}`, { cause: e })
|
||||
})
|
||||
|
||||
/** @type {string[]} */
|
||||
let optimizeDepsInclude = []
|
||||
/** @type {string[]} */
|
||||
let optimizeDepsExclude = []
|
||||
/** @type {string[]} */
|
||||
let ssrNoExternal = []
|
||||
/** @type {string[]} */
|
||||
let ssrExternal = []
|
||||
|
||||
await crawl(pkgJsonPath, pkgJson)
|
||||
|
||||
// respect vite user config
|
||||
if (options.viteUserConfig) {
|
||||
// remove includes that are explicitly excluded in optimizeDeps
|
||||
const _optimizeDepsExclude = options.viteUserConfig?.optimizeDeps?.exclude
|
||||
if (_optimizeDepsExclude) {
|
||||
optimizeDepsInclude = optimizeDepsInclude.filter(
|
||||
(dep) => !isDepExcluded(dep, _optimizeDepsExclude)
|
||||
)
|
||||
}
|
||||
// remove excludes that are explicitly included in optimizeDeps
|
||||
const _optimizeDepsInclude = options.viteUserConfig?.optimizeDeps?.include
|
||||
if (_optimizeDepsInclude) {
|
||||
optimizeDepsExclude = optimizeDepsExclude.filter(
|
||||
(dep) => !isDepIncluded(dep, _optimizeDepsInclude)
|
||||
)
|
||||
}
|
||||
// remove noExternals that are explicitly externalized
|
||||
const _ssrExternal = options.viteUserConfig?.ssr?.external
|
||||
if (_ssrExternal) {
|
||||
ssrNoExternal = ssrNoExternal.filter(
|
||||
(dep) => !isDepExternaled(dep, _ssrExternal)
|
||||
)
|
||||
}
|
||||
// remove externals that are explicitly noExternal
|
||||
const _ssrNoExternal = options.viteUserConfig?.ssr?.noExternal
|
||||
if (_ssrNoExternal) {
|
||||
ssrExternal = ssrExternal.filter(
|
||||
(dep) => !isDepNoExternaled(dep, _ssrNoExternal)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
optimizeDeps: {
|
||||
include: optimizeDepsInclude,
|
||||
exclude: optimizeDepsExclude
|
||||
},
|
||||
ssr: {
|
||||
noExternal: ssrNoExternal,
|
||||
external: ssrExternal
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* crawl the package.json dependencies for framework packages. rules:
|
||||
* 1. a framework package should be `optimizeDeps.exclude` and `ssr.noExternal`.
|
||||
* 2. the deps of the framework package should be `optimizeDeps.include` and `ssr.external`
|
||||
* unless the dep is also a framework package, in which case do no1 & no2 recursively.
|
||||
* 3. any non-framework packages that aren't imported by a framework package can be skipped entirely.
|
||||
* 4. a semi-framework package is like a framework package, except it isn't `optimizeDeps.exclude`,
|
||||
* but only applies `ssr.noExternal`.
|
||||
* @param {string} pkgJsonPath
|
||||
* @param {Record<string, any>} pkgJson
|
||||
* @param {string[]} [parentDepNames]
|
||||
*/
|
||||
async function crawl(pkgJsonPath, pkgJson, parentDepNames = []) {
|
||||
const isRoot = parentDepNames.length === 0
|
||||
|
||||
/** @type {string[]} */
|
||||
let deps = [
|
||||
...Object.keys(pkgJson.dependencies || {}),
|
||||
...(isRoot ? Object.keys(pkgJson.devDependencies || {}) : [])
|
||||
]
|
||||
|
||||
deps = deps.filter((dep) => {
|
||||
// skip circular deps
|
||||
if (parentDepNames.includes(dep)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const isFrameworkPkg = options.isFrameworkPkgByName?.(dep)
|
||||
const isSemiFrameworkPkg = options.isSemiFrameworkPkgByName?.(dep)
|
||||
if (isFrameworkPkg) {
|
||||
// framework packages should be excluded from optimization as esbuild can't handle them.
|
||||
// otherwise it'll cause https://github.com/vitejs/vite/issues/3910
|
||||
optimizeDepsExclude.push(dep)
|
||||
// framework packages should be noExternal so that they go through vite's transformation
|
||||
// pipeline, since nodejs can't support them.
|
||||
ssrNoExternal.push(dep)
|
||||
} else if (isSemiFrameworkPkg) {
|
||||
// semi-framework packages should do the same except for optimization exclude as they
|
||||
// aren't needed to work (they don't contain raw framework components)
|
||||
ssrNoExternal.push(dep)
|
||||
}
|
||||
|
||||
// only those that are explictly false can skip crawling since we don't need to do anything
|
||||
// special for them
|
||||
if (isFrameworkPkg === false || isSemiFrameworkPkg === false) {
|
||||
return false
|
||||
}
|
||||
// if `true`, we need to crawl the nested deps to deep include and ssr externalize them in dev.
|
||||
// if `undefined`, it's the same as "i don't know". we need to crawl and find the package.json
|
||||
// to find out.
|
||||
else {
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
const promises = deps.map(async (dep) => {
|
||||
const depPkgJsonPath = await findDepPkgJsonPath(dep, pkgJsonPath)
|
||||
if (!depPkgJsonPath) return
|
||||
const depPkgJson = await readJson(depPkgJsonPath).catch(() => {})
|
||||
if (!depPkgJson) return
|
||||
|
||||
// fast path if this dep is already a framework dep based on the filter condition above
|
||||
const cachedIsFrameworkPkg = ssrNoExternal.includes(dep)
|
||||
if (cachedIsFrameworkPkg) {
|
||||
return crawl(depPkgJsonPath, depPkgJson, parentDepNames.concat(dep))
|
||||
}
|
||||
|
||||
// check if this dep is a framework dep, if so, track and crawl it
|
||||
const isFrameworkPkg = options.isFrameworkPkgByJson?.(depPkgJson)
|
||||
const isSemiFrameworkPkg = options.isSemiFrameworkPkgByJson?.(depPkgJson)
|
||||
if (isFrameworkPkg || isSemiFrameworkPkg) {
|
||||
// see explanation in filter condition above
|
||||
if (isFrameworkPkg) {
|
||||
optimizeDepsExclude.push(dep)
|
||||
ssrNoExternal.push(dep)
|
||||
} else if (isSemiFrameworkPkg) {
|
||||
ssrNoExternal.push(dep)
|
||||
}
|
||||
return crawl(depPkgJsonPath, depPkgJson, parentDepNames.concat(dep))
|
||||
}
|
||||
|
||||
// if we're crawling in a non-root state, the parent is 100% a framework package
|
||||
// because of the above if block. in this case, if it's dep of a non-framework
|
||||
// package, handle special cases for them.
|
||||
if (!isRoot) {
|
||||
// deep include it if it's a CJS package, so it becomes ESM and vite is happy.
|
||||
if (await pkgNeedsOptimization(depPkgJson, depPkgJsonPath)) {
|
||||
optimizeDepsInclude.push(parentDepNames.concat(dep).join(' > '))
|
||||
}
|
||||
// also externalize it in dev so it doesn't trip vite's SSR transformation.
|
||||
// we do in dev only as build cannot access deep external packages in strict
|
||||
// dependency installations, such as pnpm.
|
||||
if (!options.isBuild && !ssrExternal.includes(dep)) {
|
||||
ssrExternal.push(dep)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all(promises)
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('./index.d.ts').findDepPkgJsonPath} */
|
||||
export async function findDepPkgJsonPath(dep, parent) {
|
||||
if (pnp) {
|
||||
try {
|
||||
const depRoot = pnp.resolveToUnqualified(dep, parent)
|
||||
if (!depRoot) return undefined
|
||||
return path.join(depRoot, 'package.json')
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
let root = parent
|
||||
while (root) {
|
||||
const pkg = path.join(root, 'node_modules', dep, 'package.json')
|
||||
try {
|
||||
await fs.access(pkg)
|
||||
// use 'node:fs' version to match 'vite:resolve' and avoid realpath.native quirk
|
||||
// https://github.com/sveltejs/vite-plugin-svelte/issues/525#issuecomment-1355551264
|
||||
return fsSync.realpathSync(pkg)
|
||||
} catch {}
|
||||
const nextRoot = path.dirname(root)
|
||||
if (nextRoot === root) break
|
||||
root = nextRoot
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/** @type {import('./index.d.ts').findClosestPkgJsonPath} */
|
||||
export async function findClosestPkgJsonPath(dir, predicate = undefined) {
|
||||
if (dir.endsWith('package.json')) {
|
||||
dir = path.dirname(dir)
|
||||
}
|
||||
while (dir) {
|
||||
const pkg = path.join(dir, 'package.json')
|
||||
try {
|
||||
const stat = await fs.stat(pkg)
|
||||
if (stat.isFile() && (!predicate || (await predicate(pkg)))) {
|
||||
return pkg
|
||||
}
|
||||
} catch {}
|
||||
const nextDir = path.dirname(dir)
|
||||
if (nextDir === dir) break
|
||||
dir = nextDir
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/** @type {import('./index.d.ts').pkgNeedsOptimization} */
|
||||
export async function pkgNeedsOptimization(pkgJson, pkgJsonPath) {
|
||||
// only optimize if is cjs, using the below as heuristic
|
||||
// see https://github.com/sveltejs/vite-plugin-svelte/issues/162
|
||||
if (pkgJson.module || pkgJson.exports) return false
|
||||
// if have main, ensure entry is js so vite can prebundle it
|
||||
// see https://github.com/sveltejs/vite-plugin-svelte/issues/233
|
||||
if (pkgJson.main) {
|
||||
const entryExt = path.extname(pkgJson.main)
|
||||
return !entryExt || entryExt === '.js' || entryExt === '.cjs'
|
||||
}
|
||||
// check if has implicit index.js entrypoint to prebundle
|
||||
// see https://github.com/sveltejs/vite-plugin-svelte/issues/281
|
||||
// see https://github.com/solidjs/vite-plugin-solid/issues/70#issuecomment-1306488154
|
||||
try {
|
||||
await fs.access(path.join(path.dirname(pkgJsonPath), 'index.js'))
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} findDepPkgJsonPath
|
||||
* @returns {Promise<Record<string, any>>}
|
||||
*/
|
||||
async function readJson(findDepPkgJsonPath) {
|
||||
return JSON.parse(await fs.readFile(findDepPkgJsonPath, 'utf8'))
|
||||
}
|
Reference in New Issue
Block a user