From c69f607db212150eca73e459be81e86ca7b0f70a Mon Sep 17 00:00:00 2001 From: Yusuke Wada Date: Sat, 13 Jan 2024 18:34:02 +0900 Subject: [PATCH] feat(vite): islands support async component --- src/vite/island-components.ts | 27 ++++++++++++++++-------- test/unit/vite/island-components.test.ts | 16 ++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/vite/island-components.ts b/src/vite/island-components.ts index 13bff55..90e6061 100644 --- a/src/vite/island-components.ts +++ b/src/vite/island-components.ts @@ -32,7 +32,7 @@ import { import type { Plugin } from 'vite' import { COMPONENT_NAME, DATA_SERIALIZED_PROPS } from '../constants.js' -function addSSRCheck(funcName: string, componentName: string) { +function addSSRCheck(funcName: string, componentName: string, isAsync = false) { const isSSR = memberExpression( memberExpression(identifier('import'), identifier('meta')), identifier('env.SSR') @@ -70,7 +70,11 @@ function addSSRCheck(funcName: string, componentName: string) { ) const returnStmt = returnStatement(conditionalExpression(isSSR, ssrElement, clientElement)) - return functionExpression(null, [identifier('props')], blockStatement([returnStmt])) + const functionExpr = functionExpression(null, [identifier('props')], blockStatement([returnStmt])) + if (isAsync) { + functionExpr.async = true + } + return functionExpr } export const transformJsxTags = (contents: string, componentName: string) => { @@ -85,18 +89,23 @@ export const transformJsxTags = (contents: string, componentName: string) => { if (path.node.declaration.type === 'FunctionDeclaration') { const functionId = path.node.declaration.id if (!functionId) return + const isAsync = path.node.declaration.async const originalFunctionId = identifier(functionId.name + 'Original') + const originalFunction = functionExpression( + null, + path.node.declaration.params, + path.node.declaration.body + ) + if (isAsync) { + originalFunction.async = true + } + path.insertBefore( - variableDeclaration('const', [ - variableDeclarator( - originalFunctionId, - functionExpression(null, path.node.declaration.params, path.node.declaration.body) - ), - ]) + variableDeclaration('const', [variableDeclarator(originalFunctionId, originalFunction)]) ) - const wrappedFunction = addSSRCheck(originalFunctionId.name, componentName) + const wrappedFunction = addSSRCheck(originalFunctionId.name, componentName, isAsync) const wrappedFunctionId = identifier('Wrapped' + functionId.name) path.replaceWith( variableDeclaration('const', [variableDeclarator(wrappedFunctionId, wrappedFunction)]) diff --git a/test/unit/vite/island-components.test.ts b/test/unit/vite/island-components.test.ts index f5b8840..ddb8ef3 100644 --- a/test/unit/vite/island-components.test.ts +++ b/test/unit/vite/island-components.test.ts @@ -20,4 +20,20 @@ export default WrappedBadge;` const code = transformJsxTags('', 'Badge.tsx') expect(code).toBe('') }) + + it('async', () => { + const code = `export default async function AsyncComponent() { + return

Hello

+ }` + const result = transformJsxTags(code, 'AsyncComponent.tsx') + expect(result).toBe( + `const AsyncComponentOriginal = async function () { + return

Hello

; +}; +const WrappedAsyncComponent = async function (props) { + return import.meta.env.SSR ? : ; +}; +export default WrappedAsyncComponent;` + ) + }) })