Skip to content
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

@angular/cli global require cleanup #21638

Merged
merged 5 commits into from
Aug 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 1 addition & 6 deletions packages/angular/cli/commands/update-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { NodeWorkflow } from '@angular-devkit/schematics/tools';
import { execSync } from 'child_process';
import * as fs from 'fs';
import npa from 'npm-package-arg';
import pickManifest from 'npm-pick-manifest';
import * as path from 'path';
import * as semver from 'semver';
import { PackageManager } from '../lib/config/workspace-schema';
Expand All @@ -25,7 +26,6 @@ import { ensureCompatibleNpm, getPackageManager } from '../utilities/package-man
import {
PackageIdentifier,
PackageManifest,
PackageMetadata,
fetchPackageManifest,
fetchPackageMetadata,
} from '../utilities/package-metadata';
Expand All @@ -37,11 +37,6 @@ import {
} from '../utilities/package-tree';
import { Schema as UpdateCommandSchema } from './update';

const pickManifest = require('npm-pick-manifest') as (
metadata: PackageMetadata,
selector: string,
) => PackageManifest;

const NG_VERSION_9_POST_MSG = colors.cyan(
'\nYour project has been updated to Angular version 9!\n' +
'For more info, please see: https://v9.angular.io/guide/updating-to-version-9',
Expand Down
22 changes: 13 additions & 9 deletions packages/angular/cli/commands/version-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { execSync } from 'child_process';
import * as path from 'path';
import nodeModule from 'module';
import { Command } from '../models/command';
import { colors } from '../utilities/color';
import { getPackageManager } from '../utilities/package-manager';
Expand All @@ -28,11 +28,15 @@ interface PartialPackageInfo {
export class VersionCommand extends Command<VersionCommandSchema> {
public static aliases = ['v'];

private readonly localRequire = nodeModule.createRequire(__filename);
// Trailing slash is used to allow the path to be treated as a directory
private readonly workspaceRequire = nodeModule.createRequire(this.context.root + '/');

async run() {
const cliPackage: PartialPackageInfo = require('../package.json');
const cliPackage: PartialPackageInfo = this.localRequire('../package.json');
let workspacePackage: PartialPackageInfo | undefined;
try {
workspacePackage = require(path.resolve(this.context.root, 'package.json'));
workspacePackage = this.workspaceRequire('./package.json');
} catch {}

const [nodeMajor] = process.versions.node.split('.').map((part) => Number(part));
Expand Down Expand Up @@ -151,28 +155,28 @@ export class VersionCommand extends Command<VersionCommandSchema> {
}

private getVersion(moduleName: string): string {
let packagePath;
let packageInfo: PartialPackageInfo | undefined;
let cliOnly = false;

// Try to find the package in the workspace
try {
packagePath = require.resolve(`${moduleName}/package.json`, { paths: [this.context.root] });
packageInfo = this.workspaceRequire(`${moduleName}/package.json`);
} catch {}

// If not found, try to find within the CLI
if (!packagePath) {
if (!packageInfo) {
try {
packagePath = require.resolve(`${moduleName}/package.json`);
packageInfo = this.localRequire(`${moduleName}/package.json`);
cliOnly = true;
} catch {}
}

let version: string | undefined;

// If found, attempt to get the version
if (packagePath) {
if (packageInfo) {
try {
version = require(packagePath).version + (cliOnly ? ' (cli-only)' : '');
version = packageInfo.version + (cliOnly ? ' (cli-only)' : '');
} catch {}
}

Expand Down
9 changes: 5 additions & 4 deletions packages/angular/cli/models/schematic-engine-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ function wrap(
moduleCache: Map<string, unknown>,
exportName?: string,
): () => unknown {
const scopedRequire = nodeModule.createRequire(schematicFile);
const hostRequire = nodeModule.createRequire(__filename);
const schematicRequire = nodeModule.createRequire(schematicFile);

const customRequire = function (id: string) {
if (legacyModules[id]) {
Expand All @@ -131,13 +132,13 @@ function wrap(
// Resolve from inside the `@angular/cli` project
const packagePath = require.resolve(id);

return require(packagePath);
return hostRequire(packagePath);
} else if (id.startsWith('.') || id.startsWith('@angular/cdk')) {
// Wrap relative files inside the schematic collection
// Also wrap `@angular/cdk`, it contains helper utilities that import core schematic packages

// Resolve from the original file
const modulePath = scopedRequire.resolve(id);
const modulePath = schematicRequire.resolve(id);

// Use cached module if available
const cachedModule = moduleCache.get(modulePath);
Expand All @@ -159,7 +160,7 @@ function wrap(
}

// All others are required directly from the original file
return scopedRequire(id);
return schematicRequire(id);
};

// Setup a wrapper function to capture the module's exports
Expand Down
10 changes: 9 additions & 1 deletion packages/angular/cli/models/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/

import { readFileSync } from 'fs';
import { resolve } from 'path';

// Same structure as used in framework packages
export class Version {
public readonly major: string;
Expand All @@ -19,4 +22,9 @@ export class Version {
}
}

export const VERSION = new Version(require('../package.json').version);
// TODO: Convert this to use build-time version stamping once implemented in the build system
export const VERSION = new Version(
(
JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf-8')) as { version: string }
).version,
);
37 changes: 37 additions & 0 deletions packages/angular/cli/src/typings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

declare module '@yarnpkg/lockfile' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function parse(data: string): Record<string, any>;
}

declare module 'ini' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function parse(data: string): Record<string, any>;
}

declare module 'npm-pick-manifest' {
function pickManifest(
metadata: import('../utilities/package-metadata').PackageMetadata,
selector: string,
): import('../utilities/package-metadata').PackageManifest;
export = pickManifest;
}

declare module 'pacote' {
export function manifest(
specifier: string,
options: Record<string, unknown>,
): Promise<{ name: string; version: string }>;

export function packument(
specifier: string,
options: Record<string, unknown>,
): Promise<import('../utilities/package-metadata').NpmRepositoryPackageJson>;
}
7 changes: 3 additions & 4 deletions packages/angular/cli/utilities/package-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
*/

import { logging } from '@angular-devkit/core';
import * as lockfile from '@yarnpkg/lockfile';
import { existsSync, readFileSync } from 'fs';
import * as ini from 'ini';
import { homedir } from 'os';
import * as pacote from 'pacote';
import * as path from 'path';
import { JsonSchemaForNpmPackageJsonFiles } from './package-json';

const lockfile = require('@yarnpkg/lockfile');
const ini = require('ini');
const pacote = require('pacote');

const npmPackageJsonCache = new Map<string, Promise<Partial<NpmRepositoryPackageJson>>>();

export interface NpmRepositoryPackageJson {
Expand Down