Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into breaking/unify-root…
Browse files Browse the repository at this point in the history
…-path
  • Loading branch information
Aslemammad committed Dec 5, 2023
2 parents a031c46 + 990ff13 commit 2f62b9d
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 182 deletions.
2 changes: 1 addition & 1 deletion e2e/fixtures/rsc-basic/src/components/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PropsWithChildren, HTMLAttributes } from 'react';
import type { PropsWithChildren, HTMLAttributes } from 'react';

export const ServerBox = ({
children,
Expand Down
3 changes: 2 additions & 1 deletion e2e/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import net from 'node:net';
import { ConsoleMessage, test as basicTest } from '@playwright/test';
import { test as basicTest } from '@playwright/test';
import type { ConsoleMessage } from '@playwright/test';

export async function getFreePort(): Promise<number> {
return new Promise<number>((res) => {
Expand Down
6 changes: 4 additions & 2 deletions packages/waku/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,16 @@ type DeepRequired<T> = T extends (...args: any[]) => any
export type ResolvedConfig = DeepRequired<Config>;

export const loadConfig = async () => {
const [fs, path] = await Promise.all([
const [fs, path, url] = await Promise.all([
import('node:fs'),
import('node:path'),
import('node:url'),
]);
for (const file of ['waku.config.ts', 'waku.config.js']) {
if (fs.existsSync(file)) {
// XXX no schema check
return (await import(path.resolve(file))).default;
return (await import(url.pathToFileURL(path.resolve(file)).toString()))
.default;
}
}
return {};
Expand Down
71 changes: 39 additions & 32 deletions packages/waku/src/lib/builder.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
import path from 'node:path';
import {
createReadStream,
createWriteStream,
existsSync,
mkdirSync,
readdirSync,
symlinkSync,
writeFileSync,
} from 'node:fs';
import fsPromises from 'node:fs/promises';
import { createHash } from 'node:crypto';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
Expand All @@ -19,7 +8,17 @@ import type { RollupLog, LoggingFunction } from 'rollup';

import type { Config, ResolvedConfig } from '../config.js';
import { resolveConfig, viteInlineConfig } from './config.js';
import { normalizePath } from './utils/path.js';
import { joinPath, extname, dirname } from './utils/path.js';
import {
createReadStream,
createWriteStream,
existsSync,
rename,
mkdir,
readFile,
writeFile,
rmdir,
} from './utils/node-fs.js';
import { encodeInput, generatePrefetchCode } from './middleware/rsc/utils.js';
import { renderRSC, getBuildConfigRSC } from './rsc/renderer.js';
import { rscIndexPlugin } from './vite-plugin/rsc-index-plugin.js';
Expand Down Expand Up @@ -130,7 +129,7 @@ const buildServerBundle = async (
build: {
ssr: true,
ssrEmitAssets: true,
outDir: path.join(config.rootDir, config.distDir),
outDir: joinPath(config.rootDir, config.distDir),
rollupOptions: {
onwarn,
input: {
Expand Down Expand Up @@ -169,7 +168,7 @@ const buildClientBundle = async (
clientEntryFiles: Record<string, string>,
serverBuildOutput: Awaited<ReturnType<typeof buildServerBundle>>,
) => {
const indexHtmlFile = path.join(
const indexHtmlFile = joinPath(
config.rootDir,
config.srcDir,
config.indexHtml,
Expand All @@ -181,7 +180,7 @@ const buildClientBundle = async (
...(await viteInlineConfig()),
plugins: [patchReactRefresh(viteReact()), rscIndexPlugin(cssAssets)],
build: {
outDir: path.join(config.rootDir, config.distDir, config.publicDir),
outDir: joinPath(config.rootDir, config.distDir, config.publicDir),
rollupOptions: {
onwarn,
input: {
Expand Down Expand Up @@ -215,14 +214,14 @@ const buildClientBundle = async (
throw new Error('Unexpected vite client build output');
}
for (const cssAsset of cssAssets) {
const from = path.join(config.rootDir, config.distDir, cssAsset);
const to = path.join(
const from = joinPath(config.rootDir, config.distDir, cssAsset);
const to = joinPath(
config.rootDir,
config.distDir,
config.publicDir,
cssAsset,
);
await fsPromises.rename(from, to);
await rename(from, to);
}
return clientBuildOutput;
};
Expand All @@ -246,16 +245,19 @@ const emitRscFiles = async (config: ResolvedConfig) => {
await Promise.all(
Object.entries(buildConfig).map(async ([, { entries, context }]) => {
for (const [input] of entries || []) {
const destFile = path.join(
const destFile = joinPath(
config.rootDir,
config.distDir,
config.publicDir,
config.rscPath,
encodeInput(normalizePath(input)),
encodeInput(
// Should we do this here? Or waku/router or in entries.ts?
input.split('\\').join('/'),
),
);
if (!rscFileSet.has(destFile)) {
rscFileSet.add(destFile);
await fsPromises.mkdir(path.dirname(destFile), { recursive: true });
await mkdir(joinPath(destFile, '..'), { recursive: true });
const readable = await renderRSC({
input,
method: 'GET',
Expand Down Expand Up @@ -283,29 +285,29 @@ const emitHtmlFiles = async (
ssr: boolean,
) => {
const basePrefix = config.basePath + config.rscPath + '/';
const publicIndexHtmlFile = path.join(
const publicIndexHtmlFile = joinPath(
config.rootDir,
config.distDir,
config.publicDir,
config.srcDir,
config.indexHtml,
);
const publicIndexHtml = await fsPromises.readFile(publicIndexHtmlFile, {
const publicIndexHtml = await readFile(publicIndexHtmlFile, {
encoding: 'utf8',
});

// https://github.com/dai-shi/waku/pull/181#discussion_r1412744262
await fsPromises.rmdir(path.dirname(publicIndexHtmlFile));
await rmdir(dirname(publicIndexHtmlFile));
clientBuildOutput.output.splice(
clientBuildOutput.output.findIndex(
(v) => v.fileName === path.join(config.srcDir, config.indexHtml),
(v) => v.fileName === joinPath(config.srcDir, config.indexHtml),
),
1,
);
const htmlFiles = await Promise.all(
Object.entries(buildConfig).map(
async ([pathStr, { entries, customCode, context }]) => {
const destFile = path.join(
const destFile = joinPath(
config.rootDir,
config.distDir,
config.publicDir,
Expand All @@ -314,9 +316,9 @@ const emitHtmlFiles = async (
);
let htmlStr: string;
if (existsSync(destFile)) {
htmlStr = await fsPromises.readFile(destFile, { encoding: 'utf8' });
htmlStr = await readFile(destFile, { encoding: 'utf8' });
} else {
await fsPromises.mkdir(path.dirname(destFile), { recursive: true });
await mkdir(joinPath(destFile, '..'), { recursive: true });
htmlStr = publicIndexHtml;
}
const inputsForPrefetch = new Set<string>();
Expand Down Expand Up @@ -351,7 +353,7 @@ const emitHtmlFiles = async (
createWriteStream(destFile),
);
} else {
await fsPromises.writeFile(destFile, htmlStr);
await writeFile(destFile, htmlStr);
}
return destFile;
},
Expand All @@ -360,12 +362,17 @@ const emitHtmlFiles = async (
return { htmlFiles };
};

const emitVercelOutput = (
const emitVercelOutput = async (
config: ResolvedConfig,
clientBuildOutput: Awaited<ReturnType<typeof buildClientBundle>>,
rscFiles: string[],
htmlFiles: string[],
) => {
// FIXME somehow utils/(path,node-fs).ts doesn't work
const [
path,
{ existsSync, mkdirSync, readdirSync, symlinkSync, writeFileSync },
] = await Promise.all([import('node:path'), import('node:fs')]);
const clientFiles = clientBuildOutput.output.map(({ fileName }) =>
path.join(config.rootDir, config.distDir, config.publicDir, fileName),
);
Expand Down Expand Up @@ -455,7 +462,7 @@ export default async function handler(req, res) {

const resolveFileName = (fname: string) => {
for (const ext of ['.js', '.ts', '.tsx', '.jsx']) {
const resolvedName = fname.slice(0, -path.extname(fname).length) + ext;
const resolvedName = fname.slice(0, -extname(fname).length) + ext;
if (existsSync(resolvedName)) {
return resolvedName;
}
Expand All @@ -466,7 +473,7 @@ const resolveFileName = (fname: string) => {
export async function build(options: { config: Config; ssr?: boolean }) {
const config = await resolveConfig(options.config);
const entriesFile = resolveFileName(
path.join(config.rootDir, config.srcDir, config.entriesJs),
joinPath(config.rootDir, config.srcDir, config.entriesJs),
);

const { commonEntryFiles, clientEntryFiles, serverEntryFiles } =
Expand Down
24 changes: 12 additions & 12 deletions packages/waku/src/lib/middleware/rsc.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import path from 'node:path'; // TODO no node dependency
import fsPromises from 'node:fs/promises'; // TODO no node dependency
import type { ViteDevServer } from 'vite';

import type { Config } from '../../config.js';
import { resolveConfig } from '../config.js';
import { joinPath } from '../utils/path.js';
import { readFile, stat } from '../utils/node-fs.js'; // TODO no node dependency
import { endStream } from '../utils/stream.js';
import { renderHtml } from './rsc/ssr.js';
import { decodeInput, hasStatusCode, deepFreeze } from './rsc/utils.js';
Expand Down Expand Up @@ -74,27 +74,27 @@ export function rsc<
const getHtmlStr = async (pathStr: string): Promise<string | null> => {
const config = await configPromise;
if (!publicIndexHtml) {
const publicIndexHtmlFile = path.join(
const publicIndexHtmlFile = joinPath(
config.rootDir,
command === 'dev'
? config.srcDir
: path.join(config.distDir, config.publicDir),
...(command === 'dev'
? [config.srcDir]
: [config.distDir, config.publicDir]),
config.indexHtml,
);
publicIndexHtml = await fsPromises.readFile(publicIndexHtmlFile, {
publicIndexHtml = await readFile(publicIndexHtmlFile, {
encoding: 'utf8',
});
}
if (command === 'start') {
const destFile = path.join(
const destFile = joinPath(
config.rootDir,
config.distDir,
config.publicDir,
pathStr,
pathStr.endsWith('/') ? 'index.html' : '',
);
try {
return await fsPromises.readFile(destFile, { encoding: 'utf8' });
return await readFile(destFile, { encoding: 'utf8' });
} catch (e) {
return publicIndexHtml;
}
Expand All @@ -106,10 +106,10 @@ export function rsc<
return null;
}
}
const destFile = path.join(config.rootDir, config.srcDir, pathStr);
const destFile = joinPath(config.rootDir, config.srcDir, pathStr);
try {
// check if exists?
const stats = await fsPromises.stat(destFile);
const stats = await stat(destFile);
if (stats.isFile()) {
return null;
}
Expand Down Expand Up @@ -226,7 +226,7 @@ export function rsc<
// HACK re-export "?v=..." URL to avoid dual module hazard.
const fname = pathStr.startsWith(config.basePath + '@fs/')
? pathStr.slice(config.basePath.length + 3)
: path.join(vite.config.root, pathStr);
: joinPath(vite.config.root, pathStr);
for (const item of vite.moduleGraph.idToModuleMap.values()) {
if (
item.file === fname &&
Expand Down
Loading

0 comments on commit 2f62b9d

Please sign in to comment.