[BUG] AppInsights breaks Angular SSR in Cloudflare Worker
Description/Screenshot
@microsoft/applicationinsights-web breaks Angular SSR in Cloudflare Worker by 1. redefining "name" property, which is not allowed by CF Worker and 2. make the rendering stuck (page not loading) for unknown reasons.
Steps to Reproduce
- Create a simple Angular SSR project with Cloudflare Worker (
pnpm create cloudflare@latest my-angular-app --framework=angular) Ref - Install
@microsoft/applicationinsights-web - Create the AppInsights instance in
app.component.ts, for example:
constructor() {
const _appInsights = new ApplicationInsights({
config: {
connectionString: '123123',
enableAutoRouteTracking: true,
enableCorsCorrelation: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
}
});
}
- Make sure the rendering mode is set to Server in
app.route.server.ts, like
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '**',
renderMode: RenderMode.Server
}
];
- Build the project and either deploy it to Cloudflare Worker or run locally with wrangler (i.e.,
npx pnpm build && npx wranger dev) - Open browser to access the running site
- OS/Browser: N/A
- SDK Version [e.g. 22]:
3.3.6 - How you initialized the SDK:
this._appInsights = new ApplicationInsights({
config: {
connectionString: environment.appInsights.connectionString,
enableAutoRouteTracking: true,
enableCorsCorrelation: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
}
});
this._appInsights.loadAppInsights();
Expected behavior Website loaded correctly
Additional context The SDK introduces two bugs:
- it somehow triggered
esbuildto redefinenameproperty. When runs in Cloudflare Worker, it cause error in the logs saying
Cannot redefine property: name
and the stack trace points to the bundled file
at defineProperty (<anonymous>)
at __name (server.js:7:33)
at dist/<redacted>/server/en-CA/chunk-M5SVHNEI.mjs (server.js:36770:5)
at __init (server.js:9:62)
at dist/<redacted>/server/en-CA/chunk-7DM6DADX.mjs (server.js:45727:5)
at __init (server.js:9:62)
at dist/<redacted>/server/en-CA/main.server.mjs (server.js:60053:5)
at __init (server.js:9:62)
at server.js:149095:73
at async e18.getAngularServerAppForRequest (server.js:149484:35)
When running locally with wrangler, the error message is:
[wrangler:err] Error: Method not implemented.
at CallSite.toString (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:11069:11)
at prepareStackTrace (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/@cspotcode/source-map-support/source-map-support.js:671:39)
at sourceMapper (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:11177:12)
at getSourceMappedStack (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:11235:27)
at reviveError (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:11268:17)
at handlePrettyErrorRequest (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:11273:17)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async #handleLoopback (/Users/<redacted>/.npm/_npx/32026684e21afda6/node_modules/miniflare/dist/src/index.js:15598:20)
This bug can be workaround by manually invoke esbuild with preserveNames=false and instruct wrangler to skip bundle. However, it will trigger the next bug.
2. It somehow make the entire rendering process unresponsive. This issue is consistent between running in CF Worker and locally. There are no error message, but the page loading was just hang. After an hour, you can observe crazy Wall Time (e.g., 1,500,581ms) in Cloudflare Worker logs. If you really want to wait, the page might or might not loaded eventually.
In order to trigger the above bugs, appInsights doesn't need to be loaded (i.e., remove _appInsights.loadAppInsights() won't help). Simply creating ApplicationInsights (i.e., new ApplicationInsights({})) object will trigger the bugs.
The workaround is to check if it is in SSR mode, and load appInsights dynamically when in CSR
private async lazyLoadAppInsights(connectionString: string) {
try {
// Dynamically import the module only at runtime in browser
const appInsights = await import('@microsoft/applicationinsights-web');
const ApplicationInsights = appInsights.ApplicationInsights;
this._appInsights = new ApplicationInsights({
config: {
connectionString: connectionString,
enableAutoRouteTracking: true,
enableCorsCorrelation: false,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
}
});
this._appInsights.loadAppInsights();
} catch (error) {
console.error('Failed to initialize ApplicationInsights:', error);
}
}
I've created a duplication issue in the dynamicProto repo to fix / address this in dynamicProto https://github.com/microsoft/DynamicProto-JS/issues/95
Based on the identified fixes in https://github.com/microsoft/DynamicProto-JS/pull/96, I'm not convinced that this is the root (or only) cause of this issue, ignoring the usage of dynamicProto what else could cause this issue?
Or does the stack trace specifically identify dynamicProto as the root cause? And if so what line
@xionglingfeng After using Co-Pilot to perform some in-depth analysis / evaluation of the code, we have not identified any specific issue within the Application Insights code, we also don't use or define the __name property.
One of the last comments from Co-Pilot is
You're correct. After looking at the DynamicProto-JS implementation, I can see it uses direct property assignments rather than Object.defineProperty.
And is specifically states the following, which seems like a likely root cause and not something specific to the Application Insights code, is this something that you can help confirm or deny?
The error message in the stack trace points to defineProperty and __name, which suggests the error is occurring during the bundling process with esbuild or within the Cloudflare Worker's JavaScript engine when handling the function property assignments, not directly in dynamicProto's code.
I am still using Co-Pilot to try and identify any specific detection or work-around that we might be able to implement, but at this point I'm not seeing anything that pinpoints the issue that we have.
Question: Does this environment have any specific polyfills / extensions to root objects like Array? As there was this issue that will be fixed in the next release that is caused by the end-users runtime adding a set function to Array.prototype which then cause the core dynamic configuration code to get confused...
@MSNev you might find its helpful to run follow the steps I posted in the bug report. I don't think your code directly redefined the name property via Object.defineProperty. Rather, I think something in your code makes esbuild to believe adding that line is necessary.
In my original bug report:
This bug can be workaround by manually invoke esbuild with preserveNames=false and instruct wrangler to skip bundle.
To me, this is quite convincing that the bug is not because your code redefined name, but somehow your code make esbuild to believe it is necessary to redefine name
@xionglingfeng , I redirected Co-Pilot at your comment above and it came up with the following PR (eventually), does this sound like a reasonable solution that would work for you?
https://github.com/microsoft/ApplicationInsights-JS/pull/2548/files
I might keep prompting Co-Pilot to investigate deeper, if this doesn't work. However, I'm convinced that as a good general solution, but I'll leave the PR as is for now so you can review
Hi @MSNev, the doc update make sense. However, I think the root cause is buried somewhere deeper, and, frankly, I am not sure if the LLM at this stage has a good chance to find it.
I Understand.
We are not experts on CloudFlare (which is why I'm throwing LLM at it), to try to see if it can provide some insights that might trigger some memories or identify a possible path forward.
As we have a general goal of not impacting any runtime that we might get loaded into ie we either workaround limitations or we have a graceful fallback. Both of which I'm currently uncertain on how do achieve this at this point. -- without spending lots of time re-creating a repo (hmm -- sound like something I might be able to get the LLM to try and do for us)
And as an FYI, we are a small team which limits our capacity as well as being impacted by recent events.
That's definitely understandable.
The issue is relatively easy to be reproduced with one npm command as I wrote in the original bug report. At least the first bug is not related to Cloudflare Worker, its more related to esbuild. I am not familiar with esbuild's behaviour, nor AppInsights-JS's implementation, thus I am unable to dig further what exactly cause esbuild to generate the line redefining name.
Just wanted to say that I experienced the exact same issue when trying to deploy my Angular SSR app with Application Insights to Cloudflare Worker.
I had no idea what was causing it.
I had the same issue in a standard angular SPA app (so not SSR). I managed to narrow down the issue to being introduced when the @nevware21/ts-utils dependency (which I think is a dependency of @nevware21/ts-async which is a dependency of @microsoft/applicationinsights-web) is a version somewhere later than 0.11.1
I have stopped for the time being, but will post again when I figure out exactly which version the issue is introduced
The issue was introduced in @nevware21/ts-async 0.12.0 although this version had another issue here https://github.com/nevware21/ts-utils/issues/398 that happens before the Cannot redefine property: name error
Cannot redefine property: name first becomes apparent in 0.12.1
This seems like it might be related to this (which is specific to Angular 20.3) but it seems to show in the same way https://github.com/microsoft/ApplicationInsights-JS/issues/2643#issuecomment-3299505597
Where The latest Angular has now reverted the root cause (on their side with 20.2) https://github.com/angular/angular-cli/issues/31198
With the above I presume you mean 0.12.1 of @nevware21/ts-utils rather than @nevware21/ts-async, looking at the changelist for that release there is nothing in there that I can see would trigger this issue -- in fact the only changes with that release is exports and some tests
Yes I meant ts-utils. The issue was introduced in 0.12.0 but gets hidden by another error in that version. Your link to angular is indeed the issue though. So it's a different root cause than the cloudflare issue in this thread
Also not seeing a lot in here (for functions we use) that "might" have introduced this behavior. Expect potentially 1 item (which is a bug fix)
And if correct it would confirm my gut feeling comment I left yesterday...
Between v0.11.8 and v0.12.0 there was a "fix" applied to the objDeepFreeze function (which we use) properly freeze all "types" (not just objects / arrays) so it also includes functions (which are used as the foundation of classes) as well as some recursion protection. Functions do have a name property, so this would be successfully traversing all enumerable properties of arrays, objects and functions and calling Object.freeze on every property.
I don't see this as a Bug either in Application Insights or ts-utils, but on the Angular (or whatever is adding (or trying to add) the __name "property"). They should either be
- checking that the object is not frozen or sealed (if doing this after the object(s) are frozen)
- Marking the new property as not-enumerable (if doing this before the object(s) are frozen)
- not updating the base prototype to introduce the non-standard names (IMHO -- although I know there will be debate on this and edge cases where it's needed)