Issue
i write an angular app and i getting a error:
"ERROR ReferenceError: localStorage is not defined"
I am just use in local-storage-service:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class LocalStorageService {
constructor() {}
setItem(key: string, value: string) {
localStorage.setItem(key, value);
}
getItem(key: string) {
return localStorage.getItem(key);
}
}
I wrote an interceptor:
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { LocalStorageService } from '../services/local-storage-service.service';
import { Injectable } from '@angular/core';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private localStorageService: LocalStorageService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let token = this.localStorageService.getItem('token');
let newRequest: HttpRequest<any>;
newRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + token),
});
return next.handle(newRequest);
}
}
And i add this line in app.module:
providers: [{provide:HTTP_INTERCEPTORS,useClass:AuthInterceptor,multi:true},provideClientHydration()],
How can I solve this problem?
I installed this npm package: localstorage-polyfill and add this 2 line
import 'localstorage-polyfill'
global['localStorage'] = localStorage;
so my server.ts like this :
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 AppServerModule from './src/main.server';
import 'localstorage-polyfill'
global['localStorage'] = localStorage;
// 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: AppServerModule,
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();
but problem is still same.
Solution
Try this:
//LocalStorageService
constructor(@Inject(PLATFORM_ID) platformId: object) {}
setItem(key: string, value: string) {
if (isPlatformBrowser(platformId)) {
localStorage.setItem(key, value);
}
}
getItem(key: string) {
if (isPlatformBrowser(platformId)) {
return localStorage.getItem(key);
}
return null;
}
The thing is that when you use SSR you must validate if its a browser to use window related objects, there are many ways to do this (check for example using domino), the example im giving you is a very simple one, but it could work.
Another way is to provide the localStorage with a factory, and validate if isPlatformBrowser, if not you could return a mocked localStorage.
Answered By - Oscar Ludick
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.