From 0c112e5d915af9f2f30879cea55e41751dbf0f1b Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Thu, 24 Sep 2020 20:09:05 -0400 Subject: [PATCH] feat(@angular-devkit/build-angular): support package references in styles & scripts options The browser builder's `styles` and `scripts` options now support using a package name in the path when specifying a style or script. This removes the need to use a relative path to the node modules directory in these options. This provides support for Yarn PnP as well as reducing the complexity of the options especially for monorepo setups. Relatively located files will take precedence over packages if they exist. This precedence provides backwards compatibility with existing configurations. Before : `"styles": ["../node_modules/bootstrap/dist/css/bootstrap.css"]` After: `"styles": ["bootstrap/dist/css/bootstrap.css"]` --- .../build_angular/src/browser/specs/styles_spec.ts | 12 +++++++++++- .../build_angular/src/dev-server/index.ts | 11 ++++++++++- .../build_angular/src/webpack/configs/common.ts | 8 ++++++-- .../build_angular/src/webpack/configs/styles.ts | 8 +++++++- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/browser/specs/styles_spec.ts b/packages/angular_devkit/build_angular/src/browser/specs/styles_spec.ts index 9c60146ff913..7da64970b00e 100644 --- a/packages/angular_devkit/build_angular/src/browser/specs/styles_spec.ts +++ b/packages/angular_devkit/build_angular/src/browser/specs/styles_spec.ts @@ -570,7 +570,7 @@ describe('Browser Builder styles', () => { expect(main).toContain(`url('/base/assets/component-img-absolute.svg')`); }, 90000); - it(`supports bootstrap@4`, async () => { + it(`supports bootstrap@4 with full path`, async () => { const bootstrapPath = dirname(require.resolve('bootstrap/package.json')); const overrides = { @@ -582,6 +582,16 @@ describe('Browser Builder styles', () => { await browserBuild(architect, host, target, overrides); }); + it(`supports bootstrap@4 with package reference`, async () => { + const overrides = { + extractCss: true, + styles: ['bootstrap/dist/css/bootstrap.css'], + scripts: ['bootstrap/dist/js/bootstrap.js'], + }; + + await browserBuild(architect, host, target, overrides); + }); + it(`supports inline javascript in less`, async () => { const overrides = { styles: [`src/styles.less`] }; host.writeMultipleFiles({ diff --git a/packages/angular_devkit/build_angular/src/dev-server/index.ts b/packages/angular_devkit/build_angular/src/dev-server/index.ts index 20be5820390c..2fdda29dad34 100644 --- a/packages/angular_devkit/build_angular/src/dev-server/index.ts +++ b/packages/angular_devkit/build_angular/src/dev-server/index.ts @@ -569,7 +569,16 @@ function _addLiveReload( // When HMR is enabled we need to add the css paths as part of the entrypoints // because otherwise no JS bundle will contain the HMR accept code. const normalizedStyles = normalizeExtraEntryPoints(browserOptions.styles, 'styles') - .map(style => path.resolve(root, style.input)); + .map(style => { + let resolvedPath = path.resolve(root, style.input); + if (!existsSync(resolvedPath)) { + try { + resolvedPath = require.resolve(style.input, { paths: [root] }); + } catch {} + } + + return resolvedPath; + }); entryPoints.push(...normalizedStyles); } diff --git a/packages/angular_devkit/build_angular/src/webpack/configs/common.ts b/packages/angular_devkit/build_angular/src/webpack/configs/common.ts index 57898cfc8919..de87acfc1f80 100644 --- a/packages/angular_devkit/build_angular/src/webpack/configs/common.ts +++ b/packages/angular_devkit/build_angular/src/webpack/configs/common.ts @@ -208,10 +208,14 @@ export function getCommonConfig(wco: WebpackConfigOptions): Configuration { 'scripts', ).reduce((prev: { bundleName: string; paths: string[]; inject: boolean }[], curr) => { const { bundleName, inject, input } = curr; - const resolvedPath = path.resolve(root, input); + let resolvedPath = path.resolve(root, input); if (!existsSync(resolvedPath)) { - throw new Error(`Script file ${input} does not exist.`); + try { + resolvedPath = require.resolve(input, { paths: [root] }); + } catch { + throw new Error(`Script file ${input} does not exist.`); + } } const existingEntry = prev.find(el => el.bundleName === bundleName); diff --git a/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts b/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts index dd6bdfab2878..74bde097204f 100644 --- a/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts +++ b/packages/angular_devkit/build_angular/src/webpack/configs/styles.ts @@ -7,6 +7,7 @@ */ import { tags } from '@angular-devkit/core'; +import * as fs from 'fs'; import * as path from 'path'; import * as webpack from 'webpack'; import { WebpackConfigOptions } from '../../utils/build-options'; @@ -58,7 +59,12 @@ export function getStylesConfig(wco: WebpackConfigOptions) { const chunkNames: string[] = []; normalizeExtraEntryPoints(buildOptions.styles, 'styles').forEach(style => { - const resolvedPath = path.resolve(root, style.input); + let resolvedPath = path.resolve(root, style.input); + if (!fs.existsSync(resolvedPath)) { + try { + resolvedPath = require.resolve(style.input, { paths: [root] }); + } catch {} + } // Add style entry points. if (entryPoints[style.bundleName]) { entryPoints[style.bundleName].push(resolvedPath);