`next export` (static builds) #604

Closed
rauchg opened this Issue Jan 1, 2017 · 30 comments

Comments

@rauchg
Contributor

rauchg commented Jan 1, 2017

This might be built in (if it's not too opinionated), or a separate "core module" (if it has too many "options").

The idea is that one will be able to run next export and yield a build directory that doesn't require a server.

  • next export -o customDir should be possible
  • Each page can optionally precompute getInitialProps to have pre-rendered data when it's first loaded
  • The export config could live in next.config.js (export object)
@arunoda

This comment has been minimized.

Show comment
Hide comment
@arunoda

arunoda Jan 1, 2017

Collaborator

How about if we ignore getInitialProps for the static build.
We simply ignore that.

Is that something we could consider?

Collaborator

arunoda commented Jan 1, 2017

How about if we ignore getInitialProps for the static build.
We simply ignore that.

Is that something we could consider?

@rauchg

This comment has been minimized.

Show comment
Hide comment
@rauchg

rauchg Jan 1, 2017

Contributor

Definitely. Client-only getInitialProps is a possibility.

Contributor

rauchg commented Jan 1, 2017

Definitely. Client-only getInitialProps is a possibility.

@yn5

This comment has been minimized.

Show comment
Hide comment
@yn5

yn5 Jan 9, 2017

@rauchg @arunoda Wouldn't ignoring getInitialProps defeat the purpose of a static site? There would still be a need for a server to get those initial props right? Or did I maybe miss something in the previous discussion?

yn5 commented Jan 9, 2017

@rauchg @arunoda Wouldn't ignoring getInitialProps defeat the purpose of a static site? There would still be a need for a server to get those initial props right? Or did I maybe miss something in the previous discussion?

@rauchg

This comment has been minimized.

Show comment
Hide comment
@rauchg

rauchg Jan 9, 2017

Contributor

There are two forms of static sites. The one where the data is 100% static, and the one where it's not. And there's a hybrid where you ship props pre-computed with each page and data can still be fetched dynamically

Contributor

rauchg commented Jan 9, 2017

There are two forms of static sites. The one where the data is 100% static, and the one where it's not. And there's a hybrid where you ship props pre-computed with each page and data can still be fetched dynamically

@yn5

This comment has been minimized.

Show comment
Hide comment
@yn5

yn5 Jan 11, 2017

@rauchg React inherently allows the hybrid form trough its componendDidMount hook. I'd love to see the next export feature to generate a truly static site, otherwise I'll have to open another feature request once it is finished ;)

yn5 commented Jan 11, 2017

@rauchg React inherently allows the hybrid form trough its componendDidMount hook. I'd love to see the next export feature to generate a truly static site, otherwise I'll have to open another feature request once it is finished ;)

@balupton

This comment has been minimized.

Show comment
Hide comment
@balupton

balupton Jan 15, 2017

There are two forms of static sites. The one where the data is 100% static, and the one where it's not. And there's a hybrid where you ship props pre-computed with each page and data can still be fetched dynamically

What type of static site is this command planning on exporting?

Let's perhaps define them these ways:

  • static sites that don't require client-side rendering (they can work without javascript)
  • static sites where certain pages or abilities require client-side rendering (needing some javascript)
  • static sites where each page is then assisted by client-side rendering (requiring some javascript) - e.g. single page web apps

balupton commented Jan 15, 2017

There are two forms of static sites. The one where the data is 100% static, and the one where it's not. And there's a hybrid where you ship props pre-computed with each page and data can still be fetched dynamically

What type of static site is this command planning on exporting?

Let's perhaps define them these ways:

  • static sites that don't require client-side rendering (they can work without javascript)
  • static sites where certain pages or abilities require client-side rendering (needing some javascript)
  • static sites where each page is then assisted by client-side rendering (requiring some javascript) - e.g. single page web apps
@balupton

This comment has been minimized.

Show comment
Hide comment
@balupton

balupton Jan 15, 2017

Also, what exactly is the benefit of zeit:next exporting a static site?

From my understanding, zeit:now will still wrap static sites in a node.js app (zeit:serve) - and zeit:now even trumps most static deployment options anyway.

balupton commented Jan 15, 2017

Also, what exactly is the benefit of zeit:next exporting a static site?

From my understanding, zeit:now will still wrap static sites in a node.js app (zeit:serve) - and zeit:now even trumps most static deployment options anyway.

@bguiz

This comment has been minimized.

Show comment
Hide comment
@bguiz

bguiz Jan 21, 2017

Also, what exactly is the benefit of zeit:next exporting a static site?

@balupton Allows one to host on github pages, aws s3, etc.

bguiz commented Jan 21, 2017

Also, what exactly is the benefit of zeit:next exporting a static site?

@balupton Allows one to host on github pages, aws s3, etc.

@bguiz

This comment has been minimized.

Show comment
Hide comment
@bguiz

bguiz Jan 21, 2017

As an alternative, I tried to get the static content using wget. Although it works with other of my projects (without using next), it does not work well here with next.

@jferrettiboke @stretchkennedy Where internal links are unknown at "build time", I think the approach used by static-site-generator-webpack-plugin where you simply list all of the URLs it needs to render in one place, works quite well.

Of course you don't want to be doing this by hand - I have a script that does this based on matching file names within a directory: find-posts

( Continuing conversation here from #604 )

bguiz commented Jan 21, 2017

As an alternative, I tried to get the static content using wget. Although it works with other of my projects (without using next), it does not work well here with next.

@jferrettiboke @stretchkennedy Where internal links are unknown at "build time", I think the approach used by static-site-generator-webpack-plugin where you simply list all of the URLs it needs to render in one place, works quite well.

Of course you don't want to be doing this by hand - I have a script that does this based on matching file names within a directory: find-posts

( Continuing conversation here from #604 )

@balupton

This comment has been minimized.

Show comment
Hide comment
@balupton

balupton Jan 30, 2017

@balupton Allows one to host on github pages, aws s3, etc.

But the only reason I can imagine of why people want to deploy to them is because they are free and quick hosting -however zeit:now + cloudflare accomplishes the same - with much more coolness

balupton commented Jan 30, 2017

@balupton Allows one to host on github pages, aws s3, etc.

But the only reason I can imagine of why people want to deploy to them is because they are free and quick hosting -however zeit:now + cloudflare accomplishes the same - with much more coolness

@yn5

This comment has been minimized.

Show comment
Hide comment
@yn5

yn5 Jan 30, 2017

@balupton Not really, if you have a static site which does not have to render the app or fetch data on the backend before it is sent to the server you can gain a lot of speed. This is the main reason I make static web-apps.

yn5 commented Jan 30, 2017

@balupton Not really, if you have a static site which does not have to render the app or fetch data on the backend before it is sent to the server you can gain a lot of speed. This is the main reason I make static web-apps.

@stretchkennedy

This comment has been minimized.

Show comment
Hide comment
@stretchkennedy

stretchkennedy Jan 31, 2017

@yn5 I think he's talking about using cloudflare's caching.

For myself, the reason I want to render a static site is to lower the attack surface and to consume fewer resources. Deploying nodejs requires keeping more dependencies up to date than just deploying nginx, and wastes a perfectly good VM even if you put it behind cloudflare.

@yn5 I think he's talking about using cloudflare's caching.

For myself, the reason I want to render a static site is to lower the attack surface and to consume fewer resources. Deploying nodejs requires keeping more dependencies up to date than just deploying nginx, and wastes a perfectly good VM even if you put it behind cloudflare.

@bguiz

This comment has been minimized.

Show comment
Hide comment
@bguiz

bguiz Feb 9, 2017

@balupton But the only reason I can imagine of why people want to deploy to them is because they are free and quick hosting -however zeit:now + cloudflare accomplishes the same - with much more coolness

I agree with the reasons mentioned by @stretchkennedy and @yn5 - but I'll also add that the over-arching goal should be to move towards being more permissive; rather than to restrict the options. If a particular site is truly static in nature, then why preclude having the option of being able to serve from a static host?

Additionally, enabling zeit to work with a flow that one has already invested time in setting up and tweaking (e.g. in your CI/ CD pipeline), rather than having to set up a new flow, is a win.

bguiz commented Feb 9, 2017

@balupton But the only reason I can imagine of why people want to deploy to them is because they are free and quick hosting -however zeit:now + cloudflare accomplishes the same - with much more coolness

I agree with the reasons mentioned by @stretchkennedy and @yn5 - but I'll also add that the over-arching goal should be to move towards being more permissive; rather than to restrict the options. If a particular site is truly static in nature, then why preclude having the option of being able to serve from a static host?

Additionally, enabling zeit to work with a flow that one has already invested time in setting up and tweaking (e.g. in your CI/ CD pipeline), rather than having to set up a new flow, is a win.

@matthewmueller

This comment has been minimized.

Show comment
Hide comment
@matthewmueller

matthewmueller Feb 21, 2017

Contributor

I'd like to toss in my hat on how I think this could work really well:

static getInitialProps ({ build, req }) {
   if (req) {
      // server-side
   } else if (build) { 
      // static build (can contains parameters about the page build)
      // this happens at the time of the build (next export)
   } else {
      // client-side
   }
}

next export will generate HTML & JSON representations of each top-level page component.

  • The HTML representation will be used to serve the initial request
  • The JSON representation will be used to asynchronously navigate around via <Link href="...">

The cool thing about this is that you can pull in markdown files and other resources (even pre-render a page) all from within that build == true condition.

Contributor

matthewmueller commented Feb 21, 2017

I'd like to toss in my hat on how I think this could work really well:

static getInitialProps ({ build, req }) {
   if (req) {
      // server-side
   } else if (build) { 
      // static build (can contains parameters about the page build)
      // this happens at the time of the build (next export)
   } else {
      // client-side
   }
}

next export will generate HTML & JSON representations of each top-level page component.

  • The HTML representation will be used to serve the initial request
  • The JSON representation will be used to asynchronously navigate around via <Link href="...">

The cool thing about this is that you can pull in markdown files and other resources (even pre-render a page) all from within that build == true condition.

@herrstucki

This comment has been minimized.

Show comment
Hide comment
@herrstucki

herrstucki Feb 21, 2017

Contributor

@matthewmueller would it be possible to eliminate code from getInitialProps() on build?

Let's say you use an API to fetch live data during development and you want to "bake" it into a static build (both in the HTML and JSON representation of a page), to eliminate any API requests in production. This would be awesome for a collaborative workflow.

To optimize the output you'd probably then remove the dependency on whatever API library you use to fetch data in getInitialProps() during dev/build time because you can basically just replace it with the API response.

static async getInitialProps ({ build, req }) {
  if (build) { 
      return myCoolAPILib.fetch('foobar.csv') // Probably load myCoolAPILib through webpack's async import()?
   }
}

gets turned into:

static async getInitialProps () {
  return {
    // Response from myCoolAPILib
  };
}
Contributor

herrstucki commented Feb 21, 2017

@matthewmueller would it be possible to eliminate code from getInitialProps() on build?

Let's say you use an API to fetch live data during development and you want to "bake" it into a static build (both in the HTML and JSON representation of a page), to eliminate any API requests in production. This would be awesome for a collaborative workflow.

To optimize the output you'd probably then remove the dependency on whatever API library you use to fetch data in getInitialProps() during dev/build time because you can basically just replace it with the API response.

static async getInitialProps ({ build, req }) {
  if (build) { 
      return myCoolAPILib.fetch('foobar.csv') // Probably load myCoolAPILib through webpack's async import()?
   }
}

gets turned into:

static async getInitialProps () {
  return {
    // Response from myCoolAPILib
  };
}
@kbingman

This comment has been minimized.

Show comment
Hide comment
@kbingman

kbingman Mar 13, 2017

So how would you handle code splitting? Right now, for dynamically rendered pages, Next requests a JSON file with the components. Would these be statically published as well?

So how would you handle code splitting? Right now, for dynamically rendered pages, Next requests a JSON file with the components. Would these be statically published as well?

@matthewmueller

This comment has been minimized.

Show comment
Hide comment
@matthewmueller

matthewmueller Mar 24, 2017

Contributor

@kbingman yep, i believe the json versions are built and written to the filesystem anyway.

Contributor

matthewmueller commented Mar 24, 2017

@kbingman yep, i believe the json versions are built and written to the filesystem anyway.

@tom2strobl

This comment has been minimized.

Show comment
Hide comment
@tom2strobl

tom2strobl Mar 29, 2017

From a dev-ops, scaling, speed and pricing point of view, nothing beats a static page on S3. So this feature is actually super important for us.

From a dev-ops, scaling, speed and pricing point of view, nothing beats a static page on S3. So this feature is actually super important for us.

@rauchg

This comment has been minimized.

Show comment
Hide comment
@rauchg

rauchg Mar 29, 2017

Contributor

@kbingman those will be statically generated indeed as well

Contributor

rauchg commented Mar 29, 2017

@kbingman those will be statically generated indeed as well

@herrstucki

This comment has been minimized.

Show comment
Hide comment
@herrstucki

herrstucki Mar 29, 2017

Contributor

Is anyone actively working on this yet? If not, I might give it a shot since I'm very interested in this feature.

I did some spelunking in the next.js codebase and got an extremely rough proof-of-concept working by basically adding another step to the build using the server's renderToHTML function.

As far as I can tell it's pretty straight-forward. One of the bigger challenges will be to deal with dynamic routes like /posts/:id, especially if they're not referenced by links in the HTML (which would make them un-crawlable). So probably the user should be able to provide a static list of routes.

Contributor

herrstucki commented Mar 29, 2017

Is anyone actively working on this yet? If not, I might give it a shot since I'm very interested in this feature.

I did some spelunking in the next.js codebase and got an extremely rough proof-of-concept working by basically adding another step to the build using the server's renderToHTML function.

As far as I can tell it's pretty straight-forward. One of the bigger challenges will be to deal with dynamic routes like /posts/:id, especially if they're not referenced by links in the HTML (which would make them un-crawlable). So probably the user should be able to provide a static list of routes.

@schoenwaldnils

This comment has been minimized.

Show comment
Hide comment
@schoenwaldnils

schoenwaldnils Mar 29, 2017

@herrstucki

One of the bigger challenges will be to deal with dynamic routes like /posts/:id, especially if they're not referenced by links in the HTML

Thats what I'm looking for. I hope to find a way to generate pages from markdown-files, and list them in a dynamic-navigation.

@herrstucki

One of the bigger challenges will be to deal with dynamic routes like /posts/:id, especially if they're not referenced by links in the HTML

Thats what I'm looking for. I hope to find a way to generate pages from markdown-files, and list them in a dynamic-navigation.

@kylehotchkiss

This comment has been minimized.

Show comment
Hide comment
@kylehotchkiss

kylehotchkiss Mar 29, 2017

@schoenwaldnils

I agree with this. Would be awesome to have a react-powered Jekyll replacement. (I realize much of that blog functionality is out of scope). But this definitely would make next.js a solid platform for a larger audience who might want to throw things on gh-pages or S3.

@schoenwaldnils

I agree with this. Would be awesome to have a react-powered Jekyll replacement. (I realize much of that blog functionality is out of scope). But this definitely would make next.js a solid platform for a larger audience who might want to throw things on gh-pages or S3.

@schoenwaldnils

This comment has been minimized.

Show comment
Hide comment
@schoenwaldnils

schoenwaldnils Mar 29, 2017

@kylehotchkiss Absolutely! This is exactly what I currently have in mind.
The main problem in my case(s) is, that the site still should be maintainable by the marketing-team through cloudcannon, prose.io or something like that.
And I think markdown with configurable meta is still the best way to add easy content-editing.

@kylehotchkiss Absolutely! This is exactly what I currently have in mind.
The main problem in my case(s) is, that the site still should be maintainable by the marketing-team through cloudcannon, prose.io or something like that.
And I think markdown with configurable meta is still the best way to add easy content-editing.

@matthewmueller

This comment has been minimized.

Show comment
Hide comment
@matthewmueller

matthewmueller Mar 30, 2017

Contributor

@herrstucki I'm working on this a bit, happy to collaborate on a branch. definitely need this feature as well. I think this can be done entirely via the plugin system, then we can make it nicer / a bit more native later.

@schoenwaldnils you could achieve that sort of functionality by passing a { build: true } or any other indicator during the static build step to getInitialProps().

Regarding routing, at least for an initial implementation, I think only the development server needs to be route-aware, which you can achieved with a custom server. When you export to static, a service like Cloudfront or netlify can take the routing from there and you can use <Link href="/post" as="/post/4">...</Link> to do the dynamic stuff.

Contributor

matthewmueller commented Mar 30, 2017

@herrstucki I'm working on this a bit, happy to collaborate on a branch. definitely need this feature as well. I think this can be done entirely via the plugin system, then we can make it nicer / a bit more native later.

@schoenwaldnils you could achieve that sort of functionality by passing a { build: true } or any other indicator during the static build step to getInitialProps().

Regarding routing, at least for an initial implementation, I think only the development server needs to be route-aware, which you can achieved with a custom server. When you export to static, a service like Cloudfront or netlify can take the routing from there and you can use <Link href="/post" as="/post/4">...</Link> to do the dynamic stuff.

@matthewmueller

This comment has been minimized.

Show comment
Hide comment
@matthewmueller

matthewmueller Mar 31, 2017

Contributor

PR has landed: #1576 💥

Contributor

matthewmueller commented Mar 31, 2017

PR has landed: #1576 💥

@morinted morinted referenced this issue in morinted/syllable_playback May 4, 2017

Open

Deploy #1

@arunoda

This comment has been minimized.

Show comment
Hide comment
@arunoda

arunoda May 15, 2017

Collaborator

Now we've "next export" support built into the core.
See: https://zeit.co/blog/next3-preview
Thanks everyone for all the help.

Collaborator

arunoda commented May 15, 2017

Now we've "next export" support built into the core.
See: https://zeit.co/blog/next3-preview
Thanks everyone for all the help.

@arunoda arunoda closed this May 15, 2017

@dejanr

This comment has been minimized.

Show comment
Hide comment
@dejanr

dejanr May 15, 2017

Great to see this happend. Amazing work guys!

dejanr commented May 15, 2017

Great to see this happend. Amazing work guys!

@tom2strobl tom2strobl referenced this issue in madebywild/wild-next May 16, 2017

Closed

Integrate next export #3

@juliandavidmr

This comment has been minimized.

Show comment
Hide comment
@juliandavidmr

juliandavidmr Jul 22, 2017

Hi, next export generates a subfolder called _next, is there any way to automatically rename it?

@arunoda

Hi, next export generates a subfolder called _next, is there any way to automatically rename it?

@arunoda

@sbe88

This comment has been minimized.

Show comment
Hide comment
@sbe88

sbe88 Aug 16, 2017

How do you guys handle DOM events with next export? Thx!

[EDIT] on Mac I need to manually change all src="/_next/xxxx" paths to src="./_next/xxxx"

@arunoda

sbe88 commented Aug 16, 2017

How do you guys handle DOM events with next export? Thx!

[EDIT] on Mac I need to manually change all src="/_next/xxxx" paths to src="./_next/xxxx"

@arunoda

@adibas03

This comment has been minimized.

Show comment
Hide comment
@adibas03

adibas03 Jan 29, 2018

@juliandavidmr @sbe88
You need to set the assetPrefix variable in the next.config.js file.
you can also look through these for better explanation.
https://medium.com/@anotherplanet/git-tips-next-js-github-pages-2dbc9a819cb8
https://medium.com/@adibas03/next-js-github-pages-contd-42a1dd47f6bc

adibas03 commented Jan 29, 2018

@juliandavidmr @sbe88
You need to set the assetPrefix variable in the next.config.js file.
you can also look through these for better explanation.
https://medium.com/@anotherplanet/git-tips-next-js-github-pages-2dbc9a819cb8
https://medium.com/@adibas03/next-js-github-pages-contd-42a1dd47f6bc

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