Skip to content

Commit

Permalink
Avoid ctx binding (#842)
Browse files Browse the repository at this point in the history
* Avoid signal binding on server side

* Avoid ctx binding on arrow func
  • Loading branch information
matheusgr authored Sep 9, 2024
1 parent 764f747 commit 9f95a4f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 32 deletions.
6 changes: 3 additions & 3 deletions vtex/hooks/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ export interface Context {

const loading = signal<boolean>(true);
const context = {
cart: signal<OrderForm | null>(null),
user: signal<Person | null>(null),
wishlist: signal<WishlistItem[] | null>(null),
cart: IS_BROWSER && signal<OrderForm | null>(null) || null,
user: IS_BROWSER && signal<Person | null>(null) || null,
wishlist: IS_BROWSER && signal<WishlistItem[] | null>(null) || null,
};

let queue = Promise.resolve();
Expand Down
33 changes: 31 additions & 2 deletions website/handlers/fresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ export const isFreshCtx = <TState>(
return typeof (ctx as HandlerContext).render === "function";
};

function abortHandler(ctrl: AbortController, signal: AbortSignal) {
let aborted = false;
const abortCtrlInstance = () => {
if (aborted) return; // Early return if already handled

try {
if (!ctrl.signal.aborted) {
ctrl?.abort();
aborted = true; // Mark as aborted after calling abort
}
} catch (_err) {
// We tried our best, but it is already dead... so.. lets ignore it :)
} finally {
signal.removeEventListener("abort", abortCtrlInstance);
}
};
return abortCtrlInstance;
}

function registerFinilizer(req: Request, abortCtrl: () => void) {
const finalizer = new FinalizationRegistry((abortCtrl: () => void) => {
req.signal.removeEventListener("abort", abortCtrl);
});

finalizer.register(req, abortCtrl);
}

/**
* @title Fresh Page
* @description Renders a fresh page.
Expand Down Expand Up @@ -57,10 +84,12 @@ export default function Fresh(

/** Controller to abort third party fetch (loaders) */
const ctrl = new AbortController();
const abortCtrl = abortHandler(ctrl, req.signal);

/** Aborts when: Incomming request is aborted */
const abortHandler = () => ctrl.abort();
req.signal.addEventListener("abort", abortHandler);
req.signal.addEventListener("abort", abortCtrl, { once: true });

registerFinilizer(req, abortCtrl);

/**
* Aborts when:
Expand Down
56 changes: 29 additions & 27 deletions website/handlers/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,34 @@ const RouterId = {
const routerCache = new weakcache.WeakLRUCache({
cacheSize: 16, // up to 16 different routers stored here.
});

const prepareRoutes = (audiences: Routes[], ctx: AppContext) => {
const routesFromProps = Array.isArray(audiences) ? audiences : [];
// everyone should come first in the list given that we override the everyone value with the upcoming flags.
const [routes, hrefRoutes] = buildRoutes(
Array.isArray(ctx.routes)
? [...ctx.routes, ...routesFromProps]
: routesFromProps,
);
// build the router from entries
const builtRoutes = Object.entries(routes).sort((
[routeStringA, { highPriority: highPriorityA }],
[routeStringB, { highPriority: highPriorityB }],
) =>
(highPriorityB ? HIGH_PRIORITY_ROUTE_RANK_BASE_VALUE : 0) +
rankRoute(routeStringB) -
((highPriorityA ? HIGH_PRIORITY_ROUTE_RANK_BASE_VALUE : 0) +
rankRoute(routeStringA))
);
return {
routes: builtRoutes.map((route) => ({
pathTemplate: route[0],
handler: { value: route[1].func },
})),
hrefRoutes,
};
};

/**
* @title Router
* @description Route requests based on audience
Expand All @@ -181,35 +209,9 @@ export default function RoutesSelection(

const timing = monitoring?.timings.start("router");

const prepareRoutes = () => {
const routesFromProps = Array.isArray(audiences) ? audiences : [];
// everyone should come first in the list given that we override the everyone value with the upcoming flags.
const [routes, hrefRoutes] = buildRoutes(
Array.isArray(ctx.routes)
? [...ctx.routes, ...routesFromProps]
: routesFromProps,
);
// build the router from entries
const builtRoutes = Object.entries(routes).sort((
[routeStringA, { highPriority: highPriorityA }],
[routeStringB, { highPriority: highPriorityB }],
) =>
(highPriorityB ? HIGH_PRIORITY_ROUTE_RANK_BASE_VALUE : 0) +
rankRoute(routeStringB) -
((highPriorityA ? HIGH_PRIORITY_ROUTE_RANK_BASE_VALUE : 0) +
rankRoute(routeStringA))
);
return {
routes: builtRoutes.map((route) => ({
pathTemplate: route[0],
handler: { value: route[1].func },
})),
hrefRoutes,
};
};
const routerId = `${RouterId.fromFlags(ctx.flags)}/${ctx.revision ?? ""}`;
if (!routerCache.has(routerId)) {
routerCache.setValue(routerId, prepareRoutes());
routerCache.setValue(routerId, prepareRoutes(audiences, ctx));
}
const { routes, hrefRoutes }: {
routes: Route[];
Expand Down

0 comments on commit 9f95a4f

Please sign in to comment.