Skip to content

Instantly share code, notes, and snippets.

@rmarscher
Last active September 19, 2024 15:49
Show Gist options
  • Save rmarscher/a22eea499ce25e30f4553e5d96eaa53f to your computer and use it in GitHub Desktop.
Save rmarscher/a22eea499ce25e30f4553e5d96eaa53f to your computer and use it in GitHub Desktop.
Waku AWS Deploy Plugin Patch
diff --git a/packages/waku/src/lib/plugins/vite-plugin-deploy-aws-lambda.ts b/packages/waku/src/lib/plugins/vite-plugin-deploy-aws-lambda.ts
index 09a09d2..452efc7 100644
--- a/packages/waku/src/lib/plugins/vite-plugin-deploy-aws-lambda.ts
+++ b/packages/waku/src/lib/plugins/vite-plugin-deploy-aws-lambda.ts
@@ -1,10 +1,22 @@
import path from 'node:path';
-import { writeFileSync } from 'node:fs';
+import {
+ appendFileSync,
+ cpSync,
+ existsSync,
+ mkdirSync,
+ readdirSync,
+ renameSync,
+ writeFileSync,
+} from 'node:fs';
import type { Plugin } from 'vite';
import { unstable_getPlatformObject } from '../../server.js';
import { SRC_ENTRIES } from '../constants.js';
-import { DIST_PUBLIC } from '../builder/constants.js';
+import {
+ DIST_PUBLIC,
+ DIST_ASSETS,
+ DIST_ENTRIES_JS,
+} from '../builder/constants.js';
const SERVE_JS = 'serve-aws-lambda.js';
@@ -20,7 +32,7 @@ import { runner, importHono, importHonoContextStorage, importHonoNodeServerServe
const { Hono } = await importHono();
const { contextStorage } = await importHonoContextStorage();
const { serveStatic } = await importHonoNodeServerServeStatic();
-const { handle } = await importHonoAwsLambda();
+const { streamHandle } = await importHonoAwsLambda();
const distDir = '${distDir}';
const publicDir = '${distPublic}';
@@ -38,12 +50,13 @@ app.notFound(async (c) => {
return c.text('404 Not Found', 404);
});
-export const handler = handle(app);
+export const handler = streamHandle(app);
`;
export function deployAwsLambdaPlugin(opts: {
srcDir: string;
distDir: string;
+ privateDir: string;
}): Plugin {
const platformObject = unstable_getPlatformObject();
let entriesFile: string;
@@ -82,6 +95,52 @@ export function deployAwsLambdaPlugin(opts: {
path.join(opts.distDir, 'package.json'),
JSON.stringify({ type: 'module' }, null, 2),
);
+
+ // Move the distDir so we can move files back to different locations
+ renameSync(opts.distDir, '_dist');
+ mkdirSync(opts.distDir);
+
+ const functionDir = path.join(opts.distDir, 'function');
+ const functionPublicDir = path.join(functionDir, DIST_PUBLIC);
+ const publicDir = path.join(opts.distDir, 'public');
+
+ // Move everything to the function folder
+ renameSync('_dist', functionDir);
+ // Then move the function public folder
+ renameSync(functionPublicDir, publicDir);
+
+ if (existsSync(opts.privateDir)) {
+ cpSync(opts.privateDir, path.join(functionDir, opts.privateDir), {
+ recursive: true,
+ });
+ }
+
+ appendFileSync(
+ path.join(functionDir, DIST_ENTRIES_JS),
+ `export const buildData = ${JSON.stringify(platformObject.buildData)};`,
+ );
+
+ // Assume that any user files in public do not need to be bundled
+ // with the lambda function but public/assets/*.js and css do.
+ // We'll also copy any html files to the function public folder
+ // for use as custom error pages.
+ mkdirSync(functionPublicDir);
+ const publicAssetsDir = path.join(publicDir, DIST_ASSETS);
+ const files = readdirSync(publicAssetsDir).filter(
+ (file) => file.endsWith('.css') || file.endsWith('.js'),
+ );
+ for (const file of files) {
+ cpSync(
+ path.join(publicAssetsDir, file),
+ path.join(functionPublicDir, DIST_ASSETS, file),
+ );
+ }
+ const htmlFiles = readdirSync(publicDir).filter((file) =>
+ file.endsWith('.html'),
+ );
+ for (const file of htmlFiles) {
+ cpSync(path.join(publicDir, file), path.join(functionPublicDir, file));
+ }
},
};
}
import path from 'node:path';
import {
appendFileSync,
cpSync,
existsSync,
mkdirSync,
readdirSync,
renameSync,
writeFileSync,
} from 'node:fs';
import type { Plugin } from 'vite';
import { unstable_getPlatformObject } from '../../server.js';
import { SRC_ENTRIES } from '../constants.js';
import {
DIST_PUBLIC,
DIST_ASSETS,
DIST_ENTRIES_JS,
} from '../builder/constants.js';
const SERVE_JS = 'serve-aws-lambda.js';
const getServeJsContent = (
distDir: string,
distPublic: string,
srcEntriesFile: string,
) => `
import path from 'node:path';
import { existsSync, readFileSync } from 'node:fs';
import { runner, importHono, importHonoContextStorage, importHonoNodeServerServeStatic, importHonoAwsLambda } from 'waku/unstable_hono';
const { Hono } = await importHono();
const { contextStorage } = await importHonoContextStorage();
const { serveStatic } = await importHonoNodeServerServeStatic();
const { streamHandle } = await importHonoAwsLambda();
const distDir = '${distDir}';
const publicDir = '${distPublic}';
const loadEntries = () => import('${srcEntriesFile}');
const app = new Hono();
app.use(contextStorage());
app.use('*', serveStatic({ root: distDir + '/' + publicDir }));
app.use('*', runner({ cmd: 'start', loadEntries, env: process.env }));
app.notFound(async (c) => {
const file = path.join(distDir, publicDir, '404.html');
if (existsSync(file)) {
return c.html(readFileSync(file, 'utf8'), 404);
}
return c.text('404 Not Found', 404);
});
export const handler = streamHandle(app);
`;
export function deployAwsLambdaPlugin(opts: {
srcDir: string;
distDir: string;
privateDir: string;
}): Plugin {
const platformObject = unstable_getPlatformObject();
let entriesFile: string;
return {
name: 'deploy-aws-lambda-plugin',
config(viteConfig) {
const { deploy, unstable_phase } = platformObject.buildOptions || {};
if (unstable_phase !== 'buildServerBundle' || deploy !== 'aws-lambda') {
return;
}
const { input } = viteConfig.build?.rollupOptions ?? {};
if (input && !(typeof input === 'string') && !(input instanceof Array)) {
input[SERVE_JS.replace(/\.js$/, '')] = `${opts.srcDir}/${SERVE_JS}`;
}
},
configResolved(config) {
entriesFile = `${config.root}/${opts.srcDir}/${SRC_ENTRIES}`;
},
resolveId(source) {
if (source === `${opts.srcDir}/${SERVE_JS}`) {
return source;
}
},
load(id) {
if (id === `${opts.srcDir}/${SERVE_JS}`) {
return getServeJsContent(opts.distDir, DIST_PUBLIC, entriesFile);
}
},
closeBundle() {
const { deploy, unstable_phase } = platformObject.buildOptions || {};
if (unstable_phase !== 'buildDeploy' || deploy !== 'aws-lambda') {
return;
}
writeFileSync(
path.join(opts.distDir, 'package.json'),
JSON.stringify({ type: 'module' }, null, 2),
);
// Move the distDir so we can move files back to different locations
renameSync(opts.distDir, '_dist');
mkdirSync(opts.distDir);
const functionDir = path.join(opts.distDir, 'function');
const functionPublicDir = path.join(functionDir, DIST_PUBLIC);
const publicDir = path.join(opts.distDir, 'public');
// Move everything to the function folder
renameSync('_dist', functionDir);
// Then move the function public folder
renameSync(functionPublicDir, publicDir);
if (existsSync(opts.privateDir)) {
cpSync(opts.privateDir, path.join(functionDir, opts.privateDir), {
recursive: true,
});
}
appendFileSync(
path.join(functionDir, DIST_ENTRIES_JS),
`export const buildData = ${JSON.stringify(platformObject.buildData)};`,
);
// Assume that any user files in public do not need to be bundled
// with the lambda function but public/assets/*.js and css do.
// We'll also copy any html files to the function public folder
// for use as custom error pages.
mkdirSync(functionPublicDir);
const publicAssetsDir = path.join(publicDir, DIST_ASSETS);
const files = readdirSync(publicAssetsDir).filter(
(file) => file.endsWith('.css') || file.endsWith('.js'),
);
for (const file of files) {
cpSync(
path.join(publicAssetsDir, file),
path.join(functionPublicDir, DIST_ASSETS, file),
);
}
const htmlFiles = readdirSync(publicDir).filter((file) =>
file.endsWith('.html'),
);
for (const file of htmlFiles) {
cpSync(path.join(publicDir, file), path.join(functionPublicDir, file));
}
},
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment