Skip to content

feat() - [Yarn Support - Part 1 and 2] Yarn and Package Manager implementation #4050

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 1, 2018

Conversation

mflor35
Copy link
Contributor

@mflor35 mflor35 commented Oct 22, 2018

PR Checklist

What is the current behavior?

Limited to only use NPM as package manager.

What is the new behavior?

Add support for the Yarn package manager.

Implements #2737.

We split this into two parts since it was a big diff. Can you please review part 2 ? CC: @rosen-vladimirov

Also do I qualify for the amazon gift card since it's my first contribution? 😛

export class BasePackageManager {
constructor(private packageManager: string) { }

protected getNpmExecutableName(isWindows: boolean): string {
Copy link
Contributor

@Fatme Fatme Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to provide isWindows as param. You can determine it inside the method. Just need to inject $hostInfo.

constructor(private packageManager: string,
    private $hostInfo: IHostInfo){ }
protected getNpmExecutableName(): string {
    const isWindows = this.$hostInfo.isWindows;
}

You'll need to change this https://github.com/NativeScript/nativescript-cli/pull/4050/files#diff-5d0fca739bb2fbd7cab602dbeaa30b89R17 as well

super('npm', $hostInfo);

This also should be changed https://github.com/NativeScript/nativescript-cli/pull/4050/files#diff-5d0fca739bb2fbd7cab602dbeaa30b89L11

constructor($hostInfo: IHostInfo, ...) { }

NOTE: No private before $hostInfo.


const npmExecutable = this.getNpmExecutableName(isWindows);

if (childProcess.stdout) {
Copy link
Contributor

@Fatme Fatme Oct 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is duplicated to this https://github.com/NativeScript/nativescript-cli/blob/master/lib/common/child-process.ts#L57
So I suggest to inject $childProcess: IChildProcess in constructor and reuse the logic here.

protected async processPackageManagerInstall(params: string[], opts: { cwd: string }) {
    const npmExecutable = this.getNpmExecutableName();
    const stdioValue = isInteractive() ? "inherit" : "pipe";
    const result = await this.$childProcess.spawnFromEvent(npmExecutable, params, "close", { cwd: opts.cwd, stdio: stdioValue });
    return result;
}

These 2 methods should be deleted in this case:

  1. https://github.com/NativeScript/nativescript-cli/pull/4050/files#diff-5d0fca739bb2fbd7cab602dbeaa30b89R215
  2. https://github.com/NativeScript/nativescript-cli/pull/4050/files#diff-f2195087b0cc167a75dcffcda9961acaR104

Copy link
Contributor

@Fatme Fatme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Thanks for the contribution.

private $yarn: INodePackageManager,
private $userSettingsService: IUserSettingsService
) {
this._determinePackageManager();
Copy link
Contributor

@Fatme Fatme Oct 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is async so it is possible to call some method from the class and this.packageManager to be null.
So I suggest an approach similar to this https://github.com/NativeScript/nativescript-cli/blob/master/lib/common/mobile/android/android-debug-bridge.ts#L56.

@cache()
private async init(): Promise<void> {
    this.packageManager = await this._determinePackageManager();
}

@exported("packageManager")
@invokeInit()
public install(packageName: string, pathToSave: string, config: INodePackageManagerInstallOptions): Promise<INpmInstallResultInfo> {
    return this.packageManager.install(packageName, pathToSave, config);
}

This way this._determinePackageManager(); should be removed from constructor and all methods that relied on this.packageManager should be decorated with @invokeInit()

On the other side init() method is decorated with cache() decorator so the value will be persisted and this._determinePackageManager() will be called only once.

Also we can rewrite _determinePackageManager method:

private async _determinePackageManager(): Promise<void> {
    let pm = null;
    try {
        pm = await this.$userSettingsService.getSettingValue('packageManager');
    } catch (err) {
        this.$errors.fail(`Unable to read package manager config from user settings ${err}`);
    }

    if (pm === 'yarn' || this.$options.yarn) {
	this.packageManager = this.$yarn;
    } else {
	this.packageManager = this.$npm;
    }	
}


@exported("yarn")
getCachePath(): Promise<string> {
throw new Error("Method not implemented.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.$errors.fail("Method not implemented.");


@exported("yarn")
public search(filter: string[], config: IDictionary<string | boolean>): Promise<string> {
throw new Error("Method not implemented. Yarn does not support searching for packages in the registry.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.$errors.fail("Method not implemented. Yarn does not support searching for packages in the registry.");

@Fatme
Copy link
Contributor

Fatme commented Oct 24, 2018

Also do I qualify for the amazon gift card since it's my first contribution?

Yes, absolutely! Congratulations on this quality PR! Have a badge!
badge

@dcarrot2
Copy link

@Fatme Thank you for the thorough feedback! Can you pls take a look at Part 2 of this once this looks good to you? We'll merge that in here once it looks good prior to merging this diff in.

@mflor35
Copy link
Contributor Author

mflor35 commented Oct 24, 2018

@Fatme Thanks! Our motivation was not the gift card 😅. We actually want to start using yarn to continue the development of The California Court Access App. So far we noticed some speed improvements when building for Android.

@Fatme
Copy link
Contributor

Fatme commented Oct 24, 2018

@dcarrot2, @mflor35 ,

I reviewed part2 of the PR and it seems ok to me. So you can merge it here.

refactor() - [Yarn Support - Part 2] - Replace npm with package manag…
@mflor35 mflor35 changed the title feat() - [Yarn Support - Part 1] Yarn and Package Manager implementation feat() - [Yarn Support - Part 1 and 2] Yarn and Package Manager implementation Oct 24, 2018
Copy link
Contributor

@DimitarTachev DimitarTachev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great Work! 💯

@Fatme
Copy link
Contributor

Fatme commented Oct 25, 2018

@dcarrot2, @mflor35,

I was ready to merge your PR and noticed the followings:

npmInstallationManager class that is registered in injector here https://github.com/mflor35/nativescript-cli/pull/10/files#diff-91928defa835fe6d9e1ae815324a33f1R87 does not use this.packageManager. It has hardcoded this.$npm.install() and this.$npm.view(). So in case when packageManager is yarn, npm will be used from this class.

I suggest to integrate packageManager inside npmInstallationManager and rename the class to packageInstallationManager.

export class PackageInstallationManager {
    	constructor(private $packageManager: INodePackageManager, ...) { }

     	private async getVersion(packageName: string, version: string): Promise<string> {
		const data: any = await this.$packageManager.view(packageName, { "dist-tags": true });
		this.$logger.trace("Using version %s. ", data[version]);

		return data[version];
	}
}
$injector.register("packageInstallationManager", PackageInstallationManager);

Also all references to npmInstallationManager should be changed to packageInstallationManager.

@dcarrot2
Copy link

@Fatme Thanks for catching that! We'll also open another diff after this to refactor the INodePackageManager to IPackageManager and similar changes to make this change clear everywhere else in the codebase.

@dcarrot2
Copy link

@Fatme Are we ok to merge this?

@Fatme
Copy link
Contributor

Fatme commented Oct 31, 2018

@dcarrot2,

Yes, absolutely! I'm waiting for green light from our QAs and after that I'll merge the PR.

@Fatme Fatme merged commit 141dfe2 into NativeScript:master Nov 1, 2018
@radeva
Copy link

radeva commented Nov 19, 2018

Hi @mflor35 and @dcarrot2 ,

Congratulations on being two of the winners in the {N} First-time contributors contest!

You can claim your prize by contacting us at nativescriptwinners[at]progress.com not later than Nov 30th 2018 . Make sure you send us the following info: 
👉Your full name 
👉Your email 
👉Your country or residence 

Best regards,
The NativeScript Team

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants