waku 0.21.1 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/client.js +4 -8
- package/dist/lib/builder/build.js +102 -33
- package/dist/lib/middleware/dev-server-impl.js +4 -2
- package/dist/lib/middleware/rsc.js +1 -1
- package/dist/lib/plugins/vite-plugin-deploy-aws-lambda.d.ts +5 -0
- package/dist/lib/plugins/vite-plugin-deploy-aws-lambda.js +52 -0
- package/dist/lib/plugins/vite-plugin-deploy-cloudflare.d.ts +7 -0
- package/dist/lib/plugins/vite-plugin-deploy-cloudflare.js +143 -0
- package/dist/lib/plugins/vite-plugin-deploy-deno.d.ts +5 -0
- package/dist/lib/plugins/{vite-plugin-rsc-serve.js → vite-plugin-deploy-deno.js} +14 -16
- package/dist/lib/plugins/vite-plugin-deploy-netlify.d.ts +6 -0
- package/dist/lib/plugins/vite-plugin-deploy-netlify.js +78 -0
- package/dist/lib/plugins/vite-plugin-deploy-partykit.d.ts +5 -0
- package/dist/lib/plugins/vite-plugin-deploy-partykit.js +61 -0
- package/dist/lib/plugins/vite-plugin-deploy-vercel.d.ts +8 -0
- package/dist/lib/plugins/vite-plugin-deploy-vercel.js +101 -0
- package/dist/lib/renderers/html-renderer.js +2 -2
- package/dist/lib/renderers/rsc-renderer.js +12 -8
- package/dist/router/create-pages.d.ts +0 -4
- package/dist/router/create-pages.js +7 -17
- package/dist/router/define-router.d.ts +0 -3
- package/dist/router/define-router.js +21 -20
- package/dist/router/fs-router.js +7 -7
- package/dist/server.d.ts +10 -5
- package/dist/server.js +5 -0
- package/package.json +7 -7
- package/dist/lib/builder/output-aws-lambda.d.ts +0 -2
- package/dist/lib/builder/output-aws-lambda.js +0 -7
- package/dist/lib/builder/output-cloudflare.d.ts +0 -2
- package/dist/lib/builder/output-cloudflare.js +0 -78
- package/dist/lib/builder/output-netlify.d.ts +0 -2
- package/dist/lib/builder/output-netlify.js +0 -31
- package/dist/lib/builder/output-partykit.d.ts +0 -2
- package/dist/lib/builder/output-partykit.js +0 -15
- package/dist/lib/builder/output-vercel.d.ts +0 -2
- package/dist/lib/builder/output-vercel.js +0 -53
- package/dist/lib/plugins/vite-plugin-rsc-serve.d.ts +0 -9
package/README.md
CHANGED
|
@@ -1007,7 +1007,7 @@ Note: When rendering in static mode, please be sure to return `render: 'static'`
|
|
|
1007
1007
|
|
|
1008
1008
|
```
|
|
1009
1009
|
npm run build -- --with-cloudflare
|
|
1010
|
-
npx wrangler dev # or deploy
|
|
1010
|
+
npx wrangler pages dev # or deploy
|
|
1011
1011
|
```
|
|
1012
1012
|
|
|
1013
1013
|
### PartyKit (experimental)
|
package/dist/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react/canary" />
|
|
2
2
|
'use client';
|
|
3
|
-
import { Component, createContext, createElement, memo, use, useCallback, useEffect, useState
|
|
3
|
+
import { Component, createContext, createElement, memo, use, useCallback, useEffect, useState } from 'react';
|
|
4
4
|
import RSDWClient from 'react-server-dom-webpack/client';
|
|
5
5
|
import { encodeInput, encodeActionId } from './lib/renderers/utils.js';
|
|
6
6
|
const { createFromFetch, encodeReply } = RSDWClient;
|
|
@@ -62,10 +62,8 @@ const defaultFetchCache = {};
|
|
|
62
62
|
callServer: (actionId, args)=>callServerRSC(actionId, args, fetchCache)
|
|
63
63
|
});
|
|
64
64
|
fetchCache[ON_FETCH_DATA]?.(data);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
fetchCache[SET_ELEMENTS]?.((prev)=>mergeElements(prev, data));
|
|
68
|
-
});
|
|
65
|
+
// FIXME this causes rerenders even if data is empty
|
|
66
|
+
fetchCache[SET_ELEMENTS]?.((prev)=>mergeElements(prev, data));
|
|
69
67
|
return (await data)._value;
|
|
70
68
|
};
|
|
71
69
|
const prefetchedParams = new WeakMap();
|
|
@@ -126,9 +124,7 @@ export const Root = ({ initialInput, initialParams, fetchCache = defaultFetchCac
|
|
|
126
124
|
// clear cache entry before fetching
|
|
127
125
|
delete fetchCache[ENTRY];
|
|
128
126
|
const data = fetchRSC(input, params, fetchCache);
|
|
129
|
-
|
|
130
|
-
setElements((prev)=>mergeElements(prev, data));
|
|
131
|
-
});
|
|
127
|
+
setElements((prev)=>mergeElements(prev, data));
|
|
132
128
|
}, [
|
|
133
129
|
fetchCache
|
|
134
130
|
]);
|
|
@@ -2,8 +2,9 @@ import { Readable } from 'node:stream';
|
|
|
2
2
|
import { pipeline } from 'node:stream/promises';
|
|
3
3
|
import { build as buildVite, resolveConfig as resolveViteConfig } from 'vite';
|
|
4
4
|
import viteReact from '@vitejs/plugin-react';
|
|
5
|
+
import { unstable_getPlatformObject } from '../../server.js';
|
|
5
6
|
import { resolveConfig, EXTENSIONS } from '../config.js';
|
|
6
|
-
import { decodeFilePathFromAbsolute, extname, filePathToFileURL, fileURLToFilePath, joinPath } from '../utils/path.js';
|
|
7
|
+
import { decodeFilePathFromAbsolute, extname, filePathToFileURL, fileURLToFilePath, getPathMapping, joinPath } from '../utils/path.js';
|
|
7
8
|
import { appendFile, createWriteStream, existsSync, mkdir, readdir, readFile, rename, unlink, writeFile } from '../utils/node-fs.js';
|
|
8
9
|
import { encodeInput, generatePrefetchCode } from '../renderers/utils.js';
|
|
9
10
|
import { getBuildConfig, getSsrConfig, renderRsc, SERVER_MODULE_MAP } from '../renderers/rsc-renderer.js';
|
|
@@ -14,16 +15,16 @@ import { rscAnalyzePlugin } from '../plugins/vite-plugin-rsc-analyze.js';
|
|
|
14
15
|
import { nonjsResolvePlugin } from '../plugins/vite-plugin-nonjs-resolve.js';
|
|
15
16
|
import { rscTransformPlugin } from '../plugins/vite-plugin-rsc-transform.js';
|
|
16
17
|
import { rscEntriesPlugin } from '../plugins/vite-plugin-rsc-entries.js';
|
|
17
|
-
import { rscServePlugin } from '../plugins/vite-plugin-rsc-serve.js';
|
|
18
18
|
import { rscEnvPlugin } from '../plugins/vite-plugin-rsc-env.js';
|
|
19
19
|
import { rscPrivatePlugin } from '../plugins/vite-plugin-rsc-private.js';
|
|
20
20
|
import { rscManagedPlugin } from '../plugins/vite-plugin-rsc-managed.js';
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
21
|
+
import { DIST_ENTRIES_JS, DIST_PUBLIC, DIST_ASSETS, DIST_SSR } from './constants.js';
|
|
22
|
+
import { deployVercelPlugin } from '../plugins/vite-plugin-deploy-vercel.js';
|
|
23
|
+
import { deployNetlifyPlugin } from '../plugins/vite-plugin-deploy-netlify.js';
|
|
24
|
+
import { deployCloudflarePlugin } from '../plugins/vite-plugin-deploy-cloudflare.js';
|
|
25
|
+
import { deployDenoPlugin } from '../plugins/vite-plugin-deploy-deno.js';
|
|
26
|
+
import { deployPartykitPlugin } from '../plugins/vite-plugin-deploy-partykit.js';
|
|
27
|
+
import { deployAwsLambdaPlugin } from '../plugins/vite-plugin-deploy-aws-lambda.js';
|
|
27
28
|
// TODO this file and functions in it are too long. will fix.
|
|
28
29
|
// Upstream issue: https://github.com/rollup/rollup/issues/4699
|
|
29
30
|
const onwarn = (warning, defaultHandler)=>{
|
|
@@ -34,6 +35,14 @@ const onwarn = (warning, defaultHandler)=>{
|
|
|
34
35
|
}
|
|
35
36
|
defaultHandler(warning);
|
|
36
37
|
};
|
|
38
|
+
const deployPlugins = (config)=>[
|
|
39
|
+
deployVercelPlugin(config),
|
|
40
|
+
deployNetlifyPlugin(config),
|
|
41
|
+
deployCloudflarePlugin(config),
|
|
42
|
+
deployDenoPlugin(config),
|
|
43
|
+
deployPartykitPlugin(config),
|
|
44
|
+
deployAwsLambdaPlugin(config)
|
|
45
|
+
];
|
|
37
46
|
const analyzeEntries = async (rootDir, config)=>{
|
|
38
47
|
const wakuClientDist = decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), '../../../client.js'));
|
|
39
48
|
const clientFileSet = new Set([
|
|
@@ -131,7 +140,7 @@ const analyzeEntries = async (rootDir, config)=>{
|
|
|
131
140
|
};
|
|
132
141
|
};
|
|
133
142
|
// For RSC
|
|
134
|
-
const buildServerBundle = async (rootDir, env, config, clientEntryFiles, serverEntryFiles, serverModuleFiles,
|
|
143
|
+
const buildServerBundle = async (rootDir, env, config, clientEntryFiles, serverEntryFiles, serverModuleFiles, isNodeCompatible, partial)=>{
|
|
135
144
|
const serverBuildOutput = await buildVite({
|
|
136
145
|
plugins: [
|
|
137
146
|
nonjsResolvePlugin(),
|
|
@@ -174,15 +183,7 @@ const buildServerBundle = async (rootDir, env, config, clientEntryFiles, serverE
|
|
|
174
183
|
]))
|
|
175
184
|
}
|
|
176
185
|
}),
|
|
177
|
-
...
|
|
178
|
-
rscServePlugin({
|
|
179
|
-
...config,
|
|
180
|
-
distServeJs: DIST_SERVE_JS,
|
|
181
|
-
distPublic: DIST_PUBLIC,
|
|
182
|
-
srcServeFile: decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), `../serve-${serve}.js`)),
|
|
183
|
-
serve
|
|
184
|
-
})
|
|
185
|
-
] : []
|
|
186
|
+
...deployPlugins(config)
|
|
186
187
|
],
|
|
187
188
|
ssr: isNodeCompatible ? {
|
|
188
189
|
resolve: {
|
|
@@ -429,6 +430,29 @@ const pathSpec2pathname = (pathSpec)=>{
|
|
|
429
430
|
}
|
|
430
431
|
return '/' + pathSpec.map(({ name })=>name).join('/');
|
|
431
432
|
};
|
|
433
|
+
const willEmitPublicIndexHtml = async (env, config, distEntries, buildConfig)=>{
|
|
434
|
+
const hasConfig = buildConfig.some(({ pathname })=>{
|
|
435
|
+
const pathSpec = typeof pathname === 'string' ? pathname2pathSpec(pathname) : pathname;
|
|
436
|
+
return !!getPathMapping(pathSpec, '/');
|
|
437
|
+
});
|
|
438
|
+
if (!hasConfig) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
try {
|
|
442
|
+
return !!await getSsrConfig({
|
|
443
|
+
env,
|
|
444
|
+
config,
|
|
445
|
+
pathname: '/',
|
|
446
|
+
searchParams: new URLSearchParams()
|
|
447
|
+
}, {
|
|
448
|
+
isDev: false,
|
|
449
|
+
entries: distEntries
|
|
450
|
+
});
|
|
451
|
+
} catch {
|
|
452
|
+
// HACK to pass e2e tests
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
};
|
|
432
456
|
const emitHtmlFiles = async (rootDir, env, config, distEntriesFile, distEntries, buildConfig, getClientModules, clientBuildOutput)=>{
|
|
433
457
|
const nonJsAssets = clientBuildOutput.output.flatMap(({ type, fileName })=>type === 'asset' && !fileName.endsWith('.js') ? [
|
|
434
458
|
fileName
|
|
@@ -439,8 +463,7 @@ const emitHtmlFiles = async (rootDir, env, config, distEntriesFile, distEntries,
|
|
|
439
463
|
const publicIndexHtml = await readFile(publicIndexHtmlFile, {
|
|
440
464
|
encoding: 'utf8'
|
|
441
465
|
});
|
|
442
|
-
if (buildConfig
|
|
443
|
-
// Delete the default index.html file unless buildConfig is empty.
|
|
466
|
+
if (await willEmitPublicIndexHtml(env, config, distEntries, buildConfig)) {
|
|
444
467
|
await unlink(publicIndexHtmlFile);
|
|
445
468
|
}
|
|
446
469
|
const publicIndexHtmlHead = publicIndexHtml.replace(/.*?<head>(.*?)<\/head>.*/s, '$1');
|
|
@@ -525,16 +548,70 @@ export const publicIndexHtml = ${JSON.stringify(publicIndexHtml)};
|
|
|
525
548
|
`;
|
|
526
549
|
await appendFile(distEntriesFile, code);
|
|
527
550
|
};
|
|
551
|
+
// For Deploy
|
|
552
|
+
const buildDeploy = async (rootDir, config)=>{
|
|
553
|
+
const DUMMY = 'dummy-entry';
|
|
554
|
+
await buildVite({
|
|
555
|
+
plugins: [
|
|
556
|
+
{
|
|
557
|
+
// FIXME This is too hacky. There must be a better way.
|
|
558
|
+
name: 'dummy-entry-plugin',
|
|
559
|
+
resolveId (source) {
|
|
560
|
+
if (source === DUMMY) {
|
|
561
|
+
return source;
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
load (id) {
|
|
565
|
+
if (id === DUMMY) {
|
|
566
|
+
return '';
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
generateBundle (_options, bundle) {
|
|
570
|
+
Object.entries(bundle).forEach(([key, value])=>{
|
|
571
|
+
if (value.name === DUMMY) {
|
|
572
|
+
delete bundle[key];
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
...deployPlugins(config)
|
|
578
|
+
],
|
|
579
|
+
publicDir: false,
|
|
580
|
+
build: {
|
|
581
|
+
emptyOutDir: false,
|
|
582
|
+
ssr: true,
|
|
583
|
+
rollupOptions: {
|
|
584
|
+
onwarn: (warning, warn)=>{
|
|
585
|
+
if (!warning.message.startsWith('Generated an empty chunk:')) {
|
|
586
|
+
warn(warning);
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
input: {
|
|
590
|
+
[DUMMY]: DUMMY
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
outDir: joinPath(rootDir, config.distDir)
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
};
|
|
528
597
|
export async function build(options) {
|
|
529
598
|
const env = options.env || {};
|
|
530
599
|
const config = await resolveConfig(options.config);
|
|
531
600
|
const rootDir = (await resolveViteConfig({}, 'build', 'production', 'production')).root;
|
|
532
601
|
const distEntriesFile = joinPath(rootDir, config.distDir, DIST_ENTRIES_JS);
|
|
533
602
|
const isNodeCompatible = options.deploy !== 'cloudflare' && options.deploy !== 'partykit' && options.deploy !== 'deno';
|
|
603
|
+
const platformObject = unstable_getPlatformObject();
|
|
604
|
+
platformObject.buildOptions ||= {};
|
|
605
|
+
platformObject.buildOptions.deploy = options.deploy;
|
|
606
|
+
platformObject.buildOptions.unstable_phase = 'analyzeEntries';
|
|
534
607
|
const { clientEntryFiles, serverEntryFiles, serverModuleFiles } = await analyzeEntries(rootDir, config);
|
|
535
|
-
|
|
608
|
+
platformObject.buildOptions.unstable_phase = 'buildServerBundle';
|
|
609
|
+
const serverBuildOutput = await buildServerBundle(rootDir, env, config, clientEntryFiles, serverEntryFiles, serverModuleFiles, isNodeCompatible, !!options.partial);
|
|
610
|
+
platformObject.buildOptions.unstable_phase = 'buildSsrBundle';
|
|
536
611
|
await buildSsrBundle(rootDir, env, config, clientEntryFiles, serverEntryFiles, serverBuildOutput, isNodeCompatible, !!options.partial);
|
|
612
|
+
platformObject.buildOptions.unstable_phase = 'buildClientBundle';
|
|
537
613
|
const clientBuildOutput = await buildClientBundle(rootDir, env, config, clientEntryFiles, serverEntryFiles, serverBuildOutput, !!options.partial);
|
|
614
|
+
delete platformObject.buildOptions.unstable_phase;
|
|
538
615
|
const distEntries = await import(filePathToFileURL(distEntriesFile));
|
|
539
616
|
// TODO: Add progress indication for static builds.
|
|
540
617
|
const buildConfig = await getBuildConfig({
|
|
@@ -543,18 +620,10 @@ export async function build(options) {
|
|
|
543
620
|
}, {
|
|
544
621
|
entries: distEntries
|
|
545
622
|
});
|
|
546
|
-
await appendFile(distEntriesFile, `export const buildConfig = ${JSON.stringify(buildConfig)};`);
|
|
547
623
|
const { getClientModules } = await emitRscFiles(rootDir, env, config, distEntries, buildConfig);
|
|
548
624
|
await emitHtmlFiles(rootDir, env, config, distEntriesFile, distEntries, buildConfig, getClientModules, clientBuildOutput);
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
} else if (options.deploy === 'cloudflare') {
|
|
554
|
-
await emitCloudflareOutput(rootDir, config, DIST_SERVE_JS);
|
|
555
|
-
} else if (options.deploy === 'partykit') {
|
|
556
|
-
await emitPartyKitOutput(rootDir, config, DIST_SERVE_JS);
|
|
557
|
-
} else if (options.deploy === 'aws-lambda') {
|
|
558
|
-
await emitAwsLambdaOutput(config);
|
|
559
|
-
}
|
|
625
|
+
platformObject.buildOptions.unstable_phase = 'buildDeploy';
|
|
626
|
+
await buildDeploy(rootDir, config);
|
|
627
|
+
delete platformObject.buildOptions.unstable_phase;
|
|
628
|
+
await appendFile(distEntriesFile, `export const buildData = ${JSON.stringify(platformObject.buildData)};`);
|
|
560
629
|
}
|
|
@@ -127,15 +127,17 @@ const createMainViteServer = (env, configPromise)=>{
|
|
|
127
127
|
return vite;
|
|
128
128
|
});
|
|
129
129
|
const loadServerModuleMain = async (idOrFileURL)=>{
|
|
130
|
+
const vite = await vitePromise;
|
|
130
131
|
if (idOrFileURL === 'waku' || idOrFileURL.startsWith('waku/')) {
|
|
131
132
|
// HACK `external: ['waku']` doesn't do the same
|
|
132
133
|
return import(/* @vite-ignore */ idOrFileURL);
|
|
133
134
|
}
|
|
134
135
|
if (idOrFileURL.startsWith('file://') && idOrFileURL.includes('/node_modules/')) {
|
|
135
136
|
// HACK node_modules should be externalized
|
|
136
|
-
|
|
137
|
+
const file = fileURLToFilePath(idOrFileURL);
|
|
138
|
+
const fileWithAbsolutePath = file.startsWith('/') ? file : joinPath(vite.config.root, file);
|
|
139
|
+
return import(/* @vite-ignore */ fileWithAbsolutePath);
|
|
137
140
|
}
|
|
138
|
-
const vite = await vitePromise;
|
|
139
141
|
return vite.ssrLoadModule(idOrFileURL.startsWith('file://') ? fileURLToFilePath(idOrFileURL) : idOrFileURL);
|
|
140
142
|
};
|
|
141
143
|
const transformIndexHtml = async (pathname)=>{
|
|
@@ -15,7 +15,7 @@ export const rsc = (options)=>{
|
|
|
15
15
|
if (ctx.req.url.pathname.startsWith(basePrefix)) {
|
|
16
16
|
const { headers } = ctx.req;
|
|
17
17
|
try {
|
|
18
|
-
const input = decodeInput(ctx.req.url.pathname.slice(basePrefix.length));
|
|
18
|
+
const input = decodeInput(decodeURI(ctx.req.url.pathname.slice(basePrefix.length)));
|
|
19
19
|
const args = {
|
|
20
20
|
env,
|
|
21
21
|
config,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { normalizePath } from 'vite';
|
|
4
|
+
// HACK: Depending on a different plugin isn't ideal.
|
|
5
|
+
// Maybe we could put in vite config object?
|
|
6
|
+
import { SRC_ENTRIES } from './vite-plugin-rsc-managed.js';
|
|
7
|
+
import { unstable_getPlatformObject } from '../../server.js';
|
|
8
|
+
import { EXTENSIONS } from '../config.js';
|
|
9
|
+
import { decodeFilePathFromAbsolute, extname, fileURLToFilePath, joinPath } from '../utils/path.js';
|
|
10
|
+
import { DIST_SERVE_JS, DIST_PUBLIC } from '../builder/constants.js';
|
|
11
|
+
const resolveFileName = (fname)=>{
|
|
12
|
+
for (const ext of EXTENSIONS){
|
|
13
|
+
const resolvedName = fname.slice(0, -extname(fname).length) + ext;
|
|
14
|
+
if (existsSync(resolvedName)) {
|
|
15
|
+
return resolvedName;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return fname; // returning the default one
|
|
19
|
+
};
|
|
20
|
+
const srcServeFile = decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), '../../builder/serve-aws-lambda.js'));
|
|
21
|
+
export function deployAwsLambdaPlugin(opts) {
|
|
22
|
+
const platformObject = unstable_getPlatformObject();
|
|
23
|
+
return {
|
|
24
|
+
name: 'deploy-aws-lambda-plugin',
|
|
25
|
+
config (viteConfig) {
|
|
26
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
27
|
+
if (unstable_phase !== 'buildServerBundle' || deploy !== 'aws-lambda') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// FIXME This seems too hacky (The use of viteConfig.root, '.', path.resolve and resolveFileName)
|
|
31
|
+
const entriesFile = normalizePath(resolveFileName(path.resolve(viteConfig.root || '.', opts.srcDir, SRC_ENTRIES + '.jsx')));
|
|
32
|
+
const { input } = viteConfig.build?.rollupOptions ?? {};
|
|
33
|
+
if (input && !(typeof input === 'string') && !(input instanceof Array)) {
|
|
34
|
+
input[DIST_SERVE_JS.replace(/\.js$/, '')] = srcServeFile;
|
|
35
|
+
}
|
|
36
|
+
viteConfig.define = {
|
|
37
|
+
...viteConfig.define,
|
|
38
|
+
'import.meta.env.WAKU_ENTRIES_FILE': JSON.stringify(entriesFile),
|
|
39
|
+
'import.meta.env.WAKU_CONFIG_PUBLIC_DIR': JSON.stringify(DIST_PUBLIC)
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
closeBundle () {
|
|
43
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
44
|
+
if (unstable_phase !== 'buildDeploy' || deploy !== 'aws-lambda') {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
writeFileSync(path.join(opts.distDir, 'package.json'), JSON.stringify({
|
|
48
|
+
type: 'module'
|
|
49
|
+
}, null, 2));
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { normalizePath } from 'vite';
|
|
4
|
+
// HACK: Depending on a different plugin isn't ideal.
|
|
5
|
+
// Maybe we could put in vite config object?
|
|
6
|
+
import { SRC_ENTRIES } from './vite-plugin-rsc-managed.js';
|
|
7
|
+
import { unstable_getPlatformObject } from '../../server.js';
|
|
8
|
+
import { EXTENSIONS } from '../config.js';
|
|
9
|
+
import { decodeFilePathFromAbsolute, extname, fileURLToFilePath, joinPath } from '../utils/path.js';
|
|
10
|
+
import { DIST_SERVE_JS, DIST_PUBLIC } from '../builder/constants.js';
|
|
11
|
+
const resolveFileName = (fname)=>{
|
|
12
|
+
for (const ext of EXTENSIONS){
|
|
13
|
+
const resolvedName = fname.slice(0, -extname(fname).length) + ext;
|
|
14
|
+
if (existsSync(resolvedName)) {
|
|
15
|
+
return resolvedName;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return fname; // returning the default one
|
|
19
|
+
};
|
|
20
|
+
const srcServeFile = decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), '../../builder/serve-cloudflare.js'));
|
|
21
|
+
const getFiles = (dir, files = [])=>{
|
|
22
|
+
const entries = readdirSync(dir, {
|
|
23
|
+
withFileTypes: true
|
|
24
|
+
});
|
|
25
|
+
for (const entry of entries){
|
|
26
|
+
const fullPath = path.join(dir, entry.name);
|
|
27
|
+
if (entry.isDirectory()) {
|
|
28
|
+
getFiles(fullPath, files);
|
|
29
|
+
} else {
|
|
30
|
+
files.push(fullPath);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return files;
|
|
34
|
+
};
|
|
35
|
+
const WORKER_JS_NAME = '_worker.js';
|
|
36
|
+
const ROUTES_JSON_NAME = '_routes.json';
|
|
37
|
+
const HEADERS_NAME = '_headers';
|
|
38
|
+
export function deployCloudflarePlugin(opts) {
|
|
39
|
+
const platformObject = unstable_getPlatformObject();
|
|
40
|
+
let rootDir;
|
|
41
|
+
return {
|
|
42
|
+
name: 'deploy-cloudflare-plugin',
|
|
43
|
+
config (viteConfig) {
|
|
44
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
45
|
+
if (unstable_phase !== 'buildServerBundle' || deploy !== 'cloudflare') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// FIXME This seems too hacky (The use of viteConfig.root, '.', path.resolve and resolveFileName)
|
|
49
|
+
const entriesFile = normalizePath(resolveFileName(path.resolve(viteConfig.root || '.', opts.srcDir, SRC_ENTRIES + '.jsx')));
|
|
50
|
+
const { input } = viteConfig.build?.rollupOptions ?? {};
|
|
51
|
+
if (input && !(typeof input === 'string') && !(input instanceof Array)) {
|
|
52
|
+
input[DIST_SERVE_JS.replace(/\.js$/, '')] = srcServeFile;
|
|
53
|
+
}
|
|
54
|
+
viteConfig.define = {
|
|
55
|
+
...viteConfig.define,
|
|
56
|
+
'import.meta.env.WAKU_ENTRIES_FILE': JSON.stringify(entriesFile)
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
configResolved (config) {
|
|
60
|
+
rootDir = config.root;
|
|
61
|
+
},
|
|
62
|
+
closeBundle () {
|
|
63
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
64
|
+
if (unstable_phase !== 'buildDeploy' || deploy !== 'cloudflare') {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const outDir = path.join(rootDir, opts.distDir);
|
|
68
|
+
// Advanced-mode Cloudflare Pages imports _worker.js
|
|
69
|
+
// and can be configured with _routes.json to serve other static root files
|
|
70
|
+
mkdirSync(path.join(outDir, WORKER_JS_NAME));
|
|
71
|
+
const outPaths = readdirSync(outDir);
|
|
72
|
+
for (const p of outPaths){
|
|
73
|
+
if (p === WORKER_JS_NAME) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
renameSync(path.join(outDir, p), path.join(outDir, WORKER_JS_NAME, p));
|
|
77
|
+
}
|
|
78
|
+
const workerEntrypoint = path.join(outDir, WORKER_JS_NAME, 'index.js');
|
|
79
|
+
if (!existsSync(workerEntrypoint)) {
|
|
80
|
+
writeFileSync(workerEntrypoint, `
|
|
81
|
+
import server from './${DIST_SERVE_JS}'
|
|
82
|
+
|
|
83
|
+
export default {
|
|
84
|
+
...server
|
|
85
|
+
}
|
|
86
|
+
`);
|
|
87
|
+
}
|
|
88
|
+
// Create _routes.json if one doesn't already exist in the public dir
|
|
89
|
+
// https://developers.cloudflare.com/pages/functions/routing/#functions-invocation-routes
|
|
90
|
+
const routesFile = path.join(outDir, ROUTES_JSON_NAME);
|
|
91
|
+
const publicDir = path.join(outDir, WORKER_JS_NAME, DIST_PUBLIC);
|
|
92
|
+
if (!existsSync(path.join(publicDir, ROUTES_JSON_NAME))) {
|
|
93
|
+
// exclude strategy
|
|
94
|
+
const staticPaths = [
|
|
95
|
+
'/assets/*'
|
|
96
|
+
];
|
|
97
|
+
const paths = getFiles(publicDir);
|
|
98
|
+
for (const p of paths){
|
|
99
|
+
const basePath = path.dirname(p.replace(publicDir, '')) || '/';
|
|
100
|
+
const name = path.basename(p);
|
|
101
|
+
const entry = name === 'index.html' ? basePath + (basePath !== '/' ? '/' : '') : path.join(basePath, name.replace(/\.html$/, ''));
|
|
102
|
+
if (entry.startsWith('/assets/') || entry.startsWith('/' + WORKER_JS_NAME + '/') || entry === '/' + WORKER_JS_NAME || entry === '/' + ROUTES_JSON_NAME || entry === '/' + HEADERS_NAME) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!staticPaths.includes(entry)) {
|
|
106
|
+
staticPaths.push(entry);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const MAX_CLOUDFLARE_RULES = 100;
|
|
110
|
+
if (staticPaths.length + 1 > MAX_CLOUDFLARE_RULES) {
|
|
111
|
+
throw new Error(`The number of static paths exceeds the limit of ${MAX_CLOUDFLARE_RULES}. ` + `You need to create a custom ${ROUTES_JSON_NAME} file in the public folder. ` + `See https://developers.cloudflare.com/pages/functions/routing/#functions-invocation-routes`);
|
|
112
|
+
}
|
|
113
|
+
const staticRoutes = {
|
|
114
|
+
version: 1,
|
|
115
|
+
include: [
|
|
116
|
+
'/*'
|
|
117
|
+
],
|
|
118
|
+
exclude: staticPaths
|
|
119
|
+
};
|
|
120
|
+
writeFileSync(routesFile, JSON.stringify(staticRoutes));
|
|
121
|
+
}
|
|
122
|
+
// Move the public files to the root of the dist folder
|
|
123
|
+
const publicPaths = readdirSync(path.join(outDir, WORKER_JS_NAME, DIST_PUBLIC));
|
|
124
|
+
for (const p of publicPaths){
|
|
125
|
+
renameSync(path.join(outDir, WORKER_JS_NAME, DIST_PUBLIC, p), path.join(outDir, p));
|
|
126
|
+
}
|
|
127
|
+
rmSync(path.join(outDir, WORKER_JS_NAME, DIST_PUBLIC), {
|
|
128
|
+
recursive: true,
|
|
129
|
+
force: true
|
|
130
|
+
});
|
|
131
|
+
const wranglerTomlFile = path.join(rootDir, 'wrangler.toml');
|
|
132
|
+
if (!existsSync(wranglerTomlFile)) {
|
|
133
|
+
writeFileSync(wranglerTomlFile, `
|
|
134
|
+
# See https://developers.cloudflare.com/pages/functions/wrangler-configuration/
|
|
135
|
+
name = "waku-project"
|
|
136
|
+
compatibility_date = "2024-04-03"
|
|
137
|
+
compatibility_flags = [ "nodejs_als" ]
|
|
138
|
+
pages_build_output_dir = "./dist"
|
|
139
|
+
`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
3
|
import { normalizePath } from 'vite';
|
|
4
4
|
// HACK: Depending on a different plugin isn't ideal.
|
|
5
5
|
// Maybe we could put in vite config object?
|
|
6
6
|
import { SRC_ENTRIES } from './vite-plugin-rsc-managed.js';
|
|
7
|
+
import { unstable_getPlatformObject } from '../../server.js';
|
|
7
8
|
import { EXTENSIONS } from '../config.js';
|
|
8
|
-
import { extname } from '../utils/path.js';
|
|
9
|
+
import { decodeFilePathFromAbsolute, extname, fileURLToFilePath, joinPath } from '../utils/path.js';
|
|
10
|
+
import { DIST_SERVE_JS, DIST_PUBLIC } from '../builder/constants.js';
|
|
9
11
|
const resolveFileName = (fname)=>{
|
|
10
12
|
for (const ext of EXTENSIONS){
|
|
11
13
|
const resolvedName = fname.slice(0, -extname(fname).length) + ext;
|
|
@@ -15,32 +17,28 @@ const resolveFileName = (fname)=>{
|
|
|
15
17
|
}
|
|
16
18
|
return fname; // returning the default one
|
|
17
19
|
};
|
|
18
|
-
|
|
20
|
+
const srcServeFile = decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), '../../builder/serve-deno.js'));
|
|
21
|
+
export function deployDenoPlugin(opts) {
|
|
22
|
+
const platformObject = unstable_getPlatformObject();
|
|
19
23
|
return {
|
|
20
|
-
name: '
|
|
24
|
+
name: 'deploy-deno-plugin',
|
|
21
25
|
config (viteConfig) {
|
|
26
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
27
|
+
if (unstable_phase !== 'buildServerBundle' || deploy !== 'deno') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
22
30
|
// FIXME This seems too hacky (The use of viteConfig.root, '.', path.resolve and resolveFileName)
|
|
23
31
|
const entriesFile = normalizePath(resolveFileName(path.resolve(viteConfig.root || '.', opts.srcDir, SRC_ENTRIES + '.jsx')));
|
|
24
32
|
const { input } = viteConfig.build?.rollupOptions ?? {};
|
|
25
33
|
if (input && !(typeof input === 'string') && !(input instanceof Array)) {
|
|
26
|
-
input[
|
|
34
|
+
input[DIST_SERVE_JS.replace(/\.js$/, '')] = srcServeFile;
|
|
27
35
|
}
|
|
28
36
|
viteConfig.define = {
|
|
29
37
|
...viteConfig.define,
|
|
30
38
|
'import.meta.env.WAKU_ENTRIES_FILE': JSON.stringify(entriesFile),
|
|
31
39
|
'import.meta.env.WAKU_CONFIG_DIST_DIR': JSON.stringify(opts.distDir),
|
|
32
|
-
'import.meta.env.WAKU_CONFIG_PUBLIC_DIR': JSON.stringify(
|
|
40
|
+
'import.meta.env.WAKU_CONFIG_PUBLIC_DIR': JSON.stringify(DIST_PUBLIC)
|
|
33
41
|
};
|
|
34
|
-
if (opts.serve === 'partykit') {
|
|
35
|
-
viteConfig.build ||= {};
|
|
36
|
-
viteConfig.build.rollupOptions ||= {};
|
|
37
|
-
viteConfig.build.rollupOptions.external ||= [];
|
|
38
|
-
if (Array.isArray(viteConfig.build.rollupOptions.external)) {
|
|
39
|
-
viteConfig.build.rollupOptions.external.push('hono');
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error('Unsupported: build.rollupOptions.external is not an array');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
42
|
}
|
|
45
43
|
};
|
|
46
44
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { normalizePath } from 'vite';
|
|
4
|
+
// HACK: Depending on a different plugin isn't ideal.
|
|
5
|
+
// Maybe we could put in vite config object?
|
|
6
|
+
import { SRC_ENTRIES } from './vite-plugin-rsc-managed.js';
|
|
7
|
+
import { unstable_getPlatformObject } from '../../server.js';
|
|
8
|
+
import { EXTENSIONS } from '../config.js';
|
|
9
|
+
import { decodeFilePathFromAbsolute, extname, fileURLToFilePath, joinPath } from '../utils/path.js';
|
|
10
|
+
import { DIST_SERVE_JS, DIST_PUBLIC } from '../builder/constants.js';
|
|
11
|
+
const resolveFileName = (fname)=>{
|
|
12
|
+
for (const ext of EXTENSIONS){
|
|
13
|
+
const resolvedName = fname.slice(0, -extname(fname).length) + ext;
|
|
14
|
+
if (existsSync(resolvedName)) {
|
|
15
|
+
return resolvedName;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return fname; // returning the default one
|
|
19
|
+
};
|
|
20
|
+
const srcServeFile = decodeFilePathFromAbsolute(joinPath(fileURLToFilePath(import.meta.url), '../../builder/serve-netlify.js'));
|
|
21
|
+
export function deployNetlifyPlugin(opts) {
|
|
22
|
+
const platformObject = unstable_getPlatformObject();
|
|
23
|
+
let rootDir;
|
|
24
|
+
return {
|
|
25
|
+
name: 'deploy-netlify-plugin',
|
|
26
|
+
config (viteConfig) {
|
|
27
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
28
|
+
if (unstable_phase !== 'buildServerBundle' || deploy !== 'netlify-functions' && deploy !== 'netlify-static') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// FIXME This seems too hacky (The use of viteConfig.root, '.', path.resolve and resolveFileName)
|
|
32
|
+
const entriesFile = normalizePath(resolveFileName(path.resolve(viteConfig.root || '.', opts.srcDir, SRC_ENTRIES + '.jsx')));
|
|
33
|
+
const { input } = viteConfig.build?.rollupOptions ?? {};
|
|
34
|
+
if (input && !(typeof input === 'string') && !(input instanceof Array)) {
|
|
35
|
+
input[DIST_SERVE_JS.replace(/\.js$/, '')] = srcServeFile;
|
|
36
|
+
}
|
|
37
|
+
viteConfig.define = {
|
|
38
|
+
...viteConfig.define,
|
|
39
|
+
'import.meta.env.WAKU_ENTRIES_FILE': JSON.stringify(entriesFile)
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
configResolved (config) {
|
|
43
|
+
rootDir = config.root;
|
|
44
|
+
},
|
|
45
|
+
closeBundle () {
|
|
46
|
+
const { deploy, unstable_phase } = platformObject.buildOptions || {};
|
|
47
|
+
if (unstable_phase !== 'buildDeploy' || deploy !== 'netlify-functions' && deploy !== 'netlify-static') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (deploy === 'netlify-functions') {
|
|
51
|
+
const functionsDir = path.join(rootDir, 'netlify/functions');
|
|
52
|
+
mkdirSync(functionsDir, {
|
|
53
|
+
recursive: true
|
|
54
|
+
});
|
|
55
|
+
const notFoundFile = path.join(rootDir, opts.distDir, DIST_PUBLIC, '404.html');
|
|
56
|
+
const notFoundHtml = existsSync(notFoundFile) ? readFileSync(notFoundFile, 'utf8') : null;
|
|
57
|
+
writeFileSync(path.join(functionsDir, 'serve.js'), `
|
|
58
|
+
globalThis.__WAKU_NOT_FOUND_HTML__ = ${JSON.stringify(notFoundHtml)};
|
|
59
|
+
export { default } from '../../${opts.distDir}/${DIST_SERVE_JS}';
|
|
60
|
+
export const config = {
|
|
61
|
+
preferStatic: true,
|
|
62
|
+
path: ['/', '/*'],
|
|
63
|
+
};
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
const netlifyTomlFile = path.join(rootDir, 'netlify.toml');
|
|
67
|
+
if (!existsSync(netlifyTomlFile)) {
|
|
68
|
+
writeFileSync(netlifyTomlFile, `
|
|
69
|
+
[build]
|
|
70
|
+
command = "npm run build -- --with-netlify"
|
|
71
|
+
publish = "${opts.distDir}/${DIST_PUBLIC}"
|
|
72
|
+
[functions]
|
|
73
|
+
included_files = ["${opts.privateDir}/**"]
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|