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
vue.conf.js
{
prefetch: {}
}
我需要使用webpack-chain,来重新配置Prefetch,对么?
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.
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.
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
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.
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:
etc. pp.
That would keep the config file lean and keep the api flexible.
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.
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.
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;
// });
}
};
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.
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
@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.
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?
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
Wow!
That was incredibly helpful! Thx!
@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?
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.
It makes sense. Hopefully service workers will be widespread soon…https://caniuse.com/#feat=serviceworkers
Closing as this is addressed in the new docs.
Not works for me :(
module.exports = {
chainWebpack: (config) => {
config.plugins.delete('prefetch');
}
};
@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')
}
thankss, worked to dismiss prefetch in index.html
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;
});
}
}
};
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.
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')
...
Most helpful comment
Thanks @Dealerpriest, that was very helpful.
This can be custimzed with webpack-chain today like this:
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