避免在 webpack 中使用动态导入的后续 API 请求

Avoid subsequent API request with dynamic import in webpack

我有一个应用程序可以转录和分析一本更大的多页乐谱中的短乐谱。每个分数都可以从下拉菜单 select 中单独提供给用户。一次只加载一个乐谱,用户通常只对任何给定会话中的少量乐谱感兴趣。最近我开始使用 Webpack,使用动态导入将每个乐谱分离到自己的包中。尽管我有大量分数(>50),应用程序的增量性质意味着它们仍然需要分解成自己单独的包,可在运行时单独加载。

我遇到的问题是每个分数也有自己的数据,这些数据是通过 API 请求从后端 (Django) 拉下来的。所以现在我有两个请求在用户为给定分数加载模块时执行(至少在第一次):模块的包,然后是额外的 API 请求以获取数据:

import(/* webpackChunkName: '[request]' */ "./someChunkName").then(module => {
  //...API request to get data...
});

我怎样才能避免这种情况?理想情况下,我希望数据与请求的块捆绑在一起,完全不需要 API 请求,但是有没有办法使用 Webpack 来做到这一点?或者可能将 import 语句和 API fetch 包装在 Promise 中?

很确定没有办法完全按照你的要求去做,因为你试图将编译时的代码(你的 webpack 块)与你不会 'have' 直到你获取的数据结合起来它在运行时(您的 Django 后端数据)。 Webpack 块是在编译时创建的,在运行时发生的所有事情都是 Webpack 加载它们以便它们可以执行。

将导入和运行时数据提取包装在 promise 中应该是可行的,但根据规范,您必须使用 require 而不是 import -- import , 不能嵌套在代码块中。 require 可以,所以你应该可以做类似

的事情
const promisifiedRequire = new Promise((resolve, reject) => {
  require.ensure('scores/score-foo', (require) => {
    resolve();    
  });
});

const promisifiedDataFetch = new Promise((resolve, reject) => {
  fetchBackendDataForScoreSomehow().then(() => {
    resolve();
  }).catch((e) => {
    console.log('error fetching data from backend');
    reject(e);
  });
});

Promise.all([ promisifiedRequire, promisifiedDataFetch ]).then(() => {
  // everything is loaded, render stuff etc. now
});

我相信这样可以更简洁、更优雅,但希望它能给您带来灵感;在这里您将有两个并行请求。您是否担心两个并行请求会很慢,而认为包含所有信息的请求会更快?我不会认为这是理所当然的,并且会在尝试优化之前对其进行测试,但是如果是这种情况并且您有充分的理由对每个分数只发出一个请求,那么可能有一种方法可以解决这个问题:

如果我真的想将乐谱和数据捆绑到一个只需要一个 http 请求的资产中,我会为乐谱 JS 文件编写一个自定义加载器,将乐谱数据捆绑或插入到乐谱中它的代码 returns。如果你以前没有写过加载器,它基本上只是一个函数,它接受源代码和 returns 其他东西,链中的最后一个加载器通常返回纯 JS。

当然,要在编译时捆绑数据,您需要 Django 应用程序中的数据在编译时可用。可以想象,您的自定义加载器可以向您在进行 webpack 构建时在本地设置的 django 后端实例发出实时请求,但这会很奇怪和尴尬。理想情况下,您首先将数据从数据库中提取到文件中,然后让您的自定义加载程序在编译时从这些文件中读取以获取数据并将其与您的代码捆绑在一起。您如何选择将以这种方式检索到的数据插入到您的代码中取决于您,并且在很大程度上是一个设计决策。这种方法意味着当您在运行时获取一个块时,该块已经包含了您决定的 pattern/format 中的数据,否则您将从 Django 获取数据,并且不再需要对 Django 进行第二次调用.