Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/vxrn/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
"watch": "yarn build --watch",
"check": "yarn depcheck",
"clean": "tamagui-build clean",
"clean:build": "tamagui-build clean:build"
"clean:build": "tamagui-build clean:build",
"test": "yarn test:deps-patching",
"test:deps-patching": "./run-tests.sh"
},
"dependencies": {
"@expo/config-plugins": "^8.0.8",
Expand Down
10 changes: 10 additions & 0 deletions packages/vxrn/run-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Get the directory where the script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

# Navigate to the utils directory where test-runner.js is located
cd "$SCRIPT_DIR/src/utils" || exit 1

# Execute the test runner using Node.js
node test-runner.js
113 changes: 80 additions & 33 deletions packages/vxrn/src/utils/patches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,45 @@ export async function applyOptimizePatches(patches: DepPatch[], config: UserConf
deepMergeOptimizeDeps(config.ssr!, { optimizeDeps }, undefined, true)
}

// --- HACK! ---
// These originally lives inside applyDependencyPatches
// but we can't be sure that `applyDependencyPatches` will only be called
// once, at least one is calling applyDependencyPatches directly, in fixDependenciesPlugin.ts
/**
* Determine if a file has already been patched by a previous run.
*
* We need this to be cached not only for performance but also for the
* fact that we may patch the same file multiple times but the "ogfile"
* will be created during the first patching.
*/
const getIsAlreadyPatched = (fullFilePath: string) => {
if (_isAlreadyPatchedMap.has(fullFilePath)) {
return _isAlreadyPatchedMap.get(fullFilePath)
}
const isAlreadyPatched = FSExtra.existsSync(getOgFilePath(fullFilePath))
_isAlreadyPatchedMap.set(fullFilePath, isAlreadyPatched)
return isAlreadyPatched
}
export const _isAlreadyPatchedMap = new Map<string, boolean>()

/**
* A set of full paths to files that have been patched during the
* current run.
*/
export const pathsBeingPatched = new Set<string>()
// --- HACK! ---

export async function applyDependencyPatches(
patches: DepPatch[],
{ root = process.cwd() }: { root?: string } = {}
{ root = process.cwd(), nodeModulesPath }: { root?: string; nodeModulesPath?: string | string[] } = {}
) {
const nodeModulesDirs = findNodeModules({
cwd: root,
}).map((relativePath) => join(root, relativePath))
const nodeModulesDirs = nodeModulesPath
? Array.isArray(nodeModulesPath)
? nodeModulesPath
: [nodeModulesPath]
: findNodeModules({
cwd: root,
}).map((relativePath) => join(root, relativePath))

await Promise.all(
patches.flatMap((patch) => {
Expand All @@ -127,44 +159,50 @@ export async function applyDependencyPatches(
}

const filesToApply = file.includes('*') ? globDir(nodeModuleDir, file) : [file]
const appliedContents = new Map<string, string>()

await Promise.all(
filesToApply.map(async (relativePath) => {
try {
const fullPath = join(nodeModuleDir, relativePath)
const ogFile = fullPath + '.vxrn.ogfile'

// for any update we store an "og" file to compare and decide if we need to run again
let existingPatch: string | null = appliedContents.get(ogFile) || null

if (!existingPatch) {
if (!process.env.VXRN_FORCE_PATCH) {
if (FSExtra.existsSync(ogFile)) {
try {
// for some reason with bun install this would say it exists? but then fail here?
existingPatch = await FSExtra.readFile(ogFile, 'utf-8')
} catch (err) {
console.warn(`Error reading patch`, err)
}
}
}

if (!process.env.VXRN_FORCE_PATCH && getIsAlreadyPatched(fullPath)) {
// if the file is already patched, skip it
return
}

let contentsIn =
existingPatch ||
(FSExtra.existsSync(fullPath)
? await FSExtra.readFile(fullPath, 'utf-8')
: '')
let contentsIn = await (async () => {
if (pathsBeingPatched.has(fullPath)) {
// If the file has been patched during the current run,
// we should always start from the already patched file
return await FSExtra.readFile(fullPath, 'utf-8')
}

if (getIsAlreadyPatched(fullPath)) {
// If a original file exists, we should start from it
// If we can reach here, basically it means
// VXRN_FORCE_PATCH is set
return await FSExtra.readFile(getOgFilePath(fullPath), 'utf-8')
}

return await FSExtra.readFile(fullPath, 'utf-8')
})()

const write = async (contents: string) => {
const possibleOrigContents = contentsIn
// update contentsIn so the next patch gets the new value if it runs multiple
contentsIn = contents
appliedContents.set(ogFile, contents)
await Promise.all([
FSExtra.writeFile(ogFile, contentsIn),
FSExtra.writeFile(fullPath, contents),
])
const alreadyPatchedPreviouslyInCurrentRun = pathsBeingPatched.has(fullPath)
pathsBeingPatched.add(fullPath)
await Promise.all(
[
!alreadyPatchedPreviouslyInCurrentRun /* only write ogfile if this is the first patch, otherwise contentsIn will be already patched content */ &&
!getIsAlreadyPatched(
fullPath
) /* an ogfile must already be there, no need to write */ &&
FSExtra.writeFile(getOgFilePath(fullPath), possibleOrigContents),
FSExtra.writeFile(fullPath, contents),
].filter((p) => !!p)
)

if (!hasLogged) {
hasLogged = true
Expand Down Expand Up @@ -226,8 +264,6 @@ export async function applyDependencyPatches(
}
})
)

appliedContents.clear()
}
}
} catch (err) {
Expand All @@ -238,3 +274,14 @@ export async function applyDependencyPatches(
})
)
}

/**
* For every patch we store an "og" file as a backup of the original.
* If such file exists, we can skip the patching since the
* file should be already patched, unless the user forces
* to apply the patch again - in such case we use the
* contents of the original file as a base to reapply patches.
*/
function getOgFilePath(fullPath: string) {
return fullPath + '.vxrn.ogfile'
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading