mirror of
https://github.com/alex8088/electron-vite.git
synced 2026-11-02 14:51:51 +08:00
176 lines
5.4 KiB
TypeScript
176 lines
5.4 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type */
|
|
import path from 'node:path'
|
|
import fs from 'node:fs'
|
|
import { createHash } from 'node:crypto'
|
|
import { createRequire } from 'node:module'
|
|
import { loadEnv as viteLoadEnv } from 'vite'
|
|
|
|
export function isObject(value: unknown): value is Record<string, unknown> {
|
|
return Object.prototype.toString.call(value) === '[object Object]'
|
|
}
|
|
|
|
export const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000'])
|
|
|
|
export function resolveHostname(optionsHost: string | boolean | undefined): string {
|
|
return typeof optionsHost === 'string' && !wildcardHosts.has(optionsHost) ? optionsHost : 'localhost'
|
|
}
|
|
|
|
export const queryRE = /\?.*$/s
|
|
export const hashRE = /#.*$/s
|
|
|
|
export const cleanUrl = (url: string): string => url.replace(hashRE, '').replace(queryRE, '')
|
|
|
|
export function getHash(text: Buffer | string): string {
|
|
return createHash('sha256')
|
|
.update(text as unknown as Uint8Array)
|
|
.digest('hex')
|
|
.substring(0, 8)
|
|
}
|
|
|
|
export function toRelativePath(filename: string, importer: string): string {
|
|
const relPath = path.posix.relative(path.dirname(importer), filename)
|
|
return relPath.startsWith('.') ? relPath : `./${relPath}`
|
|
}
|
|
|
|
/**
|
|
* Load `.env` files within the `envDir` (default: `process.cwd()`) .
|
|
* By default, only env variables prefixed with `VITE_`, `MAIN_VITE_`, `PRELOAD_VITE_` and
|
|
* `RENDERER_VITE_` are loaded, unless `prefixes` is changed.
|
|
*/
|
|
export function loadEnv(
|
|
mode: string,
|
|
envDir: string = process.cwd(),
|
|
prefixes: string | string[] = ['VITE_', 'MAIN_VITE_', 'PRELOAD_VITE_', 'RENDERER_VITE_']
|
|
): Record<string, string> {
|
|
return viteLoadEnv(mode, envDir, prefixes)
|
|
}
|
|
|
|
interface PackageData {
|
|
main?: string
|
|
type?: 'module' | 'commonjs'
|
|
dependencies?: Record<string, string>
|
|
}
|
|
|
|
let packageCached: PackageData | null = null
|
|
|
|
export function loadPackageData(root = process.cwd()): PackageData | null {
|
|
if (packageCached) return packageCached
|
|
const pkg = path.join(root, 'package.json')
|
|
if (fs.existsSync(pkg)) {
|
|
const _require = createRequire(import.meta.url)
|
|
const data = _require(pkg)
|
|
packageCached = {
|
|
main: data.main,
|
|
type: data.type,
|
|
dependencies: data.dependencies
|
|
}
|
|
return packageCached
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function isFilePathESM(filePath: string): boolean {
|
|
if (/\.m[jt]s$/.test(filePath) || filePath.endsWith('.ts')) {
|
|
return true
|
|
} else if (/\.c[jt]s$/.test(filePath)) {
|
|
return false
|
|
} else {
|
|
const pkg = loadPackageData()
|
|
return pkg?.type === 'module'
|
|
}
|
|
}
|
|
|
|
type DeepWritable<T> =
|
|
T extends ReadonlyArray<unknown>
|
|
? { -readonly [P in keyof T]: DeepWritable<T[P]> }
|
|
: T extends RegExp
|
|
? RegExp
|
|
: T[keyof T] extends Function
|
|
? T
|
|
: { -readonly [P in keyof T]: DeepWritable<T[P]> }
|
|
|
|
export function deepClone<T>(value: T): DeepWritable<T> {
|
|
if (Array.isArray(value)) {
|
|
return value.map(v => deepClone(v)) as DeepWritable<T>
|
|
}
|
|
if (isObject(value)) {
|
|
const cloned: Record<string, any> = {}
|
|
for (const key in value) {
|
|
cloned[key] = deepClone(value[key])
|
|
}
|
|
return cloned as DeepWritable<T>
|
|
}
|
|
if (typeof value === 'function') {
|
|
return value as DeepWritable<T>
|
|
}
|
|
if (value instanceof RegExp) {
|
|
return new RegExp(value) as DeepWritable<T>
|
|
}
|
|
if (typeof value === 'object' && value != null) {
|
|
throw new Error('Cannot deep clone non-plain object')
|
|
}
|
|
return value as DeepWritable<T>
|
|
}
|
|
|
|
/**
|
|
* Isolate configuration data without cloning plugins or runtime instances.
|
|
* Plugins may capture their own object in hooks, so their identity must survive.
|
|
*/
|
|
export function cloneConfig<T>(config: T): T {
|
|
const seen = new WeakMap<object, unknown>()
|
|
const pluginArrays = new WeakMap<object, unknown>()
|
|
|
|
function clone(value: unknown, plugins = false): unknown {
|
|
if (value === null || typeof value !== 'object') return value
|
|
|
|
const cache = plugins ? pluginArrays : seen
|
|
if (cache.has(value)) return cache.get(value)
|
|
|
|
if (Array.isArray(value)) {
|
|
const result: unknown[] = new Array(value.length)
|
|
cache.set(value, result)
|
|
value.forEach((item, index) => {
|
|
result[index] = clone(item, plugins)
|
|
})
|
|
return result
|
|
}
|
|
|
|
// Preserve plugin objects, promises and other opaque plugin options.
|
|
if (plugins) return value
|
|
|
|
if (value instanceof RegExp) {
|
|
const result = new RegExp(value)
|
|
result.lastIndex = value.lastIndex
|
|
cache.set(value, result)
|
|
return result
|
|
}
|
|
|
|
const prototype = Object.getPrototypeOf(value)
|
|
if (prototype !== Object.prototype && prototype !== null) return value
|
|
|
|
const result = Object.create(prototype) as Record<PropertyKey, unknown>
|
|
cache.set(value, result)
|
|
for (const key of Reflect.ownKeys(value)) {
|
|
if (!Object.prototype.propertyIsEnumerable.call(value, key)) continue
|
|
Object.defineProperty(result, key, {
|
|
value: clone((value as Record<PropertyKey, unknown>)[key], key === 'plugins'),
|
|
enumerable: true,
|
|
configurable: true,
|
|
writable: true
|
|
})
|
|
}
|
|
return result
|
|
}
|
|
|
|
return clone(config) as T
|
|
}
|
|
|
|
type AsyncFlatten<T extends unknown[]> = T extends (infer U)[] ? Exclude<Awaited<U>, U[]>[] : never
|
|
|
|
export async function asyncFlatten<T extends unknown[]>(arr: T): Promise<AsyncFlatten<T>> {
|
|
do {
|
|
arr = (await Promise.all(arr)).flat(Infinity) as any
|
|
} while (arr.some((v: any) => v?.then))
|
|
return arr as unknown[] as AsyncFlatten<T>
|
|
}
|