From 2b1dcd026a25ae8363f1ae725e8c9ddb8a21ad81 Mon Sep 17 00:00:00 2001 From: Sidhu Alluri Date: Tue, 29 Jul 2025 13:48:08 -0700 Subject: [PATCH] fix: lazy components suspending unnecessarily when already preloaded by loadableReady --- packages/component/src/createLoadable.js | 2 +- packages/component/src/loadable.test.js | 49 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/component/src/createLoadable.js b/packages/component/src/createLoadable.js index 5a3da831..e4ac0080 100644 --- a/packages/component/src/createLoadable.js +++ b/packages/component/src/createLoadable.js @@ -312,7 +312,7 @@ function createLoadable({ } = this.props const { error, loading, result } = this.state - if (options.suspense) { + if (options.suspense && loading) { const cachedPromise = this.getCache() || this.loadAsync() if (cachedPromise.status === STATUS_PENDING) { throw this.loadAsync() diff --git a/packages/component/src/loadable.test.js b/packages/component/src/loadable.test.js index 9705625c..43397976 100644 --- a/packages/component/src/loadable.test.js +++ b/packages/component/src/loadable.test.js @@ -359,6 +359,55 @@ describe('#lazy', () => { await wait(() => expect(container).toHaveTextContent('loaded')) }) + + it('should not suspend when component is preloaded with lazy', async () => { + const ContentComponent = () => 'loaded' + const ContentComponentModule = { default: ContentComponent } + + // Simulate a preloaded component via chunkExtractor and loadableReady + // This replicates the transformed output of the babel plugin constructor + const Component = lazy({ + chunkName() { return 'chunkName' }, + isReady() { return true }, + requireSync() { return ContentComponentModule }, + requireAsync() { return Promise.resolve(ContentComponentModule) }, + resolve() { return ContentComponent }, + }) + + const { container } = render( + + + , + ) + expect(container).toHaveTextContent('loaded') + expect(container).not.toHaveTextContent('progress') + }) + + + it('should suspend when component is not preloaded with lazy', async () => { + const ContentComponent = () => 'loaded' + const ContentComponentModule = { default: ContentComponent } + + // Simulate a non-preloaded component via chunkExtractor and loadableReady + // This replicates the transformed output of the babel plugin constructor + const Component = lazy({ + chunkName() { return 'chunkName' }, + isReady() { return false }, + requireSync() { return ContentComponentModule }, + requireAsync() { return Promise.resolve(ContentComponentModule) }, + resolve() { return ContentComponent }, + }) + + const { container } = render( + + + , + ) + expect(container).toHaveTextContent('progress') + expect(container).not.toHaveTextContent('loaded') + await wait(() => expect(container).toHaveTextContent('loaded')) + expect(container).not.toHaveTextContent('progress') + }) }) describe('#loadable.lib', () => {