【问题标题】:How to create const in a loop for require.ensure?如何在require.ensure的循环中创建const?
【发布时间】:2017-07-27 13:46:25
【问题描述】:

所以我使用 react-router 以及 require.ensure 和 webpack 来分块我的路线。然而,这导致了很多样板:

const getTermsAndConditions = (nextState, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/TermsAndConditions/TermsAndConditions'))
  }, 'terms')
}
const getThread = (nextState, cb) => {
  require.ensure([], require => {
    cb(null, require('../components/Thread/Thread'))
  }, 'inbox')
}
const getPrivacyPolicy = (nextState, cb) => {
  require.ensure([], require => {
    cb(null, require('../containers/PrivacyPolicy/PrivacyPolicy'))
  }, 'privacy-policy')
}

我连续大约有 25 个这样的声明,然后在实际的渲染函数中:

<Route path='privacy' getComponent={getPrivacyPolicy} />
...etc

我不介意对路由进行硬编码,因为它可以很好地了解应用程序的整体布局,但我想减少 getPrivacyPolicy 类型声明的样板文件。我该怎么做?

编辑:我接受了@Michael Jungo 的回复,但发现getComponentFactory 生成的函数内部仍然有var 名称,而不是硬编码的字符串。

例如:

const PrivacyPolicy = getComponentFactory('../containers/PrivacyPolicy/PrivacyPolicy', 'privacy-policy')

然后console.log(PrivacyPolicy) 返回:

PrivacyPolicy:  function (nextState, cb) {
  require.ensure([], function (require) {
    return cb(null, require(path))
  }, chunkName)
}

所以pathchunkName 都没有被它们的实际字符串值替换...

【问题讨论】:

  • 当然没有硬编码的字符串,闭包就是这样工作的! (您可以使用eval 解决此问题,但我认为您不希望这样做)。但是,由于您无论如何都没有声明任何明确的依赖关系,因此您应该能够调整您的 require 调用以避免警告。您可能想ask a separate question 对此。
  • @Bergi 我什至不知道该问什么,您介意解释一下我将如何调整require 电话吗?执行我的 webpack 构建后,看起来这些块甚至都没有生成,所以这不是一个微不足道的错误。
  • 啊,我错过了 webpack 尝试解析这些东西以创建块的情况。我假设如果您使用 AMD 风格的 require(带有回调),该脚本至少是可执行的。我也觉得你使用require.ensure 但没有指定任何依赖项很奇怪。
  • @Bergi 这些是组件,任何部门都被列为imports ...

标签: javascript reactjs webpack ecmascript-6 react-router


【解决方案1】:

不幸的是,您不能再真正减少代码,因为requirerequire.ensure 必须接收字符串文字,变量将不起作用。它必须在编译时知道,无需程序流分析。这些getComponent 函数只包含require.ensure 语句,因此您必须明确地编写它们。


旧答案

你是对的,这是很多样板文件,但删除其中大部分内容非常简单,因为你几乎是在复制相同的代码,只是使用不同的参数。

在进入代码之前,重要的是要知道函数是 JavaScript 中的一等公民。这意味着您可以将函数用作参数、返回值并将其分配给变量,就像任何其他值一样。事实上,这正是您所做的,您使用了 function expression 并将其分配给一个变量(例如 getPrivacyPolicy)。好吧,您使用了arrow functions,它是函数表达式的一种特殊语法(文档中显示了一些差异)。该变量只是为了引用它,您可以稍后使用。您不一定需要这些引用,您可以将它们直接传递给getComponent 属性。

考虑到这一点,您可以开始重构您的函数。在您的函数中,除了您需要的pathchunkName 之外,其他一切都相同。因此,您将创建一个以pathchunkName 作为参数并返回一个新函数 的函数,该函数将在getComponent 中使用。

const getComponentFactory = (path, chunkName) => {
  // Return the function that will be passed to getComponent
  return (nextState, cb) => {
    require.ensure([], require => cb(null, require(path)), chunkName);
  };
}

现在您可以通过调用getComponentFactory 轻松创建您拥有的功能,例如:

const getThread = getComponentFactory('../components/Thread/Thread', 'inbox');

如前所述,您实际上并不需要将此函数分配给变量,但如果您愿意,可以直接在 Route 中使用它:

<Route
  path='inbox'
  getComponent={getComponentFactory('../components/Thread/Thread', 'inbox')}
/>

注意:不要忘记调用函数和传递函数的区别。

console.log(func);       // The function func is printed
console.log(func(args)); // The return value of func is printed

【讨论】:

  • 您甚至可以将../components/ 部分和模块名称的重复部分移入工厂
  • @Michael Jungo - 这会产生以下错误require function is used in a way in which dependencies cannot be statically extracted...知道为什么吗?
  • @Michael Jungo 看起来这正在返回一个没有用字符串替换 pathchunkName 的函数。你如何产生一个里面有硬编码字符串的函数?
  • 对不起,我完全忘记了你不能有动态要求(不能传递require 变量)。我已经更新了答案。
猜你喜欢
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 2014-06-19
  • 1970-01-01
  • 2013-10-23
  • 1970-01-01
  • 2020-01-19
  • 2021-10-15
相关资源
最近更新 更多