Server.ts changes are not being process after deploying to nelify but works fine locally
mrrohit1 opened this issue ยท 9 comments
Describe the bug
Update my server.ts file to manage 301 redirect and added sanitization for json in final souuce code but both changes are not working, i can see its working locally but after deploying to netlify its not working
To Reproduce
Steps to reproduce the behavior:
- Make 301 redirects in server.ts file
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);
server.get('*.*', express.static(browserDistFolder, {
maxAge: '1y'
}));
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
const redirectUrl = redirectMap[req.url];
if (redirectUrl) {
res.redirect(301, redirectUrl);
}else{
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [
{ provide: APP_BASE_HREF, useValue: baseUrl },
],
})
.then((html) => {
// Extract the state
const stateRegex = /<script id="ng-state" type="application\/json">(.*?)<\/script>/;
const match = html.match(stateRegex);
if (match && match[1]) {
const state = JSON.parse(match[1]);
const sanitizedState = sanitizeState(state);
const serializedState = JSON.stringify(sanitizedState);
// Replace the original state with the sanitized state
html = html.replace(stateRegex, `<script id="ng-state" type="application/json">${serializedState}</script>`);
}
res.send(html);
})
.catch((err) => next(err));
}
});
return server;
}
function run(): void {
const port = process.env['PORT'] || 4000;
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
run();
redirectMap:
export const redirectMap: { [key: string]: string } = {
'old url 1' : 'new url 1',
'old url 2' : 'new url 2',
'old url 3' : 'new url 3',
// other urls
}
sanitize-state :
export function sanitizeState(state: any): any {
const sanitizedState = JSON.parse(JSON.stringify(state));
Object.keys(sanitizedState).forEach(key => {
if (sanitizedState[key]?.u) {
delete sanitizedState[key].u;
}
});
return sanitizedState;
}
Expected behavior
after deployment redirect should work but its not working and same for sanitize state
Versions
- Angular.js: 18
If you're using the CLI to build
N/A
If you're using file-based installation
[build]
command = "npm run build"
publish = "dist/dapps/browser"
[[plugins]]
package="@netlify/angular-runtime"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
reason for using redirect in server.ts because redirect is not supported in SSR and i have to redirect more than 3000 urls
Hi @mrrohit1! server.ts is a file auto-scaffolded by Angular and it can be used to run your Angular application e.g. on a VM. It doesn't work on Netlify, though. That also gives some benefits, for example it allows us to serve static assets from a CDN instead of having to use SSR for that.
For your usecase, I'd recommend you to use an Edge Function. Here's a draft for how it could look:
// .netlify/edge-functions/redirect-and-sanitize
import {
HTMLRewriter
} from 'https://ghuc.cc/worker-tools/html-rewriter/index.ts'
export default (request, context) => {
const redirectUrl = redirectMap[request.url];
if (redirectUrl) {
return Response.redirect(redirectUrl, 301);
}
const response = await context.next()
if (!response.headers.get("content-type").startsWith("text/html")) {
return response
}
return new HTMLRewriter()
.on("#ng-state", {
element(element) {
const state = JSON.parse(element.innerHTML);
const sanitizedState = sanitizeState(state);
element.innerHTML = JSON.stringify(sanitizedState);
},
})
.transform(response)
}
export const config = {
path: "/*"
}You'll notice that I replaced your Regex-based approach with HTMLRewriter. That allows us to perform the state sanitisation without blocking the response stream, reducing memory load and latency. Using a Regex should also work fine, though.
Let us know if that helps! Sorry for the confusion with server.ts, we'll add a note the README about it.
Hi, @Skn0tt.
It seems to be impossible to use custom edge functions in case of SSR. In that case, there is a default edge function called 'Angular SSR', that handles server side rendering and has '/*' as a path. In result, that default edge function blocks others from excecution.
Here is my post on the support forum regarding that issue: https://answers.netlify.com/t/netlify-redirects-to-api-server-not-working-on-angular-ssr-website/119988/5. In my case, I wanted to use a custom edge function as a proxy.
Is there any way to make custom edge functions work with SSR, for example, by excluding certain paths?
@yehor-akunishnikov As my colleague mentioned in reply to your post, I don't believe that's possible currently. However, you should be able to use a custom Netlify Function that runs at the origin, instead of a Netlify Edge Function that runs at the edge. Is that an acceptable workaround for your use case?
@serhalp I'll give it a try, thanks.
@serhalp thanks for the above! could you please point me how to set up a Netlify Function to run at the origin? I was not able to find that trigger. would be great if the fn call could be tied to a path prefix as well ๐
@daroczig I could've been clearer! What I meant was that Netlify Functions run at the origin and Netlify Edge Functions run at the edge. So the suggestion here was to use Netlify Functions: https://docs.netlify.com/functions/overview/. That page should have everything you need!
@serhalp thanks for the above! could you please point me how to set up a Netlify Function to run at the origin? I was not able to find that trigger. would be great if the fn call could be tied to a path prefix as well ๐
@daroczig,
I'll just share my own experience. I tried to use Netlify functions to solve the problem I described earlier. But I ran into the same problem as with the edge functions. In the end, I just gave up and used a VPS instead of Netlify. You may be able to achieve a better result, but for me it's too much trouble for such an obvious task, so it's not worth it.
@serhalp I went through those pages and tried deploying a Netlify Function with a custom path config, but the Angular SSR Edge Function still seems to take priority. Do you have any pointers on what I am missing?
FTR this is what I tried as a POC:
import type { Config, Context } from "@netlify/functions";
export default async (request: Request, context: Context) => {
console.log(url);
return new URL("https://reqres.in/api/users?page=2", request.url);
};
export const config: Config = {
path: "/foobar/*",
};