WebPack:如何访问单独的类/文件

时间:2017-04-27 19:45:59

标签: javascript dependency-injection webpack

我的团队正在切换到webpack,我遇到了一个我需要帮助的问题。

我不确定原因,但webpack似乎没有公开每个文件之外的依赖项。不幸的是,这破坏了我们用于抽象表渲染逻辑的模式。

foo.renderers.DefaultCellRenderer

class DefaultCellRenderer
  renderCell: (data) ->
    ... render logic goes here ...

foo.renderers.ComplexCellRenderer

class ComplexCellRenderer
  renderCell: (data) ->
    ... render logic goes here ...

foo.mixins.SimpleTableMixin

require foo.mixins.BaseTableMixin

class SimpleTableMixin
  constructor: (@data) ->
    foo.mixins.BaseTableMixin.apply @
    @columns = [
      { label: 'Col 1' }
      { label: 'Col 2' }
    ]

foo.mixins.ComplexTableMixin

require foo.mixins.BaseTableMixin
require foo.renderers.ComplexCellRenderer

class ComplexTableMixin
  constructor: (@data) ->
    foo.mixins.BaseTableMixin.apply @
    @columns = [
      { label: 'Col 1' }
      { label: 'Col 2', renderer: 'ComplexCellRenderer' }
    ]

foo.mixins.BaseTableMixin

require foo.renderers.DefaultCellRenderer

class BaseTableMixin
  render: (container) =>
    # render table header...

    # render table body...
    for row in @data
      for metadata, cellIndex in @columns
        name = metadata.renderer or 'DefaultCellRenderer'
        target = foo.renderers[name]
        container.append target.renderCell row[cellIndex]

这是一个极其简化的示例,但实际上这种方法允许我们使用可在运行时动态配置的行为层组成非常复杂的表。

在实现webpack之前,这种方法之所以有效,是因为'foo.renderers'是全局的,任何需要自定义渲染的类都负责声明该依赖,并保证它在被.render()函数调用时存在...

但是,自从转移到webpack后,这些渲染器不再可用,除非我在基表混合中明确要求。这打破了这种方法的根本好处,即使我们的表可以扩展而不必修改底层逻辑。

此外,我无法直接在columns数组中传递渲染器引用,因为app状态需要可序列化为JSON,因此可以随意对其进行脱水/再水化。

考虑到所有这些因素,任何人都可以告诉我是否有办法确保基表混合中可以使用这些依赖项,而无需在该文件中明确声明它们(从而打破了打开/关闭原则) ?

谢谢!

更新 所以基于下面的dtothefp的答案,我最终创建了一个包装类,它动态地需要相同或子目录中的所有渲染器......所以我只需要一个引用而不是单个引用(尽管它们每个都可以单独使用)同样,避免循环引用)

/foo/common/renderers/Renderers.coffee

goog.provide 'foo.common.renderers'

context = require.context './', true, /^.+\.js$/
context.keys().forEach (key) ->
  renderers = context(key)?.foo?.common?.renderers
  _.extend foo.common.renderers, renderers if renderers?
  return

1 个答案:

答案 0 :(得分:1)

尝试使用expose-loader https://github.com/webpack-contrib/expose-loader

module: {
  rules: [{
    test: path.join(yourSrcRoot, 'foo', 'renderers', 'DefaultCellRenderer'),
    use: [{
      loader: 'expose-loader',
      options: 'foo.renderers.DefaultCellRenderer'  // not sure if this works???
    }]
  }]
}

似乎试图从命令移动到Webpack,使用命名空间上的全局变量是一种反模式,但这可能会让你开始。

或者更好的是,为什么不在捆绑开始时引导整个事情呢?

// index.js

const foos = require.context('./foo', true, /(renderers|mixins)\/.+\.js$/);

global.foo = {};
global.foo.mixins = {};
global.foo.renderers = {};

foos.keys().forEach((fp) => {
  const [dir] = fp.split('/');

  global.foo[dir] = foos(fp);
});

不确定你的意思"这打破了这种方法的根本好处,即使我们的表可以扩展而不必修改底层逻辑。"如果你想使用模块加载器但不想要导入依赖关系似乎你错过了这一点。