Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server bundle]: add a possibility to include the node_modules deps with the server bundle #4292

Closed
jsmonkey opened this issue Nov 7, 2018 · 28 comments

Comments

@jsmonkey
Copy link

jsmonkey commented Nov 7, 2018

What problem does this feature solve?

During the CI, when you build the final artifact, after you can't actually run it independently (at least server side) if depends on some node_modules packages. The offer is to provide some option to make it possible to bundle all the dependencies into the final artifact for the server side part.

What does the proposed changes look like?

Some new options in the nuxt configuration.

This feature request is available on Nuxt community (#c8107)
@ghost ghost added the cmty:feature-request label Nov 7, 2018
@jsmonkey jsmonkey changed the title [Server bundle]: add a possibility to include the node_modules deps with the server budnle [Server bundle]: add a possibility to include the node_modules deps with the server bundle Nov 7, 2018
@far-blue
Copy link

far-blue commented Jun 5, 2019

I'd very much like this feature as well. Currently it looks like most but not all app files are bundled but none of the node modules are bundled. When deploying an SSR artefact you therefore have to either have node modules globally installed on the hosting destination, run npm install on the hosting destination or bundle the folder yourself. None of these make deploying a smooth experience and the node_modules folder can be huge ( > 100mb).

If webpack could bundle, minify and tree-shake an SSR bundle you can then run directly with node (rather than nuxt-cli start) it would make deploy faster, cheaper, easier and more secure while also reducing the possibility of mismatched package versions between test, staging and production.

@pi0
Copy link
Member

pi0 commented Jun 6, 2019

It is currently possible by using nuxt build --standalone

@far-blue
Copy link

far-blue commented Jun 6, 2019

If the capability already exists then that's great news! But I couldn't find any documentation on the --standalone flag for nuxt build. I found an option for --analyse in the build api docs that isn't mentioned in https://nuxtjs.org/guide/commands but nothing on --standalone.

Now I know what to search for I've found https://github.com/nuxt/docs/issues/1097 - is --standalone still considered experimental? Might be worth mentioning it in docs anyhow

@pi0
Copy link
Member

pi0 commented Jun 7, 2019

It is being used by now builder without problems. So probably worth making out of experimental and document now.

@manniL
Copy link
Member

manniL commented Jun 7, 2019

@pi0 I suggest to document it first and keep it experimental for another 1-2 minors ☺️

@pi0
Copy link
Member

pi0 commented Jun 7, 2019

@manniL I think It was experimental enough (and mainly I flagged as experimental/not-documented to first test on some projects which we already did)

@manniL
Copy link
Member

manniL commented Jun 7, 2019

@pi0 If you think it's mature enough, then go for it! 👍 I only thought that more ppl would try it as soon as it's actually documented, which would lead to more feedback.

@shainegordon
Copy link

Nuxt Version: 2.8.1

It would be great to know how to actually run nuxt after using nuxt build --standalone

as a test case I tried the following.

  • build my project using nuxt build --standalone
  • copy the resulting .nuxt folder into a separate project that bascially just contains nuxt-start + a duplicate of my nuxt.config.js
  • bootstrap as an express middleware like so:
//nuxt.js

const { Nuxt } = require('nuxt-start')

const config = require('./nuxt.config.js')
const nuxt = new Nuxt({ ...config, dev: false })
module.exports = (req, res) => nuxt.ready().then(() => nuxt.server.app(req, res))
//index.js
const sls = require('serverless-http')
const binaryMimeTypes = require('./binaryMimeTypes')

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

however, upon running and making the first request to the app, I am presented with the following error: Error: Cannot find module '@nuxtjs/axios'
This is the first module inside nuxt.config.js#modules

my expectation would be that nuxt build --standalone results in an artefact that contains everything needed to run the application

@pi0
Copy link
Member

pi0 commented Jun 22, 2019

Put modules into devModules instead of modules if they are not required for runtime (axios is build only)

Standalone deployment is in the plan

@shainegordon
Copy link

shainegordon commented Jul 2, 2019

I actually got this working, the issue was how I was bootstrapping nuxt-start in standalone mode

//nuxt.js

const { Nuxt } = require('nuxt-start')

const nuxt = new Nuxt({ dev: false })
module.exports = (req, res) => nuxt.ready().then(() => nuxt.server.app(req, res))

The key here is to NOT include the nuxt.config.js and only set dev: false

I have successfully deployed a Nuxt SSR app to AWS Lambda, serving _nuxt and static off AWS S3 transparently through API Gateway

@lionskape
Copy link

Put modules into devModules instead of modules if they are not required for runtime (axios is build only)

Standalone deployment is in the plan

Have you got any news or insider information about this feature?
May be something like roadmap or release plan for this feature?

@pi0
Copy link
Member

pi0 commented Aug 20, 2019

@lionskape both buildModules (formerly devModules) and --standalone flags are now stable, documented and tested.

We are also working on new target: 'serverless' option to make deployments even more portable.

@lionskape
Copy link

Can I have link for documentation of "--standalone" and "buildModules"?
I tried to use search on nuxtjs.org, but it gives no result.

@pi0
Copy link
Member

pi0 commented Aug 20, 2019

2.9 Docs PR is WIP (nuxt/docs#1472) will release soon. For --standalone flag, you have to simply use nuxt build --standalone.

@lionskape
Copy link

Can I find anywhere description or examples, how to use it?

@zzmark
Copy link

zzmark commented Aug 21, 2019

in nuxt 2.9, i will add '@nuxt/typescript-build' in buildModule. in package.json @nuxt/typescript-build is devDependencies.
use to npm install --production on deploy server and nuxt start, throw to

  Error: Cannot find module '@nuxt/typescript-build'
  Require stack:
  - node_modules/@nuxt/core/dist/core.js
  - node_modules/nuxt/dist/nuxt.js
  - server/index.js
  at Resolver.requireModule (node_modules/@nuxt/core/dist/core.js:627:31)
  at ModuleContainer.addModule (node_modules/@nuxt/core/dist/core.js:163:36)
  at promise.then (node_modules/@nuxt/utils/dist/utils.js:1796:43)
  at process._tickCallback (internal/process/next_tick.js:68:7)
  at Function.Module.runMain (internal/modules/cjs/loader.js:834:11)

why is the buildModule still needed during runtime?

@pi0
Copy link
Member

pi0 commented Aug 21, 2019

@zzmark This is not related to this issue. Please create another issue in typescript repo and provide nuxt.config.js or a reproduction :)

@suil
Copy link

suil commented Mar 7, 2020

I actually got this working, the issue was how I was bootstrapping nuxt-start in standalone mode

//nuxt.js

const { Nuxt } = require('nuxt-start')

const nuxt = new Nuxt({ dev: false })
module.exports = (req, res) => nuxt.ready().then(() => nuxt.server.app(req, res))

The key here is to NOT include the nuxt.config.js and only set dev: false

I have successfully deployed a Nuxt SSR app to AWS Lambda, serving _nuxt and static off AWS S3 transparently through API Gateway

@shainegordon any way you could share your working codes with me? struggling to make it work in AWS lambda

@onhate
Copy link

onhate commented Apr 11, 2020

Hi folks,

I am struggling with a similar scenario. I am running nuxt on AWS Lambda and when I bundle my lambda (with webpack) it does not includes some modules in the bundle causing it fail in runtime.

The workaround was to include an import in the serverless file

import './serverless-requires';

and it includes some modules that Nuxt is not bundling in the dist/server bundle, for example:

import 'nuxt-env';

I am building with --standalone flag with "nuxt": "^2.12.2"

@qnp
Copy link
Contributor

qnp commented Jun 25, 2020

Greetings,

I deploy my Nuxt website on GCloud Kubernetes using a Docker image. The recommended way I have found in every blog posts or tutorials is to copy the entire source in the image, install all the node_modules and build the Nuxt app there. It resulted in a ~800MB image (from node:alpine 117MB, so almost 700MB of sources, deps and built files) !

The recommended minimal Dockerfile was :

FROM node:alpine

ENV APP_ROOT /app

RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}
# copy the entire source
ADD . ${APP_ROOT} 

# install all the node packages
RUN yarn

# build nuxt app here
RUN yarn build

CMD [ "yarn", "start" ]

The installation of all the node_modules were resulting in ~450Mo of fresh layers that needed to be pushed to our docker repository for each deployment, and then pulled by kubernetes. Not really efficient !

I tried to find a way to dramatically reduce the docker image size and build more efficient image (new layers that weight only few Mo).

At the present time, I did not found any clear documentation about nuxt build --standalone and the way to deploy the resulting built files.

Then I have come across this issue. The previous answers led me to the solution but I used a slightly different method that I'll share here for the record.

So here is my method:

  1. In my project, I create a directory called deploy with 3 files:
  • nuxt.config.js
import morgan from 'morgan'; // i use morgan in production to log every incoming requests

export default {
  dev: false,
  server: {
    port: process.env.PORT || 8080,
    host: process.env.HOST || '0.0.0.0',
  },
  // the only extra config needed here are the server middlewares
  serverMiddleware: [
    morgan('combined'),
    { path: '/health', handler: '~/api/health.js' },
    { path: '/data/cities', handler: '~/api/data/handler.js' },
  ],
};
  • package.json. Declare dependencies needed in serverMiddleware (in middleware api/data/handler.js I use mongodb):
{
  "scripts": {
    "start": "nuxt-start"
  },
  "dependencies": {
    "mongodb": "^3.5.9",
    "morgan": "^1.10.0",
    "nuxt-start": "^2.13.1"
  }
}
  • start.sh
    Nuxt-start 2.13.1 keeps asking permission for "anonymous usage analytics sharing" for improvement. In thus need to automatically pass No, that's why i need this shell file to start.
yarn start << EOF
n
EOF
  1. Build the Nuxt app locally using standalone flag
nuxt build --standalone
  1. Copy the only needed files in the docker image, install nuxt-start and the few server depencies, run start.sh. The Docker file is:
FROM node:alpine

ENV APP_ROOT /src

RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}

# copy the content of deploy directory
COPY deploy ${APP_ROOT}

# copy the generated .nuxt
COPY .nuxt ${APP_ROOT}/.nuxt

# copy your static directory
COPY static ${APP_ROOT}/static

# copy the server middleware files
COPY api ${APP_ROOT}/api

# install only nuxt-start and the few server depencies
RUN yarn

CMD [ "sh", "start.sh" ]

Final image size => 266MB (For the record, I have 90MB of images and videos in /static dir).

Hope this will help.

Best regards.

@shainegordon
Copy link

@qnp look at docker multi-stage builds. this wont solve your issue completely, but it will let you get smaller images

@pi0
Copy link
Member

pi0 commented Jun 25, 2020

Hi @qnp Indeed it would worth trying multistage builds as @shainegordon mentioned :)

Here is an example: https://github.com/nuxt/nuxt.js/blob/dev/examples/docker-build/Dockerfile
yarnclean file can also help: https://github.com/nuxt/nuxt.js/blob/dev/examples/docker-build/.yarnclean

The current base for image size is ~134MB

@qnp
Copy link
Contributor

qnp commented Jun 25, 2020

Yes indeed,
Thanks for the links, I have hence used this method using the given Dockerfile and .yarnclean.
However the image size for my Nuxt project is 528MB.
Hence the former method I explained above is much better for me :-)

@pi0
Copy link
Member

pi0 commented Jun 25, 2020

Indeed :) Excluding source may help even less bundle size. BTW telemetry prompt shouldn't happen with latest update for non tty environments (you can try yarn upgrade nuxt)

@qnp
Copy link
Contributor

qnp commented Jun 25, 2020

Thanks for your answer.
BTW, can you provide me with insights about why I need to keep the serverMiddleware config in my minimal nuxt.config.js, and copy the source of the middelwares. Souldn’t they be bundled in production build with nuxt build --standalone?

@freefri
Copy link

freefri commented Sep 17, 2020

Hi guys, one year later...

@pi0 I suggest to document it first and keep it experimental for another 1-2 minors relaxed

What do you think about adding nuxt build --standalone to the docs? It will save a lot of time for people who has to dive into stackoverflow and github issues to find this.

@manniL
Copy link
Member

manniL commented Sep 17, 2020

@freefri feel free to create an issue on https://github.com/nuxt/nuxtjs.org/issues 👍🏻

@pi0
Copy link
Member

pi0 commented Sep 17, 2020

Issue is there: nuxt/website-v2#499

Closing issue as main question is resolved. There are still improvement areas like inlining serverMiddleware, config and runtime modules which we will work on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests