Skip to content

Commit

Permalink
feat(ssg): Support asynchronous hooks (#2381)
Browse files Browse the repository at this point in the history
* 1.0

* denoify
  • Loading branch information
watany-dev authored Mar 20, 2024
1 parent 31d2ea4 commit d7e9706
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 20 deletions.
22 changes: 12 additions & 10 deletions deno_dist/helper/ssg/ssg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ const determineExtension = (mimeType: string): string => {
}
}

export type BeforeRequestHook = (req: Request) => Request | false
export type AfterResponseHook = (res: Response) => Response | false
export type BeforeRequestHook = (req: Request) => Request | false | Promise<Request | false>
export type AfterResponseHook = (res: Response) => Response | false | Promise<Response | false>
export type AfterGenerateHook = (result: ToSSGResult) => void | Promise<void>

export interface ToSSGOptions {
Expand Down Expand Up @@ -117,17 +117,19 @@ export const fetchRoutesContent = function* <
const thisRouteBaseURL = new URL(route.path, baseURL).toString()

let forGetInfoURLRequest = new Request(thisRouteBaseURL) as AddedSSGDataRequest
if (beforeRequestHook) {
const maybeRequest = beforeRequestHook(forGetInfoURLRequest)
if (!maybeRequest) {
continue
}
forGetInfoURLRequest = maybeRequest as unknown as AddedSSGDataRequest
}

// eslint-disable-next-line no-async-promise-executor
yield new Promise(async (resolveGetInfo, rejectGetInfo) => {
try {
if (beforeRequestHook) {
const maybeRequest = await beforeRequestHook(forGetInfoURLRequest)
if (!maybeRequest) {
resolveGetInfo(undefined)
return
}
forGetInfoURLRequest = maybeRequest as unknown as AddedSSGDataRequest
}

await pool.run(() => app.fetch(forGetInfoURLRequest))

if (!forGetInfoURLRequest.ssgParams) {
Expand Down Expand Up @@ -160,7 +162,7 @@ export const fetchRoutesContent = function* <
return
}
if (afterResponseHook) {
const maybeResponse = afterResponseHook(response)
const maybeResponse = await afterResponseHook(response)
if (!maybeResponse) {
resolveReq(undefined)
return
Expand Down
41 changes: 41 additions & 0 deletions src/helper/ssg/ssg.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,47 @@ describe('toSSG function', () => {
expect(afterGenerateHookMock).toHaveBeenCalledWith(expect.anything())
})

it('should handle asynchronous beforeRequestHook correctly', async () => {
const beforeRequestHook: BeforeRequestHook = async (req) => {
await new Promise((resolve) => setTimeout(resolve, 10))
if (req.url.includes('/skip')) {
return false
}
return req
}

const result = await toSSG(app, fsMock, { beforeRequestHook })
expect(result.files).not.toContain(expect.stringContaining('/skip'))
expect(result.success).toBe(true)
expect(result.files.length).toBeGreaterThan(0)
})

it('should handle asynchronous afterResponseHook correctly', async () => {
const afterResponseHook: AfterResponseHook = async (res) => {
await new Promise((resolve) => setTimeout(resolve, 10))
if (res.headers.get('X-Skip') === 'true') {
return false
}
return res
}

const result = await toSSG(app, fsMock, { afterResponseHook })
expect(result.files).not.toContain(expect.stringContaining('/skip'))
expect(result.success).toBe(true)
expect(result.files.length).toBeGreaterThan(0)
})

it('should handle asynchronous afterGenerateHook correctly', async () => {
const afterGenerateHook: AfterGenerateHook = async (result) => {
await new Promise((resolve) => setTimeout(resolve, 10))
console.log(`Generated ${result.files.length} files.`)
}

const result = await toSSG(app, fsMock, { afterGenerateHook })
expect(result.success).toBe(true)
expect(result.files.length).toBeGreaterThan(0)
})

it('should avoid memory leak from `req.signal.addEventListener()`', async () => {
const fsMock: FileSystemModule = {
writeFile: vi.fn(() => Promise.resolve()),
Expand Down
22 changes: 12 additions & 10 deletions src/helper/ssg/ssg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ const determineExtension = (mimeType: string): string => {
}
}

export type BeforeRequestHook = (req: Request) => Request | false
export type AfterResponseHook = (res: Response) => Response | false
export type BeforeRequestHook = (req: Request) => Request | false | Promise<Request | false>
export type AfterResponseHook = (res: Response) => Response | false | Promise<Response | false>
export type AfterGenerateHook = (result: ToSSGResult) => void | Promise<void>

export interface ToSSGOptions {
Expand Down Expand Up @@ -117,17 +117,19 @@ export const fetchRoutesContent = function* <
const thisRouteBaseURL = new URL(route.path, baseURL).toString()

let forGetInfoURLRequest = new Request(thisRouteBaseURL) as AddedSSGDataRequest
if (beforeRequestHook) {
const maybeRequest = beforeRequestHook(forGetInfoURLRequest)
if (!maybeRequest) {
continue
}
forGetInfoURLRequest = maybeRequest as unknown as AddedSSGDataRequest
}

// eslint-disable-next-line no-async-promise-executor
yield new Promise(async (resolveGetInfo, rejectGetInfo) => {
try {
if (beforeRequestHook) {
const maybeRequest = await beforeRequestHook(forGetInfoURLRequest)
if (!maybeRequest) {
resolveGetInfo(undefined)
return
}
forGetInfoURLRequest = maybeRequest as unknown as AddedSSGDataRequest
}

await pool.run(() => app.fetch(forGetInfoURLRequest))

if (!forGetInfoURLRequest.ssgParams) {
Expand Down Expand Up @@ -160,7 +162,7 @@ export const fetchRoutesContent = function* <
return
}
if (afterResponseHook) {
const maybeResponse = afterResponseHook(response)
const maybeResponse = await afterResponseHook(response)
if (!maybeResponse) {
resolveReq(undefined)
return
Expand Down

0 comments on commit d7e9706

Please sign in to comment.