Skip to content

Commit 555424e

Browse files
bgotinkfilipesilva
authored andcommitted
fix(@angular/cli): Allow service-workers package to be installed in parent node_modules
The checks on existence of @angular/service-worker used the node_modules relative to the project root directly, but those don't exist when using yarn workspaces or lerna. Use resolve.sync instead, which looks up the tree to parent node_modules folders. A similar change is required when loading the service worker script from the @angular/service-worker package. Switch to require.resolve here as well. Fixes #8300
1 parent dcbc4b3 commit 555424e

File tree

3 files changed

+26
-14
lines changed

3 files changed

+26
-14
lines changed

packages/@angular/cli/models/webpack-configs/production.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { BundleBudgetPlugin } from '../../plugins/bundle-budget';
99
import { StaticAssetPlugin } from '../../plugins/static-asset';
1010
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
1111
import { WebpackConfigOptions } from '../webpack-config';
12+
import { resolveProjectModule } from '../../utilities/require-project-module';
1213
import { NEW_SW_VERSION } from '../../utilities/service-worker';
1314

1415
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
@@ -30,11 +31,12 @@ export function getProdConfig(wco: WebpackConfigOptions) {
3031
let entryPoints: { [key: string]: string[] } = {};
3132

3233
if (appConfig.serviceWorker) {
33-
const nodeModules = path.resolve(projectRoot, 'node_modules');
34-
const swModule = path.resolve(nodeModules, '@angular/service-worker');
34+
let swPackageJsonPath;
3535

36-
// @angular/service-worker is required to be installed when serviceWorker is true.
37-
if (!fs.existsSync(swModule)) {
36+
try {
37+
swPackageJsonPath = resolveProjectModule(projectRoot, '@angular/service-worker/package.json');
38+
} catch (_) {
39+
// @angular/service-worker is required to be installed when serviceWorker is true.
3840
throw new Error(stripIndent`
3941
Your project is configured with serviceWorker = true, but @angular/service-worker
4042
is not installed. Run \`npm install --save-dev @angular/service-worker\`
@@ -44,7 +46,7 @@ export function getProdConfig(wco: WebpackConfigOptions) {
4446

4547
// Read the version of @angular/service-worker and throw if it doesn't match the
4648
// expected version.
47-
const swPackageJson = fs.readFileSync(`${swModule}/package.json`).toString();
49+
const swPackageJson = fs.readFileSync(swPackageJsonPath).toString();
4850
const swVersion = JSON.parse(swPackageJson)['version'];
4951

5052
const isLegacySw = semver.satisfies(swVersion, OLD_SW_VERSION);
@@ -59,6 +61,9 @@ export function getProdConfig(wco: WebpackConfigOptions) {
5961
}
6062

6163
if (isLegacySw) {
64+
// Path to the @angular/service-worker package
65+
const swModule = path.dirname(swPackageJsonPath);
66+
6267
// Path to the worker script itself.
6368
const workerPath = path.resolve(swModule, 'bundles/worker-basic.min.js');
6469

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
const resolve = require('resolve');
22

3+
// resolve dependencies within the target project
4+
export function resolveProjectModule(root: string, moduleName: string) {
5+
return resolve.sync(moduleName, { basedir: root });
6+
}
7+
38
// require dependencies within the target project
49
export function requireProjectModule(root: string, moduleName: string) {
5-
return require(resolve.sync(moduleName, { basedir: root }));
10+
return require(resolveProjectModule(root, moduleName));
611
}

packages/@angular/cli/utilities/service-worker/index.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import * as fs from 'fs';
55
import * as path from 'path';
66
import * as semver from 'semver';
77

8+
import { resolveProjectModule } from '../require-project-module';
9+
810
export const NEW_SW_VERSION = '5.0.0-rc.0';
911

1012
class CliFilesystem implements Filesystem {
@@ -49,25 +51,25 @@ class CliFilesystem implements Filesystem {
4951
}
5052

5153
export function usesServiceWorker(projectRoot: string): boolean {
52-
const nodeModules = path.resolve(projectRoot, 'node_modules');
53-
const swModule = path.resolve(nodeModules, '@angular/service-worker');
54-
if (!fs.existsSync(swModule)) {
54+
let swPackageJsonPath;
55+
56+
try {
57+
swPackageJsonPath = resolveProjectModule(projectRoot, '@angular/service-worker/package.json');
58+
} catch (_) {
59+
// @angular/service-worker is not installed
5560
return false;
5661
}
5762

58-
const swPackageJson = fs.readFileSync(`${swModule}/package.json`).toString();
63+
const swPackageJson = fs.readFileSync(swPackageJsonPath).toString();
5964
const swVersion = JSON.parse(swPackageJson)['version'];
6065

6166
return semver.gte(swVersion, NEW_SW_VERSION);
6267
}
6368

6469
export function augmentAppWithServiceWorker(projectRoot: string, appRoot: string,
6570
outputPath: string, baseHref: string): Promise<void> {
66-
const nodeModules = path.resolve(projectRoot, 'node_modules');
67-
const swModule = path.resolve(nodeModules, '@angular/service-worker');
68-
6971
// Path to the worker script itself.
70-
const workerPath = path.resolve(swModule, 'ngsw-worker.js');
72+
const workerPath = resolveProjectModule(projectRoot, '@angular/service-worker/ngsw-worker.js');
7173
const configPath = path.resolve(appRoot, 'ngsw-config.json');
7274

7375
if (!fs.existsSync(configPath)) {

0 commit comments

Comments
 (0)