From df241dc4511ccff1cc2e8ea2a9486857214a6587 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Fri, 15 Feb 2019 20:48:55 -0500 Subject: [PATCH] fix(@angular-devkit/build-angular): improve webpack loader resolution Previously, all loaders either needed to be in the workspace's node modules directory or a node modules directory directly within the build angular package. A package manager can potentially hoist a loader to a node modules location inbetween the two and causing loader resolution to fail. This change causes webpack to check all intermediate node modules directories in addition to the initial two locations. --- .../models/webpack-configs/common.ts | 14 +++------- .../angular-cli-files/utilities/find-up.ts | 26 ++++++++++++++++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts index 1a40ab83023f..53db8b5761cf 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts @@ -13,8 +13,7 @@ import { AssetPatternObject } from '../../../browser/schema'; import { BundleBudgetPlugin } from '../../plugins/bundle-budget'; import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin'; import { ScriptsWebpackPlugin } from '../../plugins/scripts-webpack-plugin'; -import { findUp } from '../../utilities/find-up'; -import { isDirectory } from '../../utilities/is-directory'; +import { findAllNodeModules, findUp } from '../../utilities/find-up'; import { requireProjectModule } from '../../utilities/require-project-module'; import { BuildOptions, WebpackConfigOptions } from '../build-options'; import { getOutputHashFormat, normalizeExtraEntryPoints } from './utils'; @@ -201,15 +200,8 @@ export function getCommonConfig(wco: WebpackConfigOptions) { // Allow loaders to be in a node_modules nested inside the devkit/build-angular package. // This is important in case loaders do not get hoisted. // If this file moves to another location, alter potentialNodeModules as well. - const loaderNodeModules = ['node_modules']; - const buildAngularNodeModules = findUp('node_modules', __dirname); - if (buildAngularNodeModules - && isDirectory(buildAngularNodeModules) - && buildAngularNodeModules !== nodeModules - && buildAngularNodeModules.startsWith(nodeModules) - ) { - loaderNodeModules.push(buildAngularNodeModules); - } + const loaderNodeModules = findAllNodeModules(__dirname, projectRoot); + loaderNodeModules.unshift('node_modules'); // Load rxjs path aliases. // https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/find-up.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/find-up.ts index a57d2b64fccc..037e99235956 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/find-up.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/find-up.ts @@ -5,11 +5,9 @@ * 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 */ -// tslint:disable -// TODO: cleanup this file, it's copied as is from Angular CLI. - -import * as path from 'path'; import { existsSync } from 'fs'; +import * as path from 'path'; +import { isDirectory } from './is-directory'; export function findUp(names: string | string[], from: string, stopOnNodeModules = false) { if (!Array.isArray(names)) { @@ -38,3 +36,23 @@ export function findUp(names: string | string[], from: string, stopOnNodeModules return null; } + +export function findAllNodeModules(from: string, root?: string) { + const nodeModules: string[] = []; + + let current = from; + while (current && current !== root) { + const potential = path.join(current, 'node_modules'); + if (existsSync(potential) && isDirectory(potential)) { + nodeModules.push(potential); + } + + const next = path.dirname(current); + if (next === current) { + break; + } + current = next; + } + + return nodeModules; +}