Changing prefetch and preload options (resourceHints)

tmorehouse
223
tmorehouse
commented 2 years ago

Currently under the render section of nuxt.config.js there is an option resourceHints (boolean), which enabled (default) or disabled (by setting to false) which, based on the documentation:

Adds prefetch and preload links for faster initial page load time.

I have a rather large list of routes, and some routes that are only used by users that have certain roles/privileges.

It would be nice if:

  • prefetch could be disabled, while still having preload (for things like the common chunks) enabled.
  • Set a flag in the pages (similar to how scrollToTop is flagged), to enable/disble preload or, prefetch. for that particular page component
  • Specify chunknames (or grouping) for a set of routes (i.e. via the page component definition) to group several small pages into the same webpackChunkName file

99% of the my users cannot access administrative pages, so it is kind of a waste of b/w to pre-fetch those pages which will never be loaded by those users, without having to disable site-wide pre-fetching (which affects 100% of the users)

An other option would be able to group pre-fetches by a user speified parameter… say if someone accesses /admin (and isn't re-directed/blocked by middleware), then all the child routes of `/admin would be listed/added in the head as prefetch links.

idea
6

Implemented in v1.4.0

a year ago by Atinux

0
Atinux
26.4k
Atinux
commented 2 years ago

Hi @tmorehouse

This is actually a nice idea but not so easy to implement, I am talking with Vue.js core-team to see how they could implement something like this into the core of vue-server-renderer since it's this module that handle the resourceHints.

1
tmorehouse
223
tmorehouse
commented 2 years ago

I see that vue-server-renderer has the following options:

And both hooks are passed a filename and type. Is there a way to configure these in nuxt?

I could use these to test the filename (which is based on the page path) to signal a true/false to have certain paths not included in the prefetch list?

0
Atinux
26.4k
Atinux
commented 2 years ago

@tmorehouse

Actually you can customize it into your nuxt.config.js, see my answer on this issue: https://github.com/nuxt/nuxt.js/issues/1508#issuecomment-325655533

0
tmorehouse
223
tmorehouse
commented 2 years ago

@Atinux I just tried that for shouldPrefetch:

  render: {
    bundleRenderer: {
      shouldPrefetch: (file, type) => {
         if (type === 'script') {
            if (/admin/.test(file)) {
               return false
            }
         }
         return true
      }
    }
  }

But everything (all pages) are being added as prefetch links (including all admin files I would like excluded). I even added in a console.log in the callback and it isn't even being called either.

I'm using vue-server-renderer v2.5.2,

0
Atinux
26.4k
Atinux
commented 2 years ago

Hi @tmorehouse

It's really weird, I let this issue open, we will see with next release since I'm changing a few things right now.

0
tmorehouse
223
tmorehouse
commented 2 years ago

Hi @Atinux

Just wondering if you have discovered anything about this?

0
Atinux
26.4k
Atinux
commented 2 years ago

Hey @tmorehouse

I am focusing on releasing 1.0 right now, I added the 2.0 label here (but it could be implemented right after 1.0 with 1.1 for example).

I like your idea and might need more digging, that's why I keep it open :)

1
buhrmi
58
buhrmi
commented 2 years ago

Hello, guys. I have the same problem. I want to include some pages in the resourceHint list but others I don't want to include. I think it would be a good solution to have the setting in the page component directly, eg:

<script>
export default {
  data: {..},
  preload: false
}
</script>

Let me know what you think.

1
tmorehouse
223
tmorehouse
commented 2 years ago

It would also be nice to be able to see this based on some runtime condition as well, such as user roles, etc.

2
buhrmi
58
buhrmi
commented 2 years ago

@tmorehouse i think the browser resource hints are generated at compile time, so that would be impossible.

0
tmorehouse
223
tmorehouse
commented 2 years ago

Compile time, but stored in the manifest.

0
randyhoulahan
25
randyhoulahan
commented 2 years ago

In my opinion this really should not be an enhancement yet a critical bug. Nuxtjs indicates it is great for starting small or large apps.
"intended to provide a great starting point for both small and large applications"

Without this feature, it is only for small apps in my opinion. www.cbd.int Thousands of pages, in 6 languages, dozens of forms. It is not appropriate for the user to download the entire site and all translations for one page.

I may have to abandon nuxtjs if I cannot implement this my self asap.

@Atinux can you give some direction how to implement this?

0
randyhoulahan
25
randyhoulahan
commented 2 years ago

I missed https://nuxtjs.org/api/configuration-render#resourcehints can disable for large applications.

0
manniL
5.8k
manniL
commented a year ago

Update on that issue. I've tried using shouldPrefetch and it worked quite well as described above:

  render: {
    bundleRenderer: {
      shouldPrefetch: (file, type) => {
         if (type === 'script') {
            if (/yourPageNameHere/.test(file)) {
               return false
            }
         }
         return true
      }
    }
  }

will stop yourPageNameHere.[hash].js from being prefetched.

3
aadii104
0
aadii104
commented a year ago

hey @manniL,
could you please tell about how and which file I should add here in this code,

 if (/yourPageNameHere/.test(file)) {
               return false
            }

and do u have any repo for this working?
thanks.

0
manniL
5.8k
manniL
commented a year ago

Hey @aadii104 ☺️

You need to include the whole code snippet from my comment above in your nuxt.config.js.

I'm using custom prefetch/preload for my own website. You can find the related code here.

Be aware that this solution does not work with nuxt-edge by default.

1
sschadwick
5
sschadwick
commented a year ago

@manniL Why does it not work with nuxt-edge? Trying to solve this same issue on [email protected]

0
manniL
5.8k
manniL
commented a year ago

@sschadwick The functions behavior actually hasn't changed in nuxt-edge. Be aware that shouldPrefetch defaults to () => false while shouldPreload defaults to () => true.

But as files aren't named by default, you'll have to enable it (in case you want to distinguish by name and not by type). You can reenable names with:

nuxt.config.js

export default {
  build: {
    optimization: {
      splitChunks: {
        name: true
      }
    }
  }
}
0
sschadwick
5
sschadwick
commented a year ago

Hmm seems like changing shouldPrefetch isn't actually changing the observed behavior.

My use case is using nuxt-edge to create admin routes that are not included in the bundle served to "traditional" users. I've been able to isolate the .vue component files themselves, however the admin bundle is always loaded upon initial page load (even before authentication). I've tried using lazy component loading (import(./file.vue) instead of direct imports in router.js) but that just created multiple small bundles that are all loaded on page init.

Any suggestions/ideas to defer bundle load until it's actually requested?

0
manniL
5.8k
manniL
commented a year ago

@sschadwick I use the same approach for my blog. Here is a part of my nuxt.config.js

export default {
  /*
  * Render (preload & prefetch)
  */
  render: {
    bundleRenderer: {
      shouldPrefetch: (file, type) => ['script', 'style', 'font'].includes(type) && !file.includes('admin')
    }
  },

  /*
   * Build configuration
   */
  build: {
    optimization: {
      splitChunks: {
        name: true
      }
    }

But you are right, that's not enough. You have to set the file names appropriately:

build: {
    filenames: {
      app: ({ isDev }) => isDev ? '[name].js' : '[name].[chunkhash].js',
      chunk: ({ isDev }) => isDev ? '[name].js' : '[name].[chunkhash].js',
      css: ({ isDev }) => isDev ? '[name].js' : '[name].[contenthash].css'
    }
}

Update 2: This isn't it still… I'll investigate further how to do this fine-grained.

0
sschadwick
5
sschadwick
commented a year ago

@manniL I took a brief look at your blog code, and saw it was working as intended. However, when I update nuxt-edge to latest, the naming structure of the bundles changes possibly to the point where !file.includes('admin') no longer matches the protected routes. I'm curious if updating your deps would break the functionality.

When I use import('./component.vue') to lazy load components, they are each distributed as separate files. The only way that I am able to bundle all of the protected routes together is to use a different splitChunks object and not lazy import. However, this ceases to respect the shouldPrefetch function. I can confirm this by setting shouldPrefetch to always return false, yet the admin bundle will still be served on initial page load. Ideally it would not be served until an admin user clicks an admin route. Any ideas?

module.exports = {
  build: {
    optimization: {
      splitChunks: {
        cacheGroups: {
          admin: {
            chunks:   'all',
            priority: 1,
            test:     <REGEX TO MATCH .VUE FILES IN PROTECTED DIR>
          }
        }
      }
    }
  },
}
0
sschadwick
5
sschadwick
commented a year ago

I was finally able to configure my build exactly how I wanted. Here's some lessons I learned:

  • Lazy load with () => import('./Component') instead of import('./Component').
  • There were also a couple of babel issues, so I had to ultimately use () => import('./Component').then(m => m.default || m));
  • There were two types of JS files in my protected routes: a text abstraction and a routes abstraction, so I had to update my webpack regex to include everything but the routes abstraction.
  • I was unable to get shouldPreload or shouldPrefetch to work as expected, so I ultimately set resourceHints: false.

To protect the specified-routes bundle:

  • Enable build filenames, as demonstrated above.
  • Check the url for the name of the protected bundle before Nuxt is passed to Express. Deny bundle if unauthenticated/unauthorized.
  • The internal Nuxt serverMiddleware does not receive requests for any files, only in-app paths.
0
gera2ld
0
gera2ld
commented a year ago

Can we enable prefetch only for URLs being linked in the current page? In such way we can enable prefetch for large applications without downloading the whole site.

0
manniL
5.8k
manniL
commented a year ago

@gera2ld Please create a new feature request for this.

0
Informations
Feature RequestImplemented
#c1652 - Created 2 years ago