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

时间:2018-06-16 17:30:39

标签: javascript webpack code-splitting dynamic-import

我有一个应用程序,可以从一本较大的,多页的分数书中抄写和分析短的乐谱。每个分数都可以从下拉选项中单独提供给用户。一次只加载一个分数,并且用户通常仅对任何给定会话中的少量分数感兴趣。最近我开始使用Webpack,每个分数使用动态导入分成自己的包。尽管我有大量的分数(> 50),但应用程序的增量特性意味着它们仍需要分解为各自独立的软件包,可在运行时单独加载。

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

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

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

1 个答案:

答案 0 :(得分:1)

非常确定没有办法完全按照您的要求进行操作,因为您正在尝试将编译时的代码(您的webpack块)与您赢得的数据结合起来'有'直到你在运行时获取它(你的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
});

我确信它可以更干净,更优雅,但希望它能给你这个想法;在这里,您将有两个并行请求。您是否担心两个并行请求会变慢,并且认为拥有所有信息的请求会更快?我不会认为这是理所当然的,并且会在尝试优化之前对其进行测试,但如果是这种情况并且你有充分的理由只对每个分数提出一个请求,那么可能有办法解决这个问题: / p>

如果我真的想将得分和数据捆绑到只需要一个http请求的单个资产中,我会为得分JS文件编写一个自定义加载程序,将得分数据捆绑或插入到得分代码中它返回。如果您以前没有编写过加载程序,它基本上只是一个获取源代码并返回其他东西的函数,链中的最后一个加载器通常返回普通的JS。

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