Skip to content

feat(service-worker): support multiple apps in one domain #27080

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

Closed
wants to merge 8 commits into from

Conversation

sheikalthaf
Copy link
Contributor

Current behavior of the service-worker is caching data of multiple apps in cache DB file in a domain.
Due to this behavior service-worker makes the apps to break when switching from one app to other app in same domain. This PR will solve this issue by suffixing the base-href with ngsw string to separate caches files of an apps in a domain

Fixes issue #21388

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: #21388
Currently service-worker doen't seperate the cache files based on base-href. Due to this caches files get clashes with multiple apps hosted in one domain

What is the new behavior?

In this PR seperating the caches files by suffing the base-href with ngsw string like this ngsw:<base-href> to seperate the caches files of an app. This will avoid the storing of cache data in same file for multiple apps in one domain

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Sorry, something went wrong.

@sheikalthaf
Copy link
Contributor Author

@gkalpak Please review this PR and let me know any changes required. Also need help in test writing

* in same domain with multiple apps
*/
setBaseHref(baseHref: string) {
if (baseHref && ['/'].indexOf(baseHref) == -1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you can just compare base href with '/' string:

  if (baseHref && baseHref === '/') {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndrewKushnir Hi,

ok now directly comparing with the '/'. Motivation is not to allow when base-href is not set that is '/'.


if (baseHref && baseHref !== '/') {

so that it work like current behavior

@gkalpak
Copy link
Member

gkalpak commented Nov 14, 2018

@sheikalthaf, I see you are still pushing changes to the PR. Is this ready for review?

@gkalpak gkalpak added feature Issue that requests a new feature state: WIP target: major This PR is targeted for the next major release area: service-worker Issues related to the @angular/service-worker package labels Nov 14, 2018
@sheikalthaf
Copy link
Contributor Author

@gkalpak yes it is now ready for review

@ngbot ngbot bot added this to the needsTriage milestone Nov 14, 2018
Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general direction this is going seems reasonable. Keep in mind that we also need tests that verify the new behavior.

* Suffixing the baseHref with `ngsw` string to avoid clash of cache files
* in same domain with multiple apps
*/
setBaseHref(baseHref: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this prefix should not be able to change at runtime. It should be determined during Adapter instantiation (as it remains constant throughout the lifetime of a SW instance).

* in same domain with multiple apps
*/
setBaseHref(baseHref: string) {
if (baseHref && baseHref !== '/') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT, baseHref should never be empty (it would be at least /).
But even so, why this check? Why not use /? Is it to retain backwards compatibility with existing caches (thus avoiding re-fetching all assets from the server)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will remove this condition

*/
setBaseHref(baseHref: string) {
if (baseHref && baseHref !== '/') {
const str = baseHref.replace(/^\//, '').replace(/\/$/, '').replace(/\//, ':');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use it as-is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why because '/' is not allowed in file name right?
if the base is something like this /app/de/ then we have to replace them with ':' . so the result will be app:de.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache name is not necessarily a file name. I didn't look at the spec, but Chrome seems to handle /s in cache names fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok thanks for the clarification. will remove the replace condition and use it as-is

@@ -23,16 +23,17 @@ export class CacheDatabase implements Database {
if (this.tables.has(name)) {
this.tables.delete(name);
}
return this.scope.caches.delete(`ngsw:db:${name}`);
return this.scope.caches.delete(`${this.adapter.ngsw}:db:${name}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases (with the sole exception of the control DB), CacheDatabase methods (such as delete, list, open) are called with names that already contain ngsw:<base-href>:, so prepending it again will get a little too verbose. But it is safer. I'm on the fence on this one.

Maybe we could strip the leading ngsw:<base-href>: from the name (so that baseHref is only included in the final cache name once).

* Extract baseHref from scope
* send the baseHref to adapter to suffix with ngsw string
*/
const baseHref = new URL(scope.registration.scope).pathname;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this should be moved to Adapter's instantiation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to adapter

const oldSwCacheNames =
cacheNames.filter(name => /^ngsw:(?:active|staged|manifest:.+)$/.test(name));
const regex = new RegExp(`^${this.adapter.ngsw}:(?:active|staged|manifest:.+)$`);
const oldSwCacheNames = cacheNames.filter(name => regex.test(name));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change should be reverted. The cleanupOldSwCaches() method matches caches created by an old SW implementation.
In fact, it might be a good idea to also match (and delete) caches that don't have the pathname after ngsw:. AFAICT, URL#pathname will always start with a /, so I think it is safe to delete all caches matching /^ngsw:(?!\/)/ (i.e. starting with ngsw: but not followed by /) - assuming we keep baseHref's leading / in cache names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now changed the regex to above mentioned matching pattern. also adding baseHref without any changes to cache

@sheikalthaf
Copy link
Contributor Author

@gkalpak i have updated the code and spec but i don't know how to test this because the hostUrl is hardcode. Any guidance is helpfull.
Also i want any guide to stepup the angular development in windows machine

Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx for the changes, @sheikalthaf. I left some more comments.
As discussed "offline", the development workflow on Windows is a little problematic atm. You should be able to run the tests with sh test.sh browserNoRouter inside git bash (which comes bundled with git-for-windows).

@@ -54,6 +61,15 @@ export class Adapter {
timeout(ms: number): Promise<void> {
return new Promise<void>(resolve => { setTimeout(() => resolve(), ms); });
}

/**
* Suffixing the baseHref with `ngsw` string to avoid clash of cache files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, it is the other way around: Suffixing ngsw (aka the cache name prefix) with the baseHref.

* Suffixing the baseHref with `ngsw` string to avoid clash of cache files
* in same domain with multiple apps
*/
suffixBaseHref(hostUrl: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be a method, since the value better remain the same throughout the lifetime of the adapter. cacheNamePrefix should be set once inside the constructor and be a readonly property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes commited

@@ -254,6 +256,11 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
return promise;
}

suffixBaseHref(hostUrl: string) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, no need for a method here. We can interact with the property directly.

Copy link
Contributor Author

@sheikalthaf sheikalthaf Nov 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gkalpak removed this method

@googlebot
Copy link

So there's good news and bad news.

👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there.

😕 The bad news is that it appears that one or more commits were authored or co-authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request.

Note to project maintainer: This is a terminal state, meaning the cla/google commit status will not change from this state. It's up to you to confirm consent of all the commit author(s), set the cla label to yes (if enabled on your project), and then merge this pull request when appropriate.

@gkalpak gkalpak force-pushed the sw-multiple-app branch 4 times, most recently from 2931507 to 534632c Compare November 22, 2018 17:22
Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone ahead and made some changes:

  • Rebased on latest master.
  • Squashed your commits into one.
  • Added some more commits (including tests).

@@ -13,6 +13,12 @@
* from the global scope.
*/
export class Adapter {
cacheNamePrefix: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also mark this property as readonly (to better convey that it is not supposed or expected to change at runtime).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already it is marked as readonly in my branch.

@@ -13,6 +13,12 @@
* from the global scope.
*/
export class Adapter {
cacheNamePrefix: string;
constructor(scope: ServiceWorkerGlobalScope) {
// Suffixing the baseHref with `ngsw` string to avoid clash of cache files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change to:

Suffixing `ngsw` with the baseHref to avoid clash of cache names for SWs with different scopes on the same domain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meaningfull message 😊

@@ -77,6 +77,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
readonly clients = new MockClients();
private eventHandlers = new Map<string, Function>();
private skippedWaiting = true;
cacheNamePrefix: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark as readonly to better mimic the actual implementation.
(Note: We might still overwrite it during tests, but at least one has to be very intentional about it 😁)

@gkalpak gkalpak requested review from alxhub and IgorMinar November 22, 2018 18:36
@gkalpak gkalpak added action: review The PR is still awaiting reviews from at least one requested reviewer and removed state: WIP labels Nov 23, 2018
gkalpak and others added 8 commits March 20, 2019 23:29

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…)` optional

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ame on browser and Node.js

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
… that do not support SW

The tests will not be run anyway, so the artifacts are never used and
there might be errors if creating the testing artifacts relies on APIs
that are not available in that environment (e.g. `URL`).

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…a domain

Previously, it was not possible to have multiple apps (using
`@angular/service-worker`) on different subpaths of the same domain,
because each SW would overwrite the caches of the others (even though
their scope was different).

This commit fixes it by ensuring that the cache names created by the SW
are different for each scope.

Fixes angular#21388

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ths of a domain

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…paths of a domain

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
This commit also ensures that the correct implementation is used on
environments that do not support `URL` (e.g. Node.js).
@gkalpak
Copy link
Member

gkalpak commented Mar 20, 2019

Rebased. Thx again for working on this, @sheikalthaf 👍

merge-assistance: Needs CLA override.

@sheikalthaf
Copy link
Contributor Author

sheikalthaf commented Mar 21, 2019

@IgorMinar @gkalpak Thanks for your awesome support in helping contributors. On this PR special thanks to @gkalpak making this possible with his great help.

#loveAngular ❤

@googlebot
Copy link

A Googler has manually verified that the CLAs look good.

(Googler, please make sure the reason for overriding the CLA status is clearly documented in these comments.)

ℹ️ Googlers: Go here for more info.

@matsko matsko closed this in b3dda0e Mar 21, 2019
matsko pushed a commit that referenced this pull request Mar 21, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ame on browser and Node.js (#27080)

PR Close #27080
matsko pushed a commit that referenced this pull request Mar 21, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
… that do not support SW (#27080)

The tests will not be run anyway, so the artifacts are never used and
there might be errors if creating the testing artifacts relies on APIs
that are not available in that environment (e.g. `URL`).

PR Close #27080
matsko pushed a commit that referenced this pull request Mar 21, 2019
…a domain (#27080)

Previously, it was not possible to have multiple apps (using
`@angular/service-worker`) on different subpaths of the same domain,
because each SW would overwrite the caches of the others (even though
their scope was different).

This commit fixes it by ensuring that the cache names created by the SW
are different for each scope.

Fixes #21388

PR Close #27080
matsko pushed a commit that referenced this pull request Mar 21, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ts (#27080)

PR Close #27080
matsko pushed a commit that referenced this pull request Mar 21, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…paths of a domain (#27080)

PR Close #27080
matsko pushed a commit that referenced this pull request Mar 21, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
#27080)

This commit also ensures that the correct implementation is used on
environments that do not support `URL` (e.g. Node.js).

PR Close #27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…)` optional (angular#27080)

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ame on browser and Node.js (angular#27080)

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
… that do not support SW (angular#27080)

The tests will not be run anyway, so the artifacts are never used and
there might be errors if creating the testing artifacts relies on APIs
that are not available in that environment (e.g. `URL`).

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019
…a domain (angular#27080)

Previously, it was not possible to have multiple apps (using
`@angular/service-worker`) on different subpaths of the same domain,
because each SW would overwrite the caches of the others (even though
their scope was different).

This commit fixes it by ensuring that the cache names created by the SW
are different for each scope.

Fixes angular#21388

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…ts (angular#27080)

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
…paths of a domain (angular#27080)

PR Close angular#27080
wKoza pushed a commit to wKoza/angular that referenced this pull request Apr 17, 2019

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
angular#27080)

This commit also ensures that the correct implementation is used on
environments that do not support `URL` (e.g. Node.js).

PR Close angular#27080
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: service-worker Issues related to the @angular/service-worker package cla: yes feature Issue that requests a new feature merge: caretaker note Alert the caretaker performing the merge to check the PR for an out of normal action needed or note risk: medium target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants