Vue js预取组件

问题描述

我最近了解了延迟加载组件并开始使用它。现在,我正在尝试预取延迟加载的组件以及vue-router路由。但是,使用chrome devtools时,我发现只有当我们实际导航到延迟加载的路由(在vue-router路由的情况下)或v-if计算为true并且组件被渲染(如果是延迟加载的组件)。

我还尝试在路由器以及组件import语句中使用webpackPrefetch: true魔术字符串,但是这样做似乎没有什么区别。

项目结构:
主从布局

路由器配置:

import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);

var routes = [  
  {
    path: "/DetailPage",component: () => import(/* webpackChunkName: "Detail-chunk" */ "AppModules/views/MyModuleName/DetailPage.vue")
  },{
    path: "/MasterPage",component: () => import("AppModules/views/MyModuleName/MasterPage.vue")
  }
]

export const router = new Router({
  routes: routes,stringifyQuery(query) {
    // encrypt query string here
  }
});

export default router;

主视图:

<template> 
  <div @click="navigate">
    Some text
  </div>
</template>

<script>
export default {
  name: "MasterPage",methods: {
    navigate() {
      this.$router.push({
        path: "/DetailPage",query: {},});
    },},};
</script>

详细信息页面:

<template>
  <div>    
    <my-component v-if="showComponent" />
    <div @click="showComponent = true">Show Component</div>
  </div>
</template>

<script>
const MyComponent = () => import(/* webpackChunkName: "MyComponent-chunk" */ "AppCore/components/AppElements/Helpers/MyComponent");
export default {
  name: "DetailPage",components: {
    MyComponent,data() {
    return {
      showComponent: false
    }
  }
};
</script>

vue.js.config文件:

const path = require("path");

const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

module.exports = {
  publicPath: "some-url",outputDir: "./some/path",chainWebpack: webapckConfig => {
    webapckConfig.plugin("html").tap(() => {
      return [
        {
          inject: true,filename: "index.html",template: "./public/index.html"
        }
      ];
    });
  },productionSourceMap: true,configureWebpack: {
    plugins: [
      new BundleAnalyzerPlugin({
        analyzerMode: "server",generateStatsFile: false,statsOptions: {
          excludeModules: "node_modules"
        }
      })
    ],output: {
      filename: "some file name",libraryTarget: "window"
    },module: {
      rules: [
        {
          test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,use: [
            {
              loader: "url-loader",options: {
                limit: 50000,fallback: "file-loader",outputPath: "/assets/fonts",name: "[name].[ext]?hash=[hash]"
              }
            }
          ]
        }
      ]
    },resolve: {
      alias: {
        vue$: process.env.NODE_ENV == 'production' ? 'vue/dist/vue.min.js' : 'vue/dist/vue.js',AppCore: path.resolve(__dirname,"..","AppCoreLite"),AppModules: path.resolve(__dirname,"AppModulesLite")
      }
    }
  }
};

异步路由和组件均会分成单独的块,但这些块不会被预取。
导航到主视图时,在“网络”标签中看不到Detail-chunk.[hash].js。仅在执行母版页中的navigate方法时才会请求它(这是没有预取的正确的延迟加载行为)。
现在,当我进入详细信息页面时,仅在MyComponent-chunk.[hash].js变为showComponent(单击按钮时)时才请求true
我还在一些地方读到vue-cli v3确实默认启用了预取功能,并且不需要webpack魔术字符串。我还尝试通过删除webpackPrefetch注释来做到这一点,但这没什么区别。

我做了vue-cli-service inspect,发现webpack配置中确实存在预取插件:

 /* config.plugin('preload') */
    new PreloadPlugin(
      {
        rel: 'preload',include: 'initial',fileBlacklist: [
          /\.map$/,/hot-update\.js$/
        ]
      }
    ),/* config.plugin('prefetch') */
    new PreloadPlugin(
      {
        rel: 'prefetch',include: 'asyncChunks'
      }
    ),

更新:我尝试使用config.plugins.delete('prefetch');删除预取webpack插件,然后使用webpack魔术注释:/* webpackPrefetch: true */,但这没什么区别。

如何实现预取功能?

解决方法

延迟加载的组件仅在用户单击路由时才加载。如果您想在组件之前加载它,那就不要使用延迟加载。

vue-router会将组件加载到内存,并动态交换标签的内容,即使您将使用正常加载的组件也是如此。

,

您需要根据需要实施vue-router-prefetch软件包。这是工作中的demo

注意:在工作的演示中,您可以从x = minX; y = minY; w = maxX-minX; h = maxY-minY; letterBounds.add(new Rectangle(x,y,w,h)); 中注意到,从console.log导入的page 2组件仅预提取了QuickLink

代码:

vue-router-prefetch
,

我通过创建一个在自定义时间后加载的简单预取组件解决了这个问题。

Prefetch.vue

<script>
import LazyComp1 from "./LazyComp1.vue";
import LazyComp2 from "./LazyComp2.vue";
export default {
    components:{
        LazyComp1,LazyComp2,}
}
</script>

App.vue

<template>
    <Prefech v-if="loadPrefetch"></Prefech>
</template>
<script>
export default {
    components: {
        Prefech: () => import("./Prefetch");
    },data() {
        return {
            loadPrefetch: false
        }
    },mounted() {
        setTimeout(() => {
            this.loadPrefetch = true;
        },1000);
    }
}
</script>
,

我正在开发移动应用。并希望在显示启动画面时动态加载一些组件

@Thomas 的回答是一个很好的解决方案(一个 Prefetch 组件),但是它不会在 shadow dom 中加载该组件,并且不会通过 Vetur 验证(每个组件都必须有自己的模板)

这是我的代码:

ma​​in.vue

<template>
    <loader />
</template>
<script>
    import Loader from './Loader'
    const Prefetch = () => import('./Prefetch')
    export default {
        name: 'Main',components: {
            Loader,Prefetch
        }
    }
</script>

Prevetch.vue

<template>
    <div id="prefetch">
        <lazy-comp-a />
        <lazy-comp-b />
    </div>
</template>
<script>
import Vue from 'vue'

import LazyCompA from './LazyCompA'
import LazyCompB from './LazyCompB'

Vue.use(LazyCompA)
Vue.use(LazyCompB)
export default {
    components: {
        LazyCompA,LazyCompB
    }
}
</script>

<style lang="scss" scoped>
#prefetch {
    display: none !important;
}
</style>

加载器组件被加载和渲染,然后预取组件可以动态加载任何东西。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...