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

Themes: Bootstrap theme-details store for theme sheets #3279

Merged
merged 1 commit into from
Feb 29, 2016

Conversation

seear
Copy link
Contributor

@seear seear commented Feb 12, 2016

  • Add the theme-details data component to the layout
  • Fetch and cache theme details server-side and bootstrap to the client

screen shot 2016-02-23 at 21 24 01

To Test
Go to http://calypso.localhost:3000/themes/{theme} both logged-in and logged-out

@seear seear self-assigned this Feb 12, 2016
@seear seear added this to the Themes: Showcase M4-ThemeSheets milestone Feb 12, 2016
@seear seear mentioned this pull request Feb 15, 2016
3 tasks
@seear seear force-pushed the add/themes-sheet-data branch 2 times, most recently from 8595df2 to 8b809d7 Compare February 15, 2016 17:56
@ehg ehg mentioned this pull request Feb 15, 2016
6 tasks
@seear seear added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. and removed [Status] In Progress labels Feb 16, 2016
@@ -97,7 +97,7 @@ jsLoader = {
};

if ( CALYPSO_ENV === 'development' ) {
webpackConfig.plugins.push( new PragmaCheckPlugin() );
// webpackConfig.plugins.push( new PragmaCheckPlugin() );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Problem: state/themes/actions.js is replaced with noop in webpack.config.node.js but the pragma checker doesn't know this, so we still get the not /** @ssr-ready **/ error. @ehg: any idea how we should handle this?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, we can add analytics to the ignore array, but I think state/themes/actions.js should be ssr-ready from the start. Will take a look.

Copy link
Member

Choose a reason for hiding this comment

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

Pushed acc169f

if ( config.isEnabled( 'server-side-rendering' ) ) {
let themeData = themeDetails.get( req.params.theme_slug );
if ( ! themeData ) {
wpcom.undocumented().themeDetails( req.params.theme_slug, ( error, data ) => {
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we could get away without having to use memcache by:

  • Checking the published date of the theme details response
  • If it's greater than the one in the cache, renderToString using the new data.
  • If it's not, just serve the cached renderToString markup

We could also avoid blocking the request by always serving the data from the cache, and fire off API calls that will invalidate/update the cache when necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like that idea :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could also avoid blocking the request by always serving the data from the cache, and fire off API calls that will invalidate/update the cache when necessary.

This PR was actually working like that a few commits back and can easily be tweaked to do that again. I wasn't quite sure which way was best. It strikes me now that never rendering async is less complex overall.

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 wonder if we could get away without having to use memcache by...

Yeah, was thinking about this, or maybe even using the api response header, which may let us leverage some existing libraries to handle it?

Once we receive new api data, how do we clear the renderToString cache?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, was thinking about this, or maybe even using the api response header, which may let us leverage some existing libraries to handle it?

Yep. I wonder whether we sent ETags or what the Expires header is like.

Once we receive new api data, how do we clear the renderToString cache?

You mean how do we know what key to clear? Maybe we key the rts cache using something like dataTimestamp+lang?

Copy link
Member

Choose a reason for hiding this comment

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

I wonder whether we sent ETags or what the Expires header is like.

Expires and cache control headers are explicitly set to not cache, which makes sense. I think comparing the publish/update date is probably fine for now.

Copy link
Member

Choose a reason for hiding this comment

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

RE #3279 (comment) - implemented a basic version of this in b560f0a

@ehg ehg force-pushed the add/themes-sheet-data branch from 1818d64 to 2c6f0f0 Compare February 18, 2016 19:37
@ehg
Copy link
Member

ehg commented Feb 18, 2016

Rebased, not using makeElement() for now.

@ehg ehg added [Status] In Progress and removed [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Feb 19, 2016
@ehg
Copy link
Member

ehg commented Feb 19, 2016

Changed to 'In Progress', as this should be based off #3386, and not merged until that lands. Also, we need more discussion around #3279 (comment)

@ehg ehg force-pushed the add/themes-sheet-data branch from 0c9eccf to cf073b9 Compare February 19, 2016 15:59
@ehg
Copy link
Member

ehg commented Feb 19, 2016

this should be based off #3386

Done.

themeName: theme.name,
themeAuthor: theme.author,
themeScreenshot: theme.screenshot,
} );
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this call go somewhere deeper in the component hierarchy, e.g. inside ThemesListFetcher (to provide some initial state there, also on the client side)? Thinking about how to keep this part of server/pages as generic as possible for isomorphic routing.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, renderThemeSheet looks like something we could keep as middleware in my-sites/themes/controller: it basically writes to context and dispatches stuff via store, which should be available via context.

setSection = require( 'state/ui/actions' ).setSection;
setSection = require( 'state/ui/actions' ).setSection,
wpcom = require( 'lib/wp' ),
ActionTypes = require( 'state/themes/action-types' );
Copy link
Member

Choose a reason for hiding this comment

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

Should be ThemesActionTypes

@ehg ehg force-pushed the add/themes-sheet-data branch from 8c9b414 to f8ecf9c Compare February 23, 2016 14:18
@ehg
Copy link
Member

ehg commented Feb 23, 2016

Rebased.

@ehg
Copy link
Member

ehg commented Feb 23, 2016

Added dynamic data to content sections and fixed price. Next up: make code not suck.

@seear seear force-pushed the add/themes-sheet-data branch from 4514c0c to e128fc0 Compare February 24, 2016 11:23
@seear
Copy link
Contributor Author

seear commented Feb 24, 2016

rebased after #3464

//TODO: use makeElement()
context.primary = (
<ReduxProvider store={ context.store } >
<Head title={ props.title } isSheet>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're still using the hardcoded Pineapple Fifteen title, but I think that should be hooked up in a separate PR

title={ isSheet ? 'Pineapple Fifteen Theme — WordPress.com' : get( 'title', tier ) }

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I think we should leave this until after routing. It's possibly being implemented in one of those PRs.

Copy link
Contributor

Choose a reason for hiding this comment

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

@seear seear force-pushed the add/themes-sheet-data branch from b622acf to 1d17c23 Compare February 25, 2016 12:39
bumpStat( 'calypso-ssr', 'loggedout-design-cache-miss' );
}

export function render( element, path, initialState ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe better to have a key param instead of path and initialState, allowing caller to decide appropriate key?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, also I was thinking the API could be something like render.set( key, element ) and render.get( key )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, also I was thinking the API could be something like render.set( key, element ) and render.get( key )

I think better to put a comment before the async renderThemeSheet() than expose the caching from the render module.

@seear seear added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. and removed [Status] In Progress labels Feb 25, 2016
@seear seear force-pushed the add/themes-sheet-data branch from eac589a to e187341 Compare February 25, 2016 22:15
function updateRenderCache( themeSlug ) {
wpcom.undocumented().themeDetails( themeSlug, ( error, data ) => {
if ( error ) {
console.log( `Error fetching theme ${ themeSlug } details: `, error.message || error );
Copy link
Member

Choose a reason for hiding this comment

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

Can we use debug for these console.logs?

@ehg
Copy link
Member

ehg commented Feb 26, 2016

👍 after squash. Let's get this in and iterate.

Wrap theme sheets with the theme-details component to use real data,
and fetch and cache data server-side for initial render.

Server-side data caching:

- if the theme's details aren't in the themeDetails cache, don't SSR &
  fire and forget a theme details XHR, which will renderToString when it
  has data for the theme.
- if the theme is in the cache, then we'll have markup for it, so render
  that

doing it this way means we don't have to block the request, but we lose
SSR for cache misses. i'm unsure of whether blocking on the response
will be a problem (need timing stats), if it is, memcache or a CDN would
be preferable.
@seear seear force-pushed the add/themes-sheet-data branch from f69e60c to b2cc08d Compare February 29, 2016 11:12
seear added a commit that referenced this pull request Feb 29, 2016
Themes: Bootstrap theme-details store for theme sheets
@seear seear merged commit 09a7aad into master Feb 29, 2016
@seear seear deleted the add/themes-sheet-data branch February 29, 2016 11:24
@scruffian scruffian removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Feb 29, 2016
if ( config.isEnabled( 'server-side-rendering' ) ) {
const theme = themeDetails.get( req.params.theme_slug );
if ( theme ) {
Object.assign( context, renderThemeSheet( theme ) );
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible that this code path ends up renderingToString synchronously via renderThemeSheet() and render(), i.e. blocking the request?

@ockham
Copy link
Contributor

ockham commented Mar 3, 2016

I find the two different caches and how they interact rather confusing, hard to reconcile with #3562, and possibly error-prone. If we want to cache the markup based on date_updated, can't we just make it part of the markup cache key here -- possibly by just exposing it as part of the themeDetails object we dispatch here, so it becomes part of the initialReduxState, which is then used for the key?

If we just want to cache the theme details data for their own sake, we should do that inside our Redux reducer -- it's made for storing data for different theme IDs already, so we're kind of re-creating that logic here.

debug( 'caching', themeSlug );
themeDetails.set( themeSlug, data );
// update the render cache
renderThemeSheet( data );
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't we also render index.jade here?

@ockham
Copy link
Contributor

ockham commented Mar 4, 2016

Filed #3774 based on my comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature Group] Appearance & Themes Features related to the appearance of sites. Server Side Rendering
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants