vikejs / vike-node

🔨 Node integration for Vike
MIT License
20 stars 3 forks source link

How to deploy it on Vercel #4

Closed bitcoinvsalts closed 2 months ago

bitcoinvsalts commented 2 months ago

@nitedani any idea on how to deploy express-react example on vercel?

nitedani commented 2 months ago

I never tried vercel before. I'll try to make it work and create a new example.

bitcoinvsalts commented 2 months ago

@nitedani thank you for your reply. What do you use to deploy it? Netlify?

nitedani commented 2 months ago

https://github.com/vikejs/vike-node/tree/main/examples/express-react-vercel

The steps to add vercel support were:

  1. export the express instance from server/index.js
  2. create api/index.js, import the express instance here, and re-export it as a web request handler(because web request handlers support response streaming on vercel) The express instance is imported from the already built server entry file, so vite features like import.meta.env can be used in server/index.js. But I think this is a workaround and it can be improved.
  3. create vercel.json
bitcoinvsalts commented 2 months ago

@nitedani Thank you so much. I appreciate your quick reply and help.

Let me add my user auth logic to the server and see if it works fine with the Vike frontend.

bitcoinvsalts commented 2 months ago

@nitedani I am trying to pass the user auth info to the PageContext. Here is my code:

import express from 'express'
import vike from 'vike-node/connect'
import cookieParser from 'cookie-parser'

const { auth } = require('express-openid-connect');

export default startServer()

function autho(app) {
  const config = {
    authRequired: false,
    auth0Logout: true,
    issuerBaseURL: 'https://dev-xxnyc.us.auth0.com',
    clientID: 'HHxxxxxO',
    secret: 'Kp6xxxxxxxS2',
    baseURL: 'https://viked.vercel.app/'
  };
  app.use(cookieParser())
  app.use(express.json()) // Parse & make HTTP request body available at `req.body`
  app.use(
    auth(config)
  );
  app.use(function (req, res, next) {
    req.user = req.oidc.user;
    next();
  });
}

function startServer() {
  const app = express()
  autho(app)
  app.use(vike())
  const port = process.env.PORT || 3000
  app.listen(port, () => console.log(`Server running at http://localhost:${port}`))
  return app
}

But the user info is not yet passed to the PageContext. Any idea how to do this?

Here is a code that works but I cannot find a way to deploy it to Vercel:

import express from 'express'
import { renderPage } from 'vike/server'
import { root } from './root.js'
import cookieParser from 'cookie-parser'
import { getUser, checkCredentials } from './users.js'
const { auth } = require('express-openid-connect');

const isProduction = process.env.NODE_ENV === 'production'
const port = process.env.PORT || 3000

startServer()

async function startServer() {
  const app = express()
  autho(app)
  await assets(app)
  vike(app)
  app.listen(port)
  console.log(`Server running at http://localhost:${port}`)
}

function autho(app) {
  const config = {
    authRequired: false,
    auth0Logout: true,
    issuerBaseURL: 'https://dev-0xxxnyc.us.auth0.com',
    clientID: 'HHxxxxO',
    secret: 'Kp6xxxxxS2',
    baseURL: 'https://directbooking.netlify.app/'
  };
  app.use(cookieParser())
  app.use(express.json()) // Parse & make HTTP request body available at `req.body`
  app.use(
    auth(config)
  );
  app.use(function (req, res, next) {
    req.user = req.oidc.user;
    next();
  });
}

async function assets(app) {
  if (isProduction) {
    app.use(express.static(`${root}/dist/client`))
  } else {
    const vite = await import('vite')
    const viteDevMiddleware = (
      await vite.createServer({
        root,
        server: { middlewareMode: true }
      })
    ).middlewares
    app.use(viteDevMiddleware)
  }
}

function vike(app) {
  app.get('*', async (req, res, next) => {
    console.log("--=====--")
    const pageContextInit = {
      urlOriginal: req.originalUrl,
      headersOriginal: req.headers,
      user: req.user,
      userFullName: req.user?.fullName
    }
    const pageContext = await renderPage(pageContextInit)
    const { httpResponse } = pageContext
    if (!httpResponse) {
      return next()
    } else {
      const { statusCode, headers, earlyHints } = httpResponse
      if (res.writeEarlyHints) res.writeEarlyHints({ link: earlyHints.map((e) => e.earlyHintLink) })
      headers.forEach(([name, value]) => res.setHeader(name, value))
      res.status(statusCode)
      httpResponse.pipe(res)
    }
  })
}
phonzammi commented 2 months ago

@bitcoinvsalts Have you try this custom-pagecontext ?

bitcoinvsalts commented 2 months ago

I found the solution to my deployment issue!

If I use prerender: true in the vite config file like this, it wont process the destination API correctly while using auth

plugins: [ vike({ prerender: true, }), //mdx(), react() ], It works fine if I set prerender to false.

Big thanks to @nitedani for your help.

brillout commented 2 months ago

I'm glad you managed to achieve what you want. Btw. would your company be up for sponsoring (vikejs/vike#1350)?

bitcoinvsalts commented 2 months ago

@brillout sorry I don't have a company, I am looking for a job as a Full Stack dev if anyone is looking for one.