Skip to content
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

Add dotcom-ui-data-embed #808

Closed
wants to merge 19 commits into from
Closed

Add dotcom-ui-data-embed #808

wants to merge 19 commits into from

Conversation

NickColley
Copy link
Contributor

@NickColley NickColley commented May 5, 2020

Continued in this pull request: #812

@NickColley NickColley requested a review from a team May 5, 2020 11:29
@@ -1,4 +1,5 @@
import React from 'react'
// TODO: Figure out why importing the package name does not work.
import { ClientEmbed } from '../../../dotcom-ui-client-embed/src'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to have another go at this but I could not figure out why referencing the package name does not work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was because when I added these as a dependency I just had not ran npm install on the directory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will pull your branch and have a play.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, that tripped me up too. If there are packages with dependencies on other packages then you need to install each of them (in order, I would imagine).

@@ -3,14 +3,8 @@ import subject from '../../server/formatFlagsJSON'
const fixture = Object.freeze({ foo: 1, bar: false, baz: 'qux' })

describe('dotcom-ui-flags/src/server/formatFlagsJSON', () => {
it('returns a stringified object', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this since it seemed unnecessary to check the type when we do a strict assertion on an object below. Let me know what you'd prefer to do.

@@ -11,5 +11,5 @@ export default function formatFlagsJSON(flags: TFlagsData = {}): string {
}
})

return JSON.stringify(output)
return output

This comment was marked as resolved.

This comment was marked as resolved.

Copy link
Contributor

@andygout andygout left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it is on the right track.

I guess one of the obvious things to add to the example app would be some custom data that gets passed from server to client.

The use case for this requirement is next-video-page: https://www.ft.com/video. You can see that it is using an attribute that is denied by the appContext schema: permutiveContext (hence with it is on v0.6 and not v0.7, the latter of which validates the appContext schema and fails if there are any disallowed attributes present).

@@ -11,5 +11,5 @@ export default function formatFlagsJSON(flags: TFlagsData = {}): string {
}
})

return JSON.stringify(output)
return output

This comment was marked as resolved.

@@ -1,4 +1,5 @@
import React from 'react'
// TODO: Figure out why importing the package name does not work.
import { ClientEmbed } from '../../../dotcom-ui-client-embed/src'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will pull your branch and have a play.

@NickColley
Copy link
Contributor Author

NickColley commented May 5, 2020

Could you explain how you're testing this with the front page?

Hmm. Both flags and appContext already seem to be in object form (rather than a stringified object), which is surprising.

npm link?

@andygout
Copy link
Contributor

andygout commented May 5, 2020

Could you explain how you're testing this with the front page?

Just checking the Dev Tools Elements tab on production ft.com, which is why it was surprising that the appContext and flags data is not stringified (as code suggests we are currently stringifying it).


readyState.domready.then(() => {
const flagsClient = flags.init()
const appContextClient = appContext.init()

const customContext = loadClientEmbed('custom-context')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you can see it's simple at the moment but does not follow the init convention elsewhere + the getAll pattern.

Should we require the user to pass their ID to init or automagically find clientEmbeds when init() is called and then allow them to use the client to specify an embed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if we can keep it matching the pattern.

I think including the ID as an argument for init will make it clear which embed is being retrieved, but means it will require an individual DOM query for each embed being retrieved (although that is what the code is currently doing, and there is only one extra embed being added to one app at the moment, so this is minimal).

Copy link
Contributor Author

@NickColley NickColley May 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other alternative would be this sort of pattern:

const clientEmbed = new clientEmbed('IDHERE')
clientEmbed.init()

@pixelandpage would appreciate your thoughts on what the interface could look like here as well if you have time :)

@@ -64,6 +65,7 @@ module.exports = (_, response, next) => {
</section>
</div>
</Layout>
<ClientEmbed id="custom-context" data={{ foo: true, bar: 'qux' }} />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In documentation should make it clear to put the embed at the bottom of the page to remove risk of it blocking page render.


readyState.domready.then(() => {
const flagsClient = flags.init()
const appContextClient = appContext.init()

const clientEmbedClient = clientEmbed.init('custom-context')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should move this 'custom-context' constant into a 'constants.js' file as per convention in this repo...


getAll(): TAppContext {
return this.appContext
super(options.appContext)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to figure out how to extend a class and apply the types, as this currently has removed the type information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like what I wanted to do is not possible(?) so will need to figure out another way to achieve this: microsoft/TypeScript#3402

@@ -0,0 +1,15 @@
export default class ClientEmbedData {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any way to add types here and then make them more specific when the class gets extended?

private data

constructor(data) {
this.data = Object.freeze(data)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the data in this is likely to be nested, should we consider doing a deeper freeze? may not be worth the extra code required in the bundle...

@@ -0,0 +1,2 @@
export * from './components/ClientEmbed'
export * from './client'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had to add the client entrypoints to the main entrypoints which I assume is not ideal since we have a separate browser entrypoint for a reason. This was necessary to allow the client code to be shared in other packages with the TypeScript types working...

@NickColley
Copy link
Contributor Author

Something I noticed:

#809

@NickColley NickColley force-pushed the dotcom-ui-client-embed branch from a764a46 to e891ef7 Compare May 7, 2020 13:19
@NickColley
Copy link
Contributor Author

I have ruled out having a default 'id' prop as I'm not sure there's an easy way to communicate you need unique IDs if you use more than one embed.

@NickColley
Copy link
Contributor Author

Spoke to Maggie, we're gonna go with data-embed to clear up the weirdness with ClientEmbedClient class.

@NickColley NickColley force-pushed the dotcom-ui-client-embed branch 2 times, most recently from 76dc970 to 1a5275c Compare May 11, 2020 15:13
Nick Colley and others added 6 commits May 11, 2020 16:15
Since `dotcom-ui-app-context` and `dotcom-ui-flags` share functionality this commit moves JSON output into the embed component which is the same as how it works in app-context. This'll hopefully make it easier to use the new package in the future.

May be a breaking change if formatFlagsJSON is part of the public API.
Also rename the file since there's no JSX syntax used in this file anymore.
Also rename the file since there's no JSX syntax used in this file anymore.
This allows users to parse the data embedded in the page.
@NickColley NickColley force-pushed the dotcom-ui-client-embed branch from 1a5275c to 8d904d8 Compare May 11, 2020 15:16
@NickColley NickColley force-pushed the dotcom-ui-client-embed branch from 8d904d8 to 6f9fe16 Compare May 11, 2020 15:31
@NickColley NickColley changed the title Add dotcom-ui-client-embed Add dotcom-ui-data-embed May 11, 2020
@NickColley NickColley force-pushed the dotcom-ui-client-embed branch from 8c51043 to aa8683c Compare May 11, 2020 16:00
@NickColley
Copy link
Contributor Author

I suggested refactoring away from .init() with arguments since it felt weird but then since found that nTracking and nTracking do it. So perhaps we should go back to it...!

@NickColley
Copy link
Contributor Author

NickColley commented May 11, 2020

I've spiked putting this into next-video-page: https://github.com/Financial-Times/next-video-page/compare/spike-data-embed-2?expand=1

I'm curious if we're really solving the underlying problem. If our main worries were that app context was being passed into nTracking etc should we not have validation or an allowlist there? And allow for app context to be used for all data, which is as we've seen, what people tend to do?

If when we passed the app context into things like nTracking, nTracking allowlisting only the properties it expects, would this allow us to use AppContext in a broader way?

@andygout
Copy link
Contributor

andygout commented May 12, 2020

This PR description goes some way to answering that question: #782.

I think it's preferable to enforce the schema as far upstream as possible so that Page Kit - being the originator of the appContext object - is able to enforce the properties it contains, ensuring that they are not outside the scope of its definition.

It's fair to say that (in the case of next-video-page) developers had used the appContext object for other data simply because it was a pre-existing way of doing what they required and therefore the most convenient solution. Even though the attribute added in next-video-page is called permutiveContext, it is just an ID and API key, which are there to allow the app run rather than serving the purpose of providing context about the app.

The flags object should only contain data about flags and by the same virtue the appContext object should only contain data about the app's context.

The concern would be that appContext would become a dumping ground for all sorts of properties and have an inconsistent series of properties across apps.

If it transpires that a property should be added to appContext, then this is something on which Page Kit can make the decision by making an allowance in its JSON schema validation.

@NickColley
Copy link
Contributor Author

@andygout thanks for the clarity, let's continue. I'm still getting my head around this space. :)

@NickColley
Copy link
Contributor Author

Worked on a different branch to clean up renaming files: #812

@NickColley NickColley closed this May 12, 2020
@NickColley NickColley deleted the dotcom-ui-client-embed branch May 12, 2020 11:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create a dotcom-ui-client-embed package for sharing data between the server and the client
3 participants