build: prune packaged runtime node modules (#4020)
This commit is contained in:
parent
0c98b9f29f
commit
819998db04
|
|
@ -4,6 +4,7 @@ const { join, resolve } = require('node:path')
|
|||
const electronBuilderNativeRebuild = require('./scripts/electron-builder-native-rebuild.cjs')
|
||||
const {
|
||||
createPackagedRuntimeNodeModuleResources,
|
||||
prunePackagedRuntimeNodeModules,
|
||||
verifyPackagedMainRuntimeDeps
|
||||
} = require('./packaged-runtime-node-modules.cjs')
|
||||
|
||||
|
|
@ -122,6 +123,7 @@ module.exports = {
|
|||
if (!existsSync(resourcesDir)) {
|
||||
return
|
||||
}
|
||||
prunePackagedRuntimeNodeModules(resourcesDir, context.electronPlatformName)
|
||||
verifyPackagedMainRuntimeDeps(resourcesDir)
|
||||
for (const filename of readdirSync(resourcesDir)) {
|
||||
if (!filename.startsWith('agent-browser-')) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const { existsSync, readFileSync, realpathSync } = require('node:fs')
|
||||
const { existsSync, readFileSync, readdirSync, realpathSync, rmSync } = require('node:fs')
|
||||
const { dirname, join, resolve } = require('node:path')
|
||||
const { builtinModules, createRequire } = require('node:module')
|
||||
|
||||
|
|
@ -19,6 +19,14 @@ const PACKAGED_RUNTIME_PACKAGE_ROOTS = [
|
|||
'zod'
|
||||
]
|
||||
|
||||
const NODE_PTY_PREBUILD_PREFIX_BY_PLATFORM = {
|
||||
darwin: 'darwin-',
|
||||
linux: 'linux-',
|
||||
win32: 'win32-'
|
||||
}
|
||||
const TYPE_DECLARATION_ARTIFACT_RE = /\.d\.(?:c|m)?ts(?:\.map)?$/
|
||||
const VERSIONED_ONNXRUNTIME_DYLIB_RE = /^libonnxruntime\.\d[\d.]*\.dylib$/
|
||||
|
||||
const NODE_BUILTINS = new Set([
|
||||
...builtinModules,
|
||||
...builtinModules.map((moduleName) => `node:${moduleName}`)
|
||||
|
|
@ -150,11 +158,99 @@ function verifyPackagedMainRuntimeDeps(resourcesDir, asar = require('@electron/a
|
|||
}
|
||||
}
|
||||
|
||||
function prunePackagedNodePty(resourcesDir, electronPlatformName) {
|
||||
const nodePtyDir = join(resourcesDir, 'node_modules', 'node-pty')
|
||||
if (!existsSync(nodePtyDir)) {
|
||||
return
|
||||
}
|
||||
|
||||
const allowedPrebuildPrefix = NODE_PTY_PREBUILD_PREFIX_BY_PLATFORM[electronPlatformName]
|
||||
if (allowedPrebuildPrefix) {
|
||||
const prebuildsDir = join(nodePtyDir, 'prebuilds')
|
||||
if (existsSync(prebuildsDir)) {
|
||||
for (const entry of readdirSync(prebuildsDir, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && !entry.name.startsWith(allowedPrebuildPrefix)) {
|
||||
rmSync(join(prebuildsDir, entry.name), { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (electronPlatformName !== 'win32') {
|
||||
// Why: conpty is Windows-only and node-pty resolves runtime binaries from
|
||||
// build/Release or prebuilds/<platform>-<arch>, not third_party/conpty.
|
||||
rmSync(join(nodePtyDir, 'third_party', 'conpty'), { recursive: true, force: true })
|
||||
rmSync(join(nodePtyDir, 'deps', 'winpty'), { recursive: true, force: true })
|
||||
}
|
||||
}
|
||||
|
||||
function prunePackagedRuntimeTypeDeclarations(resourcesDir) {
|
||||
const nodeModulesDir = join(resourcesDir, 'node_modules')
|
||||
if (!existsSync(nodeModulesDir)) {
|
||||
return
|
||||
}
|
||||
pruneMatchingFiles(nodeModulesDir, (filename) => TYPE_DECLARATION_ARTIFACT_RE.test(filename))
|
||||
}
|
||||
|
||||
function prunePackagedSherpaOnnx(resourcesDir, electronPlatformName) {
|
||||
if (electronPlatformName !== 'darwin') {
|
||||
return
|
||||
}
|
||||
const nodeModulesDir = join(resourcesDir, 'node_modules')
|
||||
if (!existsSync(nodeModulesDir)) {
|
||||
return
|
||||
}
|
||||
for (const entry of readdirSync(nodeModulesDir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory() || !entry.name.startsWith('sherpa-onnx-darwin-')) {
|
||||
continue
|
||||
}
|
||||
const packageDir = join(nodeModulesDir, entry.name)
|
||||
const packageEntries = readdirSync(packageDir)
|
||||
const hasVersionedOnnxRuntime = packageEntries.some((filename) =>
|
||||
VERSIONED_ONNXRUNTIME_DYLIB_RE.test(filename)
|
||||
)
|
||||
if (hasVersionedOnnxRuntime) {
|
||||
// Why: darwin sherpa-onnx binaries link to the versioned ONNX Runtime
|
||||
// install name; the unversioned dylib is a duplicate fallback copy.
|
||||
rmSync(join(packageDir, 'libonnxruntime.dylib'), { force: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function prunePackagedZodSources(resourcesDir) {
|
||||
// Why: Zod's src tree is TypeScript source only selected by the @zod/source
|
||||
// condition; packaged runtime import/require paths resolve to built JS.
|
||||
rmSync(join(resourcesDir, 'node_modules', 'zod', 'src'), { recursive: true, force: true })
|
||||
}
|
||||
|
||||
function prunePackagedRuntimeNodeModules(resourcesDir, electronPlatformName) {
|
||||
prunePackagedNodePty(resourcesDir, electronPlatformName)
|
||||
prunePackagedRuntimeTypeDeclarations(resourcesDir)
|
||||
prunePackagedSherpaOnnx(resourcesDir, electronPlatformName)
|
||||
prunePackagedZodSources(resourcesDir)
|
||||
}
|
||||
|
||||
function pruneMatchingFiles(directory, shouldPrune) {
|
||||
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
||||
const entryPath = join(directory, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
pruneMatchingFiles(entryPath, shouldPrune)
|
||||
} else if (entry.isFile() && shouldPrune(entry.name)) {
|
||||
rmSync(entryPath, { force: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PACKAGED_RUNTIME_PACKAGE_ROOTS,
|
||||
createPackagedRuntimeNodeModuleResources,
|
||||
findAsarEntry,
|
||||
isPackagedExternalSpecifier,
|
||||
packageNameFromSpecifier,
|
||||
prunePackagedNodePty,
|
||||
prunePackagedRuntimeNodeModules,
|
||||
prunePackagedSherpaOnnx,
|
||||
prunePackagedRuntimeTypeDeclarations,
|
||||
prunePackagedZodSources,
|
||||
verifyPackagedMainRuntimeDeps
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
||||
import { mkdir, mkdtemp, readdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { createRequire } from 'node:module'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
|
@ -7,7 +7,14 @@ import { describe, expect, it } from 'vitest'
|
|||
const require = createRequire(import.meta.url)
|
||||
const electronBuilderConfig = require('../electron-builder.config.cjs')
|
||||
const electronBuilderNativeRebuild = require('./electron-builder-native-rebuild.cjs')
|
||||
const { findAsarEntry, verifyPackagedMainRuntimeDeps } = require('../packaged-runtime-node-modules.cjs')
|
||||
const {
|
||||
findAsarEntry,
|
||||
prunePackagedNodePty,
|
||||
prunePackagedSherpaOnnx,
|
||||
prunePackagedRuntimeTypeDeclarations,
|
||||
prunePackagedZodSources,
|
||||
verifyPackagedMainRuntimeDeps
|
||||
} = require('../packaged-runtime-node-modules.cjs')
|
||||
|
||||
describe('electron-builder config', () => {
|
||||
it('excludes repo-only source trees from app.asar', () => {
|
||||
|
|
@ -104,4 +111,90 @@ describe('electron-builder config', () => {
|
|||
)
|
||||
expect(findAsarEntry(['/out/main/index.js'], 'out/main/index.js')).toBe('/out/main/index.js')
|
||||
})
|
||||
|
||||
it('prunes non-target node-pty prebuilds from packaged runtime resources', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-node-pty-prune-'))
|
||||
try {
|
||||
const prebuildsDir = join(resourcesDir, 'node_modules', 'node-pty', 'prebuilds')
|
||||
await mkdir(join(prebuildsDir, 'darwin-arm64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'darwin-x64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'linux-x64'), { recursive: true })
|
||||
await mkdir(join(prebuildsDir, 'win32-x64'), { recursive: true })
|
||||
await mkdir(join(resourcesDir, 'node_modules', 'node-pty', 'third_party', 'conpty'), {
|
||||
recursive: true
|
||||
})
|
||||
await mkdir(join(resourcesDir, 'node_modules', 'node-pty', 'deps', 'winpty'), {
|
||||
recursive: true
|
||||
})
|
||||
|
||||
prunePackagedNodePty(resourcesDir, 'darwin')
|
||||
|
||||
await expect(readdir(prebuildsDir).then((entries) => entries.sort())).resolves.toEqual([
|
||||
'darwin-arm64',
|
||||
'darwin-x64'
|
||||
])
|
||||
await expect(
|
||||
readdir(join(resourcesDir, 'node_modules', 'node-pty', 'third_party'))
|
||||
).resolves.toEqual([])
|
||||
await expect(readdir(join(resourcesDir, 'node_modules', 'node-pty', 'deps'))).resolves.toEqual(
|
||||
[]
|
||||
)
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('prunes type declaration artifacts from packaged runtime node_modules', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-runtime-type-prune-'))
|
||||
try {
|
||||
const packageDir = join(resourcesDir, 'node_modules', 'example-package')
|
||||
await mkdir(join(packageDir, 'dist'), { recursive: true })
|
||||
await writeFile(join(packageDir, 'dist', 'index.cjs'), 'module.exports = {}', 'utf8')
|
||||
await writeFile(join(packageDir, 'dist', 'index.d.ts'), 'export type Value = string', 'utf8')
|
||||
await writeFile(join(packageDir, 'dist', 'index.d.cts'), 'export type Value = string', 'utf8')
|
||||
await writeFile(join(packageDir, 'dist', 'index.d.mts.map'), '{}', 'utf8')
|
||||
|
||||
prunePackagedRuntimeTypeDeclarations(resourcesDir)
|
||||
|
||||
await expect(readdir(join(packageDir, 'dist'))).resolves.toEqual(['index.cjs'])
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('prunes duplicate darwin sherpa-onnx runtime dylib aliases', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-sherpa-prune-'))
|
||||
try {
|
||||
const packageDir = join(resourcesDir, 'node_modules', 'sherpa-onnx-darwin-arm64')
|
||||
await mkdir(packageDir, { recursive: true })
|
||||
await writeFile(join(packageDir, 'sherpa-onnx.node'), '', 'utf8')
|
||||
await writeFile(join(packageDir, 'libonnxruntime.1.23.2.dylib'), '', 'utf8')
|
||||
await writeFile(join(packageDir, 'libonnxruntime.dylib'), '', 'utf8')
|
||||
|
||||
prunePackagedSherpaOnnx(resourcesDir, 'darwin')
|
||||
|
||||
await expect(readdir(packageDir).then((entries) => entries.sort())).resolves.toEqual([
|
||||
'libonnxruntime.1.23.2.dylib',
|
||||
'sherpa-onnx.node'
|
||||
])
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('prunes zod TypeScript sources from packaged runtime resources', async () => {
|
||||
const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-zod-prune-'))
|
||||
try {
|
||||
const packageDir = join(resourcesDir, 'node_modules', 'zod')
|
||||
await mkdir(join(packageDir, 'src'), { recursive: true })
|
||||
await writeFile(join(packageDir, 'index.cjs'), 'module.exports = {}', 'utf8')
|
||||
await writeFile(join(packageDir, 'src', 'index.ts'), 'export const value = true', 'utf8')
|
||||
|
||||
prunePackagedZodSources(resourcesDir)
|
||||
|
||||
await expect(readdir(packageDir)).resolves.toEqual(['index.cjs'])
|
||||
} finally {
|
||||
await rm(resourcesDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue