标签: 动态加载

  • Vite 里使用动态加载

    Vite 里使用动态加载

    有时候,我们希望根据用户当前的使用状态决定加载哪些模块。比如一个网页 IDE,用户在写 JS,我们就加载 JS 模块;用户在写 PHP 我们就加载 PHP 模块。这个功能有点类似路由懒加载,但又不完全相同。

    以前在 wepback 里,我们可以通过动态 import 加注释的方式来做:

    const _ = await import(/* webpackChunkName: "lodash" */ 'lodash');
    
    // 通过组合不同注释,还可以实现不同的分包和加载策略
    // Single target
    import(
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackExports: ["default", "named"] */
      'module'
    );
    
    // Multiple possible targets
    import(
      /* webpackInclude: /\.json$/ */
      /* webpackExclude: /\.noimport\.json$/ */
      /* webpackChunkName: "my-chunk-name" */
      /* webpackMode: "lazy" */
      /* webpackPrefetch: true */
      /* webpackPreload: true */
      `./locale/${language}`
    );

    上面的内容可以在 Webpack 官方文档 找到。

    Vite 里提供了类似的功能,不过使用方式不太一样。现在的 Vite 2 已经抛弃了以前的插件式实现,即 vite-plugin-dynamic-import 和 @rollup/plugin-dynamic-import-vars 都不会用到。

    首先,我们要使用 import.meta.glob('./*.js`) 声明哪些文件可能要用到;接下来,我们就可以根据实际需求加载具体文件。大概方式如下:

    <script lang="ts" setup>
    // <script setup> 的代码,相当于 `created`,所以可以使用动态加载
    
    // 未来要使用的变量
    let shareTexts:ShareTexts;
    
    // 声明符合 `/src/data/share*.ts` 的文件都可能要用到
    const modules = import.meta.glob('../data/share*.ts');
    
    // 如果 store 里有 `langName`,就加载 i18n 版,否则加载普通版
    modules[`../data/${store.state.langName ? 'share-i18n' : 'share'}.ts`]()
      .then(data => {
        // 因为用到 esm,所以要加 `default`
        shareTexts = data.default;
      });
    </script>

    接下来,还可以配合 vite.config.js,将相关装入特定分包:

    export default defineConfig(({command, mode}) => {
      return {
        plugins: [
          vue(),
        ],
        build: {
          rollupOptions: {
            output: {
              manualChunks(id) {
                let result;
                if (result = /(shares\/)?share\d\.txt\?raw$/.exec(id)) {
                  return result[1] ? 'share-i18n' : 'share';
                } else if (id.includes('node_modules')) {
                  return 'vendor';
                }
              },
            },
          },
        },
      };
    });