-
Notifications
You must be signed in to change notification settings - Fork 24.8k
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
feat(platform-server): add analytics token for rendering #46887
Conversation
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
62412fb
to
8b4900a
Compare
In order to analyze how a page was rendered, we add a new token that can be populated and inserted into a rendered webpage. By default, this token is just "platform-server", but can be customized by the user depending on their given setup. We do this here instead of in the individual rendering engines in order to avoid analytics gaps for customers that may not use one of the popular solutions, and instead opt to roll their own.
* | ||
* @publicApi | ||
*/ | ||
export const SERVER_CONTEXT = new InjectionToken<string>('Server.SERVER_CONTEXT'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we can put the default value into the token factory (vs having it at the injection location):
export const SERVER_CONTEXT = new InjectionToken<string>('Server.SERVER_CONTEXT'); | |
export const SERVER_CONTEXT = new InjectionToken<string>('SERVER_CONTEXT', { | |
providedIn: 'root', | |
factory: () => 'Angular platform-server' | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered this at first, but it didn't seem like it was worth the extra KBs tbh. Happy to move it there if you think it's better practice, but it seemed like a lateral move at best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this code remains on the server, extra bytes should be ok. My idea was to co-locate the definition and the default value, so that it's all in one place and is easier to manage later. Another approach might be to have an additional constant like const SERVER_CONTEXT_DEFAULT = 'Angular platform-server';
, so we can have it next to the SERVER_CONTEXT
one and use in the code where injection happens, but the factory
approach looks more organic.
const document = | ||
config?.document ? parseDocument(config.document, config.url) : getDOM().createHtmlDocument(); | ||
document.documentElement.appendChild( | ||
document.createComment(`This page was rendered with: ${context}.`)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd need to escape the context
here to make sure values like -->
do not break the markup once the document is serialized and parsed later, WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-->
in a comment does not break the syntax. The spec is robust to cases like that, so I'm comfortable leaving out serialization for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a very naive test to illustrate the scenario I had in mind. This doesn't exactly represent the serialization/deserialization that we do in the platform-server, but I was wondering if this might happen with our serialization too:
const div = document.createElement('div');
const comment = document.createComment('-->');
div.appendChild(comment);
const outputAsString = div.outerHTML;
const container = document.createElement('p'); // just used as a container
container.innerHTML = outputAsString;
console.log(container.firstChild.childNodes.length);
// Output: 2, the contents: NodeList(2) [comment, text ('-->')]
// Expecting: 1 comment node
Couple of drive by comments
<meta property="ng:page-mode" content="SSR/SSG/AppShell/other" /> or <aio-shell ng-version="13.2.2" ng-page-mode="SSR/SSG/AppShell/other">
If we are going to move forward with this, I think it should be a parameter to the |
I've looked at this PR and at angular/universal#2666 once again and I think we may need both eventually :)
Given the fact that the The NgUniversal operates on a page-level basis and controls the entire page (starting from the I'd vote for:
There are some downsides though, such as an extra complexity to query for this information on a page (we'd need to search for @alan-agius4 @CaerusKaru I'm new to this part of the codebase, so I'd be curious to get your perspective on this. // cc @jessicajaniuk |
The names I do like what you are proposing above and I am fine either way. Although adding data in the host element does seem more future proof (Since there can be multiple apps on the same page.) . One drawback of using the We'd definitely wouldn't want to parse the document multiple times and therefore one thing that comes to mind is to change the export function renderApplication<T>(rootComponent: Type<T>, options: {
appId: string;
+ document?: string;
- document?: string | Document;
url?: string;
providers?: Array<Provider | ImportedNgModuleProviders>;
platformProviders?: Provider[];
}): Promise<string>;
Technically that is possible, although I highly doubt this is works and is supported at the moment. |
Quick update: we've discussed this topic offline with @CaerusKaru and also had a chat with @alan-agius4 and @jessicajaniuk. My takeaway from the discussions is that we need both application-level annotation via an attribute (to capture cases when If that's accurate, we'd need to land 3 items:
I'm familiar with the @alan-agius4 @CaerusKaru @jessicajaniuk please let me know if I missed something or there are any concerns. Thank you. |
FYI, the PR that adds support for passing a document reference into the |
Closing as this is obsolete. |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
In order to analyze how a page was rendered, we add a new token
that can be populated and inserted into a rendered webpage. By
default, this token is just "platform-server", but can be
customized by the user depending on their given setup.
We do this here instead of in the individual rendering engines in
order to avoid analytics gaps for customers that may not use one
of the popular solutions, and instead opt to roll their own.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information