UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

461 lines (419 loc) 16.9 kB
import { describe, expect, it } from "vitest"; import { transformTreeShakeClient } from "./clientTreeShakePlugin.native.js"; describe("clientTreeShakePlugin", function () { describe("transformTreeShakeClient", function () { it("should remove loader export and its imports", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { Text } from 'react-native' import { useLoader } from 'one' export function loader() { return serverOnlyModule() } export default function Page() { const data = useLoader(loader) return <Text>{data}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); expect(result.code).toContain("react-native"); expect(result.code).toContain("one"); }); it("should remove loader export with dynamic import", async function () { var code = ` import { Text } from 'react-native' import { useLoader } from 'one' export async function loader() { const { serverFn } = await import('server-only-pkg') return serverFn() } export default function Page() { const data = useLoader(loader) return <Text>{data}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); }); it("should remove loader with const arrow function export", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { Text } from 'react-native' import { useLoader } from 'one' export const loader = async () => { return serverOnlyModule() } export default function Page() { const data = useLoader(loader) return <Text>{data}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); }); it("should handle multiple imports where only some are used in loader", async function () { var code = ` import { serverFn } from 'server-only-pkg' import { sharedUtil } from 'shared-pkg' import { Text } from 'react-native' import { useLoader } from 'one' export function loader() { return serverFn() } export default function Page() { const data = useLoader(loader) return <Text>{sharedUtil(data)}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); expect(result.code).toContain("shared-pkg"); }); it("should remove generateStaticParams and its imports", async function () { var code = ` import { getRoutes } from 'server-only-pkg' import { Text } from 'react-native' export function generateStaticParams() { return getRoutes() } export default function Page() { return <Text>Hello</Text> } `; var result = await transformTreeShakeClient(code, "/app/[slug].tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); }); it("should not transform files without loader or generateStaticParams", async function () { var code = ` import { Text } from 'react-native' export default function Page() { return <Text>Hello</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeUndefined(); }); it("should embed routeId in loader stub when root is provided", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { useLoader } from 'one' export async function loader() { return serverOnlyModule() } export default function Layout() { const data = useLoader(loader) return data } `; var result = await transformTreeShakeClient(code, "/project/app/_layout.tsx", "/project"); expect(result).toBeDefined(); expect(result.code).toContain('export function loader() {return "./_layout.tsx"}'); expect(result.code).not.toContain("__vxrn__loader__"); }); it("should strip a custom router root from the loader stub routeId", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { useLoader } from 'one' export const loader = async () => { return serverOnlyModule() } export default function Page() { const data = useLoader(loader) return data } `; var result = await transformTreeShakeClient(code, "/project/app-sootsim/(marketing)/changelog/index+ssg.tsx", "/project", "app-sootsim"); expect(result).toBeDefined(); expect(result.code).toContain('export function loader() {return "./(marketing)/changelog/index+ssg.tsx"}'); }); it("should embed routeId with render mode suffix in loader stub", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { useLoader } from 'one' export async function loader() { return serverOnlyModule() } export default function Layout() { const data = useLoader(loader) return data } `; var result = await transformTreeShakeClient(code, "/project/app/user+ssr.tsx", "/project"); expect(result).toBeDefined(); expect(result.code).toContain('export function loader() {return "./user+ssr.tsx"}'); }); it("should fall back to __vxrn__loader__ stub when no root provided", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { useLoader } from 'one' export async function loader() { return serverOnlyModule() } export default function Page() { const data = useLoader(loader) return data } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain("__vxrn__loader__"); }); it("should not transform route file when loader is imported (no inline declaration)", async function () { var code = ` import { loader } from './loaders/my-loader' import { useLoader } from 'one' export { loader } export default function Layout() { const data = useLoader(loader) return data } `; var result = await transformTreeShakeClient(code, "/project/app/_layout.tsx", "/project"); expect(result).toBeUndefined(); }); it("should tree-shake server imports from source file where loader is defined", async function () { var sourceCode = ` import { db } from 'server-only-db' export async function loader() { return db.query('SELECT * FROM users') } export function helperUsedByClient() { return 'hello' } `; var result = await transformTreeShakeClient(sourceCode, "/project/app/loaders/my-loader.ts", "/project"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-db"); expect(result.code).toContain("helperUsedByClient"); expect(result.code).toContain('export function loader() {return "./loaders/my-loader.ts"}'); }); it("should not transform re-export from source syntax", async function () { var code = ` export { loader } from './loaders/shared-loader' import { useLoader } from 'one' export default function Page() { return 'hello' } `; var result = await transformTreeShakeClient(code, "/project/app/page.tsx", "/project"); expect(result).toBeUndefined(); }); it("should preserve type-only imports during tree shaking", async function () { var code = ` import type { SomeType } from 'types-pkg' import { serverFn } from 'server-only-pkg' import { Text } from 'react-native' import { useLoader } from 'one' export function loader(): SomeType { return serverFn() } export default function Page() { const data = useLoader(loader) return <Text>{data}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain("types-pkg"); expect(result.code).not.toContain("server-only-pkg"); }); it("should preserve type imports even when used only in loader", async function () { var code = ` import type { APIGuildMember } from '@discordjs/core' import { getClient } from 'discord-client' import { Text } from 'react-native' import { useLoader } from 'one' export function loader(): APIGuildMember { return getClient() } export default function Page() { const data = useLoader(loader) return <Text>{JSON.stringify(data)}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain("@discordjs/core"); expect(result.code).not.toContain("discord-client"); }); it("should preserve side-effect imports during tree shaking", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { Text } from 'react-native' export function loader() { return serverOnlyModule() } export default function Page() { return <Text>Hello</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain("import './style.css'"); expect(result.code).not.toContain("server-only-pkg"); }); it("should remove transitive local bindings exclusively used by loader", async function () { var code = ` import { db } from 'server-only-db' import { Text } from 'react-native' const secretKey = 'my-secret' function querySecret() { return db.query(secretKey) } export async function loader() { return querySecret() } export default function Page() { return <Text>Hello</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-db"); expect(result.code).not.toContain("secretKey"); expect(result.code).not.toContain("querySecret"); expect(result.code).toContain("export default function Page"); }); it("should preserve shared local bindings used by both loader and client", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { Text } from 'react-native' const sharedConfig = { siteName: 'One' } function getTitle() { return sharedConfig.siteName } export function loader() { serverOnlyModule() return getTitle() } export default function Page() { return <Text>{getTitle()}</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("server-only-pkg"); expect(result.code).toContain("sharedConfig"); expect(result.code).toContain("getTitle"); }); it("should throw build error on syntax error in production", async function () { var origEnv = process.env.NODE_ENV; try { process.env.NODE_ENV = "production"; var code = ` import { serverOnly } from 'server-only-pkg' export function loader() { bad syntax { } `; await expect(transformTreeShakeClient(code, "/app/index.tsx")).rejects.toThrow(/Failed to parse/); } finally { process.env.NODE_ENV = origEnv; } }); it("should log warning and return undefined on syntax error in development", async function () { var origEnv = process.env.NODE_ENV; try { process.env.NODE_ENV = "development"; var code = ` import { serverOnly } from 'server-only-pkg' export function loader() { bad syntax { } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeUndefined(); } finally { process.env.NODE_ENV = origEnv; } }); it("should generate a valid sourcemap", async function () { var code = ` import { serverOnlyModule } from 'server-only-pkg' import { Text } from 'react-native' export function loader() { return serverOnlyModule() } export default function Page() { return <Text>Hello</Text> } `; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.map).toBeDefined(); expect(result.map.mappings).toBeDefined(); }); it("preserves shared import referenced in destructuring default parameter", async function () { var code = `import {shared} from "./shared"; export function loader(){return shared}; export default function Page({x = shared}) {return x}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain('import {shared} from "./shared"'); expect(result.code).toContain("Page({x = shared})"); expect(result.code).toContain("export function loader()"); }); it("preserves shared import referenced in top-level executable statement", async function () { var code = `import {shared} from "./shared"; export function loader(){return shared}; if (globalThis.ready) shared();`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain('import {shared} from "./shared"'); expect(result.code).toContain("if (globalThis.ready) shared();"); expect(result.code).toContain("export function loader()"); }); it("preserves shared import referenced in top-level retained initializer", async function () { var code = `import {shared} from "./shared"; const retained = shared(); export function loader(){return shared}; export default function Page(){return null}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain('import {shared} from "./shared"'); expect(result.code).toContain("const retained = shared();"); expect(result.code).toContain("export function loader()"); }); it("removes top-level declaration and import used exclusively by loader", async function () { var code = `import {secret} from "./secret"; const localSecret = secret(); export function loader(){return localSecret}; export default function Page(){return null}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("./secret"); expect(result.code).not.toContain("localSecret"); expect(result.code).toContain("export function loader()"); }); it("preserves shared import referenced in top-level destructuring default binding", async function () { var code = `import {shared} from "./shared"; const {x = shared} = {}; export function loader(){return [x,shared]}; export default function Page(){return x}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain('import {shared} from "./shared"'); expect(result.code).toContain("const {x = shared} = {}"); expect(result.code).toContain("return x"); }); it("removes server-only import referenced in top-level destructuring default binding when used only by loader", async function () { var code = `import {secret} from "./server"; const {x = secret} = {}; export function loader(){return x}; export default function Page(){return null}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("./server"); expect(result.code).not.toContain("secret"); expect(result.code).not.toContain("{x = secret}"); expect(result.code).toContain("Page(){return null}"); }); it("removes server-only enum and class declarations used only by loader", async function () { var code = `import {server} from "./server"; enum E { X = server() }; export function loader() {return E.X}; export default function Page(){return null}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).not.toContain("./server"); expect(result.code).not.toContain("enum E"); expect(result.code).toContain("Page(){return null}"); }); it("preserves shared enum used by both loader and client Page", async function () { var code = `import {shared} from "./shared"; enum E { X = shared() }; export function loader() {return E.X}; export default function Page(){return E.X}`; var result = await transformTreeShakeClient(code, "/app/index.tsx"); expect(result).toBeDefined(); expect(result.code).toContain('import {shared} from "./shared"'); expect(result.code).toContain("enum E"); expect(result.code).toContain("Page(){return E.X}"); }); }); }); //# sourceMappingURL=clientTreeShakePlugin.test.native.js.map