diff --git a/common/changes/@microsoft/rush/fix-rush-lib-external_2025-09-17-20-55.json b/common/changes/@microsoft/rush/fix-rush-lib-external_2025-09-17-20-55.json new file mode 100644 index 00000000000..05af2435f26 --- /dev/null +++ b/common/changes/@microsoft/rush/fix-rush-lib-external_2025-09-17-20-55.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "[rush-resolver-cache] Ensure that the correct version of rush-lib is loaded when the global version doesn't match the repository version.", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/rush-plugins/rush-resolver-cache-plugin/src/afterInstallAsync.ts b/rush-plugins/rush-resolver-cache-plugin/src/afterInstallAsync.ts index 72b9c631e76..47977f1ee7c 100644 --- a/rush-plugins/rush-resolver-cache-plugin/src/afterInstallAsync.ts +++ b/rush-plugins/rush-resolver-cache-plugin/src/afterInstallAsync.ts @@ -41,7 +41,7 @@ function getPlatformInfo(): IPlatformInfo { } const END_TOKEN: string = '/package.json":'; -const RESOLVER_CACHE_FILE_VERSION: 1 = 1; +const RESOLVER_CACHE_FILE_VERSION: 2 = 2; interface IExtendedResolverCacheFile extends IResolverCacheFile { /** @@ -94,6 +94,12 @@ export async function afterInstallAsync( throw new Error(`Failed to load shrinkwrap file: ${lockFilePath}`); } + if (!lockFile.hash) { + throw new Error( + `Shrinkwrap file does not have a hash. This indicates linking to an old version of Rush.` + ); + } + try { const oldCacheFileContent: string = await FileSystem.readFileAsync(cacheFilePath); const oldCache: IExtendedResolverCacheFile = JSON.parse(oldCacheFileContent); diff --git a/rush-plugins/rush-resolver-cache-plugin/src/externals.ts b/rush-plugins/rush-resolver-cache-plugin/src/externals.ts index 942c7d2dd89..4638cf2578c 100644 --- a/rush-plugins/rush-resolver-cache-plugin/src/externals.ts +++ b/rush-plugins/rush-resolver-cache-plugin/src/externals.ts @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type Module from 'node:module'; - import type { Operation as OperationType, OperationStatus as OperationStatusType } from '@rushstack/rush-sdk'; import type { PnpmShrinkwrapFile as PnpmShrinkwrapFileType } from '@rushstack/rush-sdk/lib/logic/pnpm/PnpmShrinkwrapFile'; import type * as rushSdkType from '@rushstack/rush-sdk'; @@ -22,27 +20,30 @@ export { Operation, OperationStatus }; // Support this plugin being webpacked. const req: typeof require = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require; -const entryModule: Module | undefined = req.main; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function getExternal(name: string): TResult { +const rushLibPath: string | undefined = process.env._RUSH_LIB_PATH; + +function importDependency(name: string): TResult { + if (!rushLibPath) { + throw new Error(`_RUSH_LIB_PATH variable is not set, cannot resolve rush-lib.`); + } const externalPath: string = req.resolve(name, { - paths: entryModule?.paths + paths: [rushLibPath] }); return req(externalPath); } // Private Rush APIs -export const { PnpmShrinkwrapFile } = getExternal< +export const { PnpmShrinkwrapFile } = importDependency< typeof import('@rushstack/rush-sdk/lib/logic/pnpm/PnpmShrinkwrapFile') >('@microsoft/rush-lib/lib/logic/pnpm/PnpmShrinkwrapFile'); // eslint-disable-next-line @typescript-eslint/no-redeclare export type PnpmShrinkwrapFile = PnpmShrinkwrapFileType; // Avoid bundling expensive stuff that's already part of Rush. -export const { Async } = getExternal( +export const { Async } = importDependency( `@rushstack/node-core-library/lib/Async` ); -export const { FileSystem } = getExternal( +export const { FileSystem } = importDependency( `@rushstack/node-core-library/lib/FileSystem` );