diff --git a/packages/universal-middleware/package.json b/packages/universal-middleware/package.json index 1409c3b..ea0c903 100644 --- a/packages/universal-middleware/package.json +++ b/packages/universal-middleware/package.json @@ -88,13 +88,14 @@ "test": "vitest run" }, "dependencies": { - "esbuild": "^0.23.0", "@universal-middleware/express": "^0.1.0", "@universal-middleware/hattip": "^0.1.0", - "@universal-middleware/hono": "^0.1.1" + "@universal-middleware/hono": "^0.1.1", + "esbuild": "^0.23.0" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", "@universal-middleware/core": "^0.1.1", "rimraf": "^6.0.1", "rollup": "^4.18.1", @@ -105,11 +106,11 @@ "vitest": "^2.0.3" }, "peerDependencies": { + "@rollup/plugin-node-resolve": "^15", "esbuild": "*", "rollup": "^4", "vite": ">=5", - "webpack": "^4 || ^5", - "@rollup/plugin-node-resolve": "^15" + "webpack": "^4 || ^5" }, "peerDependenciesMeta": { "webpack": { diff --git a/packages/universal-middleware/src/build.ts b/packages/universal-middleware/src/build.ts index 6837d78..911ff90 100644 --- a/packages/universal-middleware/src/build.ts +++ b/packages/universal-middleware/src/build.ts @@ -100,12 +100,12 @@ function appendVirtualInputs( }); } -function load(id: string) { +function load(id: string, resolve?: (handler: string, type: string) => string) { const [, , server, type, handler] = id.split(":"); const fn = type === "handler" ? "createHandler" : "createMiddleware"; const code = `import { ${fn} } from "@universal-middleware/${server}"; -import ${type} from "${handler}"; +import ${type} from "${resolve ? resolve(handler, type) : handler}"; export default ${fn}(${type}); `; return { code }; @@ -120,13 +120,19 @@ const universalMiddleware = createUnplugin((options?: Options) => { name: namespace, enforce: "post", rollup: { - async options(opts) { + options(opts) { const normalizedInput = normalizeInput(opts.input); if (normalizedInput) { opts.input = normalizedInput; appendVirtualInputs(opts.input, options?.servers); } }, + // outputOptions(opts) { + // opts.entryFileNames = (chunkInfo) => { + // console.log(chunkInfo); + // return chunkInfo.name + '-[hash]'; + // }; + // }, }, esbuild: { @@ -224,7 +230,9 @@ const universalMiddleware = createUnplugin((options?: Options) => { return id.startsWith(namespace); }, - load, + load(id) { + return load(id, (handler, type) => `${handler}?${type}`); + }, }; }); diff --git a/packages/universal-middleware/test/rollup.test.ts b/packages/universal-middleware/test/rollup.test.ts index c4dd8f7..57f8903 100644 --- a/packages/universal-middleware/test/rollup.test.ts +++ b/packages/universal-middleware/test/rollup.test.ts @@ -3,13 +3,22 @@ import { describe, expect, it } from "vitest"; import { type OutputChunk, rollup, type RollupOutput } from "rollup"; import { nodeResolve } from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; import unplugin from "../src/build"; +import { parse } from "node:path"; describe("rollup", () => { it("generates all server files (string input)", async () => { + const entry = "test/files/folder1/handler.ts"; const result = await rollup({ - input: "test/handler.ts?handler", - plugins: [unplugin.rollup(), nodeResolve()], + input: entry + "?handler", + plugins: [ + unplugin.rollup(), + nodeResolve(), + typescript({ + sourceMap: false, + }), + ], onwarn(warning) { throw new Error(warning.message); }, @@ -17,21 +26,33 @@ describe("rollup", () => { const gen = await result.generate({}); - const handler = gen.output.find( - (f: any) => f.facadeModuleId === "test/handler.ts", - ) as OutputChunk | undefined; - expect(handler?.name).toEqual("handler"); + expect( + gen.output.filter((f) => f.type === "chunk" && f.isEntry), + ).toHaveLength(expectNbOutput(1)); + + const handler = gen.output.find((f: any) => f.facadeModuleId === entry) as + | OutputChunk + | undefined; + expect(handler?.name).toEqual("test/files/folder1/handler"); - testRollupHandlers(gen); + testRollupOutput(gen, "handler", entry); }); it("generates all server files (object input)", async () => { + const entry1 = "test/files/folder1/handler.ts"; + const entry2 = "test/files/middleware.ts"; const result = await rollup({ input: { - h: "test/handler.ts?handler", - m: "test/middleware.ts?middleware", + h: entry1 + "?handler", + m: entry2 + "?middleware", }, - plugins: [unplugin.rollup(), nodeResolve()], + plugins: [ + unplugin.rollup(), + nodeResolve(), + typescript({ + sourceMap: false, + }), + ], onwarn(warning) { throw new Error(warning.message); }, @@ -39,24 +60,36 @@ describe("rollup", () => { const gen = await result.generate({}); - const handler = gen.output.find( - (f: any) => f.facadeModuleId === "test/handler.ts", - ) as OutputChunk | undefined; + expect( + gen.output.filter((f) => f.type === "chunk" && f.isEntry), + ).toHaveLength(expectNbOutput(2)); + + const handler = gen.output.find((f: any) => f.facadeModuleId === entry1) as + | OutputChunk + | undefined; expect(handler?.name).toEqual("h"); const middleware = gen.output.find( - (f: any) => f.facadeModuleId === "test/middleware.ts", + (f: any) => f.facadeModuleId === entry2, ) as OutputChunk | undefined; expect(middleware?.name).toEqual("m"); - testRollupHandlers(gen); - testRollupMiddlewares(gen); + testRollupOutput(gen, "handler", entry1); + testRollupOutput(gen, "middleware", entry2); }); it("generates all server files (array input)", async () => { + const entry1 = "test/files/folder1/handler.ts"; + const entry2 = "test/files/middleware.ts"; const result = await rollup({ - input: ["test/handler.ts?handler", "test/middleware.ts?middleware"], - plugins: [unplugin.rollup(), nodeResolve()], + input: [entry1 + "?handler", entry2 + "?middleware"], + plugins: [ + unplugin.rollup(), + nodeResolve(), + typescript({ + sourceMap: false, + }), + ], onwarn(warning) { throw new Error(warning.message); }, @@ -64,63 +97,90 @@ describe("rollup", () => { const gen = await result.generate({}); - const handler = gen.output.find( - (f: any) => f.facadeModuleId === "test/handler.ts", - ) as OutputChunk | undefined; - expect(handler?.name).toEqual("handler"); + expect( + gen.output.filter((f) => f.type === "chunk" && f.isEntry), + ).toHaveLength(expectNbOutput(2)); + + const handler = gen.output.find((f: any) => f.facadeModuleId === entry1) as + | OutputChunk + | undefined; + expect(handler?.name).toEqual("test/files/folder1/handler"); const middleware = gen.output.find( - (f: any) => f.facadeModuleId === "test/middleware.ts", + (f: any) => f.facadeModuleId === entry2, ) as OutputChunk | undefined; - expect(middleware?.name).toEqual("middleware"); + expect(middleware?.name).toEqual("test/files/middleware"); - testRollupHandlers(gen); - testRollupMiddlewares(gen); + testRollupOutput(gen, "handler", entry1); + testRollupOutput(gen, "middleware", entry2); }); -}); -function testRollupHandlers(gen: RollupOutput) { - const hattip = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:hattip:handler:test/handler.ts", - ) as OutputChunk | undefined; - expect(hattip?.name).toEqual("universal-hattip-handler"); + it("generates all server files (multiple handlers)", async () => { + const entry1 = "test/files/folder1/handler.ts"; + const entry2 = "test/files/folder2/handler.ts"; + const result = await rollup({ + input: [entry1 + "?handler", entry2 + "?handler"], + plugins: [ + unplugin.rollup(), + nodeResolve(), + typescript({ + sourceMap: false, + }), + ], + onwarn(warning) { + throw new Error(warning.message); + }, + }); - const express = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:express:handler:test/handler.ts", - ) as OutputChunk | undefined; - expect(express?.name).toEqual("universal-express-handler"); + const gen = await result.generate({}); - const hono = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:hono:handler:test/handler.ts", - ) as OutputChunk | undefined; - expect(hono?.name).toEqual("universal-hono-handler"); -} + expect( + gen.output.filter((f) => f.type === "chunk" && f.isEntry), + ).toHaveLength(expectNbOutput(2)); -function testRollupMiddlewares(gen: RollupOutput) { - const hattip = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:hattip:middleware:test/middleware.ts", - ) as OutputChunk | undefined; - expect(hattip?.name).toEqual("universal-hattip-middleware"); + const handler1 = gen.output.find( + (f: any) => f.facadeModuleId === entry1, + ) as OutputChunk | undefined; + expect(handler1?.name).toEqual("test/files/folder1/handler"); - const express = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:express:middleware:test/middleware.ts", - ) as OutputChunk | undefined; - expect(express?.name).toEqual("universal-express-middleware"); + const handler2 = gen.output.find( + (f: any) => f.facadeModuleId === entry2, + ) as OutputChunk | undefined; + expect(handler2?.name).toEqual("test/files/folder2/handler"); - const hono = gen.output.find( - (f: any) => - f.facadeModuleId === - "virtual:universal-middleware:hono:middleware:test/middleware.ts", + testRollupOutput(gen, "handler", entry1); + testRollupOutput(gen, "handler", entry2); + }); +}); + +function testRollupHandler( + gen: RollupOutput, + type: "handler" | "middleware", + server: string, + f: string, +) { + const parsed = parse(f); + const res = gen.output.find( + (file: any) => + file.facadeModuleId === + `virtual:universal-middleware:${server}:${type}:${f}`, ) as OutputChunk | undefined; - expect(hono?.name).toEqual("universal-hono-middleware"); + expect(res?.name).toEqual( + `${parsed.dir}/universal-${server}-${type}-${parsed.name}`, + ); +} + +function testRollupOutput( + gen: RollupOutput, + type: "handler" | "middleware", + f: string, +) { + // FIXME hash + testRollupHandler(gen, type, "express", f); + testRollupHandler(gen, type, "hono", f); + testRollupHandler(gen, type, "hattip", f); +} + +function expectNbOutput(i: number) { + return i * 4; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9308928..70ce7dc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,7 +138,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) tsx: specifier: ^4.16.2 version: 4.16.2 @@ -190,7 +190,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) tsx: specifier: ^4.16.2 version: 4.16.2 @@ -224,7 +224,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) tsx: specifier: ^4.16.2 version: 4.16.2 @@ -248,7 +248,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) typescript: specifier: ^5.5.3 version: 5.5.3 @@ -276,7 +276,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) typescript: specifier: ^5.5.3 version: 5.5.3 @@ -305,6 +305,15 @@ importers: '@rollup/plugin-node-resolve': specifier: ^15.2.3 version: 15.2.3(rollup@4.18.1) + '@rollup/plugin-swc': + specifier: ^0.3.1 + version: 0.3.1(@swc/core@1.6.13)(rollup@4.18.1) + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.18.1)(tslib@2.6.3)(typescript@5.5.3) + '@swc/core': + specifier: ^1.6.13 + version: 1.6.13 '@universal-middleware/core': specifier: link:../core version: link:../core @@ -316,7 +325,7 @@ importers: version: 4.18.1 tsup: specifier: ^8.1.0 - version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) typescript: specifier: ^5.5.3 version: 5.5.3 @@ -813,6 +822,29 @@ packages: rollup: optional: true + '@rollup/plugin-swc@0.3.1': + resolution: {integrity: sha512-oqHt6W2J3CoIrdWpbLiRXdRkepEv+qwCgHMnSmh7waPFxaEeO3tocA1xy2p2qoJmk1zygDoxtPeP95z8bsJ+fA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@swc/core': ^1.3.0 + rollup: ^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-typescript@11.1.6': + resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: '*' + typescript: '>=3.7.0' + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + '@rollup/pluginutils@5.1.0': resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} engines: {node: '>=14.0.0'} @@ -902,6 +934,81 @@ packages: cpu: [x64] os: [win32] + '@swc/core-darwin-arm64@1.6.13': + resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.6.13': + resolution: {integrity: sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.6.13': + resolution: {integrity: sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.6.13': + resolution: {integrity: sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.6.13': + resolution: {integrity: sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.6.13': + resolution: {integrity: sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.6.13': + resolution: {integrity: sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.6.13': + resolution: {integrity: sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.6.13': + resolution: {integrity: sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.6.13': + resolution: {integrity: sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.6.13': + resolution: {integrity: sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.9': + resolution: {integrity: sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -2492,6 +2599,9 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + smob@1.5.0: + resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -3337,6 +3447,23 @@ snapshots: optionalDependencies: rollup: 4.18.1 + '@rollup/plugin-swc@0.3.1(@swc/core@1.6.13)(rollup@4.18.1)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + '@swc/core': 1.6.13 + smob: 1.5.0 + optionalDependencies: + rollup: 4.18.1 + + '@rollup/plugin-typescript@11.1.6(rollup@4.18.1)(tslib@2.6.3)(typescript@5.5.3)': + dependencies: + '@rollup/pluginutils': 5.1.0(rollup@4.18.1) + resolve: 1.22.8 + typescript: 5.5.3 + optionalDependencies: + rollup: 4.18.1 + tslib: 2.6.3 + '@rollup/pluginutils@5.1.0(rollup@4.18.1)': dependencies: '@types/estree': 1.0.5 @@ -3393,6 +3520,58 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.18.1': optional: true + '@swc/core-darwin-arm64@1.6.13': + optional: true + + '@swc/core-darwin-x64@1.6.13': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.6.13': + optional: true + + '@swc/core-linux-arm64-gnu@1.6.13': + optional: true + + '@swc/core-linux-arm64-musl@1.6.13': + optional: true + + '@swc/core-linux-x64-gnu@1.6.13': + optional: true + + '@swc/core-linux-x64-musl@1.6.13': + optional: true + + '@swc/core-win32-arm64-msvc@1.6.13': + optional: true + + '@swc/core-win32-ia32-msvc@1.6.13': + optional: true + + '@swc/core-win32-x64-msvc@1.6.13': + optional: true + + '@swc/core@1.6.13': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.9 + optionalDependencies: + '@swc/core-darwin-arm64': 1.6.13 + '@swc/core-darwin-x64': 1.6.13 + '@swc/core-linux-arm-gnueabihf': 1.6.13 + '@swc/core-linux-arm64-gnu': 1.6.13 + '@swc/core-linux-arm64-musl': 1.6.13 + '@swc/core-linux-x64-gnu': 1.6.13 + '@swc/core-linux-x64-musl': 1.6.13 + '@swc/core-win32-arm64-msvc': 1.6.13 + '@swc/core-win32-ia32-msvc': 1.6.13 + '@swc/core-win32-x64-msvc': 1.6.13 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.9': + dependencies: + '@swc/counter': 0.1.3 + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -5120,6 +5299,8 @@ snapshots: slash@3.0.0: {} + smob@1.5.0: {} + source-map-js@1.2.0: {} source-map-support@0.5.21: @@ -5276,7 +5457,7 @@ snapshots: tslib@2.6.3: {} - tsup@8.1.0(postcss@8.4.39)(typescript@5.5.3): + tsup@8.1.0(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3): dependencies: bundle-require: 4.2.1(esbuild@0.21.5) cac: 6.7.14 @@ -5293,6 +5474,7 @@ snapshots: sucrase: 3.35.0 tree-kill: 1.2.2 optionalDependencies: + '@swc/core': 1.6.13 postcss: 8.4.39 typescript: 5.5.3 transitivePeerDependencies: