nuxt / nuxt

The Intuitive Vue Framework.
https://nuxt.com
MIT License
54.97k stars 5.03k forks source link

Cannot GET / #6270

Closed MSkred closed 5 years ago

MSkred commented 5 years ago

Version

v2.0.0

Reproduction link

https://compte.letsgocity.be

Steps to reproduce

I've an app nuxt universal deploy on aws with lambda and when I come for the first time each 30 minutes I've an error Cannot GET /

Someone can help me ? @pi0

What is expected ?

I've an app nuxt universal deploy on aws with lambda and when I come for the first time each 30 minutes I've an error Cannot GET /

Someone can help me ? @pi0

What is actually happening?

I've an app nuxt universal deploy on aws with lambda and when I come for the first time each 30 minutes I've an error Cannot GET /

Someone can help me ? @pi0

This bug report is available on Nuxt community (#c9669)
pi0 commented 5 years ago

Hi. There is something wrong with your entry-point. When the instance is waking up and during initialization, nuxt is unable to handle requests. You have to await on nuxt.ready() before rendering.

If you need further assistance, please provide custom server.js

MSkred commented 5 years ago

This is my server.js file after npm run deploy @pi0

import { stringify } from 'querystring'
import Vue from 'vue'
import fetch from 'node-fetch'
import middleware from './middleware.js'
import { applyAsyncData, getMatchedComponents, middlewareSeries, promisify, urlJoin, sanitizeComponent } from './utils.js'
import { createApp, NuxtError } from './index.js'
import NuxtLink from './components/nuxt-link.server.js' // should be included after ./index.js

// Component: <NuxtLink>
Vue.component(NuxtLink.name, NuxtLink)
Vue.component('NLink', NuxtLink)

if (!global.fetch) { global.fetch = fetch }

const noopApp = () => new Vue({ render: h => h('div') })

const createNext = ssrContext => (opts) => {
  ssrContext.redirected = opts
  // If nuxt generate
  if (!ssrContext.res) {
    ssrContext.nuxt.serverRendered = false
    return
  }
  opts.query = stringify(opts.query)
  opts.path = opts.path + (opts.query ? '?' + opts.query : '')
  const routerBase = '/'
  if (!opts.path.startsWith('http') && (routerBase !== '/' && !opts.path.startsWith(routerBase))) {
    opts.path = urlJoin(routerBase, opts.path)
  }
  // Avoid loop redirect
  if (opts.path === ssrContext.url) {
    ssrContext.redirected = false
    return
  }
  ssrContext.res.writeHead(opts.status, {
    'Location': opts.path
  })
  ssrContext.res.end()
}

// This exported function will be called by `bundleRenderer`.
// This is where we perform data-prefetching to determine the
// state of our application before actually rendering it.
// Since data fetching is async, this function is expected to
// return a Promise that resolves to the app instance.
export default async (ssrContext) => {
  // Create ssrContext.next for simulate next() of beforeEach() when wanted to redirect
  ssrContext.redirected = false
  ssrContext.next = createNext(ssrContext)
  // Used for beforeNuxtRender({ Components, nuxtState })
  ssrContext.beforeRenderFns = []
  // Nuxt object (window{{globals.context}}, defaults to window.__NUXT__)
  ssrContext.nuxt = { layout: 'default', data: [], error: null, state: null, serverRendered: true }
  // Create the app definition and the instance (created for each request)
  const { app, router, store } = await createApp(ssrContext)
  const _app = new Vue(app)

  // Add meta infos (used in renderer.js)
  ssrContext.meta = _app.$meta()
  // Keep asyncData for each matched component in ssrContext (used in app/utils.js via this.$ssrContext)
  ssrContext.asyncData = {}

  const beforeRender = async () => {
    // Call beforeNuxtRender() methods
    await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
    ssrContext.rendered = () => {
      // Add the state from the vuex store
      ssrContext.nuxt.state = store.state
    }
  }
  const renderErrorPage = async () => {
    // Load layout for error page
    const errLayout = (typeof NuxtError.layout === 'function' ? NuxtError.layout(app.context) : NuxtError.layout)
    ssrContext.nuxt.layout = errLayout || 'default'
    await _app.loadLayout(errLayout)
    _app.setLayout(errLayout)
    await beforeRender()
    return _app
  }
  const render404Page = () => {
    app.context.error({ statusCode: 404, path: ssrContext.url, message: `This page could not be found` })
    return renderErrorPage()
  }

  // Components are already resolved by setContext -> getRouteData (app/utils.js)
  const Components = getMatchedComponents(router.match(ssrContext.url))

  /*
  ** Dispatch store nuxtServerInit
  */
  if (store._actions && store._actions.nuxtServerInit) {
    try {
      await store.dispatch('nuxtServerInit', app.context)
    } catch (err) {
      console.debug('Error occurred when calling nuxtServerInit: ', err.message)
      throw err
    }
  }
  // ...If there is a redirect or an error, stop the process
  if (ssrContext.redirected) return noopApp()
  if (ssrContext.nuxt.error) return renderErrorPage()

  /*
  ** Call global middleware (nuxt.config.js)
  */
  let midd = ["isLoggedIn"]
  midd = midd.map((name) => {
    if (typeof name === 'function') return name
    if (typeof middleware[name] !== 'function') {
      app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
    }
    return middleware[name]
  })
  await middlewareSeries(midd, app.context)
  // ...If there is a redirect or an error, stop the process
  if (ssrContext.redirected) return noopApp()
  if (ssrContext.nuxt.error) return renderErrorPage()

  /*
  ** Set layout
  */
  let layout = Components.length ? Components[0].options.layout : NuxtError.layout
  if (typeof layout === 'function') layout = layout(app.context)
  await _app.loadLayout(layout)
  if (ssrContext.nuxt.error) return renderErrorPage()
  layout = _app.setLayout(layout)
  ssrContext.nuxt.layout = _app.layoutName

  /*
  ** Call middleware (layout + pages)
  */
  midd = []
  layout = sanitizeComponent(layout)
  if (layout.options.middleware) midd = midd.concat(layout.options.middleware)
  Components.forEach((Component) => {
    if (Component.options.middleware) {
      midd = midd.concat(Component.options.middleware)
    }
  })
  midd = midd.map((name) => {
    if (typeof name === 'function') return name
    if (typeof middleware[name] !== 'function') {
      app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
    }
    return middleware[name]
  })
  await middlewareSeries(midd, app.context)
  // ...If there is a redirect or an error, stop the process
  if (ssrContext.redirected) return noopApp()
  if (ssrContext.nuxt.error) return renderErrorPage()

  /*
  ** Call .validate()
  */
  let isValid = true
  try {
    for (const Component of Components) {
      if (typeof Component.options.validate !== 'function') {
        continue
      }

      isValid = await Component.options.validate(app.context)

      if (!isValid) {
        break
      }
    }
  } catch (validationError) {
    // ...If .validate() threw an error
    app.context.error({
      statusCode: validationError.statusCode || '500',
      message: validationError.message
    })
    return renderErrorPage()
  }

  // ...If .validate() returned false
  if (!isValid) {
    // Don't server-render the page in generate mode
    if (ssrContext._generate) ssrContext.nuxt.serverRendered = false
    // Render a 404 error page
    return render404Page()
  }

  // If no Components found, returns 404
  if (!Components.length) return render404Page()

  // Call asyncData & fetch hooks on components matched by the route.
  const asyncDatas = await Promise.all(Components.map((Component) => {
    const promises = []

    // Call asyncData(context)
    if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
      const promise = promisify(Component.options.asyncData, app.context)
      promise.then((asyncDataResult) => {
        ssrContext.asyncData[Component.cid] = asyncDataResult
        applyAsyncData(Component)
        return asyncDataResult
      })
      promises.push(promise)
    } else {
      promises.push(null)
    }

    // Call fetch(context)
    if (Component.options.fetch) {
      promises.push(Component.options.fetch(app.context))
    } else {
      promises.push(null)
    }

    return Promise.all(promises)
  }))

  // datas are the first row of each
  ssrContext.nuxt.data = asyncDatas.map(r => r[0] || {})

  // ...If there is a redirect or an error, stop the process
  if (ssrContext.redirected) return noopApp()
  if (ssrContext.nuxt.error) return renderErrorPage()

  // Call beforeNuxtRender methods & add store state
  await beforeRender()

  return _app
}
pi0 commented 5 years ago

@MSkred This is the auto-generated file. I mean lambda entry-point.

MSkred commented 5 years ago

serverless.yml

service: lgc-ssr-nuxt
app: serverless-side-rendering-nuxt-app
org: maximescibetta

provider:
  name: aws
  runtime: nodejs8.10
  stage: ${self:custom.secrets.NODE_ENV}
  region: eu-west-1
  environment: 
    NODE_ENV: ${self:custom.secrets.NODE_ENV}

functions:
  nuxt:
    handler: index.nuxt
    events:
      - http: ANY /
      - http: ANY /{proxy+}

plugins:
  - serverless-apigw-binary
  - serverless-domain-manager

custom:
  secrets: ${file(secrets.json)}
  apigwBinary:
    types:
      - '*/*'
  customDomain:
    domainName: ${self:custom.secrets.DOMAIN}
    basePath: ''
    stage: ${self:custom.secrets.NODE_ENV}
    createRoute53Record: true
MSkred commented 5 years ago

nuxt.js

const express = require('express')
const app = express()
const { Nuxt } = require('nuxt')
const path = require('path')

app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist')))
const config = require('./nuxt.config.js')
const nuxt = new Nuxt(config)
app.use(nuxt.render)

module.exports = app

index.js

const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')

const nuxt = require('./nuxt')
module.exports.nuxt = sls(nuxt, {
  binary: binaryMimeTypes
})

You need something else ? I'm sure that's what you wanted

MSkred commented 5 years ago

This is my terminal result @pi0

npm run deploy

> lgc-account-pwa@1.0.0 deploy /Users/lgc/Documents/LetsGoCity/PWA/lgc-account-pwa
> nuxt build && sls deploy

 WARN  devModules has been renamed to buildModules and will be removed in Nuxt 3.                                                      19:39:12

ℹ Production build                                                                                                                     19:39:14
✔ Builder initialized                                                                                                                  19:39:14
✔ Nuxt files generated                                                                                                                 19:39:14

✔ Client
  Compiled successfully in 11.54s

✔ Server
  Compiled successfully in 3.20s

Hash: 09602a36e70873c52310
Version: webpack 4.39.2
Time: 11538ms
Built at: 2019-08-21 19:39:28
                         Asset       Size  Chunks             Chunk Names
../server/client.manifest.json   12.6 KiB          [emitted]  
       08b8fc8f46b5562e8732.js   5.85 KiB      11  [emitted]  pages/motdepasseoublie/index
       2469a8ca9782532115db.js   6.78 KiB      10  [emitted]  pages/inscription
       246bf196a6911959fb3c.js   4.27 KiB      16  [emitted]  
       2a0e850a01ef1c1564d6.js   5.11 KiB       9  [emitted]  pages/information/preference
       2b39ecb496621aeec207.js   1.02 KiB      13  [emitted]  pages/motdepasseoublie/redirection
       351777d51002621f5799.js    2.6 KiB      14  [emitted]  runtime
       8d448d8d35a2678a964d.js   78.7 KiB       2  [emitted]  app
       9250c72a11d50c8c748d.js   9.91 KiB       8  [emitted]  pages/information/modification
       96381bb7067c767fe0df.js   12.2 KiB       4  [emitted]  commons.pages/inscription
                      LICENSES   1.16 KiB          [emitted]  
       a4477b96903e4364654b.js   96.4 KiB       1  [emitted]  vendors.pages/information/modification.pages/inscription
       a4aa36c2b000f162d0a3.js   29.1 KiB       0  [emitted]  pages/information/modification.pages/inscription
       a8e0a6fc3e45212086cf.js   12.9 KiB       6  [emitted]  pages/index
       b8c4518978f6db7a5d06.js   11.3 KiB      12  [emitted]  pages/motdepasseoublie/modification
       c739ca8b953d66601566.js    3.5 KiB       5  [emitted]  pages/autorisation
       cfd2904c44941e6cb913.js   32.7 KiB      15  [emitted]  vendors.app
       dcb2372377826391b267.js   4.64 KiB       7  [emitted]  pages/information/index
       f5dcccbeac0df41cbc83.js    175 KiB       3  [emitted]  commons.app
     icons/icon_120.8d8a54.png   8.51 KiB          [emitted]  
     icons/icon_144.8d8a54.png   11.1 KiB          [emitted]  
     icons/icon_152.8d8a54.png   11.8 KiB          [emitted]  
     icons/icon_192.8d8a54.png   16.2 KiB          [emitted]  
     icons/icon_384.8d8a54.png   42.8 KiB          [emitted]  
     icons/icon_512.8d8a54.png   59.6 KiB          [emitted]  
      icons/icon_64.8d8a54.png   3.91 KiB          [emitted]  
        manifest.66e615c0.json  816 bytes          [emitted]  
 + 2 hidden assets
Entrypoint app = 351777d51002621f5799.js f5dcccbeac0df41cbc83.js cfd2904c44941e6cb913.js 8d448d8d35a2678a964d.js

Hash: 275a3c7c6e5cfd468a75
Version: webpack 4.39.2
Time: 3201ms
Built at: 2019-08-21 19:39:31
                  Asset       Size  Chunks             Chunk Names
3caeab9d39523e09c618.js   3.22 KiB       3  [emitted]  pages/information/index
4db86521b8f9fc02a017.js   4.96 KiB       7  [emitted]  pages/motdepasseoublie/index
512a084e313f6e9a6cd2.js   3.13 KiB       5  [emitted]  pages/information/preference
5b379aa6d079076c0b3d.js   2.34 KiB       1  [emitted]  pages/autorisation
6244a906bb81b1e222f1.js   30.8 KiB       6  [emitted]  pages/inscription
640c72c2ff6e065c58b0.js   33.6 KiB       4  [emitted]  pages/information/modification
9ab87bb8d40ccdd1574c.js   9.33 KiB       2  [emitted]  pages/index
fdc4398f9767e768618e.js   7.88 KiB       8  [emitted]  pages/motdepasseoublie/modification
fee8114a961ae65e97b4.js  983 bytes       9  [emitted]  pages/motdepasseoublie/redirection
              server.js   59.4 KiB       0  [emitted]  app
   server.manifest.json   1.17 KiB          [emitted]  
 + 10 hidden assets
Entrypoint app = server.js server.js.map
Serverless: An updated version of Serverless Enterprise is available. Please upgrade by running `npm i -g serverless`
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service lgc-ssr-nuxt.zip file to S3 (44.97 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
..............
Serverless: Stack update finished...
Service Information
service: lgc-ssr-nuxt
stage: dev
region: eu-west-1
stack: lgc-ssr-nuxt-dev
resources: 17
api keys:
  None
endpoints:
  ANY - https://w5civxdhfb.execute-api.eu-west-1.amazonaws.com/dev
  ANY - https://w5civxdhfb.execute-api.eu-west-1.amazonaws.com/dev/{proxy+}
functions:
  nuxt: lgc-ssr-nuxt-dev-nuxt
layers:
  None
Serverless: Updated basepath mapping.
Serverless Domain Manager Summary
Domain Name
  compte.letsgocity.be
Distribution Domain Name
  Target Domain: d1quusiyn1twou.cloudfront.net
  Hosted Zone Id: XXXXXXXXXX
Serverless: Removing old service artifacts from S3...
Serverless: Publishing service to the Serverless Dashboard...
Serverless: Successfully published your service to the Serverless Dashboard: https://dashboard.serverless.com/tenants/maximescibetta/applications/serverless-side-rendering-nuxt-app/services/lgc-ssr-nuxt/stage/dev/region/eu-west-1
MSkred commented 5 years ago

I've 404 error sometime on some domain/dev/_nuxt/some_file.js @pi0

MSkred commented 5 years ago

Issue solved : https://cmty.app/nuxt/nuxt.js/issues/c8955

I've updated my nuxt.js and index.js

nuxt.js

const express = require('express');
const { Nuxt } = require('nuxt');
const path = require('path');
const config = require('./nuxt.config.js');

async function start() {
  const app = express();
  const nuxt = new Nuxt(config);
  await nuxt.ready();
  app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist')));
  app.use(nuxt.render);
  return app;
}

module.exports = start;

index.js

const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')
const nuxt = require('./nuxt')

module.exports.nuxt = (evt, ctx, callback) => {
  return nuxt()
    .then(app =>
      sls(app, {
        binary: binaryMimeTypes,
      })
    )
    .then(proxy => proxy(evt, ctx, callback))
    .catch(err => console.error(err));
};
MSkred commented 4 years ago

@pi0 All works very fine, but between before nuxt.ready() and after we've 7 SECONDS of delay … and my website is not showed during this time.

pi0 commented 4 years ago

Hey @MSkred. It must be with some modules takes long time. Can you please share nuxt.config in a new question issue regarding slow startup?

samchong1104 commented 3 years ago

nuxt.js

const express = require('express')
const app = express()
const { Nuxt } = require('nuxt')
const path = require('path')

app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist')))
const config = require('./nuxt.config.js')
const nuxt = new Nuxt(config)
app.use(nuxt.render)

module.exports = app

index.js

const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')

const nuxt = require('./nuxt')
module.exports.nuxt = sls(nuxt, {
  binary: binaryMimeTypes
})

You need something else ? I'm sure that's what you wanted

replace app.use(nuxt.render) to app.use(async (req, res) => { if (nuxt.ready) { await nuxt.ready() } nuxt.render(req, res) });

matt9mg commented 2 years ago

nuxt.js

const express = require('express')
const app = express()
const { Nuxt } = require('nuxt')
const path = require('path')

app.use('/_nuxt', express.static(path.join(__dirname, '.nuxt', 'dist')))
const config = require('./nuxt.config.js')
const nuxt = new Nuxt(config)
app.use(nuxt.render)

module.exports = app

index.js

const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')

const nuxt = require('./nuxt')
module.exports.nuxt = sls(nuxt, {
  binary: binaryMimeTypes
})

You need something else ? I'm sure that's what you wanted

replace app.use(nuxt.render) to app.use(async (req, res) => { if (nuxt.ready) { await nuxt.ready() } nuxt.render(req, res) });

This should be the prefered answer, tested in 2022 and this worked wonderfully I have not yet had the issue. thanks @samchong1104