Skip to content

Re-run ngsw after modifications in app-shell - #11583

Merged
filipesilva merged 3 commits into
angular:masterfrom
filipesilva:app-shell-sw
Jul 20, 2018
Merged

filipesilva merged 3 commits into
angular:masterfrom
filipesilva:app-shell-sw

Conversation

@filipesilva

@filipesilva filipesilva commented Jul 18, 2018 •

Copy link
Copy Markdown
Contributor

Fix #8794

@filipesilva
filipesilva force-pushed the app-shell-sw branch 2 times, most recently from cbb62f6 to 55cca33 Compare July 18, 2018 17:04

@gkalpak gkalpak left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🎉

'ngsw-worker.js',
'worker-basic.min.js',
'safety-worker.js',
];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This hard-coded list feels very fragile 😁

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Those are the files we actually write back to disk further down on this file, so I think the knowledge of which files these are needs to be on the file anyway. Someone changing this file would have to change paths in both places though.

return architect.getBuilderDescription(builderConfig).pipe(
concatMap(description => architect.validateBuilderOptions(builderConfig, description)),
map(config => join(normalize(config.options.outputPath), 'index.html')),
// map(config => join(normalize(config.options.outputPath), 'index.html')),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be removed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oops!

})
.then(() => {
if (browserOptions.serviceWorker) {
return augmentAppWithServiceWorker(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if re-running this would introduce a noticeable delay for large projects (with lots of files to hash).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a concern, yeah. I don't think ngsw has a way to just update the hashes for some files though. I don't want to duplicate the hashing logic it uses inside the CLI.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The logic to hash files and write ngsw.json leaves in angular/angular-cli fwiw (mostly here). It wouldn't be too difiicult to add a function that reads ngsw.json, updates some file hashes and writes it back.

But this is not a very robust solution imo.
The current solution is probably fine for now, but on the long run I would expect a way to schedule "post-build" tasks, which would run after all builders have finished building.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this is the bit that calculates hashes:

switchMap(configJson => {
const Generator = require(swConfigPath).Generator;
const gen = new Generator(new CliFilesystem(host, outputPath), baseHref);
return gen.process(configJson);
}),

It lives in @angular/service-worker but we import it here to obtain the updated manifest, then write it back.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Generator calls CliFilessytem.list() to get the files and CliFilesystem.hash() to hash them. Then the ngsw.json manifest is written to dist further below. So, all the tools needed to read the existins ngsw.json, read and hash files and write the updated ngsw.json back are mostly in this file. (OK, there is a tiny piece of logic; i.e. how to update the hashtable in ngsw.json 😁)

Alternatively, Generator could expose a method to update specific files in an existing ngsw.json. So, then you could read the existing ngsw.json, pass it to Generator.updateHashes() and write the updated ngsw.json back.

But, I guess, that would mean that you need to check if the method is available (and this wouldn't work with older versions). Not sure how much of a problem this would be and whether it is worth it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh wow, that is right. I hadn't noticed it.

@alxhub do you have a suggestion on what the best approach is? I think you were the one that wrote the original code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this is worth optimizing just yet.

Honestly, the "correct" solution to me is to not generate ngsw.json until the entire build is done, including the App Shell. Running it twice seems like a hack (but a hack that will work).

alxhub
alxhub previously approved these changes Jul 19, 2018

@alxhub alxhub left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

I would favor a solution which only runs ngsw generation once, after all other build steps are completed. But this is an acceptable workaround if that's architecturally difficult right now.



class CliFilesystem implements Filesystem {
private _augmentedSwPaths = [

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe extract this to a const instead of a private field, to further indicate these are hardcoded paths.

})
.then(() => {
if (browserOptions.serviceWorker) {
return augmentAppWithServiceWorker(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this is worth optimizing just yet.

Honestly, the "correct" solution to me is to not generate ngsw.json until the entire build is done, including the App Shell. Running it twice seems like a hack (but a hack that will work).

@filipesilva

Copy link
Copy Markdown
Contributor Author

@gkalpak @alxhub took a slightly different approach: when running the browser target always override serviceWorker to false, and then after rendering universal augment with service worker if the browser target had service worker on.

This way it only runs once and there's no need to change the service worker code. PTAL when you have time.

@gkalpak gkalpak left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

💯

@filipesilva
filipesilva merged commit 290929c into angular:master Jul 20, 2018
@filipesilva
filipesilva deleted the app-shell-sw branch July 20, 2018 20:21
@angular-automatic-lock-bot

Copy link
Copy Markdown

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 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[app-shell] Doesn't work together with @angular/service-worker: "Error: Hash mismatch (cacheBustedFetchFromNetwork)" (+ explanation, + solution)

5 participants