algolia / vue-instantsearch

👀 Algolia components for building search UIs with Vue.js
https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/vue
MIT License
854 stars 157 forks source link

Bundle Size / Nuxt: Why is vue-server-renderer included in Nuxt Frontend Build #886

Closed ayalon closed 1 year ago

ayalon commented 3 years ago

Bug 🐞

What is the current behavior?

Go to the folder examples/nuxt. Add the following script to package.json "analyze": "nuxt build --analyze"

This is the output: image


The vue-server-renderer with the size of 334KB is added to the frontend bundle!

What is the expected behavior?

vue-server-renderer/basic.js should not be part of the Frontend Build in nuxt.js. It is part of nuxt.js anyway and not used in the frontend.

Does this happen only in specific situations?

No it happens always. Even on the commited example.

What is the proposed solution?

I have no idea.

What is the version you are using?

4.8.0

antongorodezkiy commented 3 years ago

I also noticed the same issue though I'm using vue-instantsearch on the client-side only. Version vue-instantsearch@3.4.3 Caused by including it in vue-instantsearch/es/src/util/createServerRootMixin.js that's in turn included in vue-instantsearch/es/src/instantsearch.js

So I tried to import modules directly and it seems it worked this way and vue-server-renderer not included to the bundle anymore:

// old import
// import { AisInstantSearch, AisAutocomplete } from 'vue-instantsearch'
import AisInstantSearch from 'vue-instantsearch/es/src/components/InstantSearch.js'
import AisAutocomplete from 'vue-instantsearch/es/src/components/Autocomplete.vue.js'

( I'm not using Nuxt, but https://github.com/Akryum/vue-cli-plugin-ssr )

ayalon commented 3 years ago

Unfortunatly this does not work for me. On Nuxt I have to include AisInstantSearchSsr instead of AisInstantSearch . I tried to import it as you said but the bundle size is the same: import AisInstantSearchSsr from 'vue-instantsearch/es/src/components/InstantSearchSsr.js' As soon as I have this dependancy the build in frontend adds the view renderer. Any other ideas? These unneeded 334kb hurt so much in the frontend.

image

antongorodezkiy commented 3 years ago

@ayalon No ideas, unfortunately. SSR component seems to cause memory leak in our project (similar to the one in #834 ), so I didn't work with it.

reinoldus commented 3 years ago

Same issue here. Also the example from this repo pulls in the same dependency

image

Haroenv commented 3 years ago

Hmm, I could swear this wasn't the case when I wrote the code originally. I wonder if webpack, vue server side rendering or nuxt have changed something in module resolution.

I'm having a hard time finding the cause of this, maybe a separate method for the server-part should be used so it doesn't end up in the client build?

reinoldus commented 3 years ago

I've looked through the code a bit and do not see any reason why webpack wouldn't bundle vue-server-render. I guess this is the critical statement here:

try {
  _renderToString = require('vue-server-renderer/basic');
} catch (e) {
  // error is handled by regular if, in case it's `undefined`
}

I do not know how to fix it at the core, but I worked around it with some additional config:

In your nuxt config under build (https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-build#extend):

extend(config, { isClient }) {
  // Extend only webpack config for client-bundle
  if (isClient) {
    config.plugins.push(
      new webpack.IgnorePlugin({
        checkResource(resource, context) {
          if (resource.includes('vue-server-renderer')) {
            return true
          }
          // do something with resource
          return false
        },
      })
    )
  }
},

The dependency is gone from the front-end and SSR still works.

Edit: I forgot to mention you also have to import webpack in your nuxt.config.js:

import webpack from 'webpack'

Haroenv commented 3 years ago

Thanks @reinoldus, this is a great workaround for the time being, and I'll see how we can update the documentation to show this.

It's unfortunate that this solution uses webpack to decide the dependency isn't meant for frontend, but I really can't find any way to indicate an import is server-only in vue

Haroenv commented 1 year ago

As there's no way in vue/nuxt to declare a certain package to only be relevant for the backend, it's very easy for a dependency to sneak in the frontend bundle. I recommend using the workaround provided aliasing the package to empty for the frontend.