Skip to content

Commit

Permalink
refactor: zone and ssr/client
Browse files Browse the repository at this point in the history
  • Loading branch information
BioPhoton authored Aug 1, 2023
2 parents 0b5fcd8 + a0ce38e commit 68e4d99
Show file tree
Hide file tree
Showing 42 changed files with 413 additions and 334 deletions.
1 change: 0 additions & 1 deletion .github/workflows/cloudflare-hosting-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,3 @@ jobs:
commentId: cloudflare-preview-pages-hosting
onlyComments: on
outPath: ./dist/user-flow/cloudflare-worker
rcPath: projects/cloudflare-worker/.user-flowrc.action-hack.json
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,18 +221,20 @@ The CI has different actions:

## Docs

- **`docs-hosting-m.yml`** - runs on `m`
- **`docs-hosting-pr+m.yml`** - runs on `m`

## Test and Build

- **`ci.yml`** - runs on `pr` and `m` --affected build,test,lint,prerender

### Firebase Hosting
### Firebase

#### Hosting

- **`firebase-hosting-m.yml`** - runs on `m` firebase-function:deploy + movies:user-flow:production,
- **`firebase-hosting-pr.yml`** - runs on `pr` ng-universal-express:deploy + ng-universal-express:user-flow:preview

### Firebase Function
#### Function

As the build will not break because of require usage we need to test against function emulator

Expand Down
15 changes: 0 additions & 15 deletions projects/cloudflare-worker/.user-flowrc.action-hack.json

This file was deleted.

1 change: 1 addition & 0 deletions projects/cloudflare-worker/.user-flowrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
16 changes: 10 additions & 6 deletions projects/firebase-function/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ It is also fragile and does not allow save changes of the code.
How does it currently work:

- The `ng-universal-express` application is built in independently before the `firebase-function` build is executed
- The firebase build is a custom `tsc` execution and fragile not integrated well.
- The source code of the `ng-universal-express` application is used over a `require` statement.
This is needed to avoid consume the `main.js` bundle built the Angular CLI over webpack.
- The firebase build is a custom `tsc` execution and fragile + not integrated well.
- The source code of the `ng-universal-express` application is used over a `require` statement. ()
This is needed to avoid consume the `main.js` bundle built by the Angular CLI over webpack.
- The deployment of the `firebase-function` is entangled with the
static hosting folder structure of the `ng-universal-express` application and the `movies` application.
This is needed as the express server needs to spin up the Angular application and render it in case already rendered
version is available.
This is needed as the express server needs to spin up the Angular application and render it in case a already rendered
version is not available.
- The files `firebase.json` and `.firebaserc.json` define the project root.
- Firebase executes npm ci on the server to run the deployment.
- Firebase executes `npm ci` on the server to run the deployment. (no errors allowed no --force allowed)
- The closest `package.json` is used to execute the function (defined under the `main` property)
- This also is used as root in the functions and so in the angular app and affects the assets paths etc.
- For the targets `build`, `perender`, `serve` there are a couple of different requirements given.
ATM all of them live in the same file and are concurrent. It only works because of hacks.

##

Expand Down Expand Up @@ -70,3 +72,5 @@ const t = {
}
}
```


30 changes: 24 additions & 6 deletions projects/firebase-function/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,40 @@
"targets": {
"build": {
"executor": "@nx/webpack:webpack",
"outputs": ["{options.outputPath}"],
"outputs": [
"{options.outputPath}"
],
"options": {
"target": "node",
"compiler": "tsc",
"deleteOutputPath": false,
"sourceMap": false,
"namedChunks": true,
"compiler": "tsc",
"target": "node",
"outputPath": "./dist/projects/movies/server",
"outputFileName": "index.js",
"tsConfig": "./projects/firebase-function/tsconfig.function.json",
"main": "projects/firebase-function/src/index.ts",
"tsConfig": "./projects/firebase-function/tsconfig.function.json"
"outputFileName": "index.js"
},
"configurations": {
"production": {
"optimization": true,
"sourceMap": true
},
"development": {
"optimization": false,
"sourceMap": false
},
"stats": {
"optimization": true,
"statsJson": true
}
}
},
"serve": {
"executor": "nx:run-commands",
"options": {
"commands": [
"nx build firebase-function",
"nx run firebase-function:build",
"firebase emulators:start --project angular-movies"
],
"parallel": false
Expand Down
13 changes: 6 additions & 7 deletions projects/firebase-function/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import * as functions from 'firebase-functions';

/* Hack start */
/* HACK START */
declare const __non_webpack_require__: NodeRequire;
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
const ssrApp = __non_webpack_require__('./main').app(); // NOTE: leave this as require() since this file is built dynamically by Angular Universal CLI webpack
/* HACK END */

// tslint:disable-next-line:no-require-imports no-var-requires
// eslint-disable-next-line unicorn/prefer-module
const ssrApp = __non_webpack_require__('./main').app(); // NOTE: leave this as require() since this file is built dynamically by Angular CLI webpack
/* Hack end */

// "ssr" is the name in firebase.function.json
export const ssr = functions
.runWith({
timeoutSeconds: 5,
memory:
'4GB' /* 4096MB memory function will run at currently fastest - 4.8 GHz CPU ( https://cloud.google.com/functions/pricing) */,
// 4096MB memory function will run at currently fastest - 4.8 GHz CPU ( https://cloud.google.com/functions/pricing)
'4GB'
})
.https.onRequest(ssrApp);

Expand Down
13 changes: 0 additions & 13 deletions projects/firebase-function/tooling/generate-package-json/bin.ts

This file was deleted.

This file was deleted.

11 changes: 8 additions & 3 deletions projects/firebase-function/tsconfig.function.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"lib": ["es6", "dom", "es2015", "es2017"],
"lib": [
"es6",
"dom",
"es2015",
"es2017"
],
"module": "commonjs",
"noImplicitReturns": true,
"outDir": "../../dist/projects/movies/server",
"sourceMap": false,
"target": "es2019",
"allowJs": true,
"noImplicitAny": false,
"allowJs": false,
"noImplicitAny": true,
"strict": true,
"esModuleInterop": true
},
Expand Down
3 changes: 1 addition & 2 deletions projects/movies-user-flows/src/fixtures/tmdb.fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ export const TmdbAuthUrl = 'www.themoviedb.org/auth/access';
export const TmdbLoginUrl = 'www.themoviedb.org/login';
export const TmdbApproveBtn = 'input[value="Approve"]';
export const TmdbCookieRejectAllBtn = '#onetrust-reject-all-handler';
export const TmdbLoginBtn =
'#main > section > div > div > div:nth-child(2) > a';
export const TmdbLoginBtn = '#main > section > div > div > div:nth-child(2) > a';
export const TmdbUsernameInput = '#username';
export const TmdbPasswordInput = '#password';
export const TmdbUser = 'angular-movies';
Expand Down
11 changes: 3 additions & 8 deletions projects/movies/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@
"stats": {
"statsJson": true,
"namedChunks": true,
"sourceMap": true,
"extractLicenses": false,
"buildOptimizer": false,
"optimization": false,
"serviceWorker": false,
"budgets": false
"budgets": []
},
"production": {
"serviceWorker": true,
Expand All @@ -64,8 +59,8 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "349.9kb",
"maximumError": "350KB"
"maximumWarning": "350.8kb",
"maximumError": "351KB"
},
{
"type": "anyComponentStyle",
Expand Down
36 changes: 4 additions & 32 deletions projects/movies/src/app/app.base.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import {provideHttpClient, withInterceptors} from '@angular/common/http';
import {APP_INITIALIZER, ApplicationConfig, mergeApplicationConfig,} from '@angular/core';
import {ApplicationConfig, mergeApplicationConfig,} from '@angular/core';
import {provideClientHydration} from '@angular/platform-browser';
import {provideRouter, withDisabledInitialNavigation, withInMemoryScrolling,} from '@angular/router';
import {provideFastSVG} from '@push-based/ngx-fast-svg';
import {RxActionFactory} from '@rx-angular/state/actions';
import {ROUTES} from './routes';
import {withGobalStateInitializer} from './state/state-app-initializer.provider';
import {RX_RENDER_STRATEGIES_CONFIG} from '@rx-angular/cdk/render-strategies';
import {tmdbReadAccessInterceptor} from './auth/tmdb-http-interceptor.feature';
import {tmdbContentTypeInterceptor} from './data-access/api/tmdbContentTypeInterceptor';
import {provideTmdbImageLoader} from './data-access/images/image-loader';
import {withGlobalStateInitializer} from "./state/state-app-initializer.provider";

const appConfig: ApplicationConfig = {
providers: [
Expand Down Expand Up @@ -39,40 +37,14 @@ const appConfig: ApplicationConfig = {
scrollPositionRestoration: 'top',
})
),
provideFastSVG({
url: (name: string) => `assets/svg-icons/${name}.svg`,
}),
// global actions
// Global actions
RxActionFactory,
/**
* **🚀 Perf Tip for LCP, TTI:**
*
* Fetch data visible in viewport on app bootstrap instead of component initialization.
*/
withGobalStateInitializer(),
/**
* **🚀 Perf Tip for TBT:**
*
* Chunk app bootstrap over APP_INITIALIZER.
*/
{
provide: APP_INITIALIZER,
useFactory: () => (): Promise<void> =>
new Promise<void>((resolve) => {
setTimeout(() => resolve());
}),
deps: [],
multi: true,
},
/**
* **🚀 Perf Tip for TBT, LCP, CLS:**
*
* Configure RxAngular to get maximum performance.
*/
{
provide: RX_RENDER_STRATEGIES_CONFIG,
useValue: {patchZone: false},
},
withGlobalStateInitializer()
],
};

Expand Down
40 changes: 35 additions & 5 deletions projects/movies/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import {ApplicationConfig, NgZone} from '@angular/core';
import {
APP_INITIALIZER,
ApplicationConfig,
ɵInitialRenderPendingTasks as InitialRenderPendingTasks
} from '@angular/core';
import {mergeBaseConfig} from './app.base.config';
import {provideFastSVG} from '@push-based/ngx-fast-svg';
import {provideHttpClient, withInterceptors} from '@angular/common/http';
import {provideClientHydration} from '@angular/platform-browser';
import {RX_RENDER_STRATEGIES_CONFIG} from '@rx-angular/cdk/render-strategies';
import {tmdbContentTypeInterceptor} from './data-access/api/tmdbContentTypeInterceptor';
import {tmdbReadAccessInterceptor} from './auth/tmdb-http-interceptor.feature';
import {CustomNgZone} from './shared/zone-less/custom-zone';
import {provideServiceWorker} from '@angular/service-worker';
import {environment} from '../environments/environment';
import {waitForElementTiming} from "./shared/cdk/element-timing/wait-for-element-timing";
import {provideNgZoneZoneless} from "./shared/zone-less/provide-ngZone";

const browserConfig: ApplicationConfig = {
providers: [
Expand All @@ -28,9 +33,34 @@ const browserConfig: ApplicationConfig = {
provide: RX_RENDER_STRATEGIES_CONFIG,
useValue: {patchZone: false},
},
/**/{
provide: APP_INITIALIZER,
useFactory: (initialRenderPendingTasks: InitialRenderPendingTasks) =>
// () => Observable<unknown> | Promise<unknown> | void
(): void => {
const taskId = initialRenderPendingTasks.add();
waitForElementTiming(['header-main', 'tile-img']).finally(() => {
console.log(' initialRenderPendingTasks.remove(taskId)', taskId);
initialRenderPendingTasks.remove(taskId)
});
},
deps: [InitialRenderPendingTasks],
multi: true
},
provideNgZoneZoneless(),
/**
* **🚀 Perf Tip for TBT:**
*
* Chunk app bootstrap over APP_INITIALIZER.
*/
{
provide: NgZone,
useClass: CustomNgZone,
provide: APP_INITIALIZER,
useFactory: () => (): Promise<void> =>
new Promise<void>((resolve) => {
setTimeout(() => resolve());
}),
deps: [],
multi: true,
},
provideServiceWorker('ngsw-worker.js', {
enabled: environment.production,
Expand All @@ -41,4 +71,4 @@ const browserConfig: ApplicationConfig = {
],
};
// We provide the config function as closure to be able to inject configuration from the consuming end
export const appConfig = () => mergeBaseConfig(browserConfig);
export const appConfig = mergeBaseConfig(browserConfig);
Loading

0 comments on commit 68e4d99

Please sign in to comment.