@tanstack/router-plugin
Version:
Modern and scalable routing for React applications
239 lines (238 loc) • 9.61 kB
JavaScript
require("../_virtual/_rolldown/runtime.cjs");
const require_config = require("./config.cjs");
const require_constants = require("./constants.cjs");
const require_path_ids = require("./code-splitter/path-ids.cjs");
const require_compilers = require("./code-splitter/compilers.cjs");
const require_utils = require("./utils.cjs");
const require_framework_plugins = require("./code-splitter/plugins/framework-plugins.cjs");
let node_url = require("node:url");
let _tanstack_router_utils = require("@tanstack/router-utils");
//#region src/core/router-code-splitter-plugin.ts
/**
* It is important to familiarize yourself with how the code-splitting works in this plugin.
* https://github.com/TanStack/router/pull/3355
*/
var PLUGIN_NAME = "unplugin:router-code-splitter";
var CODE_SPLITTER_PLUGIN_NAME = "tanstack-router:code-splitter:compile-reference-file";
/**
* JSX transformation plugins grouped by framework.
* These plugins must come AFTER the TanStack Router plugin in the Vite config.
*/
var TRANSFORMATION_PLUGINS_BY_FRAMEWORK = {
react: [
{
pluginNames: ["vite:react-babel", "vite:react-refresh"],
pkg: "@vitejs/plugin-react",
usage: "react()"
},
{
pluginNames: ["vite:react-swc", "vite:react-swc:resolve-runtime"],
pkg: "@vitejs/plugin-react-swc",
usage: "reactSwc()"
},
{
pluginNames: ["vite:react-oxc:config", "vite:react-oxc:refresh-runtime"],
pkg: "@vitejs/plugin-react-oxc",
usage: "reactOxc()"
}
],
solid: [{
pluginNames: ["solid"],
pkg: "vite-plugin-solid",
usage: "solid()"
}]
};
var unpluginRouterCodeSplitterFactory = (options = {}, { framework: _framework }) => {
let ROOT = process.cwd();
let userConfig;
function initUserConfig() {
if (typeof options === "function") userConfig = options();
else userConfig = require_config.getConfig(options, ROOT);
}
const isProduction = process.env.NODE_ENV === "production";
const sharedBindingsMap = /* @__PURE__ */ new Map();
const getGlobalCodeSplitGroupings = () => {
return userConfig.codeSplittingOptions?.defaultBehavior || require_constants.defaultCodeSplitGroupings;
};
const getShouldSplitFn = () => {
return userConfig.codeSplittingOptions?.splitBehavior;
};
const handleCompilingReferenceFile = (code, id, generatorNodeInfo) => {
if (require_utils.debug) console.info("Compiling Route: ", id);
const fromCode = require_compilers.detectCodeSplitGroupingsFromRoute({ code });
if (fromCode.groupings) {
const res = require_config.splitGroupingsSchema.safeParse(fromCode.groupings);
if (!res.success) {
const message = res.error.errors.map((e) => e.message).join(". ");
throw new Error(`The groupings for the route "${id}" are invalid.\n${message}`);
}
}
const pluginSplitBehavior = getShouldSplitFn()?.({ routeId: generatorNodeInfo.routePath });
if (pluginSplitBehavior) {
const res = require_config.splitGroupingsSchema.safeParse(pluginSplitBehavior);
if (!res.success) {
const message = res.error.errors.map((e) => e.message).join(". ");
throw new Error(`The groupings returned when using \`splitBehavior\` for the route "${id}" are invalid.\n${message}`);
}
}
const splitGroupings = fromCode.groupings || pluginSplitBehavior || getGlobalCodeSplitGroupings();
const sharedBindings = require_compilers.computeSharedBindings({
code,
codeSplitGroupings: splitGroupings
});
if (sharedBindings.size > 0) sharedBindingsMap.set(id, sharedBindings);
else sharedBindingsMap.delete(id);
const addHmr = (userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction;
const compiledReferenceRoute = require_compilers.compileCodeSplitReferenceRoute({
code,
codeSplitGroupings: splitGroupings,
targetFramework: userConfig.target,
filename: id,
id,
deleteNodes: userConfig.codeSplittingOptions?.deleteNodes ? new Set(userConfig.codeSplittingOptions.deleteNodes) : void 0,
addHmr,
sharedBindings: sharedBindings.size > 0 ? sharedBindings : void 0,
compilerPlugins: require_framework_plugins.getReferenceRouteCompilerPlugins({
targetFramework: userConfig.target,
addHmr
})
});
if (compiledReferenceRoute === null) {
if (require_utils.debug) console.info(`No changes made to route "${id}", skipping code-splitting.`);
return null;
}
if (require_utils.debug) {
(0, _tanstack_router_utils.logDiff)(code, compiledReferenceRoute.code);
console.log("Output:\n", compiledReferenceRoute.code + "\n\n");
}
return compiledReferenceRoute;
};
const handleCompilingVirtualFile = (code, id) => {
if (require_utils.debug) console.info("Splitting Route: ", id);
const [_, ...pathnameParts] = id.split("?");
const splitValue = new URLSearchParams(pathnameParts.join("?")).get(require_constants.tsrSplit);
if (!splitValue) throw new Error(`The split value for the virtual route "${id}" was not found.`);
const rawGrouping = require_path_ids.decodeIdentifier(splitValue);
const grouping = [...new Set(rawGrouping)].filter((p) => require_constants.splitRouteIdentNodes.includes(p));
const baseId = id.split("?")[0];
const result = require_compilers.compileCodeSplitVirtualRoute({
code,
filename: id,
splitTargets: grouping,
sharedBindings: sharedBindingsMap.get(baseId)
});
if (require_utils.debug) {
(0, _tanstack_router_utils.logDiff)(code, result.code);
console.log("Output:\n", result.code + "\n\n");
}
return result;
};
const includedCode = [
"createFileRoute(",
"createRootRoute(",
"createRootRouteWithContext("
];
return [
{
name: "tanstack-router:code-splitter:compile-reference-file",
enforce: "pre",
transform: {
filter: {
id: {
exclude: [require_constants.tsrSplit, require_constants.tsrShared],
include: /\.(m|c)?(j|t)sx?$/
},
code: { include: includedCode }
},
handler(code, id) {
const normalizedId = require_utils.normalizePath(id);
const generatorFileInfo = globalThis.TSR_ROUTES_BY_ID_MAP?.get(normalizedId);
if (generatorFileInfo && includedCode.some((included) => code.includes(included))) return handleCompilingReferenceFile(code, normalizedId, generatorFileInfo);
return null;
}
},
vite: {
configResolved(config) {
ROOT = config.root;
initUserConfig();
const routerPluginIndex = config.plugins.findIndex((p) => p.name === CODE_SPLITTER_PLUGIN_NAME);
if (routerPluginIndex === -1) return;
const frameworkPlugins = TRANSFORMATION_PLUGINS_BY_FRAMEWORK[userConfig.target];
if (!frameworkPlugins) return;
for (const transformPlugin of frameworkPlugins) {
const transformPluginIndex = config.plugins.findIndex((p) => transformPlugin.pluginNames.includes(p.name));
if (transformPluginIndex !== -1 && transformPluginIndex < routerPluginIndex) throw new Error(`Plugin order error: '${transformPlugin.pkg}' is placed before '@tanstack/router-plugin'.\n\nThe TanStack Router plugin must come BEFORE JSX transformation plugins.\n\nPlease update your Vite config:\n\n plugins: [\n tanstackRouter(),\n ${transformPlugin.usage},\n ]\n`);
}
},
applyToEnvironment(environment) {
if (userConfig.plugin?.vite?.environmentName) return userConfig.plugin.vite.environmentName === environment.name;
return true;
}
},
rspack(compiler) {
ROOT = process.cwd();
initUserConfig();
if (compiler.options.mode === "production") compiler.hooks.done.tap(PLUGIN_NAME, () => {
console.info("✅ " + PLUGIN_NAME + ": code-splitting done!");
});
},
webpack(compiler) {
ROOT = process.cwd();
initUserConfig();
if (compiler.options.mode === "production") compiler.hooks.done.tap(PLUGIN_NAME, () => {
console.info("✅ " + PLUGIN_NAME + ": code-splitting done!");
});
}
},
{
name: "tanstack-router:code-splitter:compile-virtual-file",
enforce: "pre",
transform: {
filter: { id: /tsr-split/ },
handler(code, id) {
const url = (0, node_url.pathToFileURL)(id);
url.searchParams.delete("v");
return handleCompilingVirtualFile(code, require_utils.normalizePath((0, node_url.fileURLToPath)(url)));
}
},
vite: { applyToEnvironment(environment) {
if (userConfig.plugin?.vite?.environmentName) return userConfig.plugin.vite.environmentName === environment.name;
return true;
} }
},
{
name: "tanstack-router:code-splitter:compile-shared-file",
enforce: "pre",
transform: {
filter: { id: /tsr-shared/ },
handler(code, id) {
const url = (0, node_url.pathToFileURL)(id);
url.searchParams.delete("v");
const normalizedId = require_utils.normalizePath((0, node_url.fileURLToPath)(url));
const [baseId] = normalizedId.split("?");
if (!baseId) return null;
const sharedBindings = sharedBindingsMap.get(baseId);
if (!sharedBindings || sharedBindings.size === 0) return null;
if (require_utils.debug) console.info("Compiling Shared Module: ", id);
const result = require_compilers.compileCodeSplitSharedRoute({
code,
sharedBindings,
filename: normalizedId
});
if (require_utils.debug) {
(0, _tanstack_router_utils.logDiff)(code, result.code);
console.log("Output:\n", result.code + "\n\n");
}
return result;
}
},
vite: { applyToEnvironment(environment) {
if (userConfig.plugin?.vite?.environmentName) return userConfig.plugin.vite.environmentName === environment.name;
return true;
} }
}
];
};
//#endregion
exports.unpluginRouterCodeSplitterFactory = unpluginRouterCodeSplitterFactory;
//# sourceMappingURL=router-code-splitter-plugin.cjs.map