Skip to content

Commit bd4cdb0

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 7f572db commit bd4cdb0

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
@@ -8,6 +8,7 @@ import { PurifyPlugin } from '@angular-devkit/build-optimizer';
88
import { StaticAssetPlugin } from '../../plugins/static-asset';
99
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
1010
import { WebpackConfigOptions } from '../webpack-config';
11+
import { resolveProjectModule } from '../../utilities/require-project-module';
1112
import { NEW_SW_VERSION } from '../../utilities/service-worker';
1213

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

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

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

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

4951
const isLegacySw = semver.satisfies(swVersion, OLD_SW_VERSION);
@@ -58,6 +60,9 @@ export function getProdConfig(wco: WebpackConfigOptions) {
5860
}
5961

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

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)