Skip to content

Commit 4d18a40

Browse files
authored
feat(docs): migrated to SSR (#DS-3683) (#1121)
1 parent 8dbf871 commit 4d18a40

14 files changed

Lines changed: 228 additions & 166 deletions

File tree

angular.json

Lines changed: 43 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,38 @@
22
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
33
"version": 1,
44
"newProjectRoot": "projects",
5+
"schematics": {
6+
"@schematics/angular:component": {
7+
"style": "scss",
8+
"changeDetection": "OnPush",
9+
"standalone": true,
10+
"inlineTemplate": true,
11+
"inlineStyle": true,
12+
"skipTests": true
13+
},
14+
"@schematics/angular:application": {
15+
"strict": true,
16+
"standalone": true,
17+
"inlineTemplate": true,
18+
"inlineStyle": true,
19+
"skipTests": true,
20+
"minimal": true
21+
}
22+
},
523
"projects": {
624
"koobiq-docs": {
725
"projectType": "application",
8-
"schematics": {
9-
"@schematics/angular:component": {
10-
"style": "scss",
11-
"changeDetection": "OnPush",
12-
"standalone": true,
13-
"inlineTemplate": true,
14-
"inlineStyle": true,
15-
"skipTests": true
16-
},
17-
"@schematics/angular:application": {
18-
"strict": true
19-
}
20-
},
2126
"root": "apps/docs",
2227
"sourceRoot": "apps/docs",
23-
"prefix": "app",
28+
"prefix": "docs",
2429
"architect": {
2530
"build": {
26-
"builder": "@angular-devkit/build-angular:browser",
31+
"builder": "@angular-devkit/build-angular:application",
2732
"options": {
28-
"sourceMap": true,
29-
"outputPath": "./dist/releases/koobiq-docs",
33+
"outputPath": {
34+
"base": "dist/releases/koobiq-docs"
35+
},
3036
"index": "apps/docs/src/index.html",
31-
"main": "apps/docs/src/main.ts",
3237
"polyfills": ["zone.js"],
3338
"tsConfig": "apps/docs/tsconfig.app.json",
3439
"assets": [
@@ -76,86 +81,46 @@
7681
"stylePreprocessorOptions": {
7782
"includePaths": ["dist", "apps/docs/src"]
7883
},
79-
"styles": [
80-
"apps/docs/src/main.scss"
81-
],
84+
"styles": ["apps/docs/src/main.scss"],
8285
"scripts": [],
83-
"vendorChunk": true,
84-
"extractLicenses": false,
85-
"buildOptimizer": false,
86-
"optimization": false,
8786
"namedChunks": true,
88-
"allowedCommonJsDependencies": [
89-
"highlight.js",
90-
"@messageformat/core",
91-
"path-normalize"
92-
]
87+
"browser": "apps/docs/src/main.ts",
88+
"server": "apps/docs/src/main.server.ts",
89+
"prerender": true,
90+
"ssr": {
91+
"entry": "apps/docs/src/server.ts"
92+
}
9393
},
9494
"configurations": {
95-
"development": {
96-
"tsConfig": "apps/docs/tsconfig.app.json",
97-
"fileReplacements": [
98-
{
99-
"replace": "apps/docs/src/environments/environment.ts",
100-
"with": "apps/docs/src/environments/environment.prod.ts"
101-
}
102-
],
103-
"budgets": [
104-
{
105-
"type": "initial",
106-
"maximumWarning": "2mb",
107-
"maximumError": "5mb"
108-
}
109-
]
110-
},
11195
"production": {
96+
"outputHashing": "all",
11297
"tsConfig": "apps/docs/tsconfig.build.json",
11398
"fileReplacements": [
11499
{
115100
"replace": "apps/docs/src/environments/environment.ts",
116101
"with": "apps/docs/src/environments/environment.prod.ts"
117102
}
118-
],
119-
"optimization": {
120-
"scripts": true,
121-
"styles": true,
122-
"fonts": false
123-
},
124-
"outputHashing": "all",
125-
"sourceMap": false,
126-
"namedChunks": false,
127-
"extractLicenses": true,
128-
"vendorChunk": false,
129-
"buildOptimizer": true,
130-
"aot": true,
131-
"budgets": [
132-
{
133-
"type": "initial",
134-
"maximumWarning": "2mb",
135-
"maximumError": "5mb"
136-
},
137-
{
138-
"type": "anyComponentStyle",
139-
"maximumWarning": "6kb",
140-
"maximumError": "10kb"
141-
}
142103
]
104+
},
105+
"development": {
106+
"optimization": false,
107+
"extractLicenses": false,
108+
"sourceMap": true
143109
}
144-
}
110+
},
111+
"defaultConfiguration": "production"
145112
},
146113
"serve": {
147114
"builder": "@angular-devkit/build-angular:dev-server",
148-
"options": {
149-
"buildTarget": "koobiq-docs:build"
150-
},
151115
"configurations": {
152-
"development": {
153-
"buildTarget": "koobiq-docs:build:development"
154-
},
155116
"production": {
156117
"buildTarget": "koobiq-docs:build:production"
118+
},
119+
"development": {
120+
"buildTarget": "koobiq-docs:build:development"
157121
}
158-
}
122+
},
123+
"defaultConfiguration": "development"
159124
},
160125
"test": {
161126
"builder": "@angular-builders/jest:run",

apps/docs/README.md

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,41 @@
1-
## [Production Build](../../.github/workflows/actions/build-docs/action.yml)
1+
# Documentation application
22

3-
Before building the documentation, you must first [build packages](#build-packages) and [generate sitemap](#generate-sitemapxml)
3+
This is the [Koobiq design system](https://koobiq.io/en) website application.
44

5-
```bash
6-
yarn run build:docs-examples-module &&
7-
yarn run build:docs-examples &&
8-
yarn run build:docs-content &&
9-
yarn run build:package-docs-content &&
10-
yarn run docs:build
11-
```
5+
## Development
126

13-
## Generate `sitemap.xml`
7+
Make sure you have the [correct version](.nvmrc) of Node.js installed (we recommend using [nvm](https://github.com/nvm-sh/nvm)).
148

159
```bash
16-
yarn run docs:generate-sitemap
17-
```
10+
# Setup Node.js
11+
nvm use
1812

19-
## Build packages
13+
# Install dependencies
14+
yarn install
2015

21-
```bash
22-
yarn run build:cdk &&
23-
yarn run build:components &&
24-
yarn run build:angular-luxon-adapter &&
25-
yarn run build:angular-moment-adapter &&
16+
# Build packages
17+
yarn run build:cdk
18+
yarn run build:angular-luxon-adapter
19+
yarn run build:angular-moment-adapter
2620
yarn run styles:build-all
27-
```
28-
29-
## Generate `docs-content` folder (dgeni)
30-
31-
```bash
32-
yarn run build:docs-content && yarn run build:package-docs-content
33-
```
21+
yarn run build:components
22+
yarn run build:components-experimental
3423

35-
## Generate basic module
24+
# Generate content
25+
yarn run build:docs-content
26+
yarn run build:package-docs-content
3627

37-
```bash
28+
# Generate examples
3829
yarn run build:docs-examples-module
39-
```
40-
41-
## Generate examples
42-
43-
```bash
4430
yarn run build:docs-examples
45-
```
4631

47-
## Debugging
32+
# Generate sitemap
33+
yarn run docs:generate-sitemap
4834

49-
```bash
35+
# Run application
5036
yarn run docs:start:dev
37+
# Then open http://localhost:4200
38+
39+
# Build application
40+
yarn run docs:build
5141
```

apps/docs/src/app/components/anchors/anchors.component.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export class DocsAnchorsComponent implements OnDestroy, OnInit {
131131
return this.anchors.find((anchor) => anchor.href === href) || this.firstAnchor;
132132
}
133133

134-
setScrollPosition() {
134+
setScrollPosition(): void {
135135
this.anchors = this.createAnchors();
136136

137137
this.updateActiveAnchor();
@@ -143,14 +143,18 @@ export class DocsAnchorsComponent implements OnDestroy, OnInit {
143143
// scroll after docs-sidepanel scrolled
144144
setTimeout(() => target.scrollIntoView());
145145
} else {
146-
this.scrollContainer.scroll(0, 0);
146+
// For SSR compatibility
147+
if (typeof this.scrollContainer.scroll === 'function') this.scrollContainer.scroll(0, 0);
147148
}
148149

149150
this.scrollSubscription?.unsubscribe();
150151

151-
this.scrollSubscription = fromEvent(this.scrollContainer, 'scroll')
152-
.pipe(debounceTime(this.debounceTime), takeUntilDestroyed(this.destroyRef))
153-
.subscribe(this.onScroll);
152+
// For SSR compatibility
153+
if (typeof this.scrollContainer.scroll === 'function') {
154+
this.scrollSubscription = fromEvent(this.scrollContainer, 'scroll')
155+
.pipe(debounceTime(this.debounceTime), takeUntilDestroyed(this.destroyRef))
156+
.subscribe(this.onScroll);
157+
}
154158

155159
this.ref.detectChanges();
156160
}
@@ -209,10 +213,16 @@ export class DocsAnchorsComponent implements OnDestroy, OnInit {
209213
);
210214
}
211215

212-
private getHeaderTopOffset(header: HTMLElement) {
213-
const bodyTop = this.document.body.getBoundingClientRect().top;
216+
private getHeaderTopOffset(header: HTMLElement): number {
217+
// For SSR compatibility
218+
if (typeof this.document.body.getBoundingClientRect !== 'function') return 0;
214219

215-
return this.scrollContainer.scrollTop + header.getBoundingClientRect().top - bodyTop + this.headerHeight;
220+
return (
221+
this.scrollContainer.scrollTop +
222+
header.getBoundingClientRect().top -
223+
this.document.body.getBoundingClientRect().top +
224+
this.headerHeight
225+
);
216226
}
217227

218228
private getLevel(classList): number {

apps/docs/src/config.server.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { mergeApplicationConfig, Provider } from '@angular/core';
2+
import { provideServerRendering } from '@angular/platform-server';
3+
import { KBQ_WINDOW } from '@koobiq/components/core';
4+
import config from './config';
5+
6+
const provideServerWindow = (): Provider => {
7+
return {
8+
provide: KBQ_WINDOW,
9+
useFactory: () => {
10+
return {
11+
matchMedia: () => ({
12+
addEventListener: () => {},
13+
dispatchEvent: () => false,
14+
removeEventListener: () => {},
15+
matches: false,
16+
media: '',
17+
onchange: null,
18+
addListener: () => {},
19+
removeListener: () => {}
20+
}),
21+
localStorage: {
22+
length: 0,
23+
getItem: () => null,
24+
setItem: () => {},
25+
removeItem: () => {},
26+
clear: () => {},
27+
key: () => null
28+
},
29+
location: {
30+
host: '',
31+
protocol: '',
32+
ancestorOrigins: {} as DOMStringList,
33+
hash: '',
34+
hostname: '',
35+
href: '',
36+
origin: '',
37+
pathname: '/',
38+
port: '',
39+
search: '',
40+
assign: () => {},
41+
reload: () => {},
42+
replace: () => {}
43+
}
44+
} satisfies Partial<Window>;
45+
}
46+
};
47+
};
48+
49+
export default mergeApplicationConfig(config, {
50+
providers: [
51+
provideServerRendering(),
52+
provideServerWindow()
53+
]
54+
});

apps/docs/src/config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { provideHttpClient, withFetch } from '@angular/common/http';
2+
import { ApplicationConfig } from '@angular/core';
3+
import { provideAnimations } from '@angular/platform-browser/animations';
4+
import { provideRouter } from '@angular/router';
5+
import { KBQ_LOCALE_SERVICE, KbqLocaleService, kbqLocaleServiceLangAttrNameProvider } from '@koobiq/components/core';
6+
import { DOCS_ROUTES } from './app/routes';
7+
8+
export default {
9+
providers: [
10+
{ provide: KBQ_LOCALE_SERVICE, useClass: KbqLocaleService },
11+
kbqLocaleServiceLangAttrNameProvider('examples-lang'),
12+
provideRouter(DOCS_ROUTES),
13+
provideHttpClient(withFetch()),
14+
provideAnimations()
15+
]
16+
} satisfies ApplicationConfig;

apps/docs/src/main.server.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
2+
import { DocsAppComponent } from './app/app.component';
3+
import config from './config.server';
4+
5+
export default (context: BootstrapContext) => bootstrapApplication(DocsAppComponent, config, context);

apps/docs/src/main.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
import { provideHttpClient } from '@angular/common/http';
2-
import { enableProdMode } from '@angular/core';
31
import { bootstrapApplication } from '@angular/platform-browser';
4-
import { provideAnimations } from '@angular/platform-browser/animations';
5-
import { provideRouter } from '@angular/router';
6-
import { KBQ_LOCALE_SERVICE, KbqLocaleService, kbqLocaleServiceLangAttrNameProvider } from '@koobiq/components/core';
72
import { DocsAppComponent } from './app/app.component';
8-
import { DOCS_ROUTES } from './app/routes';
9-
import { environment } from './environments/environment';
3+
import config from './config';
104

11-
if (environment.production) {
12-
enableProdMode();
13-
}
14-
15-
bootstrapApplication(DocsAppComponent, {
16-
providers: [
17-
provideAnimations(),
18-
provideHttpClient(),
19-
provideRouter(DOCS_ROUTES),
20-
kbqLocaleServiceLangAttrNameProvider('examples-lang'),
21-
{ provide: KBQ_LOCALE_SERVICE, useClass: KbqLocaleService }]
22-
}).catch((error) => console.error(error));
5+
bootstrapApplication(DocsAppComponent, config).catch((err) => console.error(err));

0 commit comments

Comments
 (0)