Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: output cloudflare #267

Merged
merged 8 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,27 @@ Alternatively, you could create a project with something like
`npm create waku@latest` and copy files from the example
folder in the repository.

## Deploy

### Vercel

```sh
vercel
```

Then change the setting as follows (needs redeploy for the first time):

![vercel](https://github.com/dai-shi/waku/assets/490574/6bd317a8-2772-42f4-92d4-b508af7d7460)

### Cloudflare

```sh
npm run build -- --with-cloudflare
rm -r node_modules
npm install --omit=dev --omit=peer
npx wrangler dev # or deploy
```

## Tweets

<https://github.com/dai-shi/waku/discussions/150>
Expand Down
26 changes: 21 additions & 5 deletions packages/waku/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ const { values, positionals } = parseArgs({
'with-ssr': {
type: 'boolean',
},
'with-vercel': {
type: 'boolean',
},
'with-cloudflare': {
type: 'boolean',
},
version: {
type: 'boolean',
short: 'v',
Expand All @@ -46,7 +52,11 @@ if (values.version) {
runDev({ ssr: !!values['with-ssr'] });
break;
case 'build':
runBuild({ ssr: !!values['with-ssr'] });
runBuild({
ssr: !!values['with-ssr'],
vercel: values['with-vercel'],
cloudflare: !!values['with-cloudflare'],
});
break;
case 'start':
runStart({ ssr: !!values['with-ssr'] });
Expand All @@ -62,13 +72,17 @@ if (values.version) {

async function runDev(options: { ssr: boolean }) {
const app = new Hono();
app.use('*', honoDevMiddleware({ ssr: options.ssr }));
app.use('*', honoDevMiddleware(options));
const port = parseInt(process.env.PORT || '3000', 10);
startServer(app, port);
}

async function runBuild(options: { ssr: boolean }) {
await build({ ssr: options.ssr });
async function runBuild(options: {
ssr: boolean;
vercel: boolean | undefined;
cloudflare: boolean;
}) {
await build(options);
}

async function runStart(options: { ssr: boolean }) {
Expand All @@ -77,7 +91,7 @@ async function runStart(options: { ssr: boolean }) {
url.pathToFileURL(path.resolve(distDir, entriesJs)).toString()
);
const app = new Hono();
app.use('*', honoPrdMiddleware({ entries, ssr: options.ssr }));
app.use('*', honoPrdMiddleware({ entries, ...options }));
app.use('*', serveStatic({ root: path.join(distDir, publicDir) }));
const port = parseInt(process.env.PORT || '8080', 10);
startServer(app, port);
Expand Down Expand Up @@ -108,6 +122,8 @@ Commands:

Options:
--with-ssr Use opt-in SSR
--with-vercel Output for Vercel on build
--with-cloudflare Output for Cloudflare on build
-v, --version Display the version number
-h, --help Display this help message
`);
Expand Down
8 changes: 7 additions & 1 deletion packages/waku/src/lib/builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { nonjsResolvePlugin } from '../plugins/vite-plugin-nonjs-resolve.js';
import { rscTransformPlugin } from '../plugins/vite-plugin-rsc-transform.js';
import { patchReactRefresh } from '../plugins/patch-react-refresh.js';
import { emitVercelOutput } from './output-vercel.js';
import { emitCloudflareOutput } from './output-cloudflare.js';

// TODO this file and functions in it are too long. will fix.

Expand Down Expand Up @@ -481,7 +482,8 @@ const resolveFileName = (fname: string) => {
export async function build(options: {
config?: Config;
ssr?: boolean;
vercel?: boolean;
vercel?: boolean | undefined;
cloudflare?: boolean;
}) {
const config = await resolveConfig(options.config || {});
const rootDir = (
Expand Down Expand Up @@ -536,4 +538,8 @@ export async function build(options: {
!!options?.ssr,
);
}

if (options?.cloudflare) {
await emitCloudflareOutput(rootDir, config, !!options?.ssr);
}
}
54 changes: 54 additions & 0 deletions packages/waku/src/lib/builder/output-cloudflare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import path from 'node:path';
import { existsSync, writeFileSync } from 'node:fs';

import type { ResolvedConfig } from '../config.js';

// XXX this can be very limited. FIXME if anyone has better knowledge.
export const emitCloudflareOutput = async (
rootDir: string,
config: ResolvedConfig,
ssr: boolean,
) => {
const outputDir = path.resolve('.');
const relativeRootDir = path.relative(outputDir, rootDir);
const entriesFile = path.join(
relativeRootDir,
config.distDir,
config.entriesJs,
);
const publicDir = path.join(
relativeRootDir,
config.distDir,
config.publicDir,
);
if (!existsSync(path.join(outputDir, 'serve.js'))) {
writeFileSync(
path.join(outputDir, 'serve.js'),
`
import { honoMiddleware } from 'waku';
import { Hono } from 'hono';
import { serveStatic } from 'hono/cloudflare-workers';

const entries = import('./${entriesFile}');

const app = new Hono();
app.use('*', honoMiddleware({ entries, ssr: ${ssr} }));
app.use('*', serveStatic({ root: './' }));
export default app;
`,
);
}
if (!existsSync(path.join(outputDir, 'wrangler.toml'))) {
writeFileSync(
path.join(outputDir, 'wrangler.toml'),
`
name = "waku-project"
main = "serve.js"
compatibility_date = "2023-12-06"

[site]
bucket = "./${publicDir}"
`,
);
}
};
9 changes: 8 additions & 1 deletion packages/waku/src/lib/rsc/worker-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ const getWorker = () => {
return lastWorker;
}
return (lastWorker = new Promise<WorkerOrig>((resolve, reject) => {
Promise.all([import('node:worker_threads'), import('node:module')])
Promise.all([
import('node:worker_threads').catch((e) => {
throw e;
}),
import('node:module').catch((e) => {
throw e;
}),
])
.then(([{ Worker }, { default: module }]) => {
const HAS_MODULE_REGISTER = typeof module.register === 'function';
const worker = new Worker(new URL('worker-impl.js', import.meta.url), {
Expand Down
Loading