Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to disable/customize the prefetch plugin #979

Closed
wangxiangyao opened this issue Mar 13, 2018 · 24 comments
Closed

Document how to disable/customize the prefetch plugin #979

wangxiangyao opened this issue Mar 13, 2018 · 24 comments

Comments

@wangxiangyao
Copy link

What problem does this feature solve?

When I use the asyn load of vue-router, the webpack-plugin prefetch makes all asyn modules preload. This results in the inability to load on demand

What does the proposed API look like?

vue.conf.js

{
  prefetch: {}
}
@wangxiangyao
Copy link
Author

我需要使用webpack-chain,来重新配置Prefetch,对么?

@LinusBorg
Copy link
Member

LinusBorg commented Mar 13, 2018

I'm not sure what you are talking about, are you referring to the prefetching that's done when you selected the PWA option for your project?

https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa

As explained in the plugin's README, you can define what's prefetched by setting the right workbox options in your config.

@LinusBorg LinusBorg added the needs reproduction This issue is missing a minimal runnable reproduction, provided by the author label Mar 14, 2018
@gunhaxxor
Copy link

gunhaxxor commented Mar 14, 2018

I think @wangxiangyao is referring to that the vue-cli sets up a webpack configuration where the webpack preloadplugin is used to inject a prefetch html tag in the index.html for all asyncronous chunks.
Using const Foo = () => import('./Foo.vue') as described in the vue-router documentation will for example generate such prefetch tag for that component. Like so: <link rel="prefetch" href="/0.js">

Extract of webpack config, from running vue inspect:

/* PreloadPlugin */ {
      options: {
        rel: 'prefetch',
        include: 'asyncChunks',
        fileBlacklist: [
          /\.map$/
        ]
      }
    },

I guess @wangxiangyao is requesting a convenient way to alter this configuration. Perhaps the use case is that there are chunks that the developer for sure knows should only be loaded in rare cases.
I'm also interested in what way it's possible to customize the generation of prefetch tags in a vue-cli project.

@LinusBorg
Copy link
Member

LinusBorg commented Mar 14, 2018

Thanks @Dealerpriest, that was very helpful.

This can be custimzed with webpack-chain today like this:

// vue.config.js
chainWebpack: (config) => {

  // A, remove the plugin
  config.plugins.delete('prefetch')
  
  // or:
  // B. Alter settings:
  config.plugin('prefetch').tap(options => {
    if (!options[0].fileBlacklist) options[0].fileBlacklist = []
    options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
    return options
  })
}

Relevant source: https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-service/lib/config/app.js#L20-L25

We can discuss wether or not it makes sense to expose this as a config value in vue.config.js

@LinusBorg LinusBorg added discussion feature request and removed needs reproduction This issue is missing a minimal runnable reproduction, provided by the author labels Mar 14, 2018
@LinusBorg LinusBorg changed the title disable the prefetch Allow to customize / disable the prefetch plugin easily Mar 14, 2018
@gunhaxxor
Copy link

Thanks for the swift reply! I will look into the suggestions in your answer.

Regarding the discussion of exposing it in vue.config.js:
I would argue that it would be very valuable to be able to configure this in a convenient way. A good example is a SPA where there is a special route to an admin interface. This route would only be used by a very small fraction of connecting clients (the admins). The current setup would still have the browser of all 'user' clients fetch the admin chunks, using bandwidth for no reason at all. Some way to manage this would allow for a more streamlined request behaviour from the client browsers.

@LinusBorg
Copy link
Member

LinusBorg commented Mar 14, 2018

Good use case example.

However, Similar arguments can be brought up for many other plugins, and if the manipulation of said plugins is as easy as I showed above, it might be better to create some sort of recipe list which examplifies how to use chainWebpackConfig to manipulate common plugins like:

  • html-webpack-plugin
  • optimize-css
  • uglify-es
  • prefetch

etc. pp.

That would keep the config file lean and keep the api flexible.

@wangxiangyao
Copy link
Author

wangxiangyao commented Mar 15, 2018

Like @Dealerpriest said, Please forgive me for not being clear.After the question, I suddenly thought of the chain of webpack, so I went to learn how to write chain config, and then solved this problem.

webpack-chain

However, as far as the issue itself is concerned, I still hope to have a simpler, more visible way to tell developers that the prefetchPlug is used. SPA based on the need to load on route is a common optimization method.While the new vue-cli defaults to all asyn file prefetch, it may not be easy for developers to take note of this when using the new vue-cli package.For example, I directly package and upload to the formal environment, which causes the project to load slowly.

@gunhaxxor
Copy link

Hello again. I've now had time to try out the method you suggested @LinusBorg.
Using webpack-chain works pretty well.
I just want to make you aware that the example you provided use the object key chainWebpackConfig when it should actually be chainWebpack. I thought I should mentione it if someone else comes along here and wants to try it out.
My current whole vue.config.js currently looks like this:

// vue.config.js

module.exports = {
  chainWebpack: config => {
    // A, remove the plugin
    config.plugins.delete('prefetch');

    // or:
    // B. Alter settings:
    // config.plugin('prefetch').tap(options => {
    //   options.fileBlackList.push([/myasyncRoute(.)+?\.js$/]);
    //   return options;
    // });
  }
};

@LinusBorg
Copy link
Member

I just want to make you aware that the example you provided use the object key chainWebpackConfig when it should actually be chainWebpack.

Good catch, will edit my post.

My current whole vue.config.js currently looks like this:

You do realize that my code samle contains two separate options to choose, and you use them both? You can't remove the plugin and then alter its options, that doesn't make sense.

@wangxiangyao
Copy link
Author

this is my vue.config.js

// vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.plugins.delete('prefetch')
  },
  configureWebpack: () => {
    return {
      resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
      },
      plugins: [
        // new BundleAnalyzerPlugin(),
        new CompressionPlugin()
      ]
    }
  }
}

if just use webpack-chain:

// vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.plugins.delete('prefetch')
    config.resolve.alias
      .set('vue$', 'vue/dist/vue.esm.js')
    config
      .plugin('CompressionPlugin')  // the plugin name depending on your
      .use(CompressionPlugin) // if need args --> .use(webpack.somePlugin, args)
  }
}

still work well, 完美 😄O(∩_∩)O

@gunhaxxor
Copy link

@LinusBorg
Yes, I'm aware of that.
I've commented out the second option, because I thought I might use that one later. But I realized now that it's not as clear with github's syntax highlighting.

@gunhaxxor
Copy link

Btw. I'm curious if there might be a way to exclude certain vue routes from the prefetch. The only related option for the preloaderPlugin I can find is the fileBlacklist. But the asynchronously loaded chunk gets a random name from webpack if I understand this correctly. How can I retrieve the chunk corresponding to a certain dynamic import and add that one to the prefetch blacklist?

@LinusBorg
Copy link
Member

LinusBorg commented Mar 15, 2018

But the asynchronously loaded chunk gets a random name from webpack if I understand this correctly.

you can do this:

const component = () => import(/* webpackChunkName: "MyComponent.route" */ './MyComponent.vue')

Which would then create a file named MyComponent.route.238092490r2bqwkn.js , and you can use a Regexp to blacklist all *.route.*.js files

See https://webpack.js.org/api/module-methods/#import-

@gunhaxxor
Copy link

Wow!
That was incredibly helpful! Thx!

@laurentpayot
Copy link

@LinusBorg Correct me if I'm wrong but, in case of a PWA, isn't prefetch a job for Workbox only? https://developers.google.com/web/tools/workbox/modules/workbox-precaching

When workbox is used, shouldn't the prefetch plugin of webpack always be disabled?

@LinusBorg
Copy link
Member

When workbox is used, shouldn't the prefetch plugin of webpack always be disabled?

If you only care about browsers that supports service workers, then: yes.
If you do care about those other browsers as well, then: no.

Technically, the two work fine alongside each other.

@laurentpayot
Copy link

It makes sense. Hopefully service workers will be widespread soon…https://caniuse.com/#feat=serviceworkers

@yyx990803 yyx990803 changed the title Allow to customize / disable the prefetch plugin easily Document how to disable/customize the prefetch plugin Apr 27, 2018
@yyx990803
Copy link
Member

Closing as this is addressed in the new docs.

@KleinMaximus
Copy link

#2616
Not works for me :(

module.exports = {
  chainWebpack: (config) => {
    config.plugins.delete('prefetch');
  }
};

@tsurumure
Copy link

tsurumure commented Mar 29, 2019

@KleinMaximus Try this:

chainWebpack: (config) => {
  console.log(config.plugins)
  // check if the name is correct
  // then i use this name:
  config.plugins.delete('prefetch-index')
}

@bagaskarala
Copy link

thankss, worked to dismiss prefetch in index.html

@bobvandevijver
Copy link

In order to make this work, I had to use the following:

module.exports = {
    chainWebpack: config => {
        if (config.plugins.has('prefetch')) {
            config.plugin('prefetch').tap(options => {
                options[0].fileBlacklist = options.fileBlacklist || [];
                options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/);
                return options;
            });
        }
    }
};

@milky2028
Copy link

I'm using the following, but it doesn't seem to be working.

module.exports = {
  chainWebpack: (config) => {
    config.module.rule('js').exclude.add(/\.worker\.js$/);
    config.output.globalObject('self');
    if (config.plugins.has('preload')) {
      config.plugin('preload').tap((options) => {
        options[0] = {
          rel: 'preload',
          include: 'asyncChunks',
          excludeHtmlNames: [],
          fileBlacklist: [/\.map/]
        };
        return options;
      });
    }
  },
  productionSourceMap: false
};

I got these default settings from the @vue/preload-webpack-plugin source code in node_modules. I'm just trying to replicate the official settings to get started. This issue is that this loads all the modules twice in index.html when built.

Similar note, I can use config.plugins.delete('preload') to remove all preloading, but resource hints like /* webpackPreload: true */ don't seem to work. Any help would be much appreciated.

@superpig
Copy link

superpig commented Jun 2, 2020

if there are multple entry, we should config like this:

config.plugins.delete('preload-${entryName}')

for example:

config.plugins.delete('preload-index')
config.plugins.delete('preload-login')
...

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

No branches or pull requests