From 329351379772b5dcf40196a3485052149641394a Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 6 May 2023 14:47:31 +0900 Subject: [PATCH 01/27] refactor: add entry-hattip --- app/misc/entry-hattip.ts | 11 +++++++++++ package.json | 1 + pnpm-lock.yaml | 7 +++++++ 3 files changed, 19 insertions(+) create mode 100644 app/misc/entry-hattip.ts diff --git a/app/misc/entry-hattip.ts b/app/misc/entry-hattip.ts new file mode 100644 index 0000000000..49a8f18aab --- /dev/null +++ b/app/misc/entry-hattip.ts @@ -0,0 +1,11 @@ +import type { HattipHandler } from "@hattip/core"; +import * as build from "@remix-run/dev/server-build"; +import { createRequestHandler } from "@remix-run/server-runtime"; + +const remixHandler = createRequestHandler(build); + +const hattipHandler: HattipHandler = (context) => { + return remixHandler(context.request); +}; + +export default hattipHandler; diff --git a/package.json b/package.json index 209a58d5b3..d5961fc409 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@badrap/bar-of-progress": "^0.2.2", "@floating-ui/react": "^0.21.1", "@formatjs/intl": "^2.7.1", + "@hattip/core": "^0.0.33", "@headlessui/react": "^1.7.13", "@hiogawa/utils": "1.4.2-pre.9", "@hiogawa/utils-react": "1.2.1-pre.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 133fd93c2d..80f8df41ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,6 +21,9 @@ dependencies: '@formatjs/intl': specifier: ^2.7.1 version: 2.7.1(typescript@4.9.5) + '@hattip/core': + specifier: ^0.0.33 + version: 0.0.33 '@headlessui/react': specifier: ^1.7.13 version: 1.7.13(react-dom@18.2.0)(react@18.2.0) @@ -2091,6 +2094,10 @@ packages: /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + /@hattip/core@0.0.33: + resolution: {integrity: sha512-/3hhN1PYMwDDSF1zqVHEHgFHhwB2YxDPBByLZFPQG6euPTODxG9/RMpZ9YJ4cYatshSAGGwSfNXUVpflMLbJTg==} + dev: false + /@headlessui/react@1.7.13(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==} engines: {node: '>=10'} From 2dd9e0235bd3acb9ac1b84b0acbbb5317be31c8f Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sat, 6 May 2023 15:31:27 +0900 Subject: [PATCH 02/27] wip --- app/misc/entry-dev.ts | 22 +++++++++ app/misc/entry-express.ts | 11 +++++ app/misc/entry-hattip.ts | 11 ----- package.json | 7 ++- pnpm-lock.yaml | 97 ++++++++++++++++++++++++++++++++++++++- remix.config.js | 2 +- 6 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 app/misc/entry-dev.ts create mode 100644 app/misc/entry-express.ts delete mode 100644 app/misc/entry-hattip.ts diff --git a/app/misc/entry-dev.ts b/app/misc/entry-dev.ts new file mode 100644 index 0000000000..56fc0f7897 --- /dev/null +++ b/app/misc/entry-dev.ts @@ -0,0 +1,22 @@ +import * as build from "@remix-run/dev/server-build"; +import { createRequestHandler } from "@remix-run/express" +import { createApp } from "@remix-run/serve" + +// const requestHandler = createRequestHandler({ build }); + + +function main() { + const app = createApp( + "./build/remix/development/server/index.js", + "production", + "/build/remix/development/public/build", + "build/remix/development/public/build", + ) + + // const server = createServer(hattipHandler); + // server.listen(3000, "localhost", () => { + // console.log("server started at http://localhost:3000"); + // }); +} + +// main(); diff --git a/app/misc/entry-express.ts b/app/misc/entry-express.ts new file mode 100644 index 0000000000..e735a328b0 --- /dev/null +++ b/app/misc/entry-express.ts @@ -0,0 +1,11 @@ +// import type { HattipHandler } from "@hattip/core"; +// import * as build from "@remix-run/dev/server-build"; +// import { createRequestHandler } from "@remix-run/express" + +// const remixHandler = createRequestHandler({ build }); + +// const hattipHandler: HattipHandler = (context) => { +// return remixHandler(context.request); +// }; + +// export default hattipHandler; diff --git a/app/misc/entry-hattip.ts b/app/misc/entry-hattip.ts deleted file mode 100644 index 49a8f18aab..0000000000 --- a/app/misc/entry-hattip.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { HattipHandler } from "@hattip/core"; -import * as build from "@remix-run/dev/server-build"; -import { createRequestHandler } from "@remix-run/server-runtime"; - -const remixHandler = createRequestHandler(build); - -const hattipHandler: HattipHandler = (context) => { - return remixHandler(context.request); -}; - -export default hattipHandler; diff --git a/package.json b/package.json index d5961fc409..001b274bcf 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "dev-pre": "pnpm build:css", "dev-e2e": "export NODE_ENV=test && pnpm dev-pre && PORT=3001 pnpm dev:remix", "dev-ui": "vite --host", - "dev:remix": "NODE_OPTIONS='--enable-source-maps' remix dev", + "dev:remix": "remix watch", + "devx:serve": "NODE_ENV=development NODE_OPTIONS='--enable-source-maps' remix-serve build/remix/development/server/index.js", + "devx:nodemon": "nodemon remix-serve build/remix/development/server/index.js --watch build/remix/development/server/index.js", "dev-coverage:remix": "c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node_modules/.bin/remix dev", "tsc": "tsc -b", "dev:tsc": "pnpm tsc --watch --preserveWatchOutput", @@ -47,6 +49,7 @@ "@hiogawa/utils": "1.4.2-pre.9", "@hiogawa/utils-react": "1.2.1-pre.4", "@js-temporal/polyfill": "^0.4.3", + "@remix-run/express": "1.15.0", "@remix-run/node": "1.15.0", "@remix-run/react": "1.15.0", "@remix-run/server-runtime": "1.15.0", @@ -75,6 +78,7 @@ "zod": "^3.21.4" }, "devDependencies": { + "@hattip/adapter-node": "^0.0.33", "@hiogawa/isort-ts": "1.0.2-pre.1", "@hiogawa/unocss-preset-antd": "2.2.1-pre.2", "@iconify-json/ri": "^1.1.7", @@ -101,6 +105,7 @@ "fs-extra": "^10.1.0", "gh-pages": "^3.2.3", "happy-dom": "^8.9.0", + "nodemon": "^2.0.22", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", "qrcode-terminal": "^0.12.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80f8df41ca..f32f5d5a0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ dependencies: '@js-temporal/polyfill': specifier: ^0.4.3 version: 0.4.3 + '@remix-run/express': + specifier: 1.15.0 + version: 1.15.0(express@4.17.3) '@remix-run/node': specifier: 1.15.0 version: 1.15.0(patch_hash=z6mxtllsu73w4y6xnddlyl6j6y) @@ -116,6 +119,9 @@ dependencies: version: 3.21.4 devDependencies: + '@hattip/adapter-node': + specifier: ^0.0.33 + version: 0.0.33 '@hiogawa/isort-ts': specifier: 1.0.2-pre.1 version: 1.0.2-pre.1(prettier@2.8.4)(typescript@4.9.5) @@ -194,6 +200,9 @@ devDependencies: happy-dom: specifier: ^8.9.0 version: 8.9.0 + nodemon: + specifier: ^2.0.22 + version: 2.0.22 npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -2094,9 +2103,22 @@ packages: /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + /@hattip/adapter-node@0.0.33: + resolution: {integrity: sha512-tEEYo/V0Vj7kQRuruoBHUzfJnaoKjW5EHALsU9RgyPvOs1hCJUil9UEkyVebneTBdQHUcljx4a4ZgS2pnrWOAA==} + dependencies: + '@hattip/core': 0.0.33 + '@hattip/polyfills': 0.0.33 + dev: true + /@hattip/core@0.0.33: resolution: {integrity: sha512-/3hhN1PYMwDDSF1zqVHEHgFHhwB2YxDPBByLZFPQG6euPTODxG9/RMpZ9YJ4cYatshSAGGwSfNXUVpflMLbJTg==} - dev: false + + /@hattip/polyfills@0.0.33: + resolution: {integrity: sha512-8rRQv/4F1xDionmk+T42lQ3tq6tQ4/+NoYaciKx0eg0C9KL1+of5BHGDkZA7XpymeoTZXsdY1hmWusX5w/8lTg==} + dependencies: + '@hattip/core': 0.0.33 + node-fetch-native: 1.0.2 + dev: true /@headlessui/react@1.7.13(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-9n+EQKRtD9266xIHXdY5MfiXPDfYwl7zBM7KOx2Ae3Gdgxy8QML1FkCMjq6AsOf0l6N9uvI4HcFtuFlenaldKg==} @@ -3063,6 +3085,10 @@ packages: requiresBuild: true optional: true + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: true + /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3749,6 +3775,18 @@ packages: dependencies: ms: 2.0.0 + /debug@3.2.7(supports-color@5.5.0): + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 5.5.0 + dev: true + /debug@4.3.3: resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} engines: {node: '>=6.0'} @@ -4896,6 +4934,10 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + /ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + dev: true + /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -5071,7 +5113,7 @@ packages: resolution: {integrity: sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==} /is-extglob@2.1.1: - resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} /is-fullwidth-code-point@3.0.0: @@ -6115,6 +6157,30 @@ packages: /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} + /nodemon@2.0.22: + resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} + engines: {node: '>=8.10.0'} + hasBin: true + dependencies: + chokidar: 3.5.3 + debug: 3.2.7(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 5.7.1 + simple-update-notifier: 1.1.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + dev: true + + /nopt@1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: true + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -6661,6 +6727,10 @@ packages: resolution: {integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=} dev: false + /pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + dev: true + /pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} dependencies: @@ -7129,6 +7199,11 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true + /semver@7.0.0: + resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} + hasBin: true + dev: true + /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} @@ -7218,6 +7293,13 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + /simple-update-notifier@1.1.0: + resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} + engines: {node: '>=8.10.0'} + dependencies: + semver: 7.0.0 + dev: true + /sirv@2.0.2: resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} engines: {node: '>= 10'} @@ -7593,6 +7675,13 @@ packages: engines: {node: '>=6'} dev: true + /touch@3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + dependencies: + nopt: 1.0.10 + dev: true + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -7721,6 +7810,10 @@ packages: jiti: 1.18.2 dev: true + /undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + dev: true + /unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} diff --git a/remix.config.js b/remix.config.js index 92240d8637..a3220ce1a5 100644 --- a/remix.config.js +++ b/remix.config.js @@ -6,7 +6,7 @@ module.exports = { serverBuildPath: `build/remix/${env}/server/index.js`, assetsBuildDirectory: `build/remix/${env}/public/build`, publicPath: process.env.BUILD_VERCEL ? undefined : `/build/remix/${env}/public/build`, - server: process.env.BUILD_VERCEL ? "./app/misc/vercel.ts" : undefined, + // server: process.env.BUILD_VERCEL ? undefined : "./app/misc/entry-hattip.ts", future: { v2_meta: true, v2_errorBoundary: true, From 8ae519c0616a67a8c36d77fd2a66153a5b578f13 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 16:29:48 +0900 Subject: [PATCH 03/27] chore: add hattip entry --- app/misc/entry-dev.ts | 22 ------- app/misc/entry-express.ts | 11 ---- app/server/entry-dev.ts | 23 ++++++++ app/server/entry-hattip.ts | 93 ++++++++++++++++++++++++++++++ app/server/entry-vercel.ts | 12 ++++ app/server/http.ts | 52 +++++++++++++++++ app/trpc/client-internal.client.ts | 3 +- app/trpc/common.ts | 1 + package.json | 3 + pnpm-lock.yaml | 86 ++++++++++++++++++++++++++- remix.config.js | 3 +- 11 files changed, 270 insertions(+), 39 deletions(-) delete mode 100644 app/misc/entry-dev.ts delete mode 100644 app/misc/entry-express.ts create mode 100644 app/server/entry-dev.ts create mode 100644 app/server/entry-hattip.ts create mode 100644 app/server/entry-vercel.ts create mode 100644 app/server/http.ts create mode 100644 app/trpc/common.ts diff --git a/app/misc/entry-dev.ts b/app/misc/entry-dev.ts deleted file mode 100644 index 56fc0f7897..0000000000 --- a/app/misc/entry-dev.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as build from "@remix-run/dev/server-build"; -import { createRequestHandler } from "@remix-run/express" -import { createApp } from "@remix-run/serve" - -// const requestHandler = createRequestHandler({ build }); - - -function main() { - const app = createApp( - "./build/remix/development/server/index.js", - "production", - "/build/remix/development/public/build", - "build/remix/development/public/build", - ) - - // const server = createServer(hattipHandler); - // server.listen(3000, "localhost", () => { - // console.log("server started at http://localhost:3000"); - // }); -} - -// main(); diff --git a/app/misc/entry-express.ts b/app/misc/entry-express.ts deleted file mode 100644 index e735a328b0..0000000000 --- a/app/misc/entry-express.ts +++ /dev/null @@ -1,11 +0,0 @@ -// import type { HattipHandler } from "@hattip/core"; -// import * as build from "@remix-run/dev/server-build"; -// import { createRequestHandler } from "@remix-run/express" - -// const remixHandler = createRequestHandler({ build }); - -// const hattipHandler: HattipHandler = (context) => { -// return remixHandler(context.request); -// }; - -// export default hattipHandler; diff --git a/app/server/entry-dev.ts b/app/server/entry-dev.ts new file mode 100644 index 0000000000..392e73e25a --- /dev/null +++ b/app/server/entry-dev.ts @@ -0,0 +1,23 @@ +import { createServer } from "node:http"; +import { createMiddleware } from "@hattip/adapter-node"; +import * as build from "@remix-run/dev/server-build"; +import express from "express"; +import { createHattipApp } from "./entry-hattip"; +import { listenPortSearchByEnv } from "./http"; + +async function main() { + const app = express(); + const server = createServer(app); + + // serve client build assets + app.use("/build", express.static(build.assetsBuildDirectory)); + + // all application logic as hattip handler + app.use(createMiddleware(createHattipApp())); + + // start app + const port = await listenPortSearchByEnv(server); + console.log(`[entry-dev] Server running at http://localhost:${port}`); +} + +main(); diff --git a/app/server/entry-hattip.ts b/app/server/entry-hattip.ts new file mode 100644 index 0000000000..249f687275 --- /dev/null +++ b/app/server/entry-hattip.ts @@ -0,0 +1,93 @@ +import { type RequestHandler, compose } from "@hattip/compose"; +import { once } from "@hiogawa/utils"; +import * as build from "@remix-run/dev/server-build"; +import { createRequestHandler } from "@remix-run/server-runtime"; +import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; +import type * as hono from "hono"; +import { logger } from "hono/logger"; +import { initializeServer } from "../misc/initialize-server"; +import { TRPC_ENDPOINT } from "../trpc/common"; +import { createTrpcAppContext } from "../trpc/context"; +import { trpcApp } from "../trpc/server"; + +// based on https://github.com/hi-ogawa/vite-fullstack-example/blob/92649f99b041820ec86650c99cfcd49a72e79f71/src/server/hattip.ts#L16-L28 + +export function createHattipApp() { + return compose( + createBootstrapHandler(), + createLogger(), + createTrpchandler(), + createRemixHandler() + ); +} + +// +// remix +// + +function createRemixHandler(): RequestHandler { + const remixHandler = createRequestHandler(build); + return async (ctx) => { + const response = await remixHandler(ctx.request); + return response; + }; +} + +// +// trpc +// + +function createTrpchandler(): RequestHandler { + return async (ctx) => { + if (!ctx.url.pathname.startsWith(TRPC_ENDPOINT)) { + return ctx.next(); + } + return fetchRequestHandler({ + endpoint: TRPC_ENDPOINT, + req: ctx.request, + router: trpcApp, + createContext: createTrpcAppContext, + onError: (e) => { + console.error(e); + }, + }); + }; +} + +// +// bootstrap +// + +function createBootstrapHandler(): RequestHandler { + const initializeServerOnce = once(initializeServer); + return async (ctx) => { + await initializeServerOnce(); + return ctx.next(); + }; +} + +// +// logger +// + +function createLogger(): RequestHandler { + // borrow hono's logger by minimal hattip-hono compatibility layer + // https://github.com/honojs/hono/blob/0ffd795ec6cfb67d38ab902197bb5461a4740b8f/src/middleware/logger/index.ts + const honoLogger = logger(); + + return async (ctx) => { + let res!: Response; + await honoLogger( + { + req: { method: ctx.method, raw: ctx.request }, + get res() { + return res; + }, + } as hono.Context, + async () => { + res = await ctx.next(); + } + ); + return res; + }; +} diff --git a/app/server/entry-vercel.ts b/app/server/entry-vercel.ts new file mode 100644 index 0000000000..61cab9b4f6 --- /dev/null +++ b/app/server/entry-vercel.ts @@ -0,0 +1,12 @@ +import { createMiddleware } from "@hattip/adapter-node"; +import { createHattipApp } from "./entry-hattip"; + +// cf. https://github.com/hattipjs/hattip/blob/03a704fa120dfe2eddd6cf22eff00c90bda2acb5/packages/bundler/bundler-vercel/readme.md + +export default createVercelHanlder(); + +function createVercelHanlder() { + return createMiddleware(createHattipApp(), { + trustProxy: true, + }); +} diff --git a/app/server/http.ts b/app/server/http.ts new file mode 100644 index 0000000000..a3597b768b --- /dev/null +++ b/app/server/http.ts @@ -0,0 +1,52 @@ +import type { Server } from "node:http"; +import process from "node:process"; +import { newPromiseWithResolvers, range } from "@hiogawa/utils"; + +export async function listenPortSearchByEnv(server: Server) { + const initialPort = Number(process.env["PORT"] ?? 3000); + const strictPort = Boolean(process.env["STRICT_PORT"]); + return listenPortSearch(server, "localhost", initialPort, strictPort); +} + +async function listenPortSearch( + server: Server, + host: string, + initialPort: number, + strictPort: boolean +) { + for (const port of range(initialPort, 2 ** 16)) { + if (port !== initialPort) { + console.log(`[listenPortSearch] trying next port '${port}'`); + } + try { + await listenPromise(server, host, port); + return port; + } catch (e) { + if ( + !strictPort && + e instanceof Error && + (e as any).code === "EADDRINUSE" + ) { + continue; + } + throw e; + } + } + throw new Error(listenPortSearch.name); +} + +async function listenPromise( + server: Server, + host: string, + port: number +): Promise { + const { promise, resolve, reject } = newPromiseWithResolvers(); + const onError = (e: unknown) => reject(e); + server.on("error", onError); + server.listen(port, host, () => resolve()); + try { + await promise; + } finally { + server.off("error", onError); + } +} diff --git a/app/trpc/client-internal.client.ts b/app/trpc/client-internal.client.ts index b073ee5988..dcf9346768 100644 --- a/app/trpc/client-internal.client.ts +++ b/app/trpc/client-internal.client.ts @@ -1,5 +1,6 @@ import { createTRPCProxyClient, httpLink } from "@trpc/client"; import superjson from "superjson"; +import { TRPC_ENDPOINT } from "./common"; import type { trpcApp } from "./server"; // remove raw client from server bundle since it's not meant to be used on server. @@ -9,7 +10,7 @@ export const trpcClient = createTRPCProxyClient({ transformer: superjson, links: [ httpLink({ - url: "/trpc", + url: TRPC_ENDPOINT, }), ], }); diff --git a/app/trpc/common.ts b/app/trpc/common.ts new file mode 100644 index 0000000000..1b8438a6ac --- /dev/null +++ b/app/trpc/common.ts @@ -0,0 +1 @@ +export const TRPC_ENDPOINT = "/trpc"; diff --git a/package.json b/package.json index 6d65ccc9f8..4babf1ec25 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ }, "devDependencies": { "@hattip/adapter-node": "^0.0.33", + "@hattip/compose": "^0.0.34", "@hiogawa/isort-ts": "1.0.2-pre.1", "@hiogawa/unocss-preset-antd": "2.2.1-pre.2", "@iconify-json/ri": "^1.1.7", @@ -88,6 +89,7 @@ "@remix-run/serve": "1.15.0", "@tsconfig/strictest": "^1.0.2", "@types/bcryptjs": "^2.4.2", + "@types/express": "^4.17.17", "@types/fs-extra": "^9.0.13", "@types/node": "^16", "@types/qs": "^6.9.7", @@ -106,6 +108,7 @@ "fs-extra": "^10.1.0", "gh-pages": "^3.2.3", "happy-dom": "^8.9.0", + "hono": "^3.2.2", "nodemon": "^2.0.22", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c91fe5c5b..6e3c08c436 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,6 +125,9 @@ devDependencies: '@hattip/adapter-node': specifier: ^0.0.33 version: 0.0.33 + '@hattip/compose': + specifier: ^0.0.34 + version: 0.0.34 '@hiogawa/isort-ts': specifier: 1.0.2-pre.1 version: 1.0.2-pre.1(prettier@2.8.4)(typescript@4.9.5) @@ -149,6 +152,9 @@ devDependencies: '@types/bcryptjs': specifier: ^2.4.2 version: 2.4.2 + '@types/express': + specifier: ^4.17.17 + version: 4.17.17 '@types/fs-extra': specifier: ^9.0.13 version: 9.0.13 @@ -203,6 +209,9 @@ devDependencies: happy-dom: specifier: ^8.9.0 version: 8.9.0 + hono: + specifier: ^3.2.2 + version: 3.2.2 nodemon: specifier: ^2.0.22 version: 2.0.22 @@ -2124,9 +2133,19 @@ packages: '@hattip/polyfills': 0.0.33 dev: true + /@hattip/compose@0.0.34: + resolution: {integrity: sha512-faW5gIvyDmut3/lUWslHitH2+rrtkM9IQvBOmdTjS7r9vaADVh2t/M+MgitTzsSavfQUbP+uCbTPQ+ffrUhceA==} + dependencies: + '@hattip/core': 0.0.34 + dev: true + /@hattip/core@0.0.33: resolution: {integrity: sha512-/3hhN1PYMwDDSF1zqVHEHgFHhwB2YxDPBByLZFPQG6euPTODxG9/RMpZ9YJ4cYatshSAGGwSfNXUVpflMLbJTg==} + /@hattip/core@0.0.34: + resolution: {integrity: sha512-L9MRB5fVgW8vd2wKDbD1pIhsM4UloRCdsXn3x9us2Xp1jeynS83T3gHGLdUvPclgGvQZapwBgUkkn9paS+bjDg==} + dev: true + /@hattip/polyfills@0.0.33: resolution: {integrity: sha512-8rRQv/4F1xDionmk+T42lQ3tq6tQ4/+NoYaciKx0eg0C9KL1+of5BHGDkZA7XpymeoTZXsdY1hmWusX5w/8lTg==} dependencies: @@ -2649,6 +2668,13 @@ packages: resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} dev: true + /@types/body-parser@1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 16.11.35 + dev: true + /@types/cacheable-request@6.0.3: resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} dependencies: @@ -2667,6 +2693,12 @@ packages: resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true + /@types/connect@3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 16.11.35 + dev: true + /@types/cookie@0.4.1: resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} @@ -2688,6 +2720,24 @@ packages: /@types/estree@1.0.0: resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} + /@types/express-serve-static-core@4.17.35: + resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} + dependencies: + '@types/node': 16.11.35 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + '@types/send': 0.17.1 + dev: true + + /@types/express@4.17.17: + resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.35 + '@types/qs': 6.9.7 + '@types/serve-static': 1.15.1 + dev: true + /@types/fs-extra@11.0.1: resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==} dependencies: @@ -2738,6 +2788,14 @@ packages: /@types/mdurl@1.0.2: resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} + /@types/mime@1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + + /@types/mime@3.0.1: + resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + dev: true + /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -2773,6 +2831,10 @@ packages: resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} dev: true + /@types/range-parser@1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + /@types/react-dom@18.0.11: resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==} dependencies: @@ -2794,6 +2856,20 @@ packages: /@types/scheduler@0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} + /@types/send@0.17.1: + resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 16.11.35 + dev: true + + /@types/serve-static@1.15.1: + resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} + dependencies: + '@types/mime': 3.0.1 + '@types/node': 16.11.35 + dev: true + /@types/unist@2.0.6: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} @@ -4846,7 +4922,6 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true /graceful-fs@4.2.9: resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} @@ -4957,6 +5032,11 @@ packages: '@babel/runtime': 7.17.2 dev: false + /hono@3.2.2: + resolution: {integrity: sha512-yVkYyefATYGz6j7iDcugtEvg4AgpccE1tDYnmvTmXDR4NQrUJ3/SdHU9V7UuWQjGtfrBujeBUAq70oc82ADsvA==} + engines: {node: '>=16.0.0'} + dev: true + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -5438,14 +5518,14 @@ packages: /jsonfile@4.0.0: resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} optionalDependencies: - graceful-fs: 4.2.9 + graceful-fs: 4.2.11 /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: universalify: 2.0.0 optionalDependencies: - graceful-fs: 4.2.9 + graceful-fs: 4.2.11 /keyv@4.5.2: resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==} diff --git a/remix.config.js b/remix.config.js index 425473fc7b..6507ba6f88 100644 --- a/remix.config.js +++ b/remix.config.js @@ -5,8 +5,7 @@ const env = process.env.NODE_ENV ?? "development"; module.exports = { serverBuildPath: `build/remix/${env}/server/index.js`, assetsBuildDirectory: `build/remix/${env}/public/build`, - publicPath: process.env.BUILD_VERCEL ? undefined : `/build/remix/${env}/public/build`, - // server: process.env.BUILD_VERCEL ? undefined : "./app/misc/entry-hattip.ts", + server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/misc/entry-dev.ts", future: { v2_meta: true, v2_errorBoundary: true, From 3f8cf80c7c15ed718781194e62668c0cd7140db3 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 17:38:10 +0900 Subject: [PATCH 04/27] chore: add dev-server.sh --- package.json | 4 ++-- remix.config.js | 3 ++- scripts/dev-server.sh | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 scripts/dev-server.sh diff --git a/package.json b/package.json index 4babf1ec25..d1cd992e7a 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "dev-e2e": "export NODE_ENV=test && pnpm dev-pre && PORT=3001 pnpm dev:remix", "dev-ui": "vite --host", "dev:remix": "remix watch", - "devx:serve": "NODE_ENV=development NODE_OPTIONS='--enable-source-maps' remix-serve build/remix/development/server/index.js", - "devx:nodemon": "nodemon remix-serve build/remix/development/server/index.js --watch build/remix/development/server/index.js", + "dev2:remix-watch": "remix watch", + "dev2:dev-server": "bash scripts/dev-server.sh", "dev-coverage:remix": "c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node_modules/.bin/remix dev", "tsc": "tsc -b", "dev:tsc": "pnpm tsc --watch --preserveWatchOutput", diff --git a/remix.config.js b/remix.config.js index 6507ba6f88..e4d2cc9839 100644 --- a/remix.config.js +++ b/remix.config.js @@ -5,7 +5,8 @@ const env = process.env.NODE_ENV ?? "development"; module.exports = { serverBuildPath: `build/remix/${env}/server/index.js`, assetsBuildDirectory: `build/remix/${env}/public/build`, - server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/misc/entry-dev.ts", + server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/server/entry-dev.ts", + serverDependenciesToBundle: "all", future: { v2_meta: true, v2_errorBoundary: true, diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh new file mode 100644 index 0000000000..7e598264b6 --- /dev/null +++ b/scripts/dev-server.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -eu -o pipefail + +server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" + +# TODO: wait for "$server_entry" to be created +exec nodemon --enable-source-maps "$server_entry" --watch "$server_entry" From 2b739d65c2f2b7cdf258de8583bb5d31d700c855 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 19:33:36 +0900 Subject: [PATCH 05/27] fix: remove installGlobals + node 18 --- app/entry.server.tsx | 3 --- app/misc/initialize-server.ts | 7 ------- app/server/entry-hattip.ts | 2 +- misc/vercel/.vc-config.json | 2 +- package.json | 2 +- 5 files changed, 3 insertions(+), 13 deletions(-) diff --git a/app/entry.server.tsx b/app/entry.server.tsx index 09d40840ef..89d35fd319 100644 --- a/app/entry.server.tsx +++ b/app/entry.server.tsx @@ -1,9 +1,6 @@ import { RemixServer } from "@remix-run/react"; import type { HandleDocumentRequestFunction } from "@remix-run/server-runtime"; import { renderToString } from "react-dom/server"; -import { injectInitializeServer } from "./misc/initialize-server"; - -injectInitializeServer(); const handler: HandleDocumentRequestFunction = ( request, diff --git a/app/misc/initialize-server.ts b/app/misc/initialize-server.ts index daf9ce0422..4436ff9ebe 100644 --- a/app/misc/initialize-server.ts +++ b/app/misc/initialize-server.ts @@ -1,5 +1,4 @@ import { once } from "@hiogawa/utils"; -import { installGlobals } from "@remix-run/node"; import { finalizeDrizzleClient, initializeDrizzleClient, @@ -8,7 +7,6 @@ import { initializeConfigServer } from "../utils/config"; import { initializeSessionStore } from "../utils/session.server"; export const initializeServer = once(async () => { - installGlobals(); initializeConfigServer(); initializeSessionStore(); await initializeDrizzleClient(); @@ -17,8 +15,3 @@ export const initializeServer = once(async () => { export async function finalizeServer() { await finalizeDrizzleClient(); } - -// to workaround async initialization on the server (cf. @remix-run/server-runtime patch) -export function injectInitializeServer() { - Object.assign(globalThis, { __onRequestHandler: initializeServer }); -} diff --git a/app/server/entry-hattip.ts b/app/server/entry-hattip.ts index 249f687275..99496af61c 100644 --- a/app/server/entry-hattip.ts +++ b/app/server/entry-hattip.ts @@ -14,8 +14,8 @@ import { trpcApp } from "../trpc/server"; export function createHattipApp() { return compose( - createBootstrapHandler(), createLogger(), + createBootstrapHandler(), createTrpchandler(), createRemixHandler() ); diff --git a/misc/vercel/.vc-config.json b/misc/vercel/.vc-config.json index f2585d43df..4052d4570e 100644 --- a/misc/vercel/.vc-config.json +++ b/misc/vercel/.vc-config.json @@ -1,5 +1,5 @@ { - "runtime": "nodejs16.x", + "runtime": "nodejs18.x", "handler": "index.js", "launcherType": "Nodejs", "regions": ["hnd1"] diff --git a/package.json b/package.json index d1cd992e7a..c99312b18b 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "zx": "^7.2.2" }, "volta": { - "node": "16.20.0" + "node": "18.16.0" }, "pnpm": { "patchedDependencies": { From 35ddf31a5e05a487f1bdeb44a7251d3965e26015 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:19:20 +0900 Subject: [PATCH 06/27] chore: add wait-for.sh --- app/e2e/videos.test.ts | 1 - package.json | 6 +++--- scripts/dev-server.sh | 3 ++- scripts/wait-for.sh | 14 ++++++++++++++ 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 scripts/wait-for.sh diff --git a/app/e2e/videos.test.ts b/app/e2e/videos.test.ts index b8148fc79c..8d360d143c 100644 --- a/app/e2e/videos.test.ts +++ b/app/e2e/videos.test.ts @@ -224,7 +224,6 @@ test.describe("video playback rate", () => { await page .getByTestId("PlaybackRateSelect") .selectOption({ label: "0.75" }); - await page.pause(); }); }); diff --git a/package.json b/package.json index c99312b18b..9000863cbb 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "dev-pre": "pnpm build:css", "dev-e2e": "export NODE_ENV=test && pnpm dev-pre && PORT=3001 pnpm dev:remix", "dev-ui": "vite --host", - "dev:remix": "remix watch", - "dev2:remix-watch": "remix watch", - "dev2:dev-server": "bash scripts/dev-server.sh", + "dev:remix": "run-p remix-watch remix-dev-server", + "remix-watch": "remix watch", + "remix-dev-server": "bash scripts/dev-server.sh", "dev-coverage:remix": "c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node_modules/.bin/remix dev", "tsc": "tsc -b", "dev:tsc": "pnpm tsc --watch --preserveWatchOutput", diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 7e598264b6..804f2e30f1 100644 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -3,5 +3,6 @@ set -eu -o pipefail server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" -# TODO: wait for "$server_entry" to be created +bash scripts/wait-for.sh test -f "$server_entry" + exec nodemon --enable-source-maps "$server_entry" --watch "$server_entry" diff --git a/scripts/wait-for.sh b/scripts/wait-for.sh new file mode 100644 index 0000000000..caeffa3e48 --- /dev/null +++ b/scripts/wait-for.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eu -o pipefail + +# usage +# bash scripts/wait-for.sh test -f build/test/server/index.js + +for ((i=0; ;i++)); do + echo "[wait-for:$i] ${*}" + sleep "$i" + if "${@}"; then + echo "[wait-for:$i:success] ${*}" + break; + fi +done From 11ef49e064cf78ff8b352898e2a230a9ee27fcff Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:20:08 +0900 Subject: [PATCH 07/27] chore: tweak script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9000863cbb..56281d9e6e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "scripts": { "dev": "pnpm dev-pre && run-p dev:*", "dev-pre": "pnpm build:css", - "dev-e2e": "export NODE_ENV=test && pnpm dev-pre && PORT=3001 pnpm dev:remix", + "dev-e2e": "export NODE_ENV=test && pnpm dev-pre && PORT=3001 STRICT_PORT=true pnpm dev:remix", "dev-ui": "vite --host", "dev:remix": "run-p remix-watch remix-dev-server", "remix-watch": "remix watch", From 4fb0fcdee789888e2efe3b6c5c17d433c0010568 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:22:27 +0900 Subject: [PATCH 08/27] chore: tweak e2e --- playwright.config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index 31fac31ec2..33a4d15065 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -7,15 +7,15 @@ export default defineConfig({ baseURL: "http://localhost:3001", actionTimeout: 10_000, navigationTimeout: 10_000, - trace: process.env.E2E_CLIENT_TRACE ? "on" : "off", + trace: process.env.E2E_CLIENT_TRACE ? "retain-on-failure" : "off", }, projects: [ { name: "chromium", use: { browserName: "chromium", - // https://github.com/microsoft/playwright/issues/1086#issuecomment-592227413 - viewport: null, // adopt to browser window size specified below + // adapt to browser window size specified below (cf. https://github.com/microsoft/playwright/issues/1086#issuecomment-592227413) + viewport: null, launchOptions: { args: ["--window-size=600,800"], }, From 7d01ba9d0dd8ecc6c8f4c610ecd50b9af80c71b7 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:26:04 +0900 Subject: [PATCH 09/27] chore: remove unused --- app/routes/trpc/$trpc.tsx | 22 ---------- package.json | 1 - .../@remix-run__server-runtime@1.15.0.patch | 13 ------ pnpm-lock.yaml | 40 ++++++++++--------- 4 files changed, 21 insertions(+), 55 deletions(-) delete mode 100644 app/routes/trpc/$trpc.tsx delete mode 100644 patches/@remix-run__server-runtime@1.15.0.patch diff --git a/app/routes/trpc/$trpc.tsx b/app/routes/trpc/$trpc.tsx deleted file mode 100644 index 827f51f2bd..0000000000 --- a/app/routes/trpc/$trpc.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { ActionFunction, LoaderFunction } from "@remix-run/server-runtime"; -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { createTrpcAppContext } from "../../trpc/context"; -import { trpcApp } from "../../trpc/server"; - -// catch-all trpc endpoint (cf. https://trpc.io/docs/server/adapters/fetch#remix) - -export const loader: LoaderFunction = trpcHandler; -export const action: ActionFunction = trpcHandler; - -function trpcHandler(args: { request: Request }) { - return fetchRequestHandler({ - endpoint: "/trpc", - req: args.request, - router: trpcApp, - createContext: createTrpcAppContext, - // quick error logging since otherwise remix only shows 500 access log - onError: (e) => { - console.error(e); - }, - }); -} diff --git a/package.json b/package.json index 56281d9e6e..2601d3c030 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,6 @@ "pnpm": { "patchedDependencies": { "@remix-run/dev@1.15.0": "patches/@remix-run__dev@1.15.0.patch", - "@remix-run/server-runtime@1.15.0": "patches/@remix-run__server-runtime@1.15.0.patch", "@remix-run/node@1.15.0": "patches/@remix-run__node@1.15.0.patch" } } diff --git a/patches/@remix-run__server-runtime@1.15.0.patch b/patches/@remix-run__server-runtime@1.15.0.patch deleted file mode 100644 index 542d08c416..0000000000 --- a/patches/@remix-run__server-runtime@1.15.0.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/dist/server.js b/dist/server.js -index fd10bc563175ba69bda9b21ccc7732b20f794900..ebb6e94785bee2bca35031977d083ad516a3ae94 100644 ---- a/dist/server.js -+++ b/dist/server.js -@@ -29,6 +29,8 @@ const createRequestHandler = (build, mode$1) => { - let serverMode = mode.isServerMode(mode$1) ? mode$1 : mode.ServerMode.Production; - let staticHandler = router.createStaticHandler(dataRoutes); - return async function requestHandler(request, loadContext = {}) { -+ // see misc/initialize-server.ts -+ await globalThis.__onRequestHandler?.(); - let url = new URL(request.url); - - // special __REMIX_ASSETS_MANIFEST endpoint for checking if app server serving up-to-date routes and assets \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e3c08c436..e329f4d532 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,9 +7,6 @@ patchedDependencies: '@remix-run/node@1.15.0': hash: z6mxtllsu73w4y6xnddlyl6j6y path: patches/@remix-run__node@1.15.0.patch - '@remix-run/server-runtime@1.15.0': - hash: qalbsgt3akixld37vecooshrwu - path: patches/@remix-run__server-runtime@1.15.0.patch dependencies: '@badrap/bar-of-progress': @@ -50,7 +47,7 @@ dependencies: version: 1.15.0(react-dom@18.2.0)(react@18.2.0) '@remix-run/server-runtime': specifier: 1.15.0 - version: 1.15.0(patch_hash=qalbsgt3akixld37vecooshrwu) + version: 1.15.0 '@remix-run/v1-route-convention': specifier: ^0.1.1 version: 0.1.1(@remix-run/dev@1.15.0) @@ -107,7 +104,7 @@ dependencies: version: 7.43.7(react@18.2.0) react-hot-toast: specifier: ^2.4.0 - version: 2.4.0(react-dom@18.2.0)(react@18.2.0) + version: 2.4.0(csstype@3.0.11)(react-dom@18.2.0)(react@18.2.0) react-remove-scroll: specifier: ^2.5.5 version: 2.5.5(@types/react@18.0.28)(react@18.2.0) @@ -133,7 +130,7 @@ devDependencies: version: 1.0.2-pre.1(prettier@2.8.4)(typescript@4.9.5) '@hiogawa/unocss-preset-antd': specifier: 2.2.1-pre.2 - version: 2.2.1-pre.2(unocss@0.50.6) + version: 2.2.1-pre.2(@unocss/preset-uno@0.50.6)(unocss@0.50.6) '@iconify-json/ri': specifier: ^1.1.7 version: 1.1.7 @@ -232,7 +229,7 @@ devDependencies: version: 4.9.5 unocss: specifier: ^0.50.6 - version: 0.50.6(vite@4.2.0) + version: 0.50.6(postcss@8.4.23)(vite@4.2.0) vite: specifier: ^4.2.0 version: 4.2.0(@types/node@16.11.35) @@ -2178,15 +2175,16 @@ packages: typescript: 4.9.5 dev: true - /@hiogawa/unocss-preset-antd@2.2.1-pre.2(unocss@0.50.6): + /@hiogawa/unocss-preset-antd@2.2.1-pre.2(@unocss/preset-uno@0.50.6)(unocss@0.50.6): resolution: {integrity: sha512-IyLBst49BiscFZ+lcO1d2fJ7S7YhEK+ikgZNymtgbcMYhIbgzY6Qju4FW5BpBivQ3csMblzvgz+sfJDaXC0viw==} peerDependencies: '@unocss/preset-uno': '*' unocss: '*' dependencies: + '@unocss/preset-uno': 0.50.6 '@unocss/reset': 0.48.5 local-pkg: 0.4.3 - unocss: 0.50.6(vite@4.2.0) + unocss: 0.50.6(postcss@8.4.23)(vite@4.2.0) dev: true /@hiogawa/utils-experimental@0.0.1: @@ -2366,7 +2364,7 @@ packages: '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) '@npmcli/package-json': 2.0.0 '@remix-run/serve': 1.15.0 - '@remix-run/server-runtime': 1.15.0(patch_hash=qalbsgt3akixld37vecooshrwu) + '@remix-run/server-runtime': 1.15.0 '@vanilla-extract/integration': 6.2.1(@types/node@16.11.35) arg: 5.0.2 cacache: 15.3.0 @@ -2436,7 +2434,7 @@ packages: resolution: {integrity: sha512-CS0p8T6A2KvMoAW5zzLA/BtNNCsv34A5RJoouJvXK9/o6MriAQ/YSugg6ldS5mec49neSep+CGeL1RS6tL+3NQ==} engines: {node: '>=14'} dependencies: - '@remix-run/server-runtime': 1.15.0(patch_hash=qalbsgt3akixld37vecooshrwu) + '@remix-run/server-runtime': 1.15.0 '@remix-run/web-fetch': 4.3.3 '@remix-run/web-file': 3.0.2 '@remix-run/web-stream': 1.0.3 @@ -2477,7 +2475,7 @@ packages: transitivePeerDependencies: - supports-color - /@remix-run/server-runtime@1.15.0(patch_hash=qalbsgt3akixld37vecooshrwu): + /@remix-run/server-runtime@1.15.0: resolution: {integrity: sha512-DL9xjHfYYrEcOq5VbhYtrjJUWo/nFQAT7Y+Np/oC55HokyU6cb2jGhl52nx96aAxKwaFCse5N90GeodFsRzX7w==} engines: {node: '>=14'} dependencies: @@ -2488,7 +2486,6 @@ packages: cookie: 0.4.2 set-cookie-parser: 2.4.8 source-map: 0.7.4 - patched: true /@remix-run/v1-route-convention@0.1.1(@remix-run/dev@1.15.0): resolution: {integrity: sha512-jmy/TbdwWdJnDaYVN0byyyKPUHlsJvZ+pUiXQqLouCEcjo7aQgF5gBGwRQP5bxlWJaIqYD4oNHiSVq/RkTziRA==} @@ -2929,9 +2926,11 @@ packages: sirv: 2.0.2 dev: true - /@unocss/postcss@0.50.6: + /@unocss/postcss@0.50.6(postcss@8.4.23): resolution: {integrity: sha512-pRPBVPmwjsVu3v1T0hQuqq3L4K74Wobo6pGDypvK/MuzWdWDhHiktWwmXGNxlYSWK7mGJBIa+vI10pp4e15OUw==} engines: {node: '>=14'} + peerDependencies: + postcss: ^8.4.21 dependencies: '@unocss/config': 0.50.6 '@unocss/core': 0.50.6 @@ -4893,10 +4892,12 @@ packages: pinkie-promise: 2.0.1 dev: true - /goober@2.1.12: + /goober@2.1.12(csstype@3.0.11): resolution: {integrity: sha512-yXHAvO08FU1JgTXX6Zn6sYCUFfB/OJSX8HHjDSgerZHZmFKAb08cykp5LBw5QnmyMcZyPRMqkdyHUSSzge788Q==} peerDependencies: csstype: ^3.0.10 + dependencies: + csstype: 3.0.11 dev: false /gopd@1.0.1: @@ -7014,14 +7015,14 @@ packages: react: 18.2.0 dev: false - /react-hot-toast@2.4.0(react-dom@18.2.0)(react@18.2.0): + /react-hot-toast@2.4.0(csstype@3.0.11)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-qnnVbXropKuwUpriVVosgo8QrB+IaPJCpL8oBI6Ov84uvHZ5QQcTp2qg6ku2wNfgJl6rlQXJIQU5q+5lmPOutA==} engines: {node: '>=10'} peerDependencies: react: '>=16' react-dom: '>=16' dependencies: - goober: 2.1.12 + goober: 2.1.12(csstype@3.0.11) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -8129,7 +8130,7 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - /unocss@0.50.6(vite@4.2.0): + /unocss@0.50.6(postcss@8.4.23)(vite@4.2.0): resolution: {integrity: sha512-7cKiIB/ssAPvCDUcFMs0jm0FzIyQKfgIjUzBYZ5dVFthOvN5dcFh7bCZE9dIM862n7oW8FjbkTxwdTbRqqJQVQ==} engines: {node: '>=14'} peerDependencies: @@ -8141,7 +8142,7 @@ packages: '@unocss/astro': 0.50.6(vite@4.2.0) '@unocss/cli': 0.50.6 '@unocss/core': 0.50.6 - '@unocss/postcss': 0.50.6 + '@unocss/postcss': 0.50.6(postcss@8.4.23) '@unocss/preset-attributify': 0.50.6 '@unocss/preset-icons': 0.50.6 '@unocss/preset-mini': 0.50.6 @@ -8157,6 +8158,7 @@ packages: '@unocss/transformer-variant-group': 0.50.6 '@unocss/vite': 0.50.6(vite@4.2.0) transitivePeerDependencies: + - postcss - rollup - supports-color - vite From 7ef2bce03cfb6dab4c75062e0febd4022c3f0992 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:29:16 +0900 Subject: [PATCH 10/27] ci: node 18 --- .github/workflows/ci.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c83b1a5814..15536334ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,10 +8,10 @@ jobs: - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2 with: - version: 7 + version: 8 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: pnpm - run: make lint - run: pnpm i @@ -25,10 +25,10 @@ jobs: - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2 with: - version: 7 + version: 8 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: pnpm - run: pnpm i - run: make docker/up db/reset/test db/seed-download @@ -44,10 +44,10 @@ jobs: - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2 with: - version: 7 + version: 8 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: pnpm - run: pnpm i - uses: actions/cache@v3 @@ -76,10 +76,10 @@ jobs: - uses: actions/checkout@v3 - uses: pnpm/action-setup@v2 with: - version: 7 + version: 8 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: pnpm - run: pnpm i - run: make docker/up db/recreate @@ -103,7 +103,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 - uses: actions/download-artifact@v3 with: name: coverage-unit From 97d12fc553c65fffce4f99f842ffef2a6d295f09 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:34:33 +0900 Subject: [PATCH 11/27] chore: simplify initialization --- app/db/drizzle-client.server.ts | 27 +++++++++------------------ app/misc/initialize-server.ts | 5 ++--- app/utils/config.ts | 4 ++-- app/utils/session.server.ts | 5 ++--- 4 files changed, 15 insertions(+), 26 deletions(-) diff --git a/app/db/drizzle-client.server.ts b/app/db/drizzle-client.server.ts index 14eedc95d9..5c326e7659 100644 --- a/app/db/drizzle-client.server.ts +++ b/app/db/drizzle-client.server.ts @@ -1,4 +1,4 @@ -import { difference, once, tinyassert } from "@hiogawa/utils"; +import { difference, tinyassert } from "@hiogawa/utils"; import { sql } from "drizzle-orm"; import * as E from "drizzle-orm/expressions"; import { @@ -317,24 +317,15 @@ export async function dbGetMigrationStatus() { // client // -// persist through dev auto reloading -declare let globalThis: { - __drizzleClient: MySql2Database; -}; - -export let db = uninitialized as typeof globalThis.__drizzleClient; +export let db = uninitialized as MySql2Database; -export const initializeDrizzleClient = once(async () => { - db = globalThis.__drizzleClient ??= await inner(); - - async function inner() { - const config = knexfile(); - const connection = await createConnection(config.connection); - return drizzle(connection, { - logger: process.env["DEBUG"]?.includes("drizzle"), // enable query logging by DEBUG=drizzle - }); - } -}); +export async function initializeDrizzleClient() { + const config = knexfile(); + const connection = await createConnection(config.connection); + db = drizzle(connection, { + logger: process.env["DEBUG"]?.includes("drizzle"), // enable query logging by DEBUG=drizzle + }); +} export async function finalizeDrizzleClient() { __dbExtra().connection.destroy(); diff --git a/app/misc/initialize-server.ts b/app/misc/initialize-server.ts index 4436ff9ebe..21854016bc 100644 --- a/app/misc/initialize-server.ts +++ b/app/misc/initialize-server.ts @@ -1,4 +1,3 @@ -import { once } from "@hiogawa/utils"; import { finalizeDrizzleClient, initializeDrizzleClient, @@ -6,11 +5,11 @@ import { import { initializeConfigServer } from "../utils/config"; import { initializeSessionStore } from "../utils/session.server"; -export const initializeServer = once(async () => { +export async function initializeServer() { initializeConfigServer(); initializeSessionStore(); await initializeDrizzleClient(); -}); +} export async function finalizeServer() { await finalizeDrizzleClient(); diff --git a/app/utils/config.ts b/app/utils/config.ts index 9f4807affe..b812117f3f 100644 --- a/app/utils/config.ts +++ b/app/utils/config.ts @@ -31,7 +31,7 @@ export type PublicConfig = z.infer; export let serverConfig = uninitialized as z.infer; -export const initializeConfigServer = once(() => { +export function initializeConfigServer() { serverConfig = Z_SERVER_CONFIG.parse(process.env); initializePublicConfigServer(Z_PUBLIC_CONFIG.parse(process.env)); -}); +} diff --git a/app/utils/session.server.ts b/app/utils/session.server.ts index c6c57afe80..b4db912539 100644 --- a/app/utils/session.server.ts +++ b/app/utils/session.server.ts @@ -1,4 +1,3 @@ -import { once } from "@hiogawa/utils"; import { Session, SessionStorage, @@ -8,7 +7,7 @@ import { serverConfig } from "./config"; export let sessionStore: SessionStorage; -export const initializeSessionStore = once(() => { +export function initializeSessionStore() { sessionStore = createCookieSessionStorage({ cookie: { httpOnly: true, @@ -18,7 +17,7 @@ export const initializeSessionStore = once(() => { secrets: [serverConfig.APP_SESSION_SECRET], }, }); -}); +} // // utils From f3fa16c7533c881c33624f80662674cd994e57d7 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:36:03 +0900 Subject: [PATCH 12/27] chore: lint --- app/utils/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/utils/config.ts b/app/utils/config.ts index b812117f3f..dea187b547 100644 --- a/app/utils/config.ts +++ b/app/utils/config.ts @@ -1,5 +1,4 @@ import * as process from "process"; -import { once } from "@hiogawa/utils"; import { z } from "zod"; import { initializePublicConfigServer } from "./config-public"; import { uninitialized } from "./misc"; From 0145c088d8743a018ed3ae55a5ca87a31e3c75cd Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 20:52:25 +0900 Subject: [PATCH 13/27] test: fix e2e coverage --- package.json | 1 - scripts/dev-server.sh | 6 +++++- scripts/test-e2e-coverage.sh | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2601d3c030..301665503b 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "dev:remix": "run-p remix-watch remix-dev-server", "remix-watch": "remix watch", "remix-dev-server": "bash scripts/dev-server.sh", - "dev-coverage:remix": "c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node_modules/.bin/remix dev", "tsc": "tsc -b", "dev:tsc": "pnpm tsc --watch --preserveWatchOutput", "build:css": "unocss 'app/**/*.tsx' --out-file ./build/css/index.css", diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 804f2e30f1..1f5ff0b802 100644 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -5,4 +5,8 @@ server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" bash scripts/wait-for.sh test -f "$server_entry" -exec nodemon --enable-source-maps "$server_entry" --watch "$server_entry" +if [ -n "$E2E_COVERAGE_SERVER" ]; then + exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node --enable-source-maps "$server_entry" +else + exec npx nodemon --enable-source-maps "$server_entry" --watch "$server_entry" +fi diff --git a/scripts/test-e2e-coverage.sh b/scripts/test-e2e-coverage.sh index 4258ddb0e4..75345e6fbd 100644 --- a/scripts/test-e2e-coverage.sh +++ b/scripts/test-e2e-coverage.sh @@ -4,6 +4,7 @@ set -eux -o pipefail export NODE_ENV=test export PORT=3001 export E2E_NO_SERVER=1 +export E2E_COVERAGE_SERVER=1 export E2E_COVERAGE_CLIENT=1 log_file=logs/remix-coverage.log @@ -11,7 +12,7 @@ trap 'cat "${log_file}"' EXIT # run remix server with c8 pnpm dev-pre -pnpm dev-coverage:remix > "$log_file" 2>&1 & +pnpm dev:remix > "$log_file" 2>&1 & coverage_pid="$!" # wait server @@ -24,7 +25,7 @@ playwright test "${@}" npx c8 report -o coverage/e2e-client -r text -r html --exclude build --exclude-after-remap --temp-directory coverage/e2e-client/tmp # stop remix server -curl "http://localhost:$PORT/dev/stop" +curl "http://localhost:$PORT/dev/stop" || true # wait for c8 to create e2e-server coverage wait "$coverage_pid" || true From 83fa69d71ea6a5509433400e9b58688eef3bd2df Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 21:01:29 +0900 Subject: [PATCH 14/27] chore: move noSourceMapNodeModulesPlugin to remix config --- misc/vercel/build.sh | 4 +--- remix.config.js | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/misc/vercel/build.sh b/misc/vercel/build.sh index f1edd05510..20250dbe40 100644 --- a/misc/vercel/build.sh +++ b/misc/vercel/build.sh @@ -30,9 +30,6 @@ pnpm build:css # remix's default "node-cjs" build with custom server entry NODE_ENV=production BUILD_VERCEL=1 npx remix build --sourcemap -# bundle server entry -node -r esbuild-register ./misc/vercel/bundle.ts build/remix/production/server/index.js .vercel/output/functions/index.func/index.js - # config.json cp misc/vercel/config.json .vercel/output/config.json @@ -40,6 +37,7 @@ cp misc/vercel/config.json .vercel/output/config.json cp -r ./build/remix/production/public .vercel/output/static # serverless +cp build/remix/production/server/{index.js,index.js.map} .vercel/output/functions/index.func cp misc/vercel/.vc-config.json .vercel/output/functions/index.func/.vc-config.json cat > ".vercel/output/functions/index.func/index-bootstrap.js" < { + if (args.path.endsWith("js")) { + return { + contents: + fs.readFileSync(args.path, "utf8") + + "\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==", + loader: "default", + }; + } + }); + }, + }; +} From ec66caff50d8097313b9664750eba40d74fb079c Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 21:04:02 +0900 Subject: [PATCH 15/27] chore: remove unused --- misc/vercel/bundle.ts | 45 ------------------------------------------- 1 file changed, 45 deletions(-) delete mode 100644 misc/vercel/bundle.ts diff --git a/misc/vercel/bundle.ts b/misc/vercel/bundle.ts deleted file mode 100644 index 41c84eb865..0000000000 --- a/misc/vercel/bundle.ts +++ /dev/null @@ -1,45 +0,0 @@ -import fs from "node:fs"; -import esbuild from "esbuild"; - -// the purposes of this extra build step are: -// - bundle server app into single file for simpler vercel deployment -// - exclude node_modules from generating source map to reduce deployment size - -// references -// - https://esbuild.github.io/plugins/ -// - https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409 - -async function main() { - const [infile, outfile] = process.argv.slice(2); - - await esbuild.build({ - logLevel: "info", - entryPoints: [infile], - outfile, - bundle: true, - sourcemap: "inline", - platform: "node", - plugins: [noSourceMapNodeModulesPlugin()], - }); -} - -// https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409 -function noSourceMapNodeModulesPlugin(): esbuild.Plugin { - return { - name: noSourceMapNodeModulesPlugin.name, - setup(build) { - build.onLoad({ filter: /node_modules/ }, (args) => { - if (args.path.endsWith("js")) { - return { - contents: - fs.readFileSync(args.path, "utf8") + - "\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==", - loader: "default", - }; - } - }); - }, - }; -} - -main(); From 27e6565866a33ab64d61be85f98cd19f04b23bbc Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 21:18:44 +0900 Subject: [PATCH 16/27] chore: give up sourcemap --- misc/vercel/build.sh | 18 +++++++----------- remix.config.js | 25 +------------------------ 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/misc/vercel/build.sh b/misc/vercel/build.sh index 20250dbe40..04de6d604d 100644 --- a/misc/vercel/build.sh +++ b/misc/vercel/build.sh @@ -10,12 +10,12 @@ set -eu -o pipefail # project.json # output/ # config.json -# static/ (= (remix-output)/public) +# static/ = (remix-outdir)/public # functions/ # index.func/ # .vc-config.json -# index-bootstrap.js (require index.js after process.setSourceMapsEnabled) -# index.js +# bootstrap.js +# index.js = (remix-outdir)/server/index.js # # cleanup @@ -27,8 +27,8 @@ mkdir -p .vercel/output/functions/index.func # css pnpm build:css -# remix's default "node-cjs" build with custom server entry -NODE_ENV=production BUILD_VERCEL=1 npx remix build --sourcemap +# remix build with custom server entry +NODE_ENV=production BUILD_VERCEL=1 npx remix build # config.json cp misc/vercel/config.json .vercel/output/config.json @@ -37,9 +37,5 @@ cp misc/vercel/config.json .vercel/output/config.json cp -r ./build/remix/production/public .vercel/output/static # serverless -cp build/remix/production/server/{index.js,index.js.map} .vercel/output/functions/index.func -cp misc/vercel/.vc-config.json .vercel/output/functions/index.func/.vc-config.json -cat > ".vercel/output/functions/index.func/index-bootstrap.js" < { - if (args.path.endsWith("js")) { - return { - contents: - fs.readFileSync(args.path, "utf8") + - "\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==", - loader: "default", - }; - } - }); - }, - }; -} From 4e7efdb0fc09bdd0a4938bdaef8ba54cda298ea5 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 26 May 2023 21:43:28 +0900 Subject: [PATCH 17/27] refactor: simplify public assets --- app/assets/.gitignore | 1 - app/assets/README.md | 11 ----- app/root.tsx | 2 +- app/routes/manifest[.json].tsx | 41 ------------------- app/routes/service-worker[.js].tsx | 17 -------- app/server/entry-dev.ts | 1 + misc/vercel/build.sh | 6 ++- misc/vercel/config.json | 3 ++ app/assets/icon-32.png => public/favicon.ico | Bin {app/assets => public}/icon-192.png | Bin {app/assets => public}/icon-512.png | Bin public/manifest.json | 31 ++++++++++++++ public/service-worker.js | 4 ++ scripts/dev-server.sh | 2 +- 14 files changed, 45 insertions(+), 74 deletions(-) delete mode 100644 app/assets/.gitignore delete mode 100644 app/assets/README.md delete mode 100644 app/routes/manifest[.json].tsx delete mode 100644 app/routes/service-worker[.js].tsx rename app/assets/icon-32.png => public/favicon.ico (100%) rename {app/assets => public}/icon-192.png (100%) rename {app/assets => public}/icon-512.png (100%) create mode 100644 public/manifest.json create mode 100644 public/service-worker.js diff --git a/app/assets/.gitignore b/app/assets/.gitignore deleted file mode 100644 index a5a955f965..0000000000 --- a/app/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -subtitles_v1_24px.svg diff --git a/app/assets/README.md b/app/assets/README.md deleted file mode 100644 index fd3c4d7bd3..0000000000 --- a/app/assets/README.md +++ /dev/null @@ -1,11 +0,0 @@ -assets - -```sh -# Download the original svg -curl https://fonts.gstatic.com/s/i/materialicons/subtitles/v1/24px.svg > app/assets/subtitles_v1_24px.svg - -# Convert to different sizes -for px in 32 192 512; do - convert -density 1000 -resize "${px}x${px}" -background none app/assets/subtitles_v1_24px.svg "app/assets/icon-${px}.png" -done -``` diff --git a/app/root.tsx b/app/root.tsx index 9d1a22de82..d0ae42f6c2 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -40,7 +40,7 @@ export const links: LinksFunction = () => { // prettier-ignore return [ { rel: "stylesheet", href: require("../build/css/index.css") }, - { rel: "icon", href: require("./assets/icon-32.png"), sizes: "32x32" }, + { rel: "icon", href: "/favicon.ico" }, { rel: "manifest", href: "/manifest.json" }, ]; }; diff --git a/app/routes/manifest[.json].tsx b/app/routes/manifest[.json].tsx deleted file mode 100644 index 07ca696619..0000000000 --- a/app/routes/manifest[.json].tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { prettierJson } from "../utils/loader-utils"; -import { makeLoader } from "../utils/loader-utils.server"; - -// it could be moved to `/public` but the loader conveniently works for now. - -export const loader = makeLoader(({ ctx }) => { - ctx.cacheResponse(); - return prettierJson(MANIFEST_JSON); -}); - -const MANIFEST_JSON = { - short_name: "Ytsub", - name: "Ytsub", - icons: [ - { - src: require("../assets/icon-192.png"), - type: "image/png", - sizes: "192x192", - }, - { - src: require("../assets/icon-512.png"), - type: "image/png", - sizes: "512x512", - }, - ], - start_url: "/", - scope: "/", - theme_color: "#FFFFFF", - background_color: "#FFFFFF", - display: "standalone", - share_target: { - action: "/share-target", - method: "GET", - enctype: "application/x-www-form-urlencoded", - params: { - title: "share-target-title", - text: "share-target-text", - url: "share-target-url", - }, - }, -}; diff --git a/app/routes/service-worker[.js].tsx b/app/routes/service-worker[.js].tsx deleted file mode 100644 index 56deb59144..0000000000 --- a/app/routes/service-worker[.js].tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { makeLoader } from "../utils/loader-utils.server"; - -export const loader = makeLoader(({ ctx }) => { - ctx.cacheResponse(); - return new Response(SERVICE_WORKER_JS, { - headers: { - "content-type": "application/javascript; charset=utf-8", - }, - }); -}); - -const SERVICE_WORKER_JS = ` -// satisfy minimal requirements for PWA -self.addEventListener("fetch", (event) => { - event.respondWith(fetch(event.request)); -}); -`; diff --git a/app/server/entry-dev.ts b/app/server/entry-dev.ts index 392e73e25a..d0a391418b 100644 --- a/app/server/entry-dev.ts +++ b/app/server/entry-dev.ts @@ -11,6 +11,7 @@ async function main() { // serve client build assets app.use("/build", express.static(build.assetsBuildDirectory)); + app.use("/", express.static("./public")); // all application logic as hattip handler app.use(createMiddleware(createHattipApp())); diff --git a/misc/vercel/build.sh b/misc/vercel/build.sh index 04de6d604d..67d983432d 100644 --- a/misc/vercel/build.sh +++ b/misc/vercel/build.sh @@ -10,7 +10,7 @@ set -eu -o pipefail # project.json # output/ # config.json -# static/ = (remix-outdir)/public +# static/ = (remix-outdir)/public + (root)/public # functions/ # index.func/ # .vc-config.json @@ -23,6 +23,7 @@ rm -rf build/remix/production rm -rf build/css rm -rf .vercel/output mkdir -p .vercel/output/functions/index.func +mkdir -p .vercel/output/static # css pnpm build:css @@ -34,7 +35,8 @@ NODE_ENV=production BUILD_VERCEL=1 npx remix build cp misc/vercel/config.json .vercel/output/config.json # static -cp -r ./build/remix/production/public .vercel/output/static +cp -a ./public/. .vercel/output/static/ +cp -a ./build/remix/production/public/. .vercel/output/static/ # serverless cp build/remix/production/server/index.js .vercel/output/functions/index.func diff --git a/misc/vercel/config.json b/misc/vercel/config.json index ab1eddb2a9..0f99076cc3 100644 --- a/misc/vercel/config.json +++ b/misc/vercel/config.json @@ -7,6 +7,9 @@ "cache-control": "public, immutable, max-age=31536000" } }, + { + "handle": "filesystem" + }, { "src": "^/(.*)$", "dest": "/" diff --git a/app/assets/icon-32.png b/public/favicon.ico similarity index 100% rename from app/assets/icon-32.png rename to public/favicon.ico diff --git a/app/assets/icon-192.png b/public/icon-192.png similarity index 100% rename from app/assets/icon-192.png rename to public/icon-192.png diff --git a/app/assets/icon-512.png b/public/icon-512.png similarity index 100% rename from app/assets/icon-512.png rename to public/icon-512.png diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000000..17099b7abe --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,31 @@ +{ + "short_name": "Ytsub", + "name": "Ytsub", + "icons": [ + { + "src": "/icon-192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "/icon-512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": "/", + "scope": "/", + "theme_color": "#FFFFFF", + "background_color": "#FFFFFF", + "display": "standalone", + "share_target": { + "action": "/share-target", + "method": "GET", + "enctype": "application/x-www-form-urlencoded", + "params": { + "title": "share-target-title", + "text": "share-target-text", + "url": "share-target-url" + } + } +} diff --git a/public/service-worker.js b/public/service-worker.js new file mode 100644 index 0000000000..1ca04e1f6f --- /dev/null +++ b/public/service-worker.js @@ -0,0 +1,4 @@ +// satisfy minimal requirements for PWA +self.addEventListener("fetch", (event) => { + event.respondWith(fetch(event.request)); +}); diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 1f5ff0b802..3a1f51a14d 100644 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -5,7 +5,7 @@ server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" bash scripts/wait-for.sh test -f "$server_entry" -if [ -n "$E2E_COVERAGE_SERVER" ]; then +if [ -n "${E2E_COVERAGE_SERVER:-}" ]; then exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node --enable-source-maps "$server_entry" else exec npx nodemon --enable-source-maps "$server_entry" --watch "$server_entry" From 2c847b78d1eacdb1bc3923f1ac791ca06885867d Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:02:47 +0900 Subject: [PATCH 18/27] fix: fix dev server reload --- app/server/entry-dev.ts | 29 +++++++-- app/server/entry-hattip.ts | 3 + package.json | 4 +- patches/@remix-run__react@1.15.0.patch | 13 ++++ pnpm-lock.yaml | 82 ++------------------------ remix.config.js | 2 +- scripts/dev-server.sh | 4 +- 7 files changed, 52 insertions(+), 85 deletions(-) create mode 100644 patches/@remix-run__react@1.15.0.patch diff --git a/app/server/entry-dev.ts b/app/server/entry-dev.ts index d0a391418b..165ca157bd 100644 --- a/app/server/entry-dev.ts +++ b/app/server/entry-dev.ts @@ -1,11 +1,29 @@ +import fs from "node:fs"; import { createServer } from "node:http"; +import path from "node:path"; +import process from "node:process"; import { createMiddleware } from "@hattip/adapter-node"; -import * as build from "@remix-run/dev/server-build"; import express from "express"; -import { createHattipApp } from "./entry-hattip"; import { listenPortSearchByEnv } from "./http"; async function main() { + const buildPath = path.resolve(process.argv[2]); + + // require.cache trick as a cheap live reload + function requireBuild() { + console.log(`[entry-dev] Loading ${buildPath}`); + delete require.cache[buildPath]; + return require(path.resolve(buildPath)) as typeof import("./entry-hattip"); + } + + // reload remix build output on nodemon's signal + let build = requireBuild(); + fs.watch(path.dirname(buildPath), (eventType) => { + if (eventType === "change") { + build = undefined!; + } + }); + const app = express(); const server = createServer(app); @@ -13,8 +31,11 @@ async function main() { app.use("/build", express.static(build.assetsBuildDirectory)); app.use("/", express.static("./public")); - // all application logic as hattip handler - app.use(createMiddleware(createHattipApp())); + // main app + app.all("*", (req, res, next) => { + build ??= requireBuild(); + return createMiddleware(build.createHattipApp())(req, res, next); + }); // start app const port = await listenPortSearchByEnv(server); diff --git a/app/server/entry-hattip.ts b/app/server/entry-hattip.ts index 99496af61c..0e6fd45cf7 100644 --- a/app/server/entry-hattip.ts +++ b/app/server/entry-hattip.ts @@ -21,6 +21,9 @@ export function createHattipApp() { ); } +// re-export for entry-dev +export const assetsBuildDirectory = build.assetsBuildDirectory; + // // remix // diff --git a/package.json b/package.json index 9b1871f15a..e95160198a 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,6 @@ "gh-pages": "^3.2.3", "happy-dom": "^8.9.0", "hono": "^3.2.2", - "nodemon": "^2.0.22", "node-mailjet": "^6.0.2", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", @@ -128,7 +127,8 @@ "pnpm": { "patchedDependencies": { "@remix-run/dev@1.15.0": "patches/@remix-run__dev@1.15.0.patch", - "@remix-run/node@1.15.0": "patches/@remix-run__node@1.15.0.patch" + "@remix-run/node@1.15.0": "patches/@remix-run__node@1.15.0.patch", + "@remix-run/react@1.15.0": "patches/@remix-run__react@1.15.0.patch" } } } diff --git a/patches/@remix-run__react@1.15.0.patch b/patches/@remix-run__react@1.15.0.patch new file mode 100644 index 0000000000..4c754fe8fe --- /dev/null +++ b/patches/@remix-run__react@1.15.0.patch @@ -0,0 +1,13 @@ +diff --git a/dist/components.js b/dist/components.js +index b355788f65867c8ca672d87c7cc1d26532ca1306..03c5bd9f0ac4787c20e23c800aaa7bcef884b696 100644 +--- a/dist/components.js ++++ b/dist/components.js +@@ -1237,7 +1237,7 @@ function convertRouterFetcherToRemixFetcher(fetcherRR) { + // This way devs don't have to worry about doing the NODE_ENV check themselves. + // If running an un-bundled server outside of `remix dev` you will still need + // to set the REMIX_DEV_SERVER_WS_PORT manually. +-const LiveReload = process.env.NODE_ENV !== "development" ? () => null : function LiveReload({ ++const LiveReload = false ? () => null : function LiveReload({ + port = Number(process.env.REMIX_DEV_SERVER_WS_PORT || 8002), + timeoutMs = 1000, + nonce = undefined \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a96c47f901..8737668868 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,9 @@ patchedDependencies: '@remix-run/node@1.15.0': hash: z6mxtllsu73w4y6xnddlyl6j6y path: patches/@remix-run__node@1.15.0.patch + '@remix-run/react@1.15.0': + hash: ihwj5xhtucgszzff6swnc244hq + path: patches/@remix-run__react@1.15.0.patch dependencies: '@badrap/bar-of-progress': @@ -44,7 +47,7 @@ dependencies: version: 1.15.0(patch_hash=z6mxtllsu73w4y6xnddlyl6j6y) '@remix-run/react': specifier: 1.15.0 - version: 1.15.0(react-dom@18.2.0)(react@18.2.0) + version: 1.15.0(patch_hash=ihwj5xhtucgszzff6swnc244hq)(react-dom@18.2.0)(react@18.2.0) '@remix-run/server-runtime': specifier: 1.15.0 version: 1.15.0 @@ -215,9 +218,6 @@ devDependencies: node-mailjet: specifier: ^6.0.2 version: 6.0.2 - nodemon: - specifier: ^2.0.22 - version: 2.0.22 npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -2454,7 +2454,7 @@ packages: stream-slice: 0.1.2 patched: true - /@remix-run/react@1.15.0(react-dom@18.2.0)(react@18.2.0): + /@remix-run/react@1.15.0(patch_hash=ihwj5xhtucgszzff6swnc244hq)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-S0RuIeHvQTqryCZ3KVl8EsIWCqL6/ky1/kmDpN2n5Pdjew2BLC6DX7OdrY1ZQjbzOMHAROsZlyaSSVXCItunag==} engines: {node: '>=14'} peerDependencies: @@ -2467,6 +2467,7 @@ packages: react-router-dom: 6.10.0(react-dom@18.2.0)(react@18.2.0) use-sync-external-store: 1.2.0(react@18.2.0) dev: false + patched: true /@remix-run/router@1.5.0: resolution: {integrity: sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==} @@ -3238,10 +3239,6 @@ packages: requiresBuild: true optional: true - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: true - /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3968,18 +3965,6 @@ packages: dependencies: ms: 2.0.0 - /debug@3.2.7(supports-color@5.5.0): - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - supports-color: 5.5.0 - dev: true - /debug@4.3.3: resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} engines: {node: '>=6.0'} @@ -5208,10 +5193,6 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - /ignore-by-default@1.0.1: - resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} - dev: true - /ignore@5.2.4: resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} @@ -6473,30 +6454,6 @@ packages: /node-releases@2.0.10: resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==} - /nodemon@2.0.22: - resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} - engines: {node: '>=8.10.0'} - hasBin: true - dependencies: - chokidar: 3.5.3 - debug: 3.2.7(supports-color@5.5.0) - ignore-by-default: 1.0.1 - minimatch: 3.1.2 - pstree.remy: 1.1.8 - semver: 5.7.1 - simple-update-notifier: 1.1.0 - supports-color: 5.5.0 - touch: 3.1.0 - undefsafe: 2.0.5 - dev: true - - /nopt@1.0.10: - resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: true - /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -7057,10 +7014,6 @@ packages: resolution: {integrity: sha1-8FKijacOYYkX7wqKw0wa5aaChrM=} dev: false - /pstree.remy@1.1.8: - resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} - dev: true - /pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} dependencies: @@ -7529,11 +7482,6 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true - /semver@7.0.0: - resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} - hasBin: true - dev: true - /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} @@ -7638,13 +7586,6 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - /simple-update-notifier@1.1.0: - resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} - engines: {node: '>=8.10.0'} - dependencies: - semver: 7.0.0 - dev: true - /sirv@2.0.2: resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} engines: {node: '>= 10'} @@ -8018,13 +7959,6 @@ packages: engines: {node: '>=6'} dev: true - /touch@3.1.0: - resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} - hasBin: true - dependencies: - nopt: 1.0.10 - dev: true - /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -8153,10 +8087,6 @@ packages: jiti: 1.18.2 dev: true - /undefsafe@2.0.5: - resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} - dev: true - /unicode-canonical-property-names-ecmascript@2.0.0: resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} engines: {node: '>=4'} diff --git a/remix.config.js b/remix.config.js index e4d2cc9839..31a07b2ab7 100644 --- a/remix.config.js +++ b/remix.config.js @@ -5,7 +5,7 @@ const env = process.env.NODE_ENV ?? "development"; module.exports = { serverBuildPath: `build/remix/${env}/server/index.js`, assetsBuildDirectory: `build/remix/${env}/public/build`, - server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/server/entry-dev.ts", + server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/server/entry-hattip.ts", serverDependenciesToBundle: "all", future: { v2_meta: true, diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 3a1f51a14d..3e259a7b16 100644 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -6,7 +6,7 @@ server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" bash scripts/wait-for.sh test -f "$server_entry" if [ -n "${E2E_COVERAGE_SERVER:-}" ]; then - exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node --enable-source-maps "$server_entry" + exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node -- -r esbuild-register ./app/server/entry-dev.ts "$server_entry" else - exec npx nodemon --enable-source-maps "$server_entry" --watch "$server_entry" + exec npx node -r esbuild-register ./app/server/entry-dev.ts "$server_entry" fi From 9490af76452c43a2855388890fe12801ac0e36a9 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:05:18 +0900 Subject: [PATCH 19/27] chore: tweak serverDependenciesToBundle --- remix.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/remix.config.js b/remix.config.js index 31a07b2ab7..6b6e195475 100644 --- a/remix.config.js +++ b/remix.config.js @@ -6,7 +6,9 @@ module.exports = { serverBuildPath: `build/remix/${env}/server/index.js`, assetsBuildDirectory: `build/remix/${env}/public/build`, server: process.env.BUILD_VERCEL ? "./app/server/entry-vercel.ts" : "./app/server/entry-hattip.ts", - serverDependenciesToBundle: "all", + serverDependenciesToBundle: process.env.BUILD_VERCEL ? "all" : [ + /@hattip/, /@js-temporal/ + ], future: { v2_meta: true, v2_errorBoundary: true, From 9717c8cb15ab069491521432eaa62bdb94099df6 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:08:15 +0900 Subject: [PATCH 20/27] chore: tweak cache --- app/server/entry-dev.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/server/entry-dev.ts b/app/server/entry-dev.ts index 165ca157bd..370266ee57 100644 --- a/app/server/entry-dev.ts +++ b/app/server/entry-dev.ts @@ -28,7 +28,13 @@ async function main() { const server = createServer(app); // serve client build assets - app.use("/build", express.static(build.assetsBuildDirectory)); + app.use( + "/build", + express.static(build.assetsBuildDirectory, { + immutable: true, + maxAge: "1y", + }) + ); app.use("/", express.static("./public")); // main app From 903503fbd9dbe4bb1ad1962a17839fefe3a8ea83 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:26:40 +0900 Subject: [PATCH 21/27] chore: comment --- app/server/entry-dev.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/server/entry-dev.ts b/app/server/entry-dev.ts index 370266ee57..1581aca791 100644 --- a/app/server/entry-dev.ts +++ b/app/server/entry-dev.ts @@ -7,6 +7,10 @@ import express from "express"; import { listenPortSearchByEnv } from "./http"; async function main() { + // + // require buildPath with require.cache invalidation + // + const buildPath = path.resolve(process.argv[2]); // require.cache trick as a cheap live reload @@ -16,14 +20,17 @@ async function main() { return require(path.resolve(buildPath)) as typeof import("./entry-hattip"); } - // reload remix build output on nodemon's signal let build = requireBuild(); - fs.watch(path.dirname(buildPath), (eventType) => { - if (eventType === "change") { + fs.watch(path.dirname(buildPath), (eventType, filename) => { + if (eventType === "change" && path.basename(buildPath) === filename) { build = undefined!; } }); + // + // express app + // + const app = express(); const server = createServer(app); @@ -37,7 +44,7 @@ async function main() { ); app.use("/", express.static("./public")); - // main app + // main logic as hattip handler app.all("*", (req, res, next) => { build ??= requireBuild(); return createMiddleware(build.createHattipApp())(req, res, next); From eab1d2f28c6be12e986239157c650df400e21fe8 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:28:00 +0900 Subject: [PATCH 22/27] chore: lint --- app/server/entry-hattip.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/server/entry-hattip.ts b/app/server/entry-hattip.ts index 0e6fd45cf7..e3ef84ee5c 100644 --- a/app/server/entry-hattip.ts +++ b/app/server/entry-hattip.ts @@ -22,7 +22,8 @@ export function createHattipApp() { } // re-export for entry-dev -export const assetsBuildDirectory = build.assetsBuildDirectory; +// ts-prune-ignore-next +export const assetsBuildDirectory = build.assetsBuildDirectory // // remix From e06b6019b25db195c20ef3f7872bf481b119acb7 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:30:21 +0900 Subject: [PATCH 23/27] chore: lint --- app/server/entry-hattip.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/server/entry-hattip.ts b/app/server/entry-hattip.ts index e3ef84ee5c..199840ec2d 100644 --- a/app/server/entry-hattip.ts +++ b/app/server/entry-hattip.ts @@ -23,7 +23,7 @@ export function createHattipApp() { // re-export for entry-dev // ts-prune-ignore-next -export const assetsBuildDirectory = build.assetsBuildDirectory +export const assetsBuildDirectory = build.assetsBuildDirectory; // // remix From 038ab01b69b8ad7dcaeb407a7e6a0cff5e16eab3 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:34:58 +0900 Subject: [PATCH 24/27] chore: fix dev-server.sh --- scripts/dev-server.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 3e259a7b16..4fba889f56 100644 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -5,8 +5,10 @@ server_entry="./build/remix/${NODE_ENV:-development}/server/index.js" bash scripts/wait-for.sh test -f "$server_entry" +entry_dev_cmd=(node -r esbuild-register ./app/server/entry-dev.ts "$server_entry") + if [ -n "${E2E_COVERAGE_SERVER:-}" ]; then - exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap node -- -r esbuild-register ./app/server/entry-dev.ts "$server_entry" + exec npx c8 -o coverage/e2e-server -r text -r html --exclude build --exclude-after-remap "${entry_dev_cmd[@]}" else - exec npx node -r esbuild-register ./app/server/entry-dev.ts "$server_entry" + exec "${entry_dev_cmd[@]}" fi From 71d1e0b376fbdae02691cd433bb1b23ebc24d073 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:39:38 +0900 Subject: [PATCH 25/27] chore: revert globalThis hack --- app/db/drizzle-client.server.ts | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/app/db/drizzle-client.server.ts b/app/db/drizzle-client.server.ts index ba622b29a2..6b163f3694 100644 --- a/app/db/drizzle-client.server.ts +++ b/app/db/drizzle-client.server.ts @@ -1,4 +1,4 @@ -import { difference, tinyassert } from "@hiogawa/utils"; +import { difference, once, tinyassert } from "@hiogawa/utils"; import { sql } from "drizzle-orm"; import * as E from "drizzle-orm/expressions"; import { @@ -349,15 +349,24 @@ export async function dbGetMigrationStatus() { // client // -export let db = uninitialized as MySql2Database; +// persist through dev auto reloading +declare let globalThis: { + __drizzleClient: MySql2Database; +}; -export async function initializeDrizzleClient() { - const config = knexfile(); - const connection = await createConnection(config.connection); - db = drizzle(connection, { - logger: process.env["DEBUG"]?.includes("drizzle"), // enable query logging by DEBUG=drizzle - }); -} +export let db = uninitialized as typeof globalThis.__drizzleClient; + +export const initializeDrizzleClient = once(async () => { + db = globalThis.__drizzleClient ??= await inner(); + + async function inner() { + const config = knexfile(); + const connection = await createConnection(config.connection); + return drizzle(connection, { + logger: process.env["DEBUG"]?.includes("drizzle"), // enable query logging by DEBUG=drizzle + }); + } +}); export async function finalizeDrizzleClient() { __dbExtra().connection.destroy(); From 7b986e7cc042a655d509504b17119fccd42b5569 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:41:53 +0900 Subject: [PATCH 26/27] chore: remove unused --- package.json | 1 - pnpm-lock.yaml | 3 --- 2 files changed, 4 deletions(-) diff --git a/package.json b/package.json index e95160198a..1407961dda 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "@hiogawa/utils-experimental": "^0.0.1", "@hiogawa/utils-react": "1.2.1-pre.4", "@js-temporal/polyfill": "^0.4.3", - "@remix-run/express": "1.15.0", "@remix-run/node": "1.15.0", "@remix-run/react": "1.15.0", "@remix-run/server-runtime": "1.15.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8737668868..cc7a8a5cab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,9 +39,6 @@ dependencies: '@js-temporal/polyfill': specifier: ^0.4.3 version: 0.4.3 - '@remix-run/express': - specifier: 1.15.0 - version: 1.15.0(express@4.17.3) '@remix-run/node': specifier: 1.15.0 version: 1.15.0(patch_hash=z6mxtllsu73w4y6xnddlyl6j6y) From f0ba97fcdd8b5f7bc636ab132abbf7b70b57ad15 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 28 May 2023 20:45:13 +0900 Subject: [PATCH 27/27] chore: tweak LiveReload --- app/root.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/root.tsx b/app/root.tsx index d0ae42f6c2..f76c8d733b 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -132,7 +132,7 @@ function Root() { - + {process.env.NODE_ENV !== "production" && } ); }