Skip to content

Commit e0194cd

Browse files
fix: pnpm support should work on macOS and Linux
Currently we are unable to build applications on macOS and Linux when pnpm is set as package manager. The problem seems to be caused by the way pnpm produces files in node_modules and the way webpack expects them. However, the issue is resolved in case we do not pass `--preserve-symlinks` option to Node.js when starting the webpack process. According to docs (https://pnpm.js.org/en/faq) the preserve-symlinks does not work very well and pnpm does not require it. So, to resolve the issue, skip the `--preserve-symlinks` option when pnpm is used. To achieve this, introduce a new method in the packageManager that returns the package manager used for the current process.
1 parent 3b6ae39 commit e0194cd

File tree

5 files changed

+47
-8
lines changed

5 files changed

+47
-8
lines changed

lib/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,3 +415,9 @@ export enum LoggerConfigData {
415415
}
416416

417417
export const EMIT_APPENDER_EVENT_NAME = "logData";
418+
419+
export enum PackageManagers {
420+
npm = "npm",
421+
pnpm = "pnpm",
422+
yarn = "yarn"
423+
}

lib/declarations.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ interface INodePackageManager {
7676
}
7777

7878
interface IPackageManager extends INodePackageManager {
79+
/**
80+
* Gets the name of the package manager used for the current process.
81+
* It can be read from the user settings or by passing -- option.
82+
*/
83+
getPackageManagerName(): Promise<string>;
84+
7985
/**
8086
* Gets the version corresponding to the tag for the package
8187
* @param {string} packageName The name of the package.

lib/package-manager.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11

22
import { cache, exported, invokeInit } from './common/decorators';
33
import { performanceLog } from "./common/decorators";
4+
import { PackageManagers } from './constants';
45
export class PackageManager implements IPackageManager {
56
private packageManager: INodePackageManager;
7+
private _packageManagerName: string;
68

79
constructor(
810
private $errors: IErrors,
@@ -19,6 +21,11 @@ export class PackageManager implements IPackageManager {
1921
this.packageManager = await this._determinePackageManager();
2022
}
2123

24+
@invokeInit()
25+
public async getPackageManagerName(): Promise<string> {
26+
return this._packageManagerName;
27+
}
28+
2229
@exported("packageManager")
2330
@performanceLog()
2431
@invokeInit()
@@ -97,11 +104,14 @@ export class PackageManager implements IPackageManager {
97104
this.$errors.fail(`Unable to read package manager config from user settings ${err}`);
98105
}
99106

100-
if (pm === 'yarn' || this.$options.yarn) {
107+
if (pm === PackageManagers.yarn || this.$options.yarn) {
108+
this._packageManagerName = PackageManagers.yarn;
101109
return this.$yarn;
102-
} else if (pm === 'pnpm' || this.$options.pnpm) {
110+
} else if (pm === PackageManagers.pnpm || this.$options.pnpm) {
111+
this._packageManagerName = PackageManagers.pnpm;
103112
return this.$pnpm;
104113
} else {
114+
this._packageManagerName = PackageManagers.npm;
105115
return this.$npm;
106116
}
107117
}

lib/services/webpack/webpack-compiler-service.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as child_process from "child_process";
33
import * as semver from "semver";
44
import { EventEmitter } from "events";
55
import { performanceLog } from "../../common/decorators";
6-
import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME } from "../../constants";
6+
import { WEBPACK_COMPILATION_COMPLETE, WEBPACK_PLUGIN_NAME, PackageManagers } from "../../constants";
77

88
export class WebpackCompilerService extends EventEmitter implements IWebpackCompilerService {
99
private webpackProcesses: IDictionary<child_process.ChildProcess> = {};
@@ -18,6 +18,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
1818
private $logger: ILogger,
1919
private $mobileHelper: Mobile.IMobileHelper,
2020
private $cleanupService: ICleanupService,
21+
private $packageManager: IPackageManager,
2122
private $packageInstallationManager: IPackageInstallationManager
2223
) { super(); }
2324

@@ -155,6 +156,15 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
155156
}
156157
}
157158

159+
private async shouldUsePreserveSymlinksOption(projectData: IProjectData): Promise<boolean> {
160+
// pnpm does not require symlink (https://github.com/nodejs/node-eps/issues/46#issuecomment-277373566)
161+
// and it also does not work in some cases.
162+
// Check https://github.com/NativeScript/nativescript-cli/issues/5259 for more information
163+
const currentPackageManager = await this.$packageManager.getPackageManagerName();
164+
const res = currentPackageManager !== PackageManagers.pnpm;
165+
return res;
166+
}
167+
158168
@performanceLog()
159169
private async startWebpackProcess(platformData: IPlatformData, projectData: IProjectData, prepareData: IPrepareData): Promise<child_process.ChildProcess> {
160170
if (!this.$fs.exists(projectData.webpackConfigPath)) {
@@ -164,18 +174,22 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
164174
const envData = this.buildEnvData(platformData.platformNameLowerCase, projectData, prepareData);
165175
const envParams = await this.buildEnvCommandLineParams(envData, platformData, projectData, prepareData);
166176
const additionalNodeArgs = semver.major(process.version) <= 8 ? ["--harmony"] : [];
177+
178+
if (await this.shouldUsePreserveSymlinksOption(projectData)) {
179+
additionalNodeArgs.push("--preserve-symlinks");
180+
}
181+
182+
if (process.arch === "x64") {
183+
additionalNodeArgs.unshift("--max_old_space_size=4096");
184+
}
185+
167186
const args = [
168187
...additionalNodeArgs,
169-
"--preserve-symlinks",
170188
path.join(projectData.projectDir, "node_modules", "webpack", "bin", "webpack.js"),
171189
`--config=${projectData.webpackConfigPath}`,
172190
...envParams
173191
];
174192

175-
if (process.arch === "x64") {
176-
args.unshift("--max_old_space_size=4096");
177-
}
178-
179193
if (prepareData.watch) {
180194
args.push("--watch");
181195
}

test/services/webpack/webpack-compiler-service.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ function getAllEmittedFiles(hash: string) {
1313

1414
function createTestInjector(): IInjector {
1515
const testInjector = new Yok();
16+
testInjector.register("packageManager", {
17+
getPackageManagerName: async () => "npm"
18+
});
1619
testInjector.register("webpackCompilerService", WebpackCompilerService);
1720
testInjector.register("childProcess", {});
1821
testInjector.register("hooksService", {});

0 commit comments

Comments
 (0)