Skip to content

Commit

Permalink
feat: use undici as fetch polyfill
Browse files Browse the repository at this point in the history
feat: use native node web stream
  • Loading branch information
jacob-ebey committed Mar 22, 2024
1 parent 964a94d commit 1e767c1
Show file tree
Hide file tree
Showing 19 changed files with 92 additions and 138 deletions.
5 changes: 0 additions & 5 deletions jest/jest.config.shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ const ignorePatterns = [
/** @type {import('jest').Config} */
module.exports = {
moduleNameMapper: {
"^@remix-run/web-blob$": require.resolve("@remix-run/web-blob"),
"^@remix-run/web-fetch$": require.resolve("@remix-run/web-fetch"),
"^@remix-run/web-file": require.resolve("@remix-run/web-file"),
"^@remix-run/web-form-data$": require.resolve("@remix-run/web-form-data"),
"^@remix-run/web-stream$": require.resolve("@remix-run/web-stream"),
"^@web3-storage/multipart-parser$": require.resolve(
"@web3-storage/multipart-parser"
),
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
"@remix-run/css-bundle": "workspace:*",
"@remix-run/dev": "workspace:*",
"@remix-run/node": "workspace:*",
"@remix-run/web-fetch": "^4.4.2",
"@remix-run/react": "workspace:*",
"@remix-run/testing": "workspace:*",
"@rollup/plugin-babel": "^5.2.2",
Expand Down
17 changes: 5 additions & 12 deletions packages/create-remix/copy-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,12 @@ import fs from "node:fs";
import path from "node:path";
import stream from "node:stream";
import { promisify } from "node:util";
import { fetch } from "@remix-run/web-fetch";
import gunzip from "gunzip-maybe";
import tar from "tar-fs";
import { ProxyAgent } from "proxy-agent";
import { fetch } from "undici";

import { color, isUrl } from "./utils";

const defaultAgent = new ProxyAgent();
const httpsAgent = new ProxyAgent();
httpsAgent.protocol = "https:";
function agent(url: string) {
return new URL(url).protocol === "https:" ? httpsAgent : defaultAgent;
}

export async function copyTemplate(
template: string,
destPath: string,
Expand Down Expand Up @@ -235,7 +227,6 @@ async function downloadAndExtractTarball(
: `https://api.github.com/repos/${info.owner}/${info.name}/releases/tags/${info.tag}`;

let response = await fetch(releaseUrl, {
agent: agent("https://api.github.com"),
headers,
});

Expand Down Expand Up @@ -275,7 +266,6 @@ async function downloadAndExtractTarball(
headers.Accept = "application/octet-stream";
}
let response = await fetch(resourceUrl, {
agent: agent(resourceUrl),
headers,
});

Expand Down Expand Up @@ -307,7 +297,10 @@ async function downloadAndExtractTarball(
try {
let input = new stream.PassThrough();
// Start reading stream into passthrough, don't await to avoid buffering
writeReadableStreamToWritable(response.body, input);
writeReadableStreamToWritable(
response.body as ReadableStream<Uint8Array>,
input
);
await pipeline(
input,
gunzip(),
Expand Down
4 changes: 2 additions & 2 deletions packages/create-remix/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"tsc": "tsc"
},
"dependencies": {
"@remix-run/web-fetch": "^4.4.2",
"arg": "^5.0.1",
"chalk": "^4.1.2",
"execa": "5.1.1",
Expand All @@ -33,7 +32,8 @@
"sisteransi": "^1.0.5",
"sort-package-json": "^1.55.0",
"strip-ansi": "^6.0.1",
"tar-fs": "^2.1.1"
"tar-fs": "^2.1.1",
"undici": "^6.10.1"
},
"devDependencies": {
"@types/gunzip-maybe": "^1.4.0",
Expand Down
8 changes: 4 additions & 4 deletions packages/remix-architect/__tests__/server-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ describe("architect createRemixHeaders", () => {
"x-foo": "bar, baz",
"x-bar": "baz",
});
expect(headers.getAll("x-foo")).toEqual(["bar, baz"]);
expect(headers.get("x-foo")).toEqual("bar, baz");
expect(headers.get("x-bar")).toBe("baz");
});

Expand All @@ -226,9 +226,9 @@ describe("architect createRemixHeaders", () => {
"__session=some_value",
"__other=some_other_value",
]);
expect(headers.getAll("cookie")).toEqual([
"__session=some_value; __other=some_other_value",
]);
expect(headers.get("cookie")).toEqual(
"__session=some_value; __other=some_other_value"
);
});
});
});
Expand Down
4 changes: 3 additions & 1 deletion packages/remix-architect/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ export function createRemixHeaders(
}

if (requestCookies) {
headers.append("Cookie", requestCookies.join("; "));
for (let cookie of requestCookies) {
headers.append("Cookie", cookie);
}
}

return headers;
Expand Down
4 changes: 2 additions & 2 deletions packages/remix-express/__tests__/server-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe("express createRemixHeaders", () => {
"x-foo": ["bar", "baz"],
"x-bar": "baz",
});
expect(headers.getAll("x-foo")).toEqual(["bar", "baz"]);
expect(headers.get("x-foo")).toEqual("bar, baz");
expect(headers.get("x-bar")).toBe("baz");
});

Expand All @@ -189,7 +189,7 @@ describe("express createRemixHeaders", () => {
"__other=some_other_value; Path=/; Secure; HttpOnly; Expires=Wed, 21 Oct 2015 07:28:00 GMT; SameSite=Lax",
],
});
expect(headers.getAll("set-cookie")).toEqual([
expect(headers.getSetCookie()).toEqual([
"__session=some_value; Path=/; Secure; HttpOnly; MaxAge=7200; SameSite=Lax",
"__other=some_other_value; Path=/; Secure; HttpOnly; Expires=Wed, 21 Oct 2015 07:28:00 GMT; SameSite=Lax",
]);
Expand Down
5 changes: 0 additions & 5 deletions packages/remix-node/__tests__/fileUploadHandler-test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { ReadableStream } from "@remix-run/web-stream";

import { NodeOnDiskFile } from "../upload/fileUploadHandler";
import { readableStreamToString } from "../stream";

beforeAll(() => {
global.ReadableStream = ReadableStream;
});

describe("NodeOnDiskFile", () => {
let filepath = path.resolve(__dirname, "assets/test.txt");
let size = fs.statSync(filepath).size;
Expand Down
43 changes: 29 additions & 14 deletions packages/remix-node/globals.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
import {
File as NodeFile,
fetch as nodeFetch,
FormData as NodeFormData,
Headers as NodeHeaders,
Request as NodeRequest,
Response as NodeResponse,
} from "@remix-run/web-fetch";
import {
ByteLengthQueuingStrategy as NodeByteLengthQueuingStrategy,
CountQueuingStrategy as NodeCountQueuingStrategy,
Expand All @@ -20,7 +12,15 @@ import {
WritableStream as NodeWritableStream,
WritableStreamDefaultController as NodeWritableStreamDefaultController,
WritableStreamDefaultWriter as NodeWritableStreamDefaultWriter,
} from "@remix-run/web-stream";
} from "node:stream/web";
import {
File as NodeFile,
fetch as nodeFetch,
FormData as NodeFormData,
Headers as NodeHeaders,
Request as NodeRequest,
Response as NodeResponse,
} from "undici";

declare global {
namespace NodeJS {
Expand All @@ -41,30 +41,45 @@ declare global {
WritableStream: typeof WritableStream;
}
}

interface RequestInit {
duplex?: "half";
}
}

export function installGlobals() {
global.File = NodeFile;
global.File = NodeFile as unknown as typeof File;

global.Headers = NodeHeaders as typeof Headers;
global.Request = NodeRequest as typeof Request;
global.Response = NodeResponse as unknown as typeof Response;
global.fetch = nodeFetch as typeof fetch;
// @ts-expect-error - overriding globals
global.Headers = NodeHeaders;
// @ts-expect-error - overriding globals
global.Request = NodeRequest;
// @ts-expect-error - overriding globals
global.Response = NodeResponse;
// @ts-expect-error - overriding globals
global.fetch = nodeFetch;
// @ts-expect-error - overriding globals
global.FormData = NodeFormData;

// Export everything from https://developer.mozilla.org/en-US/docs/Web/API/Streams_API
global.ByteLengthQueuingStrategy = NodeByteLengthQueuingStrategy;
global.CountQueuingStrategy = NodeCountQueuingStrategy;
// @ts-expect-error - overriding globals
global.ReadableByteStreamController = NodeReadableByteStreamController;
// @ts-expect-error - overriding globals
global.ReadableStream = NodeReadableStream;
global.ReadableStreamBYOBReader = NodeReadableStreamBYOBReader;
global.ReadableStreamBYOBRequest = NodeReadableStreamBYOBRequest;
global.ReadableStreamDefaultController = NodeReadableStreamDefaultController;
// @ts-expect-error - overriding globals
global.ReadableStreamDefaultReader = NodeReadableStreamDefaultReader;
// @ts-expect-error - overriding globals
global.TransformStream = NodeTransformStream;
global.TransformStreamDefaultController =
NodeTransformStreamDefaultController;
// @ts-expect-error - overriding globals
global.WritableStream = NodeWritableStream;
// @ts-expect-error - overriding globals
global.WritableStreamDefaultController = NodeWritableStreamDefaultController;
global.WritableStreamDefaultWriter = NodeWritableStreamDefaultWriter;
}
6 changes: 2 additions & 4 deletions packages/remix-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@
},
"dependencies": {
"@remix-run/server-runtime": "workspace:*",
"@remix-run/web-fetch": "^4.4.2",
"@remix-run/web-file": "^3.1.0",
"@remix-run/web-stream": "^1.1.0",
"@web3-storage/multipart-parser": "^1.0.0",
"cookie-signature": "^1.1.0",
"source-map-support": "^0.5.21",
"stream-slice": "^0.1.2"
"stream-slice": "^0.1.2",
"undici": "^6.10.1"
},
"devDependencies": {
"@types/cookie-signature": "^1.0.3",
Expand Down
9 changes: 7 additions & 2 deletions packages/remix-react/__tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { installGlobals } from "@remix-run/node";
const JSDOMFormData = global.FormData;
global.TextDecoder = require("util").TextDecoder;
global.TextEncoder = require("util").TextEncoder;
global.ReadableStream = require("stream/web").ReadableStream;
global.WritableStream = require("stream/web").WritableStream;

installGlobals();
require("@remix-run/node").installGlobals();
global.FormData = JSDOMFormData;
10 changes: 9 additions & 1 deletion packages/remix-server-runtime/__tests__/formData-test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { parseMultipartFormData } from "../formData";

declare global {
interface RequestInit {
duplex?: "half";
}
}

class CustomError extends Error {
constructor() {
super("test error");
Expand All @@ -21,7 +27,7 @@ describe("parseMultipartFormData", () => {
let parsedFormData = await parseMultipartFormData(
req,
async ({ filename, data, contentType }) => {
let chunks = [];
let chunks: Uint8Array[] = [];
for await (let chunk of data) {
chunks.push(chunk);
}
Expand Down Expand Up @@ -111,6 +117,7 @@ describe("parseMultipartFormData", () => {
method: "post",
body,
headers: underlyingRequest.headers,
duplex: "half",
});

let error: Error;
Expand Down Expand Up @@ -151,6 +158,7 @@ describe("parseMultipartFormData", () => {
method: "post",
body,
headers: underlyingRequest.headers,
duplex: "half",
});

let error: Error;
Expand Down
9 changes: 7 additions & 2 deletions packages/remix-testing/jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { installGlobals } from "@remix-run/node";
const JSDOMFormData = global.FormData;
global.TextDecoder = require("util").TextDecoder;
global.TextEncoder = require("util").TextEncoder;
global.ReadableStream = require("stream/web").ReadableStream;
global.WritableStream = require("stream/web").WritableStream;

installGlobals();
require("@remix-run/node").installGlobals();
global.FormData = JSDOMFormData;
2 changes: 1 addition & 1 deletion packages/remix-testing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@types/node": "^18.17.1",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"jest-environment-jsdom": "^29.6.4",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.1.6"
Expand Down
Loading

0 comments on commit 1e767c1

Please sign in to comment.