Cannot find module error
jansedlon opened this issue · 9 comments
Hello @kiliman . Just ran into similar error as others here.
Internal server error: Cannot find module '/Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.5.0-beta/node_modules/remix-create-express-app/dist/middleware' imported from /Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.5.0-beta/node_modules/remix-create-express-app/dist/index.js
When i manually changed the import in your remix-create-express-app/dist/index.js
file to middleware.js
the error changed to
Cannot find module '/Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/@remix-run/express/dist/server' imported from /Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/remix-create-express-app/dist/middleware.js
Did you mean to import @remix-run+express@2.9.1_express@4.19.2_typescript@5.4.5/node_modules/@remix-run/express/dist/server.js?
Aaand when i did that again and changed the import in middleware.js
to @remix-run/express/dist/server.js
it said
Directory import '/Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/remix-create-express-app/dist/' is not supported resolving ES modules imported from /Users/jansedlon/Work/Flixy/flixy/node_modules/.pnpm/remix-create-express-app@0.3.0_react-dom@18.3.1_react@18.3.1_typescript@5.4.5/node_modules/remix-create-express-app/dist/middleware.js
Did you mean to import ../../../../../../../index.js?
And also the example app throws WebSocket server error: Port is already in use
(that's mentioned in the readme)
Which references to this
And weirdly enough, even though the default port is 3000, vite always shows 5173
Right now createServer
only runs in production. When working with socket.io
I need to return server regardless of whether it's production or development. That's because setting up socket.io looks like this
import { createServer } from "node:http";
createServer(app) {
const httpServer = createServer(app);
const io = new SocketIOServer(httpServer);
io.on('connection', () => {
// ...
})
return httpServer;
}
When i run npm run dev
, the dev server reloads multiple times before starting saying that vite config has changed even though it hasn't changed
Thanks for the feedback. So, are you having an issue with the example app in this repo? Or did you add this to your existing app? Now that I have the initial release published, I'll create a more full-featured app to stress-test it.
Vite manages the server in development, and this plugin creates the server in production.
To control the dev server, you do that in vite.config.ts https://vitejs.dev/config/server-options.html
export default defineConfig({
server: {
port: 3000, // default is 5173
},
plugins: [remix(), tsconfigPaths()],
});
And yes, the createServer
callback is only executed in production. This is for creating the HTTP or custom server that clients connect to.
If you want to create a server (e.g., socket server) all the time, you should do that in the configure
callback. This is where the Express app is configured and called during your app's initial startup.
export const app = createExpressApp({
configure: app => {
// create socket.io server
const httpServer = createServer(app);
const io = new SocketIOServer(httpServer);
io.on('connection', () => {
// ...
})
},
})
So, are you having an issue with the example app in this repo? Or did you add this to your existing app? Now that I have the initial release published
I have tried both. Honestly i don't remember if it happened in the example app. But in my app certainly.
I was able to fix the import issue by cloning your repo and changed the build process from tsc
to tsup
.
PS: If you install the packages directly in the example folder instead of referencing them like file:../../
then the imports break
To control the dev server, you do that in vite.config.ts https://vitejs.dev/config/server-options.html
This works, thank you
If you want to create a server (e.g., socket server) all the time, you should do that in the configure callback. This is where the Express app is configured and called during your app's initial startup.
This sadly doesn't work because i need to return the created server. That server is then used for .listen
. From what I understand, it's not really a separate server but a server that extends the express's one.
This is my vite config
PS: I'd be happy to provide any non-business critical code to help you the most i can
import { vitePlugin as remix } from "@remix-run/dev";
import { installGlobals } from "@remix-run/node";
import { sentryVitePlugin } from "@sentry/vite-plugin";
import "dotenv/config";
import { glob } from "glob";
import { expressDevServer } from "remix-express-dev-server";
import { flatRoutes } from "remix-flat-routes";
import { type PluginOption, defineConfig } from "vite";
// @ts-ignore They need to update their types
import oxlintPlugin from "vite-plugin-oxlint";
import tsconfigPaths from "vite-tsconfig-paths";
const MODE = process.env.NODE_ENV;
installGlobals();
function I18nHotReload(): PluginOption {
return {
name: "i18n-hot-reload",
handleHotUpdate({ file, server }) {
if (file.includes("public/locales") && file.endsWith(".json")) {
server.hot.send({
type: "custom",
event: "i18n:updated",
});
}
},
};
}
export default defineConfig({
build: {
cssMinify: MODE === "production",
rollupOptions: {
external: [/node:.*/, "stream", "crypto", "fsevents"],
output: {
experimentalMinChunkSize: 16 * 1024,
},
},
sourcemap: true,
},
plugins: [
MODE === "production" && oxlintPlugin(),
I18nHotReload(),
expressDevServer(),
remix({
serverModuleFormat: "esm",
ignoredRouteFiles: ["**/*"],
routes: async (defineRoutes) => {
return flatRoutes("routes", defineRoutes, {
ignoredRouteFiles: [
".*",
"**/*.css",
"**/*.test.{jsx,jsx,ts,tsx}",
"**/__*.*",
// This is for server-side utilities you wan to colocate next to
// your routes without making an additional directory.
// If you need to a route that includes "server" or "client" in the
// filename, use the scape brackets like: my-route.[server].tsx
"**/*.server.*",
"**/*.client.*",
],
});
},
}),
tsconfigPaths(),
process.env.SENTRY_AUTH_TOKEN
? sentryVitePlugin({
disable: MODE !== "production",
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
telemetry: false,
sourcemaps: {
filesToDeleteAfterUpload: await glob([
"./build/**/*.map",
".server-build/**/*.map",
]),
},
})
: null,
],
optimizeDeps: {
exclude: ["@mapbox/node-pre-gyp"],
include: ["./app/entry.client.tsx", "./app/root.tsx", "./app/routes/**/*"],
// extensions: ["ts", "tsx"],
// entries: ["./app/entry-client.tsx", "./app/root.tsx", "./app/routes/**/*"],
},
server: {
port: 3000,
warmup: {
clientFiles: [
"./app/entry.client.tsx",
"./app/root.tsx",
"./app/routes/**/*",
"./app/features/**/!*.server.tsx?",
],
ssrFiles: ["app/utils/**/*.server.*"],
},
},
});
And this is how it is used when using websockets
const createRequestHandler =
MODE === "production"
? Sentry.wrapExpressCreateRequestHandler(createRequestHandler_)
: createRequestHandler_;
const viteDevServer =
MODE === "production"
? undefined
: await import("vite").then((vite) =>
vite.createServer({ server: { middlewareMode: true } }),
);
// Create express app
const app = express();
// Setup middlewares
// ...
// Setup vite dev server
if (viteDevServer) {
app.use(viteDevServer.middlewares);
} else {
// Remix 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" }));
}
// More middlewares
// ...
// Create request handler
async function getBuild() {
const build = viteDevServer
? viteDevServer.ssrLoadModule("virtual:remix/server-build")
: // @ts-ignore this should exist before running the server
// but it may not exist just yet.
await import("../build/server/index.js");
return build as unknown as ServerBuild;
}
app.all(
"*",
createRequestHandler({
mode: MODE,
getLoadContext: (_, res) => ({
cspNonce: res.locals.cspNonce,
serverBuild: getBuild(),
io,
}),
build: getBuild,
}),
);
// Create new http server and pass express into it
const httpServer = createServer(app);
// Create socket.io server
export const io = new SocketIOServer(httpServer);
io.on('connection', () => {});
// Here i have to call `listen` on the httpServer, not express, otherwise socket.io doesn't work
const server = httpServer.listen(3000, async () => {
// More code...
})
Ok, let's treat this as 2 separate issues.
The first one is the module not found. It looks like a build issue. When I patch the files in node_modules/remix-create-express-app, it not only works, but removes the stupid WebSocket server error: Port is already in use
error.
Not sure why it's not specifying the correct path.
diff --git a/node_modules/remix-create-express-app/dist/index.js b/node_modules/remix-create-express-app/dist/index.js
index 2389af3..71faa82 100644
--- a/node_modules/remix-create-express-app/dist/index.js
+++ b/node_modules/remix-create-express-app/dist/index.js
@@ -3,7 +3,7 @@ import url from 'node:url';
import { createRequestHandler as createExpressRequestHandler, } from '@remix-run/express';
import express from 'express';
import sourceMapSupport from 'source-map-support';
-import { createMiddlewareRequestHandler } from './middleware';
+import { createMiddlewareRequestHandler } from './middleware.js';
export function createExpressApp({ configure, getLoadContext, customRequestHandler, getExpress, createServer, unstable_middleware, }) {
sourceMapSupport.install({
retrieveSourceMap: function (source) {
diff --git a/node_modules/remix-create-express-app/dist/middleware.js b/node_modules/remix-create-express-app/dist/middleware.js
index 432a123..a46dd17 100644
--- a/node_modules/remix-create-express-app/dist/middleware.js
+++ b/node_modules/remix-create-express-app/dist/middleware.js
@@ -1,7 +1,7 @@
-import { createRemixRequest, sendRemixResponse, } from '@remix-run/express/dist/server';
+import { createRemixRequest, sendRemixResponse, } from '@remix-run/express/dist/server.js';
import { createRequestHandler as createRemixRequestHandler, } from '@remix-run/node';
import { matchRoutes } from '@remix-run/react';
-import { getRoutes } from '.';
+import { getRoutes } from './index.js';
export function createMiddlewareRequestHandler({ build, getLoadContext, mode = process.env.NODE_ENV, }) {
const handleRequest = createRemixRequestHandler(build, mode);
return async (req, res, expressNext) => {
Anyway, can you create a separate issue for the createServer
enhancement?
Thanks!
Will do!
The first one is the module not found. It looks like a build issue. When I patch the files in node_modules/remix-create-express-app, it not only works, but removes the stupid WebSocket server error: Port is already in use error.
Can confirm the path issue is gone with the patch.
This is fixed in v0.3.1