Skip to content

Commit a9d4568

Browse files
committed
feat: load rush-lib from rush global folder
1 parent dbaebcd commit a9d4568

File tree

7 files changed

+171
-44
lines changed

7 files changed

+171
-44
lines changed

common/config/subspaces/default/pnpm-lock.yaml

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libraries/rush-sdk/config/api-extractor.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
33

4-
"mainEntryPointFilePath": "<projectFolder>/lib-shim/loader.d.ts",
4+
"mainEntryPointFilePath": "<projectFolder>/lib-commonjs/loader.d.ts",
55

66
"apiReport": {
77
"enabled": true,

libraries/rush-sdk/config/heft.json

+9-2
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,20 @@
3232
"taskDependencies": ["copy-rush-lib-types"]
3333
},
3434

35-
"generate-stubs": {
35+
"webpack": {
3636
"taskDependencies": ["typescript"],
37+
"taskPlugin": {
38+
"pluginPackage": "@rushstack/heft-webpack5-plugin"
39+
}
40+
},
41+
42+
"generate-stubs": {
43+
"taskDependencies": ["webpack"],
3744
"taskPlugin": {
3845
"pluginPackage": "@rushstack/heft",
3946
"pluginName": "run-script-plugin",
4047
"options": {
41-
"scriptPath": "./lib-shim/generate-stubs.js"
48+
"scriptPath": "./lib-commonjs/generate-stubs.js"
4249
}
4350
}
4451
}

libraries/rush-sdk/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@
3737
"@microsoft/rush-lib": "workspace:*",
3838
"@rushstack/heft": "workspace:*",
3939
"local-node-rig": "workspace:*",
40+
"@rushstack/heft-webpack5-plugin": "workspace:*",
4041
"@rushstack/stream-collator": "workspace:*",
4142
"@rushstack/ts-command-line": "workspace:*",
43+
"@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*",
4244
"@types/semver": "7.5.0",
43-
"@types/webpack-env": "1.18.0"
45+
"@types/webpack-env": "1.18.0",
46+
"webpack": "~5.82.1"
4447
}
4548
}

libraries/rush-sdk/src/index.ts

+71-39
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import {
2121
sdkContext
2222
} from './helpers';
2323

24-
const verboseEnabled: boolean = typeof process !== 'undefined' && process.env.RUSH_SDK_DEBUG === '1';
24+
const verboseEnabled: boolean =
25+
typeof process !== 'undefined' &&
26+
(process.env.RUSH_SDK_DEBUG === '1' || process.env._RUSH_SDK_DEBUG === '1');
2527
const terminal: Terminal = new Terminal(
2628
new ConsoleTerminalProvider({
2729
verboseEnabled
@@ -31,6 +33,7 @@ const terminal: Terminal = new Terminal(
3133
declare const global: typeof globalThis & {
3234
___rush___rushLibModule?: RushLibModuleType;
3335
___rush___rushLibModuleFromEnvironment?: RushLibModuleType;
36+
___rush___rushLibModuleFromRushGlobalFolder?: RushLibModuleType;
3437
___rush___rushLibModuleFromInstallAndRunRush?: RushLibModuleType;
3538
};
3639

@@ -42,6 +45,7 @@ if (sdkContext.rushLibModule === undefined) {
4245
sdkContext.rushLibModule =
4346
global.___rush___rushLibModule ||
4447
global.___rush___rushLibModuleFromEnvironment ||
48+
global.___rush___rushLibModuleFromRushGlobalFolder ||
4549
global.___rush___rushLibModuleFromInstallAndRunRush;
4650
}
4751

@@ -111,7 +115,8 @@ if (sdkContext.rushLibModule === undefined) {
111115
}
112116

113117
// SCENARIO 4: A standalone tool or script depends on "rush-sdk", and is meant to be used inside a monorepo folder.
114-
// In this case, we can use install-run-rush.js to obtain the appropriate rush-lib version for the monorepo.
118+
// In this case, we can first load the rush-lib version in rush global folder. If the expected version is not installed,
119+
// using install-run-rush.js to obtain the appropriate rush-lib version for the monorepo.
115120
if (sdkContext.rushLibModule === undefined) {
116121
try {
117122
const rushJsonPath: string | undefined = tryFindRushJsonLocation(process.cwd());
@@ -126,51 +131,78 @@ if (sdkContext.rushLibModule === undefined) {
126131
const rushJson: JsonObject = JsonFile.load(rushJsonPath);
127132
const { rushVersion } = rushJson;
128133

129-
const installRunNodeModuleFolder: string = path.join(
130-
monorepoRoot,
131-
`common/temp/install-run/@microsoft+rush@${rushVersion}`
132-
);
133-
134134
try {
135-
// First, try to load the version of "rush-lib" that was installed by install-run-rush.js
136-
terminal.writeVerboseLine(`Trying to load ${RUSH_LIB_NAME} installed by install-run-rush`);
137-
sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder);
138-
} catch (e1) {
139-
let installAndRunRushStderrContent: string = '';
140-
try {
141-
const installAndRunRushJSPath: string = path.join(monorepoRoot, 'common/scripts/install-run-rush.js');
135+
const { RushGlobalFolder } = require('@microsoft/rush-lib/lib-esnext/api/RushGlobalFolder');
136+
terminal.writeLine(RushGlobalFolder);
137+
terminal.writeVerboseLine(`Try to load ${RUSH_LIB_NAME} from rush global folder`);
138+
const rushGlobalFolder: typeof RushGlobalFolder = new RushGlobalFolder();
139+
// The path needs to keep align with the logic inside RushVersionSelector
140+
const expectedGlobalRushInstalledFolder: string = path.join(
141+
rushGlobalFolder.nodeSpecificPath,
142+
`rush-${rushVersion}`
143+
);
144+
terminal.writeVerboseLine(
145+
`The expected global rush installed folder is "${expectedGlobalRushInstalledFolder}"`
146+
);
147+
sdkContext.rushLibModule = requireRushLibUnderFolderPath(expectedGlobalRushInstalledFolder);
148+
} catch (e) {
149+
terminal.writeVerboseLine(`Failed to load ${RUSH_LIB_NAME} from rush global folder: ${e.message}`);
150+
}
142151

143-
terminal.writeLine('The Rush engine has not been installed yet. Invoking install-run-rush.js...');
152+
if (sdkContext.rushLibModule !== undefined) {
153+
// to track which scenario is active and how it got initialized.
154+
global.___rush___rushLibModuleFromRushGlobalFolder = sdkContext.rushLibModule;
155+
terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} installed from rush global folder`);
156+
} else {
157+
const installRunNodeModuleFolder: string = path.join(
158+
monorepoRoot,
159+
`common/temp/install-run/@microsoft+rush@${rushVersion}`
160+
);
144161

145-
const installAndRunRushProcess: SpawnSyncReturns<string> = Executable.spawnSync(
146-
'node',
147-
[installAndRunRushJSPath, '--help'],
148-
{
149-
stdio: 'pipe'
162+
try {
163+
// First, try to load the version of "rush-lib" that was installed by install-run-rush.js
164+
terminal.writeVerboseLine(`Trying to load ${RUSH_LIB_NAME} installed by install-run-rush`);
165+
sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder);
166+
} catch (e1) {
167+
let installAndRunRushStderrContent: string = '';
168+
try {
169+
const installAndRunRushJSPath: string = path.join(
170+
monorepoRoot,
171+
'common/scripts/install-run-rush.js'
172+
);
173+
174+
terminal.writeLine('The Rush engine has not been installed yet. Invoking install-run-rush.js...');
175+
176+
const installAndRunRushProcess: SpawnSyncReturns<string> = Executable.spawnSync(
177+
'node',
178+
[installAndRunRushJSPath, '--help'],
179+
{
180+
stdio: 'pipe'
181+
}
182+
);
183+
184+
installAndRunRushStderrContent = installAndRunRushProcess.stderr;
185+
if (installAndRunRushProcess.status !== 0) {
186+
throw new Error(`The ${RUSH_LIB_NAME} package failed to install`);
150187
}
151-
);
152188

153-
installAndRunRushStderrContent = installAndRunRushProcess.stderr;
154-
if (installAndRunRushProcess.status !== 0) {
155-
throw new Error(`The ${RUSH_LIB_NAME} package failed to install`);
189+
// Retry to load "rush-lib" after install-run-rush run
190+
terminal.writeVerboseLine(
191+
`Trying to load ${RUSH_LIB_NAME} installed by install-run-rush a second time`
192+
);
193+
sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder);
194+
} catch (e2) {
195+
// eslint-disable-next-line no-console
196+
console.error(`${installAndRunRushStderrContent}`);
197+
throw new Error(`The ${RUSH_LIB_NAME} package failed to load`);
156198
}
157-
158-
// Retry to load "rush-lib" after install-run-rush run
159-
terminal.writeVerboseLine(
160-
`Trying to load ${RUSH_LIB_NAME} installed by install-run-rush a second time`
161-
);
162-
sdkContext.rushLibModule = requireRushLibUnderFolderPath(installRunNodeModuleFolder);
163-
} catch (e2) {
164-
// eslint-disable-next-line no-console
165-
console.error(`${installAndRunRushStderrContent}`);
166-
throw new Error(`The ${RUSH_LIB_NAME} package failed to load`);
167199
}
168-
}
169200

170-
if (sdkContext.rushLibModule !== undefined) {
171-
// to track which scenario is active and how it got initialized.
172-
global.___rush___rushLibModuleFromInstallAndRunRush = sdkContext.rushLibModule;
173-
terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} installed by install-run-rush`);
201+
if (sdkContext.rushLibModule !== undefined) {
202+
// to track which scenario is active and how it got initialized.
203+
global.___rush___rushLibModuleFromInstallAndRunRush = sdkContext.rushLibModule;
204+
terminal.writeVerboseLine(`Loaded ${RUSH_LIB_NAME} installed by install-run-rush`);
205+
}
174206
}
175207
} catch (e) {
176208
// no-catch

libraries/rush-sdk/tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json",
33
"compilerOptions": {
4-
"outDir": "lib-shim",
4+
"outDir": "lib-commonjs",
55
"types": [
66
"node",
77
"heft-jest",

libraries/rush-sdk/webpack.config.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* eslint-env es6 */
2+
'use strict';
3+
4+
const webpack = require('webpack');
5+
const { PackageJsonLookup } = require('@rushstack/node-core-library');
6+
const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin');
7+
8+
module.exports = () => {
9+
const packageJson = PackageJsonLookup.loadOwnPackageJson(__dirname);
10+
11+
const externalDependencyNames = new Set([...Object.keys(packageJson.dependencies || {})]);
12+
13+
// Explicitly exclude @microsoft/rush-lib
14+
externalDependencyNames.delete('@microsoft/rush-lib');
15+
16+
return {
17+
context: __dirname,
18+
mode: 'development', // So the output isn't minified
19+
devtool: 'source-map',
20+
entry: {
21+
index: `${__dirname}/lib-commonjs/index.js`,
22+
loader: `${__dirname}/lib-commonjs/loader.js`
23+
},
24+
output: {
25+
path: `${__dirname}/lib-shim`,
26+
filename: '[name].js',
27+
chunkFilename: 'chunks/[name].js',
28+
library: {
29+
type: 'commonjs2'
30+
}
31+
},
32+
target: 'node',
33+
plugins: [
34+
new PreserveDynamicRequireWebpackPlugin(),
35+
new webpack.ids.DeterministicModuleIdsPlugin({
36+
maxLength: 6
37+
})
38+
],
39+
externals: [
40+
({ request }, callback) => {
41+
let packageName;
42+
let firstSlashIndex = request.indexOf('/');
43+
if (firstSlashIndex === -1) {
44+
packageName = request;
45+
} else if (request.startsWith('@')) {
46+
let secondSlash = request.indexOf('/', firstSlashIndex + 1);
47+
if (secondSlash === -1) {
48+
packageName = request;
49+
} else {
50+
packageName = request.substring(0, secondSlash);
51+
}
52+
} else {
53+
packageName = request.substring(0, firstSlashIndex);
54+
}
55+
56+
if (externalDependencyNames.has(packageName)) {
57+
callback(null, `commonjs ${request}`);
58+
} else {
59+
callback();
60+
}
61+
}
62+
],
63+
optimization: {
64+
splitChunks: {
65+
chunks: 'all',
66+
minChunks: 1,
67+
cacheGroups: {
68+
commons: {
69+
name: 'commons',
70+
chunks: 'initial'
71+
}
72+
}
73+
}
74+
}
75+
};
76+
};

0 commit comments

Comments
 (0)