@@ -39,7 +39,15 @@
|
|
39 |
"styles": [
|
40 |
"src/styles.css"
|
41 |
],
|
42 |
-
"scripts": []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
},
|
44 |
"configurations": {
|
45 |
"production": {
|
39 |
"styles": [
|
40 |
"src/styles.css"
|
41 |
],
|
42 |
+
"scripts": [],
|
43 |
+
"server": "src/main.server.ts",
|
44 |
+
"prerender": {
|
45 |
+
"discoverRoutes": true,
|
46 |
+
"routesFile": "routes.txt"
|
47 |
+
},
|
48 |
+
"ssr": {
|
49 |
+
"entry": "src/server.ts"
|
50 |
+
}
|
51 |
},
|
52 |
"configurations": {
|
53 |
"production": {
|
@@ -7,7 +7,8 @@
|
|
7 |
"build": "ng build",
|
8 |
"watch": "ng build --watch --configuration development",
|
9 |
"test": "ng test",
|
10 |
-
"lint": "ng lint"
|
|
|
11 |
},
|
12 |
"private": true,
|
13 |
"dependencies": {
|
@@ -19,9 +20,12 @@
|
|
19 |
"@angular/forms": "^19.1.0",
|
20 |
"@angular/platform-browser": "^19.1.0",
|
21 |
"@angular/platform-browser-dynamic": "^19.1.0",
|
|
|
22 |
"@angular/router": "^19.1.0",
|
|
|
23 |
"angular-date-value-accessor": "^3.0.0",
|
24 |
"book-monkey5-styles": "^1.0.4",
|
|
|
25 |
"rxjs": "~7.8.0",
|
26 |
"tslib": "^2.3.0",
|
27 |
"zone.js": "~0.15.0"
|
@@ -30,7 +34,9 @@
|
|
30 |
"@angular-devkit/build-angular": "^19.1.1",
|
31 |
"@angular/cli": "^19.1.1",
|
32 |
"@angular/compiler-cli": "^19.1.0",
|
|
|
33 |
"@types/jasmine": "~5.1.0",
|
|
|
34 |
"angular-eslint": "19.0.2",
|
35 |
"eslint": "^9.16.0",
|
36 |
"jasmine-core": "~5.5.0",
|
@@ -42,4 +48,4 @@
|
|
42 |
"typescript": "~5.7.2",
|
43 |
"typescript-eslint": "8.18.0"
|
44 |
}
|
45 |
-
}
|
7 |
"build": "ng build",
|
8 |
"watch": "ng build --watch --configuration development",
|
9 |
"test": "ng test",
|
10 |
+
"lint": "ng lint",
|
11 |
+
"serve:ssr:book-monkey": "node dist/book-monkey/server/server.mjs"
|
12 |
},
|
13 |
"private": true,
|
14 |
"dependencies": {
|
20 |
"@angular/forms": "^19.1.0",
|
21 |
"@angular/platform-browser": "^19.1.0",
|
22 |
"@angular/platform-browser-dynamic": "^19.1.0",
|
23 |
+
"@angular/platform-server": "^19.1.0",
|
24 |
"@angular/router": "^19.1.0",
|
25 |
+
"@angular/ssr": "^19.1.1",
|
26 |
"angular-date-value-accessor": "^3.0.0",
|
27 |
"book-monkey5-styles": "^1.0.4",
|
28 |
+
"express": "^4.18.2",
|
29 |
"rxjs": "~7.8.0",
|
30 |
"tslib": "^2.3.0",
|
31 |
"zone.js": "~0.15.0"
|
34 |
"@angular-devkit/build-angular": "^19.1.1",
|
35 |
"@angular/cli": "^19.1.1",
|
36 |
"@angular/compiler-cli": "^19.1.0",
|
37 |
+
"@types/express": "^4.17.17",
|
38 |
"@types/jasmine": "~5.1.0",
|
39 |
+
"@types/node": "^18.18.0",
|
40 |
"angular-eslint": "19.0.2",
|
41 |
"eslint": "^9.16.0",
|
42 |
"jasmine-core": "~5.5.0",
|
48 |
"typescript": "~5.7.2",
|
49 |
"typescript-eslint": "8.18.0"
|
50 |
}
|
51 |
+
}
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/
|
2 |
+
/home
|
3 |
+
/books
|
4 |
+
/books/9783864909467
|
5 |
+
/books/9783864907791
|
6 |
+
/books/9783864906466
|
7 |
+
/books/9783864903571
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NgModule } from '@angular/core';
|
2 |
+
import { ServerModule } from '@angular/platform-server';
|
3 |
+
|
4 |
+
import { AppModule } from './app.module';
|
5 |
+
import { AppComponent } from './app.component';
|
6 |
+
|
7 |
+
@NgModule({
|
8 |
+
imports: [
|
9 |
+
AppModule,
|
10 |
+
ServerModule,
|
11 |
+
],
|
12 |
+
bootstrap: [AppComponent],
|
13 |
+
})
|
14 |
+
export class AppServerModule {}
|
@@ -1,6 +1,6 @@
|
|
1 |
import { NgModule } from '@angular/core';
|
2 |
import { provideHttpClient, withInterceptorsFromDi, HTTP_INTERCEPTORS } from '@angular/common/http';
|
3 |
-
import { BrowserModule } from '@angular/platform-browser';
|
4 |
|
5 |
import { AppRoutingModule } from './app-routing.module';
|
6 |
import { AppComponent } from './app.component';
|
@@ -24,7 +24,8 @@ import { AuthInterceptor } from './shared/auth.interceptor';
|
|
24 |
provide: HTTP_INTERCEPTORS,
|
25 |
useClass: AuthInterceptor,
|
26 |
multi: true
|
27 |
-
}
|
|
|
28 |
],
|
29 |
bootstrap: [AppComponent]
|
30 |
})
|
1 |
import { NgModule } from '@angular/core';
|
2 |
import { provideHttpClient, withInterceptorsFromDi, HTTP_INTERCEPTORS } from '@angular/common/http';
|
3 |
+
import { BrowserModule, provideClientHydration } from '@angular/platform-browser';
|
4 |
|
5 |
import { AppRoutingModule } from './app-routing.module';
|
6 |
import { AppComponent } from './app.component';
|
24 |
provide: HTTP_INTERCEPTORS,
|
25 |
useClass: AuthInterceptor,
|
26 |
multi: true
|
27 |
+
},
|
28 |
+
provideClientHydration()
|
29 |
],
|
30 |
bootstrap: [AppComponent]
|
31 |
})
|
@@ -0,0 +1 @@
|
|
|
1 |
+
export { AppServerModule as default } from './app/app.module.server';
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { APP_BASE_HREF } from '@angular/common';
|
2 |
+
import { CommonEngine, isMainModule } from '@angular/ssr/node';
|
3 |
+
import express from 'express';
|
4 |
+
import { dirname, join, resolve } from 'node:path';
|
5 |
+
import { fileURLToPath } from 'node:url';
|
6 |
+
import AppServerModule from './main.server';
|
7 |
+
|
8 |
+
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
|
9 |
+
const browserDistFolder = resolve(serverDistFolder, '../browser');
|
10 |
+
const indexHtml = join(serverDistFolder, 'index.server.html');
|
11 |
+
|
12 |
+
const app = express();
|
13 |
+
const commonEngine = new CommonEngine();
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Example Express Rest API endpoints can be defined here.
|
17 |
+
* Uncomment and define endpoints as necessary.
|
18 |
+
*
|
19 |
+
* Example:
|
20 |
+
* ```ts
|
21 |
+
* app.get('/api/**', (req, res) => {
|
22 |
+
* // Handle API request
|
23 |
+
* });
|
24 |
+
* ```
|
25 |
+
*/
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Serve static files from /browser
|
29 |
+
*/
|
30 |
+
app.get(
|
31 |
+
'**',
|
32 |
+
express.static(browserDistFolder, {
|
33 |
+
maxAge: '1y',
|
34 |
+
index: 'index.html'
|
35 |
+
}),
|
36 |
+
);
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Handle all other requests by rendering the Angular application.
|
40 |
+
*/
|
41 |
+
app.get('**', (req, res, next) => {
|
42 |
+
const { protocol, originalUrl, baseUrl, headers } = req;
|
43 |
+
|
44 |
+
commonEngine
|
45 |
+
.render({
|
46 |
+
bootstrap: AppServerModule,
|
47 |
+
documentFilePath: indexHtml,
|
48 |
+
url: `${protocol}://${headers.host}${originalUrl}`,
|
49 |
+
publicPath: browserDistFolder,
|
50 |
+
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
|
51 |
+
})
|
52 |
+
.then((html) => res.send(html))
|
53 |
+
.catch((err) => next(err));
|
54 |
+
});
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Start the server if this module is the main entry point.
|
58 |
+
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
|
59 |
+
*/
|
60 |
+
if (isMainModule(import.meta.url)) {
|
61 |
+
const port = process.env['PORT'] || 4000;
|
62 |
+
app.listen(port, () => {
|
63 |
+
console.log(`Node Express server listening on http://localhost:${port}`);
|
64 |
+
});
|
65 |
+
}
|
@@ -4,10 +4,14 @@
|
|
4 |
"extends": "./tsconfig.json",
|
5 |
"compilerOptions": {
|
6 |
"outDir": "./out-tsc/app",
|
7 |
-
"types": [
|
|
|
|
|
8 |
},
|
9 |
"files": [
|
10 |
-
"src/main.ts"
|
|
|
|
|
11 |
],
|
12 |
"include": [
|
13 |
"src/**/*.d.ts"
|
4 |
"extends": "./tsconfig.json",
|
5 |
"compilerOptions": {
|
6 |
"outDir": "./out-tsc/app",
|
7 |
+
"types": [
|
8 |
+
"node"
|
9 |
+
]
|
10 |
},
|
11 |
"files": [
|
12 |
+
"src/main.ts",
|
13 |
+
"src/main.server.ts",
|
14 |
+
"src/server.ts"
|
15 |
],
|
16 |
"include": [
|
17 |
"src/**/*.d.ts"
|