vite-plugin-remix-routes
Version:
Use Remix routing in your Vite project
202 lines (197 loc) • 6.41 kB
JavaScript
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined")
return require.apply(this, arguments);
throw new Error('Dynamic require of "' + x + '" is not supported');
});
// lib/node/index.ts
import path2 from "path";
import fs from "fs";
// lib/node/remix.ts
var defineConventionalRoutes;
var defineRoutes;
try {
defineConventionalRoutes = __require("@remix-run/dev/config/routesConvention").defineConventionalRoutes;
} catch (e) {
defineConventionalRoutes = __require("@remix-run/dev/dist/config/routesConvention").defineConventionalRoutes;
}
try {
defineRoutes = __require("@remix-run/dev/config/routes").defineRoutes;
} catch (e) {
defineRoutes = __require("@remix-run/dev/dist/config/routes").defineRoutes;
}
async function getRoutes(options) {
const {
appDirectory,
dataRouterCompatible = true,
is404Route = (route) => route.id.endsWith("/404"),
ignoredRouteFiles,
routes
} = options;
const routeManifest = {
root: { path: "", id: "root", file: "" }
};
const conventionalRoutes = defineConventionalRoutes(
appDirectory,
ignoredRouteFiles
);
for (const key of Object.keys(conventionalRoutes)) {
const route = conventionalRoutes[key];
routeManifest[route.id] = {
...route,
parentId: route.parentId || "root"
};
}
if (routes) {
let manualRoutes = await routes(defineRoutes);
for (const key of Object.keys(manualRoutes)) {
const route = manualRoutes[key];
routeManifest[route.id] = {
...route,
parentId: route.parentId || "root"
};
}
}
const routeConfig = createRoutes(routeManifest)[0].children;
const modifyRoute = (route) => ({
...route,
path: !dataRouterCompatible && is404Route(route) ? "*" : route.path,
children: route.children.map(modifyRoute)
});
return routeConfig.map(modifyRoute);
}
function createRoutes(routeManifest, parentId) {
return Object.keys(routeManifest).filter((key) => routeManifest[key].parentId === parentId).map((key) => {
const route = createRoute(routeManifest[key]);
route.children = createRoutes(routeManifest, route.id);
return route;
});
}
function createRoute(route) {
return {
id: route.id,
file: route.file,
path: route.path || "",
index: !!route.index,
children: []
};
}
// lib/node/utils.ts
import path from "path";
function stringifyRoutes(routes, context) {
const components = { sync: [], async: [] };
const routesString = routesToString(routes, context, components);
return {
routesString,
componentsString: [...components.sync, ...components.async].join("\n")
};
}
function routesToString(routes, context, components) {
return "[" + routes.map((route) => routeToString(route, context, components)).join(",") + "]";
}
function routeToString(route, context, components) {
var _a;
const importMode = ((_a = context.importMode) == null ? void 0 : _a.call(context, route)) || "sync";
const componentName = getRouteComponentName(route);
const componentPath = `${context.prefix}${path.sep}${route.file}`.split(path.sep).join(path.posix.sep);
const props = /* @__PURE__ */ new Map();
if (route.path !== "") {
props.set("path", `'${route.path}'`);
}
if (context.dataRouterCompatible) {
components.sync.push(
`import * as ${componentName} from '${componentPath}';`
);
props.set(
"element",
`${componentName}.default ? createElement(${componentName}.default) : undefined`
);
props.set("loader", `${componentName}.loader`);
props.set("action", `${componentName}.action`);
props.set(
"errorElement",
`${componentName}.ErrorBoundary ? createElement(${componentName}.ErrorBoundary) : undefined`
);
props.set("handle", `${componentName}.handle`);
props.set("shouldRevalidate", `${componentName}.shouldRevalidate`);
} else {
if (importMode === "async") {
components.async.push(
`const ${componentName} = () => import('${componentPath}');`
);
props.set("element", `createElement(lazy(${componentName}))`);
props.set("importPromise", componentName);
}
if (importMode === "sync") {
components.sync.push(`import ${componentName} from '${componentPath}';`);
props.set("element", `createElement(${componentName})`);
}
}
if (route.index === true) {
props.set("index", "true");
}
if (route.children.length) {
const children = routesToString(route.children, context, components);
props.set("children", children);
}
return "{" + [...props.entries()].map(([k, v]) => `${k}:${v}`).join(",") + "}";
}
function getRouteComponentName(route) {
return route.id.split(/[/.]/).map((str) => str.replace(/^\w/, (c) => c.toUpperCase())).join("");
}
// lib/node/index.ts
function plugin(options = {}) {
const virtualModuleId = "virtual:remix-routes";
const {
appDirectory = "app",
dataRouterCompatible,
importMode,
is404Route,
routes,
ignoredRouteFiles
} = options;
const dir = path2.resolve(process.cwd(), appDirectory);
const prefix = `.${path2.sep}${path2.relative(process.cwd(), dir)}`;
if (!fs.existsSync(path2.join(dir, "routes")) || !fs.statSync(path2.join(dir, "routes")).isDirectory()) {
throw new Error(
`[vite-plugin-remix-routes] routes directory not found in appDirectory: ${path2.relative(
process.cwd(),
appDirectory
)}`
);
}
return {
name: "vite-plugin-remix-routes",
resolveId(id) {
if (id === virtualModuleId) {
return id;
}
},
async load(id) {
if (id === virtualModuleId) {
const generatedRoutes = await getRoutes({
appDirectory: dir,
dataRouterCompatible,
is404Route,
routes,
ignoredRouteFiles
});
const { routesString, componentsString } = stringifyRoutes(
generatedRoutes,
{ prefix, dataRouterCompatible, importMode }
);
return `import { createElement, lazy, useEffect } from 'react';
${componentsString}
export default ${routesString};
`;
}
}
};
}
var node_default = plugin;
export {
node_default as default,
getRoutes,
stringifyRoutes
};