Description
Reproduction
- Stackblitz: https://stackblitz.com/~/github.com/drewdecarme/remix-imports (I use yarn berry so you might have to clone the repo)
- Github Repo: https://github.com/drewdecarme/remix-imports
System Info
System:
OS: macOS 14.6.1
CPU: (10) arm64 Apple M1 Pro
Memory: 166.48 MB / 32.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 22.1.0 - ~/.nvm/versions/node/v22.1.0/bin/node
Yarn: 4.5.0 - ~/.nvm/versions/node/v22.1.0/bin/yarn
npm: 10.7.0 - ~/.nvm/versions/node/v22.1.0/bin/npm
Watchman: 2022.08.22.00 - /usr/local/bin/watchman
Browsers:
Brave Browser: 126.1.67.134
Chrome: 129.0.6668.58
Safari: 17.6
Used Package Manager
yarn
Expected Behavior
I'm trying to build a Remix app by defining custom routes outside of the app
directory. When I run it in DEV mode, things seem to be working fine, but when I try to build it I get some issues when the server manifest is trying to be built. I would expect if I define a route such as the below, that the absolute path would resolve correctly and the server bundle manifest would compile correctly.
Let's say I define an index route like the below:
export default defineConfig({
plugins: [
remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true
},
routes(defineRoutes) {
return defineRoutes((route) => {
route(
"/",
"/Users/user_name/absolute/path/to/route/file.tsx",
{
index: true
}
);
});
}
})
]
})
Actual Behavior
Client building works fine, but when the ssr
is true and vite attempts to build the server bundles, the asbolute of the routes are being prepended with the absolute app
directory. I've done some tracing and found what I believe to be issue to be here:
in the generateRemixManifestsForBuild
of the vite plugin, the absolute file path is being joined to the app directory which results in a the route.file
being incorrect.
for (let [key, route] of Object.entries(ctx.remixConfig.routes)) {
let routeFilePath = path.join(ctx.remixConfig.appDirectory, route.file);
let sourceExports = routeManifestExports[key];
let isRootRoute = route.parentId === undefined;
let routeManifestEntry = {
id: route.id,
parentId: route.parentId,
path: route.path,
index: route.index,
caseSensitive: route.caseSensitive,
hasAction: sourceExports.includes("action"),
hasLoader: sourceExports.includes("loader"),
hasClientAction: sourceExports.includes("clientAction"),
hasClientLoader: sourceExports.includes("clientLoader"),
hasErrorBoundary: sourceExports.includes("ErrorBoundary"),
...getRemixManifestBuildAssets(
ctx,
viteManifest,
routeFilePath,
// If this is the root route, we also need to include assets from the
// client entry file as this is a common way for consumers to import
// global reset styles, etc.
isRootRoute ? [ctx.entryClientFilePath] : []
),
};
The route.file
from the defineRoutes
function is /Users/user_name/absolute/path/to/route/file
, but when it's joined with the ctx.remixConfig.appDirectory
, it then becomes /Users/user_name/absolute/path/to/route/file/app/Users/user_name/absolute/path/to/route/file.tsx
.
This in turn then fails the lookup for the manifest since the manifest key is relative
{
"../../../../.rel/stuff/_index.tsx?__remix-build-client-route": {
"file": "assets/_index-DDBvjPKe.js",
"name": "_index",
"src": "../../../../.relative/stuff/_index.tsx?__remix-build-client-route",
"isEntry": true,
"imports": [
"_jsx-runtime-SuB_ucaY.js",
"_classes-CfpolwFq.js"
],
"css": [
"assets/_index-2pbE-c8t.css"
]
}
}
This then throws the No manifest entry found
error since the absolute filepath doesn't match the relative key the manifest was created with.
My question is... does remix have a way around this or is this really a bug?