Next.js: use content hash in pages chunk name

Created on 15 Feb 2019  ·  24Comments  ·  Source: vercel/next.js

Feature request

Is your feature request related to a problem? Please describe.

GitHub Logo
for entries under pages folder , nextJs will not add content_hash to entries' name. Instead the path will be__next/$nextVersion/page/$pageName.js.
As a result , each time when we make a new release , nextJs will generate a new version, and all the path of pages js will be changed and in turn the web cache is gone. For example, if we have 10 page , and we only modify one page in next release , but all the 10 page js need to be downloaded again.

Describe the solution you'd like

use content hash in page name
__next/$nextVersion/page/$pageName.js. => __next/page/$pageName_$contentHash.js

story 21

Most helpful comment

It's slightly more complicated than saying "I want to add hashes", the problem space is bigger than that. For example how are you going to route? The client side is not aware of the hashes for the script tag, and it shouldn't have a list of all possible routes + hashes (that wouldn't scale).

I've just created a flow chart that (from the top of my mind) explains how the router currently works:

screenshot 2019-02-15 at 13 23 33

This issue actually comes really close to the dynamic routing one, because there needs to be a way to specify patterns to a certain page.

Adding hashes would be super simple if for example we were to do something like:

import Link, {page} from 'next/link'

export default function MyPage() {
   return <>
     <Link href={page`./blog/post.js`} as="/blog/hello-world">
       <a>To Hello World Blog Post</a>
     </Link>
   </>
}

Because in that case we can compile the href into the hashed page route.

Another one that came up when thinking about this is:

import Link, {page} from 'next/link'

export default function MyPage() {
   return <>
     <Link href={() => import('./blog/post.js')} as="/blog/hello-world">
       <a>To Hello World Blog Post</a>
     </Link>
   </>
}

Note that this is just me brainstorming on solutions, this is not something we're currently implementing (still thinking more about it).

All 24 comments

Aha~! I am planning to submit an issue like this. This is also a problem that has been bothering me for a long time.

As @wbr911 said, this wastes a lot of resources and greatly reduces development and user experience.

@timneutkens
I remember u said 「Adding hashes to page files is going to be up to us the future.」last year.#4255
Can you provide the next solution, it is very important.
Look forward to your favourable reply~~~~

It's slightly more complicated than saying "I want to add hashes", the problem space is bigger than that. For example how are you going to route? The client side is not aware of the hashes for the script tag, and it shouldn't have a list of all possible routes + hashes (that wouldn't scale).

I've just created a flow chart that (from the top of my mind) explains how the router currently works:

screenshot 2019-02-15 at 13 23 33

This issue actually comes really close to the dynamic routing one, because there needs to be a way to specify patterns to a certain page.

Adding hashes would be super simple if for example we were to do something like:

import Link, {page} from 'next/link'

export default function MyPage() {
   return <>
     <Link href={page`./blog/post.js`} as="/blog/hello-world">
       <a>To Hello World Blog Post</a>
     </Link>
   </>
}

Because in that case we can compile the href into the hashed page route.

Another one that came up when thinking about this is:

import Link, {page} from 'next/link'

export default function MyPage() {
   return <>
     <Link href={() => import('./blog/post.js')} as="/blog/hello-world">
       <a>To Hello World Blog Post</a>
     </Link>
   </>
}

Note that this is just me brainstorming on solutions, this is not something we're currently implementing (still thinking more about it).

Thank @timneutkens for your detailed answers, and I agree that this feature is difficult to achieve.

Maybe we have to alleviate this problem by dividing complex projects into multiple next.js apps.

@timneutkens First of All , Thanks a lot for your patient explanation
I could understand your concerns about routes, while my architecture is MPA (multiple-pages) instead of SPA which means we don't have the routes problems.
Could NextJs provides an alternative to add hashes to page js for MPA cases?

@wbr911 could expand on this more, do you mean you're not using next/link and doing full page transitions?

@wbr911 could expand on this more, do you mean you're not using next/link and doing full page transitions?

yes @timneutkens

There is no way for us to distinguish between that, so the solution has to be generic and work for all cases.

could you let developer do it, for example to add a configuration in next.config.js to declare whether use contentHash and remove versionId in the path of page.js @timneutkens

It's not a simple as changing a configuration. We can't maintain 2 versions of page loading and building just for this one use case.

just to share my solution to people sharing same situation with us:

  1. use hash in filename !isDev && (config.output.filename = '[name]_[chunkhash:8].js');
  2. use assets-webpack-plugin to record the relationship between entry and hashed js name;
  3. create custom _document.js and build your own NextScript by extending nextJs's one to replace js src with the json file created at step2

So I got the custom NextScript part working.

But this is very much tied with implementation details of next.js and is very fragile and can break with next.js versions. I think if next.js would be open to a few changes, then just a plugin to modify the asset filename can become very easy:

  1. Save the asset path which is currently being ignored.
    https://github.com/zeit/next.js/blob/a6ddaefe226b7ecf8d984244f82114df7e12c909/packages/next/build/webpack/plugins/build-manifest-plugin.js#L65-L67
  2. Use the path in NextScript and Head components
    https://github.com/zeit/next.js/blob/eb28d4cdcff48fb9d2d1f3f7e8ab93e5f9d334ce/packages/next/pages/_document.js#L445-L462

@timneutkens if you would be ok with this I can create a PR.

Then next-plugin creators like me can easily modify the asset pathname from webpack.
Then there is the part of Link component. Which we can create a wrapper around the original next/link and pick the href and map it to the correct asset path and set the correct url using asPath (unless specified). This would be very easy.

and map it to the correct asset path and set the correct url using asPath (unless specified). This would be very easy.

Actually it's not easy, because it implies you know all routes + it doesn't account for dynamic href or as. Either way we're working on something to address this and it will be very different from above solution, so I would not pursue a PR for it at this point in time 🙏

Can you share your solution that you are working on or if there is a PR or a task list, maybe we can contribute?

I'm still discussing it internally before writing up something.

Posted #7329

Correct me if I'm wrong. What's the issue of storing the page->hash map on the client side and do a lookup during page transition when via Link? I'm sure I missed something.

A middle ground IMO is to generate a BUILD ID that's a total hash of all frontend source code. This helps in my case, to not invalidate frontend cache when there's only backend changes. Do you guys think it's reasonable to do this?

@zenozen yup it's possible. I've documented the process https://medium.com/@azizhk/next-js-netlify-file-naming-and-caching-strategies-8665b213963f
Though not recommended by Next.js developers and can break in future versions of Next.js.

@azizhk Yeah, I've seen your blog post. It's really helpful!

The process sounds just right, with the asset hash mapping dictionary. But as you said, the hack is a bit too involved and likely to break when an official solution comes up. That's why I'm considering the single total hash solution and hopefully we don't have to wait long for an official solution :)

I would highly recommend not using the outlined solution, it will break for every single release we'll do, especially the ones that will be out soon.

@timneutkens Is there any update on this issue? A small change cause all js need to be downloaded again on user side seems not elegant, especially for big sites. I'm eager for the solution.

@timneutkens also asking for an update on this. Since we often have multiple deploys of the same nextjs applications per week or even per day, we are constantly invalidating caches, even from pages, that didn't change. A more user focused solution on this problem would be great.

We're making some changes soon, but will take a while as it's non-trivial to make it work. Feel free to reach out to [email protected] if you want us working on it in a shorter timeframe.

FYI - this feature was a part of v9.5 release.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robinvdvleuten picture robinvdvleuten  ·  74Comments

matthewmueller picture matthewmueller  ·  102Comments

nvartolomei picture nvartolomei  ·  78Comments

timneutkens picture timneutkens  ·  72Comments

poyiding picture poyiding  ·  73Comments