如何使用 preact 进行手动代码拆分?

How can I do manual code-splitting with preact?

我想使用 preact 手动进行代码拆分。 Preact 已经为路由拆分了代码,但我想自己做。

我的用例是我正在构建一个工具,用户可以在其中将小部件添加到仪表板。在主页上我只想包含用户已配置的小部件的代码,而不是用户未使用的小部件的代码。

所以我不想将所有小部件的代码捆绑在 bundle.js 中,而是在呈现小部件列表时在需要时懒惰地请求它。

我曾尝试使用 async! 语法,我在样板的一些旧提交中看到过这种语法,但没有用。

我的代码的一个简化示例

配置数据

[{ "type": "notes", "title": "Widget 1}, { "type": "todo", "title": "Widget 2"}]

列表的渲染函数

const Grid = ({ widgets }) => (
    <ul>
        {widgets.map((widget) => <li key={widget.title}><Widget widget={widget} /></li>)}
    </ul>
);

小部件组件

这里我有一个从类型到组件的映射:

import notes from widgets/notes;
import todo from widgets/todo;

class Widget extends Component {
    widgetMap(widget) {
      if (widget.type === 'notes') {
         return notes;
      }
      if (widget.type === 'todo') {
          return todo;
      }
    }

    render ({ widget }) {
        const widgetComponent = this.widgetMap(map);
        return (
            <div>
                <h1>{widget.title}</h1>
                <widgetComponent />
            </div>
        );
    } 
}

如果您使用的是 Preact X,它具有 <Suspense>lazy 相同的功能 API React 也使用。你可以在这里阅读更多关于它的深度:https://reactjs.org/docs/concurrent-mode-suspense.html

你的例子,修改后看起来像这样(代码调整自 here):

import { Suspense, lazy } from `preact/compat`;

const notes = lazy(() => import('./widgets/notes'));
const todo = lazy(() => import('./widgets/todo'));

class Widget extends Component {
    widgetMap(widget) {
      if (widget.type === 'notes') {
         return notes;
      }
      if (widget.type === 'todo') {
          return todo;
      }
    }

    render ({ widget }) {
        const widgetComponent = this.widgetMap(map);
        return (
            <Suspense fallback={<div>loading...</div>}>
                <div>
                    <h1>{widget.title}</h1>
                    <widgetComponent />
                </div>
            </Suspense>
        );
    } 
}

对于旧版本的 Preact,只要你设置了 Babel 或其他一些转译器来处理,你就可以自己组合异步加载 HOC dynamic module loading

export default asyncComponent = (importComponent) => {
  class AsyncComponent extends Component {
    constructor(props) {
      super(props);
      this.state = { component: null };
    }

    async componentDidMount() {
      const { default: component } = await importComponent();
      this.setState({ component });
    }

    render() {
      const Component = this.state.component;
      return Component ? <Component {...this.props} /> : <div>loading...</div>;
    }
  }

  return AsyncComponent;
}