diff --git a/socket.io/.eslintrc.cjs b/socket.io/.eslintrc.cjs
new file mode 100644
index 00000000..bb26c82d
--- /dev/null
+++ b/socket.io/.eslintrc.cjs
@@ -0,0 +1,84 @@
+/**
+ * This is intended to be a basic starting point for linting in your app.
+ * It relies on recommended configs out of the box for simplicity, but you can
+ * and should modify this configuration to best suit your team's needs.
+ */
+
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ root: true,
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ env: {
+ browser: true,
+ commonjs: true,
+ es6: true,
+ },
+ ignorePatterns: ["!**/.server", "!**/.client"],
+
+ // Base config
+ extends: ["eslint:recommended"],
+
+ overrides: [
+ // React
+ {
+ files: ["**/*.{js,jsx,ts,tsx}"],
+ plugins: ["react", "jsx-a11y"],
+ extends: [
+ "plugin:react/recommended",
+ "plugin:react/jsx-runtime",
+ "plugin:react-hooks/recommended",
+ "plugin:jsx-a11y/recommended",
+ ],
+ settings: {
+ react: {
+ version: "detect",
+ },
+ formComponents: ["Form"],
+ linkComponents: [
+ { name: "Link", linkAttribute: "to" },
+ { name: "NavLink", linkAttribute: "to" },
+ ],
+ "import/resolver": {
+ typescript: {},
+ },
+ },
+ },
+
+ // Typescript
+ {
+ files: ["**/*.{ts,tsx}"],
+ plugins: ["@typescript-eslint", "import"],
+ parser: "@typescript-eslint/parser",
+ settings: {
+ "import/internal-regex": "^~/",
+ "import/resolver": {
+ node: {
+ extensions: [".ts", ".tsx"],
+ },
+ typescript: {
+ alwaysTryTypes: true,
+ },
+ },
+ },
+ extends: [
+ "plugin:@typescript-eslint/recommended",
+ "plugin:import/recommended",
+ "plugin:import/typescript",
+ ],
+ },
+
+ // Node
+ {
+ files: [".eslintrc.cjs", "server.js"],
+ env: {
+ node: true,
+ },
+ },
+ ],
+};
diff --git a/socket.io/.eslintrc.js b/socket.io/.eslintrc.js
deleted file mode 100644
index 2061cd22..00000000
--- a/socket.io/.eslintrc.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/** @type {import('eslint').Linter.Config} */
-module.exports = {
- extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
-};
diff --git a/socket.io/.gitignore b/socket.io/.gitignore
index d9418258..80ec311f 100644
--- a/socket.io/.gitignore
+++ b/socket.io/.gitignore
@@ -1,6 +1,5 @@
node_modules
/.cache
-/server/build
-/public/build
+/build
.env
diff --git a/socket.io/app/root.tsx b/socket.io/app/root.tsx
index 61943191..e4a57ceb 100644
--- a/socket.io/app/root.tsx
+++ b/socket.io/app/root.tsx
@@ -1,7 +1,5 @@
-import type { MetaFunction } from "@remix-run/node";
import {
Links,
- LiveReload,
Meta,
Outlet,
Scripts,
@@ -13,11 +11,23 @@ import io from "socket.io-client";
import { SocketProvider } from "~/context";
-export const meta: MetaFunction = () => ({
- charset: "utf-8",
- title: "New Remix App",
- viewport: "width=device-width,initial-scale=1",
-});
+export function Layout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
export default function App() {
const [socket, setSocket] = useState();
@@ -38,19 +48,7 @@ export default function App() {
}, [socket]);
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+
+
+ );
}
diff --git a/socket.io/package.json b/socket.io/package.json
index aedd8d25..a47d7fa4 100644
--- a/socket.io/package.json
+++ b/socket.io/package.json
@@ -1,36 +1,49 @@
{
+ "name": "eps",
"private": true,
"sideEffects": false,
+ "type": "module",
"scripts": {
- "build": "remix build",
- "dev": "remix watch",
- "start": "cross-env NODE_ENV=production node server/index.js",
- "start:dev": "cross-env NODE_ENV=development node server/index.js",
+ "build": "remix vite:build",
+ "dev": "node ./server.js",
+ "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
+ "start": "cross-env NODE_ENV=production node ./server.js",
"typecheck": "tsc"
},
"dependencies": {
- "@remix-run/express": "^1.19.3",
- "@remix-run/node": "^1.19.3",
- "@remix-run/react": "^1.19.3",
+ "@remix-run/express": "^2.9.2",
+ "@remix-run/node": "^2.9.2",
+ "@remix-run/react": "^2.9.2",
"compression": "^1.7.4",
- "cross-env": "^7.0.3",
- "express": "^4.17.3",
+ "express": "^4.18.2",
+ "isbot": "^4.1.0",
"morgan": "^1.10.0",
- "isbot": "^3.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "socket.io": "^4.4.1",
- "socket.io-client": "^4.4.1"
+ "socket.io": "^4.7.5",
+ "socket.io-client": "^4.7.5"
},
"devDependencies": {
- "@remix-run/dev": "^1.19.3",
- "@remix-run/eslint-config": "^1.19.3",
- "@types/react": "^18.0.25",
- "@types/react-dom": "^18.0.8",
- "eslint": "^8.27.0",
- "typescript": "^4.8.4"
+ "@remix-run/dev": "^2.9.2",
+ "@types/compression": "^1.7.5",
+ "@types/express": "^4.17.20",
+ "@types/morgan": "^1.9.9",
+ "@types/react": "^18.2.20",
+ "@types/react-dom": "^18.2.7",
+ "@typescript-eslint/eslint-plugin": "^6.7.4",
+ "@typescript-eslint/parser": "^6.7.4",
+ "cross-env": "^7.0.3",
+ "eslint": "^8.38.0",
+ "eslint-import-resolver-typescript": "^3.6.1",
+ "eslint-plugin-import": "^2.28.1",
+ "eslint-plugin-jsx-a11y": "^6.7.1",
+ "eslint-plugin-react": "^7.33.2",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "typescript": "^5.1.6",
+ "vite": "^5.1.0",
+ "vite-tsconfig-paths": "^4.2.1"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=20.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/socket.io/remix.config.js b/socket.io/remix.config.js
deleted file mode 100644
index 76048d0c..00000000
--- a/socket.io/remix.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/** @type {import('@remix-run/dev').AppConfig} */
-module.exports = {
- future: {
- v2_routeConvention: true,
- },
- ignoredRouteFiles: ["**/.*"],
- serverBuildDirectory: "server/build",
- // appDirectory: "app",
- // assetsBuildDirectory: "public/build",
- // publicPath: "/build/",
-};
diff --git a/socket.io/remix.env.d.ts b/socket.io/remix.env.d.ts
deleted file mode 100644
index dcf8c45e..00000000
--- a/socket.io/remix.env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-///
-///
diff --git a/socket.io/server.js b/socket.io/server.js
new file mode 100644
index 00000000..4936d516
--- /dev/null
+++ b/socket.io/server.js
@@ -0,0 +1,77 @@
+import { createRequestHandler } from "@remix-run/express";
+import compression from "compression";
+import express from "express";
+import morgan from "morgan";
+import { createServer } from "http";
+import { Server } from "socket.io";
+
+const viteDevServer =
+ process.env.NODE_ENV === "production"
+ ? undefined
+ : await import("vite").then((vite) =>
+ vite.createServer({
+ server: { middlewareMode: true },
+ })
+ );
+
+const remixHandler = createRequestHandler({
+ build: viteDevServer
+ ? () => viteDevServer.ssrLoadModule("virtual:remix/server-build")
+ : await import("./build/server/index.js"),
+});
+
+const app = express();
+
+// You need to create the HTTP server from the Express app
+const httpServer = createServer(app);
+
+// And then attach the socket.io server to the HTTP server
+const io = new Server(httpServer);
+
+// Then you can use `io` to listen the `connection` event and get a socket
+// from a client
+io.on("connection", (socket) => {
+ // from this point you are on the WS connection with a specific client
+ console.log(socket.id, "connected");
+
+ socket.emit("confirmation", "connected!");
+
+ socket.on("event", (data) => {
+ console.log(socket.id, data);
+ socket.emit("event", "pong");
+ });
+});
+
+
+app.use(compression());
+
+// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header
+app.disable("x-powered-by");
+
+// handle asset requests
+if (viteDevServer) {
+ app.use(viteDevServer.middlewares);
+} else {
+ // Vite fingerprints its assets so we can cache forever.
+ app.use(
+ "/assets",
+ express.static("build/client/assets", { immutable: true, maxAge: "1y" })
+ );
+}
+
+// Everything else (like favicon.ico) is cached for an hour. You may want to be
+// more aggressive with this caching.
+app.use(express.static("build/client", { maxAge: "1h" }));
+
+app.use(morgan("tiny"));
+
+// handle SSR requests
+app.all("*", remixHandler);
+
+const port = process.env.PORT || 3000;
+
+// instead of running listen on the Express app, do it on the HTTP server
+httpServer.listen(port, () => {
+ console.log(`Express server listening at http://localhost:${port}`)
+});
+
diff --git a/socket.io/server/index.js b/socket.io/server/index.js
deleted file mode 100644
index 17d45959..00000000
--- a/socket.io/server/index.js
+++ /dev/null
@@ -1,81 +0,0 @@
-const fs = require("fs");
-const { createServer } = require("http");
-const path = require("path");
-
-const { createRequestHandler } = require("@remix-run/express");
-const compression = require("compression");
-const express = require("express");
-const morgan = require("morgan");
-const { Server } = require("socket.io");
-
-const MODE = process.env.NODE_ENV;
-const BUILD_DIR = path.join(process.cwd(), "server/build");
-
-if (!fs.existsSync(BUILD_DIR)) {
- console.warn(
- "Build directory doesn't exist, please run `npm run dev` or `npm run build` before starting the server.",
- );
-}
-
-const app = express();
-
-// You need to create the HTTP server from the Express app
-const httpServer = createServer(app);
-
-// And then attach the socket.io server to the HTTP server
-const io = new Server(httpServer);
-
-// Then you can use `io` to listen the `connection` event and get a socket
-// from a client
-io.on("connection", (socket) => {
- // from this point you are on the WS connection with a specific client
- console.log(socket.id, "connected");
-
- socket.emit("confirmation", "connected!");
-
- socket.on("event", (data) => {
- console.log(socket.id, data);
- socket.emit("event", "pong");
- });
-});
-
-app.use(compression());
-
-// You may want to be more aggressive with this caching
-app.use(express.static("public", { maxAge: "1h" }));
-
-// Remix fingerprints its assets so we can cache forever
-app.use(express.static("public/build", { immutable: true, maxAge: "1y" }));
-
-app.use(morgan("tiny"));
-app.all(
- "*",
- MODE === "production"
- ? createRequestHandler({ build: require("./build") })
- : (req, res, next) => {
- purgeRequireCache();
- const build = require("./build");
- return createRequestHandler({ build, mode: MODE })(req, res, next);
- },
-);
-
-const port = process.env.PORT || 3000;
-
-// instead of running listen on the Express app, do it on the HTTP server
-httpServer.listen(port, () => {
- console.log(`Express server listening on port ${port}`);
-});
-
-////////////////////////////////////////////////////////////////////////////////
-function purgeRequireCache() {
- // purge require cache on requests for "server side HMR" this won't let
- // you have in-memory objects between requests in development,
- // alternatively you can set up nodemon/pm2-dev to restart the server on
- // file changes, we prefer the DX of this though, so we've included it
- // for you by default
- for (const key in require.cache) {
- if (key.startsWith(BUILD_DIR)) {
- delete require.cache[key];
- }
- }
-}
diff --git a/socket.io/tsconfig.json b/socket.io/tsconfig.json
index 20f8a386..9d87dd37 100644
--- a/socket.io/tsconfig.json
+++ b/socket.io/tsconfig.json
@@ -1,22 +1,32 @@
{
- "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "**/.server/**/*.ts",
+ "**/.server/**/*.tsx",
+ "**/.client/**/*.ts",
+ "**/.client/**/*.tsx"
+ ],
"compilerOptions": {
- "lib": ["DOM", "DOM.Iterable", "ES2019"],
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "types": ["@remix-run/node", "vite/client"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
- "moduleResolution": "node",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
"resolveJsonModule": true,
- "target": "ES2019",
+ "target": "ES2022",
"strict": true,
"allowJs": true,
+ "skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
- // Remix takes care of building everything in `remix build`.
+ // Vite takes care of building everything, not tsc.
"noEmit": true
}
}
diff --git a/socket.io/vite.config.ts b/socket.io/vite.config.ts
new file mode 100644
index 00000000..54066fb7
--- /dev/null
+++ b/socket.io/vite.config.ts
@@ -0,0 +1,16 @@
+import { vitePlugin as remix } from "@remix-run/dev";
+import { defineConfig } from "vite";
+import tsconfigPaths from "vite-tsconfig-paths";
+
+export default defineConfig({
+ plugins: [
+ remix({
+ future: {
+ v3_fetcherPersist: true,
+ v3_relativeSplatPath: true,
+ v3_throwAbortReason: true,
+ },
+ }),
+ tsconfigPaths(),
+ ],
+});