Skip to content
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

test(ssr): extending the bundle-test project for SSR #13911

Merged
merged 6 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

strategy:
matrix:
node-version: [18.x, 20.5.x]
node-version: [18.x, 20.x]

steps:
- name: Checkout
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:
run: |
npm run build:i18n
npm run test:i18n:dist
- name: Bundle Tree-Shake Test
- name: Bundle Tree-Shake & SSR Test
run: npm run build:bundletest
- name: Publish to coveralls.io
if: github.repository == 'IgniteUI/igniteui-angular' && matrix.node-version == '18.x'
Expand Down
5 changes: 5 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@
"includePaths": [
"node_modules"
]
},
"server": "projects/bundle-test/src/main.server.ts",
"prerender": true,
"ssr": {
"entry": "projects/bundle-test/server.ts"
}
},
"configurations": {
Expand Down
56 changes: 56 additions & 0 deletions projects/bundle-test/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine } from '@angular/ssr';
import express from 'express';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import bootstrap from './src/main.server';

// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');

const commonEngine = new CommonEngine();

server.set('view engine', 'html');
server.set('views', browserDistFolder);

// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(browserDistFolder, {
maxAge: '1y'
}));

// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;

commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});

return server;
}

function run(): void {
const port = process.env['PORT'] || 4000;

// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}

run();
2 changes: 1 addition & 1 deletion projects/bundle-test/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { AppComponent } from './app.component';

describe('AppComponent', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [AppComponent]
imports: [AppComponent]
}));

it('should create the app', () => {
Expand Down
9 changes: 6 additions & 3 deletions projects/bundle-test/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { Component } from '@angular/core';
import { ChipResourceStringsBG } from 'igniteui-angular-i18n';
import { RouterOutlet } from '@angular/router';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
standalone: true,
imports: [RouterOutlet]
})
export class AppComponent {
protected chipStrings = ChipResourceStringsBG;
Expand Down
11 changes: 11 additions & 0 deletions projects/bundle-test/src/app/app.config.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';

const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering()
]
};

export const config = mergeApplicationConfig(appConfig, serverConfig);
9 changes: 9 additions & 0 deletions projects/bundle-test/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { provideClientHydration } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideClientHydration()]
};
18 changes: 0 additions & 18 deletions projects/bundle-test/src/app/app.module.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { Routes } from '@angular/router';
import { ChipComponent } from './chip/chip.component';
import { ButtonGroupComponent } from './button-group/button-group.component';

const routes: Routes = [
export const routes: Routes = [
{ path: '', redirectTo: '/chip', pathMatch: 'full' },
{ path: 'chip', component: ChipComponent },
{ path: 'button-group', component: ButtonGroupComponent}
// { path: 'form', loadComponent: () => import('./form/form.component').then(m => m.FormComponent) },
// { path: 'stepper', loadComponent: () => import('./stepper/stepper.component').then(m => m.StepperComponent) },
// { path: 'grid', loadComponent: () => import('./grid/grid.component').then(m => m.GridComponent) }
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<igx-buttongroup>
<button type="button" igxButton="flat">Button 1</button>
<button type="button" igxButton="flat">Button 2</button>
<button type="button" igxButton="flat">Button 3</button>
</igx-buttongroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IGX_BUTTON_GROUP_DIRECTIVES } from 'igniteui-angular';

@Component({
selector: 'app-button-group',
standalone: true,
imports: [
IGX_BUTTON_GROUP_DIRECTIVES
],
templateUrl: './button-group.component.html',
styleUrl: './button-group.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ButtonGroupComponent { }
7 changes: 7 additions & 0 deletions projects/bundle-test/src/main.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';

const bootstrap = () => bootstrapApplication(AppComponent, config);

export default bootstrap;
9 changes: 4 additions & 5 deletions projects/bundle-test/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppComponent } from './app/app.component';
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';

import { AppModule } from './app/app.module';


platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err));
1 change: 1 addition & 0 deletions projects/bundle-test/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ $app-palette: palette(

$include: (
igx-chip,
igx-buttongroup,
// igx-checkbox,
// igx-radio,
// igx-switch,
Expand Down
8 changes: 6 additions & 2 deletions projects/bundle-test/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/app",
"types": [],
"types": [
"node"
],
"paths": {
"igniteui-angular": [
"dist/igniteui-angular"
Expand All @@ -17,7 +19,9 @@
}
},
"files": [
"src/main.ts"
"src/main.ts",
"src/main.server.ts",
"server.ts"
],
"include": [
"src/**/*.d.ts"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ export class IgxButtonGroupComponent extends DisplayDensityBase implements After

this.mutationObserver = this.setMutationsObserver();

this.mutationObserver.observe(this._el.nativeElement, this.observerConfig);
this.mutationObserver?.observe(this._el.nativeElement, this.observerConfig);
}

/**
Expand All @@ -483,7 +483,7 @@ export class IgxButtonGroupComponent extends DisplayDensityBase implements After
this.queryListNotifier$.next();
this.queryListNotifier$.complete();

this.mutationObserver.disconnect();
this.mutationObserver?.disconnect();
}

/**
Expand Down Expand Up @@ -513,28 +513,35 @@ export class IgxButtonGroupComponent extends DisplayDensityBase implements After
}
}

this.mutationObserver.observe(this._el.nativeElement, this.observerConfig);
this.mutationObserver?.observe(this._el.nativeElement, this.observerConfig);
}

private setMutationsObserver() {
return new MutationObserver((records, observer) => {
// Stop observing while handling changes
observer.disconnect();
if (typeof MutationObserver !== 'undefined') {
return new MutationObserver((records, observer) => {
// Stop observing while handling changes
observer.disconnect();

const updatedButtons = this.getUpdatedButtons(records);
const updatedButtons = this.getUpdatedButtons(records);

if (updatedButtons.length > 0) {
updatedButtons.forEach((button) => {
const index = this.buttons.map((b) => b.nativeElement).indexOf(button);
const args: IButtonGroupEventArgs = { owner: this, button: this.buttons[index], index };
if (updatedButtons.length > 0) {
updatedButtons.forEach((button) => {
const index = this.buttons.map((b) => b.nativeElement).indexOf(button);
const args: IButtonGroupEventArgs = { owner: this, button: this.buttons[index], index };

this.updateButtonSelectionState(index, args);
});
}
this.updateButtonSelectionState(index, args);
});
}

// Watch for changes again
observer.observe(this._el.nativeElement, this.observerConfig);
});
// Watch for changes again
observer.observe(this._el.nativeElement, this.observerConfig);

// Cleanup function
this._renderer.listen(this._el.nativeElement, 'DOMNodeRemoved', () => {
observer.disconnect();
});
});
}
}

private getUpdatedButtons(records: MutationRecord[]) {
Expand Down
9 changes: 6 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
"baseUrl": "./",
"downlevelIteration": true,
"importHelpers": true,
"module": "es2020",
"module": "es2022",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"moduleResolution": "node",
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"target": "ES2022",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2019",
"es2022",
"dom"
],
"paths": {
Expand Down Expand Up @@ -45,6 +47,7 @@
"generateDeepReexports": true,
"strictTemplates": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
}
}
Loading