Skip to content

Commit

Permalink
test(compiler): browser and server bundles for deno
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed May 11, 2022
1 parent 5c08b90 commit 6f98618
Show file tree
Hide file tree
Showing 10 changed files with 340 additions and 1 deletion.
231 changes: 231 additions & 0 deletions integration/deno-compiler-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import { test, expect } from "@playwright/test";
import * as fse from "fs-extra";
import path from "path";
import shell from "shelljs";
import glob from "glob";

import { createFixtureProject, js, json } from "./helpers/create-fixture";

let projectDir: string;

const findBrowserBundle = (projectDir: string): string =>
path.resolve(projectDir, "public", "build");

const findServerBundle = (projectDir: string): string =>
path.resolve(projectDir, "build", "index.js");

const importPattern = (importSpecifier: string) =>
new RegExp(
String.raw`import\s*{.*}\s*from\s*"` + importSpecifier + String.raw`"`
);

const findCodeFiles = async (directory: string) =>
glob.sync("**/*.@(js|jsx|ts|tsx)", {
cwd: directory,
absolute: true,
});
const searchFiles = async (pattern: string | RegExp, files: string[]) => {
let result = shell.grep("-l", pattern, files);
return result.stdout
.trim()
.split("\n")
.filter((line) => line.length > 0);
};

test.beforeAll(async () => {
projectDir = await createFixtureProject({
template: "deno-template",
files: {
"package.json": json({
private: true,
sideEffects: false,
dependencies: {
"@remix-run/deno": "0.0.0-local-version",
"@remix-run/react": "0.0.0-local-version",
react: "0.0.0-local-version",
"react-dom": "0.0.0-local-version",
component: "0.0.0-local-version",
"deno-pkg": "0.0.0-local-version",
},
devDependencies: {
"@remix-run/dev": "0.0.0-local-version",
},
}),
"app/routes/index.jsx": js`
import fake from "deno-pkg";
import { urlComponent } from "https://deno.land/x/component.ts";
import { urlUtil } from "https://deno.land/x/util.ts";
import { urlServerOnly } from "https://deno.land/x/server-only.ts";
import { npmComponent } from "npm-component";
import { npmUtil } from "npm-util";
import { npmServerOnly } from "npm-server-only";
import { useLoaderData } from "@remix-run/react";
export const loader = () => {
return json({
a: urlUtil(),
b: urlServerOnly(),
c: npmUtil(),
d: npmServerOnly(),
});
}
export default function Index() {
const data = useLoaderData();
return (
<ul>
<li>{fake}</li>
<li>{urlComponent}</li>
<li>{urlUtil()}</li>
<li>{data.a}</li>
<li>{data.b}</li>
<li>{npmComponent}</li>
<li>{npmUtil()}</li>
<li>{data.c}</li>
<li>{data.d}</li>
</ul>
)
}
`,
"node_modules/npm-component/package.json": json({
name: "npm-component",
version: "1.0.0",
sideEffects: false,
}),
"node_modules/npm-component/index.js": js`
module.exports = { npmComponent: () => "NPM_COMPONENT" };
`,
"node_modules/npm-util/package.json": json({
name: "npm-util",
version: "1.0.0",
sideEffects: false,
}),
"node_modules/npm-util/index.js": js`
module.exports = { npmUtil: () => "NPM_UTIL" };
`,
"node_modules/npm-server-only/package.json": json({
name: "npm-server-only",
version: "1.0.0",
sideEffects: false,
}),
"node_modules/npm-server-only/index.js": js`
module.exports = { npmServerOnly: () => "NPM_SERVER_ONLY" };
`,
"node_modules/deno-pkg/package.json": json({
name: "deno-pkg",
version: "1.0.0",
type: "module",
main: "./default.js",
exports: {
deno: "./deno.js",
worker: "./worker.js",
default: "./default.js",
},
sideEffects: false,
}),
"node_modules/deno-pkg/deno.js": js`
export default "DENO_EXPORTS";
`,
"node_modules/deno-pkg/worker.js": js`
export default "WORKER_EXPORTS";
`,
"node_modules/deno-pkg/default.js": js`
export default "DEFAULT_EXPORTS";
`,
},
});
});

test("compiler does not bundle url imports for server", async () => {
let serverBundle = await fse.readFile(findServerBundle(projectDir), "utf8");
expect(serverBundle).toMatch(importPattern("https://deno.land/x/util.ts"));
expect(serverBundle).toMatch(
importPattern("https://deno.land/x/server-only.ts")
);

// server-side rendering
expect(serverBundle).toMatch(
importPattern("https://deno.land/x/component.ts")
);
});

test("compiler does not bundle url imports for browser", async () => {
let browserBundle = findBrowserBundle(projectDir);
let browserCodeFiles = await findCodeFiles(browserBundle);

let utilFiles = await searchFiles(
importPattern("https://deno.land/x/util.ts"),
browserCodeFiles
);
expect(utilFiles.length).toBeGreaterThanOrEqual(1);

let componentFiles = await searchFiles(
importPattern("https://deno.land/x/component.ts"),
browserCodeFiles
);
expect(componentFiles.length).toBeGreaterThanOrEqual(1);

/*
url imports _could_ have side effects,
so esbuild will keep url imports even when they are unused,
as is the case for `https://deno.land/x/server-only.ts` within the browser bundle.
*/
// let serverOnlyUtilFiles = await searchFiles(
// importPattern("https://deno.land/x/server-only.ts"),
// browserCodeFiles
// );
// expect(serverOnlyUtilFiles.length).toBe(0);
});

test("compiler bundles npm imports for server", async () => {
let serverBundle = await fse.readFile(findServerBundle(projectDir), "utf8");

expect(serverBundle).not.toMatch(importPattern("npm-component"));
expect(serverBundle).toContain("NPM_COMPONENT");

expect(serverBundle).not.toMatch(importPattern("npm-util"));
expect(serverBundle).toContain("NPM_UTIL");

expect(serverBundle).not.toMatch(importPattern("npm-server-only"));
expect(serverBundle).toContain("NPM_SERVER_ONLY");
});

test("compiler bundles npm imports for browser", async () => {
let browserBundle = findBrowserBundle(projectDir);
let browserCodeFiles = await findCodeFiles(browserBundle);

let utilImports = await searchFiles(
importPattern("npm-util"),
browserCodeFiles
);
expect(utilImports.length).toBe(0);
let utilFiles = await searchFiles("NPM_UTIL", browserCodeFiles);
expect(utilFiles.length).toBeGreaterThanOrEqual(1);

let componentImports = await searchFiles(
importPattern("npm-component"),
browserCodeFiles
);
expect(componentImports.length).toBe(0);
let componentFiles = await searchFiles("NPM_COMPONENT", browserCodeFiles);
expect(componentFiles.length).toBeGreaterThanOrEqual(1);

let serverOnlyImports = await searchFiles(
importPattern("npm-server-only"),
browserCodeFiles
);
expect(serverOnlyImports.length).toBe(0);
let serverOnlyFiles = await searchFiles("NPM_SERVER_ONLY", browserCodeFiles);
expect(serverOnlyFiles.length).toBe(0);
});

test("compiles bundles deno export of 3rd party package", async () => {
let serverBundle = await fse.readFile(findServerBundle(projectDir), "utf8");

expect(serverBundle).toMatch("DENO_EXPORTS");
expect(serverBundle).not.toMatch("DEFAULT_EXPORTS");
});
2 changes: 1 addition & 1 deletion integration/helpers/create-fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface FixtureInit {
buildStdio?: Writable;
sourcemap?: boolean;
files: { [filename: string]: string };
template?: "cf-template" | "node-template";
template?: "cf-template" | "deno-template" | "node-template";
setup?: "node" | "cloudflare";
}

Expand Down
5 changes: 5 additions & 0 deletions integration/helpers/deno-template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/node_modules/

/.cache
/build
/public/build
5 changes: 5 additions & 0 deletions integration/helpers/deno-template/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "react";
import ReactDOM from "react-dom";
import { RemixBrowser } from "@remix-run/react";

ReactDOM.hydrate(<RemixBrowser />, document);
22 changes: 22 additions & 0 deletions integration/helpers/deno-template/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import { renderToString } from "react-dom/server";
import { RemixServer } from "@remix-run/react";
import type { EntryContext } from "@remix-run/deno";

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />,
);

responseHeaders.set("Content-Type", "text/html");

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
33 changes: 33 additions & 0 deletions integration/helpers/deno-template/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from "react";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import type { MetaFunction } from "@remix-run/deno";

export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});

export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
17 changes: 17 additions & 0 deletions integration/helpers/deno-template/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "remix-template-deno",
"private": true,
"sideEffects": false,
"dependencies": {
"@remix-run/deno": "*",
"@remix-run/react": "*",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@remix-run/dev": "*"
},
"engines": {
"node": ">=14"
}
}
Binary file not shown.
12 changes: 12 additions & 0 deletions integration/helpers/deno-template/remix.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module.exports = {
serverBuildTarget: "deno",
server: "./server.ts",

/*
If live reload causes page to re-render without changes (live reload is too fast),
increase the dev server broadcast delay.
If live reload seems slow, try to decrease the dev server broadcast delay.
*/
devServerBroadcastDelay: 300,
};
14 changes: 14 additions & 0 deletions integration/helpers/deno-template/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { serve } from "https://deno.land/std@0.128.0/http/server.ts";
import { createRequestHandlerWithStaticFiles } from "@remix-run/deno";
// Import path interpreted by the Remix compiler
import * as build from "@remix-run/dev/server-build";

const remixHandler = createRequestHandlerWithStaticFiles({
build,
mode: process.env.NODE_ENV,
getLoadContext: () => ({}),
});

const port = Number(Deno.env.get("PORT")) || 8000;
console.log(`Listening on http://localhost:${port}`);
serve(remixHandler, { port });

0 comments on commit 6f98618

Please sign in to comment.