代码拆分

Rspack 支持代码分割特性,允许让你对代码进行分割,控制生成的资源体积和资源数量来获取资源加载性能的提升。

Rspack - 代码分割

懒加载组件

通常,我们使用静态 import 来导入组件:

import LazyComponent from './LazyComponent.jsx';

export function App() {
  return (
    <view>
      <LazyComponent />
    </view>
  );
}

如果要将“加载组件代码”延迟至该组件被渲染时,可以将此 import 替换为:

- import LazyComponent from './LazyComponent.jsx'
+ import { lazy } from '@lynx-js/react'
+ const LazyComponent = lazy(() => import('./LazyComponent.jsx'))

此代码依赖于动态 import()。使用此模式要求导入的懒加载组件必须作为默认导出(Default Export)进行导出。

现在,由于你的组件代码按需加载,你还需要指定在加载期间应显示的内容。你可以通过将懒加载组件或其任何父组件包装在 <Suspense> 边界中来实现这一点:

src/App.tsx
import { Suspense, lazy } from '@lynx-js/react';

const LazyComponent = lazy(() => import('./LazyComponent.jsx'));

export function App() {
  return (
    <view>
      <Suspense fallback={<text>Loading...</text>}>
        <LazyComponent />
      </Suspense>
    </view>
  );
}

按需懒加载

在此示例中,LazyComponent 的代码在尝试渲染它之前不会被加载。如果 LazyComponent 尚未加载,则会在其位置显示“Loading...”。例如:

src/App.tsx
import { Suspense, lazy, useState } from '@lynx-js/react';

const LazyComponent = lazy(() => import('./LazyComponent.jsx'));

export function App() {
  const [shouldDisplay, setShouldDisplay] = useState(false);
  const handleClick = () => {
    setShouldDisplay(true);
  };
  return (
    <view>
      <view bindtap={handleClick}>Load Component</view>
      {shouldShow && (
        <Suspense fallback={<text>Loading...</text>}>
          <LazyComponent />
        </Suspense>
      )}
    </view>
  );
}

错误处理

使用 ErrorBoundary

如果加载完成,懒加载组件本质上也是一个 React 组件,因此 React 中的错误处理实践仍然适用。

细节请参考 React - Catching rendering errors with an error boundary

懒加载独立项目

你还可以延迟加载在独立的 Rspeedy 项目中构建的模块。

术语表

  • 生产者:一个向其他 Lynx 应用程序提供模块以供使用的应用程序。
  • 消费者:一个从其他生产者中消费模块的应用程序。

创建一个独立的生产者项目

使用 create-rspeedy 创建一个独立项目:

pnpm create rspeedy@latest

lynx.config.js 中将 pluginReactLynxexperimental_isLazyBundle 选项设置为 true

import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin';
import { defineConfig } from '@lynx-js/rspeedy';

export default defineConfig({
  source: {
    entry: './src/index.tsx',
  },
  plugins: [
    pluginReactLynx({
      experimental_isLazyBundle: true,
    }),
  ],
});

最后修改 src/index.tsx 来导出 App 组件:

src/index.tsx
import { App } from './App.jsx';

export default App;

修改消费者项目

要加载 Producer 项目,请在入口的开头添加对 @lynx-js/react/experimental/lazy/import 的导入:

src/index.tsx
import '@lynx-js/react/experimental/lazy/import';
import { root } from '@lynx-js/react';

import { App } from './App.jsx';

root.render(<App />);

这将提供生产者所需的基本 API。

然后,可以使用动态 import() 加载生产者:

src/App.tsx
import { Suspense, lazy } from '@lynx-js/react';

const LazyComponent = lazy(
  () =>
    import('https://<host>:<port>/path/to/[name]lynx.bundle', {
      with: { type: 'component' },
    }),
);

export function App() {
  return (
    <view>
      <Suspense fallback={<text>Loading...</text>}>
        <LazyComponent />
      </Suspense>
    </view>
  );
}

开发生产者项目

建议在生产者项目中创建一个单独的消费者入口:

src/Consumer.tsx
import { Suspense, lazy, root } from '@lynx-js/react';

// You may use static import if you want
const App = lazy(() => import('./App.jsx'));

root.render(
  <Suspense>
    <App />
  </Suspense>,
);

然后,创建一个单独的 lynx.config.consumer.js

lynx.config.consumer.js
import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin';
import { defineConfig } from '@lynx-js/rspeedy';

export default defineConfig({
  source: {
    entry: './src/Consumer.tsx',
  },
  plugins: [pluginReactLynx()],
});

使用 npx rspeedy dev --config lynx.config.consumer.js 来开始开发生产者项目。

除非另有说明,本项目采用知识共享署名 4.0 国际许可协议进行许可,代码示例采用 Apache License 2.0 许可协议进行许可。