Skip to content

Commit

Permalink
Merge pull request #57 from squidit/feat/SQ-63811-ajustar-components-…
Browse files Browse the repository at this point in the history
…do-ngx-css-para-funcionar-em-ssr

SQ-63811 Ajustar components do NGX-CSS para funcionar em SSR
  • Loading branch information
CaioDalo committed May 10, 2024
2 parents 576c2e2 + 9de12a8 commit 66b6ab2
Show file tree
Hide file tree
Showing 25 changed files with 8,180 additions and 9,169 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ testem.log
.DS_Store
Thumbs.db
documentation

/.nx
3 changes: 3 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# auto-install-peers=true
shamefully-hoist=true
node-linker=hoisted
63 changes: 59 additions & 4 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"allowedCommonJsDependencies": [
"lodash.isequal"
],
"outputPath": "dist/application",
"outputPath": "dist/application/browser",
"index": "application/src/index.html",
"main": "application/src/main.ts",
"polyfills": [
Expand Down Expand Up @@ -81,18 +81,18 @@
},
"configurations": {
"production": {
"browserTarget": "application:build:production"
"buildTarget": "application:build:production"
},
"development": {
"browserTarget": "application:build:development"
"buildTarget": "application:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "application:build"
"buildTarget": "application:build"
}
},
"test": {
Expand Down Expand Up @@ -126,6 +126,61 @@
"options": {
"lintFilePatterns": ["application/src/**/*.{ts,html,js,json}"]
}
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "dist/application/server",
"main": "application/server.ts",
"tsConfig": "application/tsconfig.server.json",
"inlineStyleLanguage": "scss"
},
"configurations": {
"production": {
"outputHashing": "media"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"sourceMap": true,
"extractLicenses": false,
"vendorChunk": true
}
},
"defaultConfiguration": "production"
},
"serve-ssr": {
"builder": "@nguniversal/builders:ssr-dev-server",
"configurations": {
"development": {
"buildTarget": "application:build:development",
"serverTarget": "application:server:development"
},
"production": {
"buildTarget": "application:build:production",
"serverTarget": "application:server:production"
}
},
"defaultConfiguration": "development"
},
"prerender": {
"builder": "@nguniversal/builders:prerender",
"options": {
"routes": [
"/"
]
},
"configurations": {
"production": {
"buildTarget": "application:build:production",
"serverTarget": "application:server:production"
},
"development": {
"buildTarget": "application:build:development",
"serverTarget": "application:server:development"
}
},
"defaultConfiguration": "production"
}
}
},
Expand Down
56 changes: 56 additions & 0 deletions application/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 application/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'

const routes: Routes = []
export const routes: Routes = []

@NgModule({
imports: [RouterModule.forRoot(routes)],
Expand Down
2 changes: 1 addition & 1 deletion application/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
<router-outlet></router-outlet>
<!-- Use Here to test library components -->
</main>
</div>
</div>
26 changes: 18 additions & 8 deletions application/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core'
import { DOCUMENT, isPlatformServer } from '@angular/common'
import { Component, Inject, InjectionToken, OnInit, PLATFORM_ID } from '@angular/core'
import { GetWindow } from 'src/helpers/window.helper'


@Component({
Expand All @@ -7,19 +9,27 @@ import { Component, OnInit } from '@angular/core'
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
theme = window.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light'
isServer = isPlatformServer(this.platformId)

constructor(@Inject(PLATFORM_ID) private platformId: InjectionToken<Object>,
@Inject(DOCUMENT) private document: Document,
public getWindow: GetWindow
) {}

ngOnInit() {
this.theme = localStorage.getItem('theme') || this.theme
const html = document.getElementsByTagName('html')[0]
theme = this.getWindow.window()?.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light'

ngOnInit() {
this.theme = localStorage?.getItem('theme') || this.theme
const html = this.document.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
}

toggleTheme() {
this.theme = this.theme === 'dark' ? 'light' : 'dark'
const html = document.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
localStorage.setItem('theme', this.theme)
if(!this.isServer) {
const html = this.document.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
localStorage.setItem('theme', this.theme)
}
}
}
11 changes: 11 additions & 0 deletions application/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 application/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-routing.module'
import { provideClientHydration } from '@angular/platform-browser'

export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideClientHydration()]
}
24 changes: 24 additions & 0 deletions application/src/app/app.server.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core'
import { ServerModule } from '@angular/platform-server'

import { AppModule } from './app.module'
import { AppComponent } from './app.component'

import { UniversalRelativeInterceptor } from '../universal-relative.interceptor'
import { HTTP_INTERCEPTORS } from '@angular/common/http'

@NgModule({
imports: [
AppModule,
ServerModule,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UniversalRelativeInterceptor,
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
22 changes: 15 additions & 7 deletions application/src/app/components/header/header.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Component, OnInit } from '@angular/core'
import { isPlatformServer, DOCUMENT } from '@angular/common'
import { Component, Inject, InjectionToken, OnInit, PLATFORM_ID } from '@angular/core'
import { GetWindow } from 'src/helpers/window.helper'


@Component({
Expand All @@ -7,18 +9,24 @@ import { Component, OnInit } from '@angular/core'
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
theme = window.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light'
isServer = isPlatformServer(this.platformId)

constructor(@Inject(PLATFORM_ID) private platformId: InjectionToken<Object>, @Inject(DOCUMENT) private _doc: Document, public getWindow: GetWindow) {}

theme = this.getWindow.window()?.matchMedia('(prefers-color-scheme:dark)').matches ? 'dark' : 'light'

ngOnInit() {
this.theme = localStorage.getItem('theme') || this.theme
const html = document.getElementsByTagName('html')[0]
this.theme = localStorage?.getItem('theme') || this.theme
const html = this._doc.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
}

toggleTheme() {
this.theme = this.theme === 'dark' ? 'light' : 'dark'
const html = document.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
localStorage.setItem('theme', this.theme)
if(!this.isServer) {
const html = document.getElementsByTagName('html')[0]
html.classList.value = `${this.theme}`
localStorage.setItem('theme', this.theme)
}
}
}
9 changes: 9 additions & 0 deletions application/src/main.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export { AppServerModule } from './app/app.server.module'
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
31 changes: 31 additions & 0 deletions application/src/universal-relative.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'
import { Inject, Injectable, Optional } from '@angular/core'
import { REQUEST } from '@nguniversal/express-engine/tokens'
import { Request } from 'express'

// case insensitive check against config and value
const startsWithAny = (arr: string[] = []) => (value = '') => {
return arr.some(test => value.toLowerCase().startsWith(test.toLowerCase()))
}

// http, https, protocol relative
const isAbsoluteURL = startsWithAny(['http', '//'])

@Injectable()
export class UniversalRelativeInterceptor implements HttpInterceptor {
constructor(@Optional() @Inject(REQUEST) protected request: Request) {}

intercept(req: HttpRequest<any>, next: HttpHandler) {
if (this.request && !isAbsoluteURL(req.url)) {
const protocolHost = `${this.request.protocol}://${this.request.get(
'host'
)}`
const pathSeparator = !req.url.startsWith('/') ? '/' : ''
const url = protocolHost + pathSeparator + req.url
const serverRequest = req.clone({ url })
return next.handle(serverRequest)
} else {
return next.handle(req)
}
}
}
14 changes: 14 additions & 0 deletions application/tsconfig.server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.app.json",
"compilerOptions": {
"outDir": "../out-tsc/server",
"types": [
"node"
]
},
"files": [
"src/main.server.ts",
"server.ts"
]
}
Loading

0 comments on commit 66b6ab2

Please sign in to comment.