saltyshiomix / nextron

⚡ Next.js + Electron ⚡
https://npm.im/nextron
MIT License
3.88k stars 223 forks source link

Cookie not working in Prod #353

Open Ishu1998 opened 1 year ago

Ishu1998 commented 1 year ago

Cookies work in Dev but not in Prod

image image

Same issue - https://github.com/electron-userland/electron-builder/issues/5278

Please let me know how to solve this. Thanks

dhineshtp commented 1 year ago

use electron-store to store and persist the data.

Check this out for more. https://www.npmjs.com/package/electron-store

alexis-piquet commented 1 year ago

Hey @Ishu1998, as @dhineshtp suggested, you will use electron-store to do it. Would you want to have a basic usage example?

Server-Side (IpcMain)

Constants

export const WINDOW_NAME_APP = 'my_awesome_application'

export const IPC_EVENT_CONFIG = 'event:config'
export const IPC_EVENTS = [
  IPC_EVENT_CONFIG,
] as const
export type IpcEvent = typeof IPC_EVENTS[number]

export const IPC_PROMISE_CONFIG = 'promise:config'
export const IPC_PROMISES = [
  IPC_PROMISE_CONFIG,
] as const
export type IpcPromise = typeof IPC_PROMISES[number]

export const STORE_KEY_CONFIG= 'system'
export const STORE_KEYS = [
  STORE_KEY_CONFIG,
] as const

export type StoreKey = typeof STORE_KEYS[number]

index.ts (background.ts)

import { app } from 'electron'
import { createWindow } from '#server/window'
import serve from 'electron-serve'

const is_prod: boolean = process.env.NODE_ENV === 'production'

if (is_prod) {
  serve({ directory: 'app' })
} else {
  app.setPath('userData', `${app.getPath('userData')}-development`)
}

(async () => {
  await app.whenReady()
  const mainWindow = createWindow(app)
  if (is_prod) return mainWindow.loadURL('app://./index.html')
  const port = process.argv[2]
  await mainWindow.loadURL(`http://localhost:${port}/`)
  mainWindow.webContents.openDevTools()
})()

app.on('window-all-closed', () => app.quit())

window.ts

import { getConfig } from '#server/config'
import { BrowserWindow, ipcMain } from 'electron'
import { IPC_EVENT_CONFIG, IPC_PROMISE_CONFIG, WINDOW_NAME_APP } from '#constants'
import Store from 'electron-store'

export function createWindow (app: Electron.App): BrowserWindow {
  const name = WINDOW_NAME_APP
  const store = new Store({ name })

  store.set(STORE_KEY_CONFIG, {
    arch: process.arch,
    user_path: app.getPath('userData'),
  })

  const application = new BrowserWindow({
    width: 875,
    height: 585,
    center: true,
    frame: false,
    transparent: true,
    resizable: false,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    },
  })

  // IPC_EVENTS
  ipcMain.on(IPC_EVENT_CONFIG, (event) => getConfig(store))

  // IPC_PROMISES
  ipcMain.handle(IPC_PROMISE_CONFIG, async () => getConfig(store))
  return application
}

config.ts

import { STORE_KEY_CONFIG } from '#constants'

export type User = {
  name?: string
  email?: string
}

export type ConfigProps = {
  user?: User
}

export async function getConfigPromise(store: Store<ConfigProps>): Promise<ConfigProps> {
  const system = store.get(STORE_KEY_CONFIG)
  return { user }
}

And finally in the client you can implement a class service like the folowing:

import {  IPC_EVENT_CONFIG, IPC_PROMISE_CONFIG} from '#constants'
import { ConfigProps } from '#server/config'
import { IpcRenderer } from 'electron'

export class Service {
  ipcRenderer: IpcRenderer

  constructor(ipcRenderer: IpcRenderer) {
    this.ipcRenderer = ipcRenderer
  }

  async getConfig(): Promise<void> {
    return this.ipcRenderer.send(IPC_EVENT_CONFIG)
  }

  async getConfigPromise(): Promise<ConfigProps> {
    return this.ipcRenderer.invoke(IPC_PROMISE_CONFIG)
  }
}

You can also use a hook to catch an event payload:

import { IpcEvent } from '#constants'
import { useMemo, useState } from 'react'
import electron from 'electron'

export function useEvent <T> (event_name: IpcEvent): T {
  const [ state, setState ] = useState<T>()
  electron?.ipcRenderer?.removeAllListeners(event_name)
  electron?.ipcRenderer?.on(event_name, (_event, args) => setState(args))
  return useMemo(() => state, [ state ])
}

Usage in a component

import { User as TUser } from '#server/config'
import React, { useEffect, useState } from 'react'

export const User: React.FC = () => {
  const { service } = useHelpers()
  const payload = useEvent<ConfigProps>(IPC_EVENT_CONFIG)
  const [ state, setState ] = useState<TUser>()
  useEffect(() => {
    if (payload?.user) setState(payload?.user)
     getConfig()
  }, [ payload ])

  return (
    <>
      <span>{state?.name}</span>
      <span>{state?.email}</span>
    </>
  )

  async function getConfig(): Promise<void> {
    const config = await service.getConfig()
    setState(config?.user)
  }

}

helper context

import { Service } from '#service'
import { ConfigProps } from '#types'
import React, { createContext, PropsWithChildren, useContext } from 'react'

export interface Helpers {
  service?: Service
}

export type ProviderProps = {
  helpers: Helpers
}

export const HelpersContext = createContext<Helpers>({})
export const HelpersProvider: React.FC<PropsWithChildren<ProviderProps>> = (
  { helpers, children }: PropsWithChildren<ProviderProps>
) => (
  <HelpersContext.Provider value={helpers}>{children}</HelpersContext.Provider>
)
export function useHelpers(): Helpers {
  return useContext<Helpers>(HelpersContext)
}

_app.tsx

import { AppProps } from 'next/app'
import { Helpers, HelpersProvider } from '#shared/hooks/helper'
import { Service } from '#service'
import electron from 'electron'
import React, { useEffect, useMemo, useState } from 'react'

export default (
  { Component, pageProps }: AppProps
) => {
  const service = useMemo<Helpers['service']>(() => (
    new Service(electron.ipcRenderer)
  ), [ electron.ipcRenderer ])
  const [ helpers, setHelpers ] = useState<Helpers>({ service })

  return (
    <HelpersProvider helpers={helpers}>
      <Component {...pageProps}/>
    </HelpersProvider>
  )
}

I hope it will help you, do not hesitate to give me a feedback. Good luck and have fun dude!

alexis-piquet commented 1 year ago

Ive added my suggest in the discussions section 😘

alexis-piquet commented 1 year ago

Ah and of course If our suggests solve your issue, could you close it ASAP? 😘

alexis-piquet commented 1 year ago

@Ishu1998 , are you still alive? ❤️

0xPT commented 1 year ago

Even with using electron-store it doesn't help with cookies that are necessary for 3rd party libraries (Supabase)