Next.js: Document how to do stuff differently server-side vs. client-side

Created on 21 Feb 2017  ·  14Comments  ·  Source: vercel/next.js

In Slack and in issues there comes repeatedly the question of how to do stuff differently server-side vs. client-side. I added a note in Wiki related to this: https://github.com/zeit/next.js/wiki/FAQ but it's obviously not clear enough.

I think it would be nice to add to README:

  • that e.g in getInitialProps you can use process.browser var to check where you are (which AFAIK is better than !!ctx.req because this one still returns true on the first client-side render...?)
  • that componentDidMount only runs client-side, so can add client-only code there. More generally, precise which React lifecycle methods are client-only.
  • or suggest to use something like component in render, or other libraries which render server-side only above-the-fold (link to examples, e.g https://github.com/zeit/next.js/tree/master/examples/progressive-render?)
  • note that these should hopefully be exceptions, and it's nice to strive for code which is as universal as possible
documentation

Most helpful comment

@knipferrc we want to provide a server API that you can run vanilla (node x.js), that's why we don't transpile server code. But we might introduce next start server.js with transpilation in the future. It depends on how close Node modules support is.

Honestly, transpilation brings performance down. Something that I think about often is that Next.js could have an opportunity soon to bring some sanity back to development by avoiding transpilation during development (or keeping it at a minimum)[1], and only doing it upon next build for multi-platform support.

[1] This is supported by the fact that Node is now tracking V8 very closely, and almost everyone develops on a modern browser with great ES support

All 14 comments

Would also be nice to know how to write ES6 code on the server side.

@knipferrc Node.js already support ES6, only modules aren't supported.

@sergiodxa but cant I use babel-cli or something to get all the import, export and module stuff somehow?

@sedubois there's a slack channel? maybe one could add that to the readme too ;)

@sakulstra there's a slack badge at the top of the README

@knipferrc we want to provide a server API that you can run vanilla (node x.js), that's why we don't transpile server code. But we might introduce next start server.js with transpilation in the future. It depends on how close Node modules support is.

Honestly, transpilation brings performance down. Something that I think about often is that Next.js could have an opportunity soon to bring some sanity back to development by avoiding transpilation during development (or keeping it at a minimum)[1], and only doing it upon next build for multi-platform support.

[1] This is supported by the fact that Node is now tracking V8 very closely, and almost everyone develops on a modern browser with great ES support

But we might introduce next start server.js with transpilation in the future. It depends on how close Node modules support is.

I believe @bnb mentioned it being around 1,5 years out :sweat_smile:

So ES6 import syntax is still quite far away. According to this very recent update, at least another year:

At the current point in time, there are still a number of specification and implementation issues that need to happen on the ES6 and Virtual Machine side of things before Node.js can even begin working up a supportable implementation of ES6 modules. Work is in progress but it is going to take some time — We’re currently looking at around a year at least.

So hopefully it will arrive sometime in 2018, but in the meantime, I'd really like some option to just write the same code on server and client, this is a really annoying mental overhead to remember to import syntaxes. And some features like object destructuring would also be really nice to use on the server side. So is there any workaround for now at least, or any way in which one could contribute to making the proposed next start server.js reality?

It is pretty simple to use ES6+ syntax on the server in development, following the description here. Basically just replace the start script with:
"start": "babel-node server.js --presets es2015,stage-2"

I haven't quite figured out, how to deploy this though and it seems there are some issues with hot reloading of the server code and using nodemon, doesn't work out of the box either (using it leads to constant reloading). I'll have to look into this a little more later.

Hey @MrLoh, just wondering if you found a clean way to implement this? babel-node works decently for dev work but curious what the process would entail for a deploy.

@tconroy you need to use Babel to generate files in disk with the code of your server and then use node built/index.js or something like that.

@tconroy I ended up doing something like this:

.babelrc:

{
  "env": {
    "server": {
      "presets": [["env", {
        "targets": {
          "node": ["current"]
        }
      }]]
    },
    "test": {
      "presets": [["env", {
        "targets": {
          "node": ["current"]
        }
      }]]
    },
    "development": {
      "presets": ["next/babel"]
    },
    "production": {
      "presets": ["next/babel"]
    }
  },
  "plugins": [
    ["root-import"],
    ["transform-object-rest-spread"],
    ["transform-flow-strip-types"],
    ["import", [
      {"libraryName": "antd"},
      {"libraryName": "lodash", "libraryDirectory": "/", "camel2DashComponentName": false}
    ]]
  ]
}

Than my start script looks like:

    "develop": "NODE_ENV=server nodemon --inspect -w server.js -w api server.js --exec babel-node",
    "build": "NODE_ENV=development next build & NODE_ENV=server babel server.js -d .dist & NODE_ENV=server babel api -d .dist/api"
    "start": "NODE_ENV=production node .dist/server.js",

Then I have a .env that contains BABEL_ENV=development

Which is called first thing in server.js changing the environment for the client code from server to development:

import { config } from 'dotenv'

config() // load .env variables into process.env

Worked great, thanks @MrLoh!

that e.g in getInitialProps you can use process.browser var to check where you are

Worth noting that it has to be referenced as process.browser exactly. I get process is not defined error when navigating to the page with this code:

image

Fixed by changing to:

Index.getInitialProps = ({ query }) => {
  return { query, browser: process.browser }
}
Was this page helpful?
0 / 5 - 0 ratings