将react渲染方法拆分为单独的npm包

时间:2019-01-10 13:02:04

标签: javascript reactjs react-native

我们有一个在React中开发的前端应用程序。 现在,我们还想制作一个本机应用程序,但是要尽可能多地从当前应用程序中重用。

我已经看到,在这些情况下,经常使用react-native-web,但是,我们已经开发了仅带有react的应用,而将所有当前组件替换为react-native-web组件将花费太多时间(因为我们正在使用antd组件库)。

我的想法是将所有渲染方法移至另一个npm包(以及其他一些需要重写才能使用react-native的部分),然后从主包中导入它们。

我想象这样的文件夹结构:

    • 核心-将包含所有可重复使用的代码
    • web-将包含所有带有antd组件的渲染方法
    • native-将包含所有具有本机组件的render方法

通过这种方式,Web和本机软件包将分别具有其npm启动和构建脚本。 如何在核心程序包中并基于平台(在这种情况下为Web或本机)基于正确的程序包导入渲染部分?

我认为我可以使用lerna库来分离包和commonjs或requirejs之类的东西,然后动态导入正确的render元素。

您能推荐一些其他有用的工具吗? 还是整个方法都是错误的,还有另一种方法可以实现?

换句话说,我们如何实现从Web程序包到核心程序包的依赖注入?

想象一下,我们在核心包中有一个Home组件:

class Home extends Component {
..
    render() {
        // somehow import required 'view'
        // example: import('path_to_web_package_from_some_global_variable' + '/HomeRender.js');
        // There would be a HomeRender.js in 'web' package and another one in 'native' package
    }
..
}

1 个答案:

答案 0 :(得分:0)

发布的程序包应该按照常规方式构建到ES5,可以选择通过ES6导出和导入(ESM构建)来在模块化环境中更有效地使用它。

ES6的进出口是静态的。它们至少在构建工具中没有模块篡改的情况下无法交换。动态import()a proposal,而不是ES6的一部分。这将防止有效的摇树,这将导致webnative都包含在捆绑包中,即使其中一个未使用也是如此。

DI的某些变体应用于使core渲染器不可知。

其中一种方法是允许core中使用某种插件系统:

import { configureRenderer } from '@foo/core';
import * as renderers from '@foo/web';

configureRenderer(renderers);

这在某些情况下可能会起作用,但是对于组件来说效果不佳,因为这会阻止renderers摇晃树并限制core使用native或在这种情况下,网络. This results in网络package bundled entirely, even if only small portion is used. The restriction to本机or web可能会起作用,因为平台是互斥的,但通常这不是一个好的设计解决方案。

一个更好的方法是以相反的方式来实现。 core没有依赖关系,包含通用抽象,而webnative是具体的实现。这可以通过使用具有类组件的OOP继承来解决,并且有很多方法可以用功能方法来实现DI,适合这种情况的一种方法是render prop(因此得名):

// @foo/core
export class Home extends Component {
    ...
    render() {
        const {render, ...props} = this.props;
        return render(props);
    }
}

// @foo/web
import { Home as HomeWithoutRenderer } from '@foo/core';

const rendererHOC = (Comp, renderer) => props => <Comp render={renderer} ...props />;

export const Home = rendererHOC(HomeWithoutRenderer, props => {
  // platform-specific view
});