From ec3ca75572ec7de7b2ed76502b3dde4d6a2c3d4a Mon Sep 17 00:00:00 2001 From: Matt Seccafien Date: Wed, 11 Sep 2019 01:02:26 -0400 Subject: [PATCH] wip --- packages/react-network/src/hooks.ts | 26 ++++++++- packages/react-network/src/index.ts | 1 + packages/react-network/src/manager.ts | 62 ++++++++++----------- packages/react-network/src/server.ts | 1 + packages/react-server/src/render/render.tsx | 4 +- 5 files changed, 54 insertions(+), 40 deletions(-) diff --git a/packages/react-network/src/hooks.ts b/packages/react-network/src/hooks.ts index 2a8bb007eb..713e87d0a1 100644 --- a/packages/react-network/src/hooks.ts +++ b/packages/react-network/src/hooks.ts @@ -1,11 +1,11 @@ import {parse, Language} from 'accept-language-parser'; -import {useContext, useState} from 'react'; +import {useContext, useState, useEffect} from 'react'; import {CookieSerializeOptions} from 'cookie'; import {CspDirective, StatusCode, Header} from '@shopify/network'; import {useServerEffect} from '@shopify/react-effect'; import {NetworkContext} from './context'; -import {NetworkManager} from './manager'; +import {NetworkManager, setBrowserCookie} from './manager'; export function useNetworkEffect(perform: (network: NetworkManager) => void) { const network = useContext(NetworkContext); @@ -50,6 +50,16 @@ export function useAcceptLanguage( return locales; } +export function useServerCookie(key: string) { + console.log('using server cookie', key); + useNetworkEffect(network => { + console.log(network); + const cookie = network.getCookie(key); + console.log(cookie, key); + return cookie; + }); +} + export function useCookie( key: string, ): [ @@ -58,15 +68,25 @@ export function useCookie( ] { const network = useContext(NetworkContext); const [cookie, setCookieValue] = useState(() => { + console.log('the network is', network); return network ? network.getCookie(key) : undefined; }); + useEffect( + () => { + console.log('the network is', network); + }, + [network], + ); + const setCookie = (value: string, options?: CookieSerializeOptions) => { + setCookieValue(value); + if (!network) { + setBrowserCookie(key, value, options); return; } - setCookieValue(value); network.setCookie(key, value, options); }; diff --git a/packages/react-network/src/index.ts b/packages/react-network/src/index.ts index 0dd57ec41f..2a93c67ee2 100644 --- a/packages/react-network/src/index.ts +++ b/packages/react-network/src/index.ts @@ -12,4 +12,5 @@ export { useRedirect, useAcceptLanguage, useCookie, + useServerCookie, } from './hooks'; diff --git a/packages/react-network/src/manager.ts b/packages/react-network/src/manager.ts index cdd78c84d4..e32906e78f 100644 --- a/packages/react-network/src/manager.ts +++ b/packages/react-network/src/manager.ts @@ -1,3 +1,4 @@ +import {Context} from 'koa'; import cookie, {CookieSerializeOptions} from 'cookie'; import {StatusCode, CspDirective, Header} from '@shopify/network'; import {EffectKind} from '@shopify/react-effect'; @@ -6,11 +7,6 @@ export {NetworkContext} from './context'; export const EFFECT_ID = Symbol('network'); -interface Options { - headers?: Record; - cookies?: string | object | null; -} - export class NetworkManager { readonly effect: EffectKind = { id: EFFECT_ID, @@ -34,18 +30,16 @@ export class NetworkManager { } & CookieSerializeOptions >(); - constructor({headers, cookies}: Options = {}) { - this.requestHeaders = lowercaseEntries(headers); + constructor(ctx: Context) { + this.requestHeaders = lowercaseEntries(ctx.headers); + const cookies = ctx.request.headers.cookie || ''; - if (!cookies) { - return; - } - - const parsedCookies = + const parsedCookies: object = typeof cookies === 'string' ? cookie.parse(cookies) : cookies; Object.entries(parsedCookies).forEach(([key, value]) => { - this.cookies.set(key.toLowerCase(), {value}); + console.log(key, value); + this.cookies.set(key, {value}); }); } @@ -53,7 +47,6 @@ export class NetworkManager { this.statusCodes = []; this.csp.clear(); this.headers.clear(); - this.cookies.clear(); this.redirectUrl = undefined; } @@ -76,12 +69,13 @@ export class NetworkManager { options: CookieSerializeOptions = {}, ) { this.cookies.set(cookie, {value, ...options}); - this.setBrowserCookie(cookie, value, options); + // sync server cookie + setBrowserCookie(cookie, value, options); } removeCookie(cookie: string) { this.cookies.delete(cookie); - this.setBrowserCookie(cookie, ''); + setBrowserCookie(cookie, ''); } redirectTo(url: string, status = StatusCode.Found) { @@ -144,24 +138,6 @@ export class NetworkManager { redirectUrl: this.redirectUrl, }; } - - private get browser() { - return Boolean( - typeof document === 'object' && typeof document.cookie === 'string', - ); - } - - private setBrowserCookie( - name: string, - value: string, - options?: CookieSerializeOptions, - ) { - if (!this.browser) { - return; - } - - document.cookie = cookie.serialize(name, value, options); - } } function lowercaseEntries(entries: undefined | Record) { @@ -174,3 +150,21 @@ function lowercaseEntries(entries: undefined | Record) { return accumulator; }, {}); } + +function isBrowser() { + return Boolean( + typeof document === 'object' && typeof document.cookie === 'string', + ); +} + +export function setBrowserCookie( + name: string, + value: string, + options?: CookieSerializeOptions, +) { + if (!isBrowser()) { + return; + } + + document.cookie = cookie.serialize(name, value, options); +} diff --git a/packages/react-network/src/server.ts b/packages/react-network/src/server.ts index 0775f27b2d..5615d2498f 100644 --- a/packages/react-network/src/server.ts +++ b/packages/react-network/src/server.ts @@ -24,6 +24,7 @@ export function applyToContext( for (const [cookie, options] of cookies) { const {value, ...rest} = options; + console.log('setting server ', cookie, value); ctx.cookies.set(cookie, value, rest as any); } diff --git a/packages/react-server/src/render/render.tsx b/packages/react-server/src/render/render.tsx index 0663aba28c..e653fe7233 100644 --- a/packages/react-server/src/render/render.tsx +++ b/packages/react-server/src/render/render.tsx @@ -41,9 +41,7 @@ export function createRender(render: RenderFunction, options: Options = {}) { return async function renderFunction(ctx: Context) { const logger = getLogger(ctx) || console; const assets = getAssets(ctx); - const networkManager = new NetworkManager({ - headers: ctx.headers, - }); + const networkManager = new NetworkManager(ctx); const htmlManager = new HtmlManager(); const asyncAssetManager = new AsyncAssetManager(); const hydrationManager = new HydrationManager();