Skip to content

Commit

Permalink
use workers for full API routes cache busting in development mode
Browse files Browse the repository at this point in the history
  • Loading branch information
thescientist13 committed May 1, 2023
1 parent 9686fc1 commit e49da21
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 8 deletions.
43 changes: 43 additions & 0 deletions packages/cli/src/lib/api-route-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// https://github.com/nodejs/modules/issues/307#issuecomment-858729422
import { parentPort } from 'worker_threads';

// based on https://stackoverflow.com/questions/57447685/how-can-i-convert-a-request-object-into-a-stringifiable-object-in-javascript
async function responseAsObject (response) {
if (!response instanceof Response) {
throw Object.assign(
new Error(),
{ name: 'TypeError', message: 'Argument must be a Response object' }
);
}
response = response.clone();

function stringifiableObject (obj) {
const filtered = {};
for (const key in obj) {
if (['boolean', 'number', 'string'].includes(typeof obj[key]) || obj[key] === null) {
filtered[key] = obj[key];
}
}
return filtered;
}

return {
...stringifiableObject(response),
headers: Object.fromEntries(response.headers),
// signal: stringifiableObject(request.signal),
body: await response.text()
};
}

async function executeRouteModule({ href, request }) {
// console.log('WORKER', { href, message, request })
const { handler } = await import(href);
const response = await handler(request);

// console.log('WORKER', { response })
parentPort.postMessage(await responseAsObject(response));
}

parentPort.on('message', async (task) => {
await executeRouteModule(task);
});
74 changes: 66 additions & 8 deletions packages/cli/src/plugins/resource/plugin-api-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,35 @@
*
*/
import { ResourceInterface } from '../../lib/resource-interface.js';
import { Worker } from 'worker_threads';

// https://stackoverflow.com/questions/57447685/how-can-i-convert-a-request-object-into-a-stringifiable-object-in-javascript
function requestAsObject (request) {
if (!request instanceof Request) {
throw Object.assign(
new Error(),
{ name: 'TypeError', message: 'Argument must be a Request object' }
);
}
request = request.clone();

function stringifiableObject (obj) {
const filtered = {};
for (const key in obj) {
if (['boolean', 'number', 'string'].includes(typeof obj[key]) || obj[key] === null) {
filtered[key] = obj[key];
}
}
return filtered;
}

return {
...stringifiableObject(request),
headers: Object.fromEntries(request.headers),
signal: stringifiableObject(request.signal)
// bodyText: await request.text(), // requires function to be async
};
}

class ApiRoutesResource extends ResourceInterface {
constructor(compilation, options) {
Expand All @@ -19,17 +48,46 @@ class ApiRoutesResource extends ResourceInterface {
async serve(url, request) {
const api = this.compilation.manifest.apis.get(url.pathname);
const apiUrl = new URL(`.${api.path}`, this.compilation.context.userWorkspace);
// https://github.com/nodejs/modules/issues/307#issuecomment-1165387383
const href = process.env.__GWD_COMMAND__ === 'develop' // eslint-disable-line no-underscore-dangle
? `${apiUrl.href}?t=${Date.now()}`
: apiUrl.href;

const { handler } = await import(href);
const req = new Request(new URL(`${request.url.origin}${url}`), {
const href = apiUrl.href;
const req = new Request(new URL(url), {
...request
});

return await handler(req);
// console.log({ req });

// TODO does this ever run in anything but development mode?
if (process.env.__GWD_COMMAND__ === 'develop') { // eslint-disable-line no-underscore-dangle
const workerUrl = new URL('../../lib/api-route-worker.js', import.meta.url);

const response = await new Promise((resolve, reject) => {
const worker = new Worker(workerUrl);
const req = requestAsObject(request);

worker.on('message', (result) => {
// console.log('RESULT =====>', { result });
resolve(result);
});
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});

// console.log('OUT', { reqUnrevied });

worker.postMessage({ href, request: req });
});

// console.log('SUCCESS', {response})
return new Response(response.body, {
...response
});
} else {
const { handler } = await import(href);

return await handler(req);
}
}
}

Expand Down

0 comments on commit e49da21

Please sign in to comment.