aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Colin McDonnell <colinmcd94@gmail.com> 2023-04-04 16:26:40 -0700
committerGravatar GitHub <noreply@github.com> 2023-04-04 16:26:40 -0700
commit76adc5be8a4f35730bbd81f06f043073e7160af8 (patch)
treea6e32fee2faf6418be6e6dc7c447086fa4c4ce13
parentf3ab445c3fcae6a5177eb89e710e47f83cd7db42 (diff)
downloadbun-76adc5be8a4f35730bbd81f06f043073e7160af8.tar.gz
bun-76adc5be8a4f35730bbd81f06f043073e7160af8.tar.zst
bun-76adc5be8a4f35730bbd81f06f043073e7160af8.zip
Add npm benchmark (#2555)
* Add install bench * Update scripts and readme * remove lockfiles * Format bench * Add dev instructions
-rw-r--r--bench/install/.eslintrc.js4
-rw-r--r--bench/install/.gitignore10
-rw-r--r--bench/install/README.md18
-rw-r--r--bench/install/app/entry.client.tsx18
-rw-r--r--bench/install/app/entry.server.tsx101
-rw-r--r--bench/install/app/root.tsx20
-rw-r--r--bench/install/app/routes/_index.tsx30
-rw-r--r--bench/install/package.json31
-rw-r--r--bench/install/public/favicon.icobin0 -> 16958 bytes
-rw-r--r--bench/install/remix.config.js14
-rw-r--r--bench/install/remix.env.d.ts2
-rw-r--r--bench/install/tsconfig.json22
-rw-r--r--package.json2
13 files changed, 271 insertions, 1 deletions
diff --git a/bench/install/.eslintrc.js b/bench/install/.eslintrc.js
new file mode 100644
index 000000000..2061cd226
--- /dev/null
+++ b/bench/install/.eslintrc.js
@@ -0,0 +1,4 @@
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
+};
diff --git a/bench/install/.gitignore b/bench/install/.gitignore
new file mode 100644
index 000000000..eff95a8ce
--- /dev/null
+++ b/bench/install/.gitignore
@@ -0,0 +1,10 @@
+node_modules
+
+/.cache
+/build
+/public/build
+.env
+package-lock.json
+yarn.lock
+pnpm-lock.yaml
+bun.lockb \ No newline at end of file
diff --git a/bench/install/README.md b/bench/install/README.md
new file mode 100644
index 000000000..e9b617995
--- /dev/null
+++ b/bench/install/README.md
@@ -0,0 +1,18 @@
+# `install` benchmark
+
+Requires [`hyperfine`](https://github.com/sharkdp/hyperfine)
+
+```
+$ hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'
+```
+
+To check that the app is working as expected:
+
+```
+$ bun run dev
+$ npm run dev
+$ yarn dev
+$ pnpm dev
+```
+
+Then visit [http://localhost:3000](http://localhost:3000).
diff --git a/bench/install/app/entry.client.tsx b/bench/install/app/entry.client.tsx
new file mode 100644
index 000000000..186cd9344
--- /dev/null
+++ b/bench/install/app/entry.client.tsx
@@ -0,0 +1,18 @@
+/**
+ * By default, Remix will handle hydrating your app on the client for you.
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
+ * For more information, see https://remix.run/docs/en/main/file-conventions/entry.client
+ */
+
+import { RemixBrowser } from "@remix-run/react";
+import { startTransition, StrictMode } from "react";
+import { hydrateRoot } from "react-dom/client";
+
+startTransition(() => {
+ hydrateRoot(
+ document,
+ <StrictMode>
+ <RemixBrowser />
+ </StrictMode>,
+ );
+});
diff --git a/bench/install/app/entry.server.tsx b/bench/install/app/entry.server.tsx
new file mode 100644
index 000000000..fbea6220e
--- /dev/null
+++ b/bench/install/app/entry.server.tsx
@@ -0,0 +1,101 @@
+/**
+ * By default, Remix will handle generating the HTTP Response for you.
+ * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
+ * For more information, see https://remix.run/docs/en/main/file-conventions/entry.server
+ */
+
+import { PassThrough } from "node:stream";
+import type { EntryContext } from "@remix-run/node";
+import { Response } from "@remix-run/node";
+import { RemixServer } from "@remix-run/react";
+import isbot from "isbot";
+import { renderToPipeableStream } from "react-dom/server";
+
+const ABORT_DELAY = 5_000;
+
+export default function handleRequest(
+ request: Request,
+ responseStatusCode: number,
+ responseHeaders: Headers,
+ remixContext: EntryContext,
+) {
+ return isbot(request.headers.get("user-agent"))
+ ? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
+ : handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
+}
+
+function handleBotRequest(
+ request: Request,
+ responseStatusCode: number,
+ responseHeaders: Headers,
+ remixContext: EntryContext,
+) {
+ return new Promise((resolve, reject) => {
+ const { pipe, abort } = renderToPipeableStream(
+ <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
+ {
+ onAllReady() {
+ const body = new PassThrough();
+
+ responseHeaders.set("Content-Type", "text/html");
+
+ resolve(
+ new Response(body, {
+ headers: responseHeaders,
+ status: responseStatusCode,
+ }),
+ );
+
+ pipe(body);
+ },
+ onShellError(error: unknown) {
+ reject(error);
+ },
+ onError(error: unknown) {
+ responseStatusCode = 500;
+ console.error(error);
+ },
+ },
+ );
+
+ setTimeout(abort, ABORT_DELAY);
+ });
+}
+
+function handleBrowserRequest(
+ request: Request,
+ responseStatusCode: number,
+ responseHeaders: Headers,
+ remixContext: EntryContext,
+) {
+ return new Promise((resolve, reject) => {
+ const { pipe, abort } = renderToPipeableStream(
+ <RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />,
+ {
+ onShellReady() {
+ const body = new PassThrough();
+
+ responseHeaders.set("Content-Type", "text/html");
+
+ resolve(
+ new Response(body, {
+ headers: responseHeaders,
+ status: responseStatusCode,
+ }),
+ );
+
+ pipe(body);
+ },
+ onShellError(error: unknown) {
+ reject(error);
+ },
+ onError(error: unknown) {
+ console.error(error);
+ responseStatusCode = 500;
+ },
+ },
+ );
+
+ setTimeout(abort, ABORT_DELAY);
+ });
+}
diff --git a/bench/install/app/root.tsx b/bench/install/app/root.tsx
new file mode 100644
index 000000000..4d0236fb2
--- /dev/null
+++ b/bench/install/app/root.tsx
@@ -0,0 +1,20 @@
+import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "@remix-run/react";
+
+export default function App() {
+ return (
+ <html lang="en">
+ <head>
+ <meta charSet="utf-8" />
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
+ <Meta />
+ <Links />
+ </head>
+ <body>
+ <Outlet />
+ <ScrollRestoration />
+ <Scripts />
+ <LiveReload />
+ </body>
+ </html>
+ );
+}
diff --git a/bench/install/app/routes/_index.tsx b/bench/install/app/routes/_index.tsx
new file mode 100644
index 000000000..92fccd4ad
--- /dev/null
+++ b/bench/install/app/routes/_index.tsx
@@ -0,0 +1,30 @@
+import type { V2_MetaFunction } from "@remix-run/node";
+
+export const meta: V2_MetaFunction = () => {
+ return [{ title: "New Remix App" }];
+};
+
+export default function Index() {
+ return (
+ <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
+ <h1>Welcome to Remix</h1>
+ <ul>
+ <li>
+ <a target="_blank" href="https://remix.run/tutorials/blog" rel="noreferrer">
+ 15m Quickstart Blog Tutorial
+ </a>
+ </li>
+ <li>
+ <a target="_blank" href="https://remix.run/tutorials/jokes" rel="noreferrer">
+ Deep Dive Jokes App Tutorial
+ </a>
+ </li>
+ <li>
+ <a target="_blank" href="https://remix.run/docs" rel="noreferrer">
+ Remix Docs
+ </a>
+ </li>
+ </ul>
+ </div>
+ );
+}
diff --git a/bench/install/package.json b/bench/install/package.json
new file mode 100644
index 000000000..02bb8e92f
--- /dev/null
+++ b/bench/install/package.json
@@ -0,0 +1,31 @@
+{
+ "private": true,
+ "sideEffects": false,
+ "scripts": {
+ "build": "remix build",
+ "dev": "remix dev",
+ "start": "remix-serve build",
+ "typecheck": "tsc",
+ "clean": "rm -rf node_modules",
+ "bench": "hyperfine --prepare 'rm -rf node_modules' --warmup 1 --runs 3 'bun install' 'pnpm install' 'yarn' 'npm install'"
+ },
+ "dependencies": {
+ "@remix-run/node": "^1.15.0",
+ "@remix-run/react": "^1.15.0",
+ "@remix-run/serve": "^1.15.0",
+ "isbot": "^3.6.5",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@remix-run/dev": "^1.15.0",
+ "@remix-run/eslint-config": "^1.15.0",
+ "@types/react": "^18.0.25",
+ "@types/react-dom": "^18.0.8",
+ "eslint": "^8.27.0",
+ "typescript": "^4.8.4"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+}
diff --git a/bench/install/public/favicon.ico b/bench/install/public/favicon.ico
new file mode 100644
index 000000000..8830cf682
--- /dev/null
+++ b/bench/install/public/favicon.ico
Binary files differ
diff --git a/bench/install/remix.config.js b/bench/install/remix.config.js
new file mode 100644
index 000000000..a1a396661
--- /dev/null
+++ b/bench/install/remix.config.js
@@ -0,0 +1,14 @@
+/** @type {import('@remix-run/dev').AppConfig} */
+module.exports = {
+ ignoredRouteFiles: ["**/.*"],
+ // appDirectory: "app",
+ // assetsBuildDirectory: "public/build",
+ // serverBuildPath: "build/index.js",
+ // publicPath: "/build/",
+ future: {
+ v2_errorBoundary: true,
+ v2_meta: true,
+ v2_normalizeFormMethod: true,
+ v2_routeConvention: true,
+ },
+};
diff --git a/bench/install/remix.env.d.ts b/bench/install/remix.env.d.ts
new file mode 100644
index 000000000..dcf8c45e1
--- /dev/null
+++ b/bench/install/remix.env.d.ts
@@ -0,0 +1,2 @@
+/// <reference types="@remix-run/dev" />
+/// <reference types="@remix-run/node" />
diff --git a/bench/install/tsconfig.json b/bench/install/tsconfig.json
new file mode 100644
index 000000000..20f8a386a
--- /dev/null
+++ b/bench/install/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
+ "compilerOptions": {
+ "lib": ["DOM", "DOM.Iterable", "ES2019"],
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "target": "ES2019",
+ "strict": true,
+ "allowJs": true,
+ "forceConsistentCasingInFileNames": true,
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["./app/*"]
+ },
+
+ // Remix takes care of building everything in `remix build`.
+ "noEmit": true
+ }
+}
diff --git a/package.json b/package.json
index e488635c2..477f237e7 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,7 @@
"build-fallback": "esbuild --target=esnext --bundle src/fallback.ts --format=iife --platform=browser --minify > src/fallback.out.js",
"postinstall": "bash .scripts/postinstall.sh",
"typecheck": "tsc --noEmit",
- "fmt": "prettier --write './test/**/*.{mjs,ts,tsx,js,jsx}' './src/*.{mjs,ts,tsx,js,jsx}' './src/*/*.{mjs,ts,tsx,js,jsx}' './src/*/*/*.{mjs,ts,tsx,js,jsx}' './bench/*.{mjs,ts,tsx,js,jsx}' --config .prettierrc.cjs",
+ "fmt": "prettier --write './test/**/*.{mjs,ts,tsx,js,jsx}' './src/*.{mjs,ts,tsx,js,jsx}' './src/*/*.{mjs,ts,tsx,js,jsx}' './src/*/*/*.{mjs,ts,tsx,js,jsx}' './bench/**/*.{mjs,ts,tsx,js,jsx}' --config .prettierrc.cjs",
"lint": "eslint './**/*.d.ts' --cache",
"lint:fix": "eslint './**/*.d.ts' --cache --fix"
},