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

[Experiment] Full-page navigations using Speculation Rules #60959

Draft
wants to merge 5 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
changes
  • Loading branch information
cbravobernal committed Apr 13, 2024
commit 4a81546febb8970fc450ccf9110521e994670a08
30 changes: 9 additions & 21 deletions packages/interactivity/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,16 @@ if (
document.prerendering
) {
document.addEventListener( 'prerenderingchange', () => {
const token = window.sessionStorage.getItem( 'interactivity-token' );
const bc = new BroadcastChannel( token );
bc.addEventListener( 'message', ( event ) => {
// First, populate the state from the previous page.
populateInitialData( JSON.parse( event.data ) );
// Then, overwrite it with the state from the new HTML.
const data = parseInitialData();
populateInitialData( data );
} );
bc.postMessage( 'state_request' );
const store = window.sessionStorage.getItem(
'interactivity-api-store'
);
populateInitialData( JSON.parse( store ) );
} );
} else {
// Create a unique token for this session.
// eslint-disable-next-line no-restricted-syntax
const token = Math.random().toString( 36 ).slice( 2 );
window.sessionStorage.setItem( 'interactivity-token', token );

// Now, listen to the message event that
const bc = new BroadcastChannel( token );
bc.addEventListener( 'message', ( event ) => {
if ( event.data === 'state_request' ) {
bc.postMessage( serializeStore() );
}
window.addEventListener( 'beforeunload', () => {
window.sessionStorage.setItem(
'interactivity-api-store',
serializeStore()
);
} );
}
54 changes: 53 additions & 1 deletion packages/interactivity/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,63 @@ export const populateInitialData = ( data?: {
const data = parseInitialData();
populateInitialData( data );

function createFilteredReplacer( object ) {
const propertiesWithGettersSetters = {};

// Loop over each property to find getters or setters
for ( const key of Object.keys( object ) ) {
const descriptor = Object.getOwnPropertyDescriptor( object, key );
if ( descriptor.get || descriptor.set ) {
propertiesWithGettersSetters[ key ] = true;
}
}

// Return a replacer function that checks against this list
return function ( key, value ) {
if ( propertiesWithGettersSetters[ key ] ) {
// Replace getter/setter with undefined or any custom value
return undefined;
}
// Pass other values through
return value;
};
}

function replacer( key, value ) {
// Determine the type of the value
const type = typeof value;

// Handle arrays explicitly to keep them in the output
if ( Array.isArray( value ) ) {
return value;
}

// Check for objects, ignore null, functions, and others
if ( type === 'object' && value !== null ) {
// Skip getters and setters (functions within objects)
const plainObject = {};
for ( const [ k, v ] of Object.entries( value ) ) {
if ( ! Object.getOwnPropertyDescriptor( value, k ).get ) {
plainObject[ k ] = v;
}
}
return plainObject;
}

// Allow only strings and numbers, ignore functions and symbols
if ( type === 'string' || type === 'number' ) {
return value;
}

// Ignore functions, symbols, undefined
return undefined;
}

// Serialize the current store.
export const serializeStore = () => {
const stateData = { state: {} };
for ( const [ namespace, value ] of stores.entries() ) {
stateData.state[ namespace ] = JSON.stringify( value.state );
stateData.state[ namespace ] = JSON.stringify( value.state, replacer );
}

return JSON.stringify( stateData );
Expand Down
Loading