unplugin-vue-router
Advanced tools
Comparing version 0.1.2 to 0.2.0
import * as esbuild from 'esbuild'; | ||
import { R as ResolvedOptions } from './options-7cf6c9a2.js'; | ||
import { O as Options } from './options-66491ed4.js'; | ||
import 'vue-router'; | ||
declare const _default: (options?: Partial<ResolvedOptions> | undefined) => esbuild.Plugin; | ||
declare const _default: (options: Options) => esbuild.Plugin; | ||
export { _default as default }; |
@@ -36,5 +36,2 @@ "use strict"; | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
// src/core/utils.ts | ||
@@ -154,24 +151,6 @@ var import_scule = require("scule"); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
// src/core/treeLeafValue.ts | ||
var _TreeLeafValueBase = class { | ||
// src/core/treeNodeValue.ts | ||
var _TreeNodeValueBase = class { | ||
constructor(rawSegment, parent, pathSegment = rawSegment, subSegments = [rawSegment]) { | ||
@@ -207,3 +186,3 @@ this._overrides = /* @__PURE__ */ new Map(); | ||
}; | ||
var TreeLeafValueStatic = class extends _TreeLeafValueBase { | ||
var TreeNodeValueStatic = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, pathSegment = rawSegment) { | ||
@@ -214,3 +193,3 @@ super(rawSegment, parent, pathSegment); | ||
}; | ||
var TreeLeafValueParam = class extends _TreeLeafValueBase { | ||
var TreeNodeValueParam = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, params, pathSegment, subSegments) { | ||
@@ -222,9 +201,9 @@ super(rawSegment, parent, pathSegment, subSegments); | ||
}; | ||
function createTreeLeafValue(segment, parent) { | ||
function createTreeNodeValue(segment, parent) { | ||
if (!segment || segment === "index") { | ||
return new TreeLeafValueStatic("", parent); | ||
return new TreeNodeValueStatic("", parent); | ||
} | ||
const [pathSegment, params, subSegments] = parseSegment(segment); | ||
if (params.length) { | ||
return new TreeLeafValueParam( | ||
return new TreeNodeValueParam( | ||
segment, | ||
@@ -237,3 +216,3 @@ parent, | ||
} | ||
return new TreeLeafValueStatic(segment, parent, pathSegment); | ||
return new TreeNodeValueStatic(segment, parent, pathSegment); | ||
} | ||
@@ -322,8 +301,9 @@ function parseSegment(segment) { | ||
// src/core/tree.ts | ||
var TreeLeaf = class { | ||
var TreeNode = class { | ||
constructor(options, filePath, parent) { | ||
this.children = /* @__PURE__ */ new Map(); | ||
this.hasDefinePage = false; | ||
this.options = options; | ||
this.parent = parent; | ||
this.value = createTreeLeafValue(filePath, parent == null ? void 0 : parent.value); | ||
this.value = createTreeNodeValue(filePath, parent == null ? void 0 : parent.value); | ||
} | ||
@@ -333,3 +313,3 @@ insert(path, filePath = path) { | ||
if (!this.children.has(segment)) { | ||
this.children.set(segment, new TreeLeaf(this.options, segment, this)); | ||
this.children.set(segment, new TreeNode(this.options, segment, this)); | ||
} | ||
@@ -407,7 +387,7 @@ const child = this.children.get(segment); | ||
toString() { | ||
return `${this.value}${this.value.filePaths.size ? ` \u{1F4C4} (${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}`; | ||
return `${this.value}${this.value.filePaths.size > 1 || this.value.filePaths.size === 1 && !this.value.filePaths.get("default") ? ` \u2388(${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}${this.hasDefinePage ? " \u2691 definePage()" : ""}`; | ||
} | ||
}; | ||
function createPrefixTree(options) { | ||
return new TreeLeaf(options, ""); | ||
return new TreeNode(options, ""); | ||
} | ||
@@ -475,6 +455,6 @@ function splitFilePath(filePath) { | ||
// src/codegen/generateRouteRecords.ts | ||
function generateRouteRecord(node, indent = 0) { | ||
function generateRouteRecord(node, options, importList, indent = 0) { | ||
if (node.value.path === "/" && indent === 0) { | ||
return `[ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 1)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 1)).join(",\n")} | ||
]`; | ||
@@ -484,18 +464,55 @@ } | ||
const indentStr = " ".repeat((indent + 1) * 2); | ||
return `${startIndent}{ | ||
const routeRecord = `${startIndent}{ | ||
${indentStr}path: '${node.path}', | ||
${indentStr}${node.value.filePaths.size ? `name: '${node.name}',` : "/* no name */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent(node, indentStr) : "/* no component */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent( | ||
node, | ||
indentStr, | ||
options.importMode, | ||
importList | ||
) : "/* no component */"} | ||
${indentStr}${node.value.overrides.props != null ? `props: ${node.value.overrides.props},` : "/* no props */"} | ||
${indentStr}${node.children.size > 0 ? `children: [ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 2)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 2)).join(",\n")} | ||
${indentStr}],` : "/* no children */"}${formatMeta(node, indentStr)} | ||
${startIndent}}`; | ||
if (node.hasDefinePage) { | ||
const definePageDataList = []; | ||
for (const [name, filePath] of node.value.filePaths) { | ||
const definePageData = `_definePage_${name}_${importList.size}`; | ||
definePageDataList.push(definePageData); | ||
importList.set(`${filePath}?definePage&vue`, definePageData); | ||
} | ||
if (definePageDataList.length) { | ||
return ` _mergeRouteRecord( | ||
${routeRecord}, | ||
${definePageDataList.join(",\n")} | ||
)`; | ||
} | ||
} | ||
return routeRecord; | ||
} | ||
function generateRouteRecordComponent(node, indentStr) { | ||
function generateRouteRecordComponent(node, indentStr, importMode, importList) { | ||
const files = Array.from(node.value.filePaths); | ||
const isDefaultExport = files.length === 1 && files[0][0] === "default"; | ||
return isDefaultExport ? `component: () => import('${files[0][1]}'),` : `components: { | ||
${files.map(([key, path]) => `${indentStr + " "}'${key}': () => import('${path}')`).join(",\n")} | ||
return isDefaultExport ? `component: ${generatePageImport(files[0][1], importMode, importList)},` : `components: { | ||
${files.map( | ||
([key, path]) => `${indentStr + " "}'${key}': ${generatePageImport( | ||
path, | ||
importMode, | ||
importList | ||
)}` | ||
).join(",\n")} | ||
${indentStr}},`; | ||
} | ||
function generatePageImport(filepath, importMode, importList) { | ||
const mode = typeof importMode === "function" ? importMode(filepath) : importMode; | ||
if (mode === "async") { | ||
return `() => import('${filepath}')`; | ||
} else { | ||
const importName = `_page_${filepath.replace(/[\/\.]/g, "_")}`; | ||
importList.set(filepath, importName); | ||
return importName; | ||
} | ||
} | ||
function generateImportList(node, indentStr) { | ||
@@ -513,3 +530,3 @@ const files = Array.from(node.value.filePaths); | ||
LOADER_GUARD_RE, | ||
"[_LoaderSymbol]: " + generateImportList(node, indent + " ") + "," | ||
"[_HasDataLoaderMeta]: " + generateImportList(node, indent + " ") + "," | ||
) | ||
@@ -522,3 +539,3 @@ ).join("\n"); | ||
var import_fast_glob = __toESM(require("fast-glob")); | ||
var import_pathe = require("pathe"); | ||
var import_pathe2 = require("pathe"); | ||
@@ -585,2 +602,3 @@ // src/core/customBlock.ts | ||
var import_chokidar = __toESM(require("chokidar")); | ||
var import_pathe = require("pathe"); | ||
var RoutesFolderWatcher = class { | ||
@@ -602,2 +620,3 @@ constructor(routesFolder, options) { | ||
this.watcher.on(event, (filePath) => { | ||
filePath = (0, import_pathe.normalize)(filePath); | ||
if (this.options.extensions.every( | ||
@@ -654,4 +673,4 @@ (extension) => !filePath.endsWith(extension) | ||
// data fetching | ||
DataLoader, | ||
DefineLoaderOptions, | ||
_DataLoader, | ||
_DefineLoaderOptions, | ||
} from 'unplugin-vue-router' | ||
@@ -708,2 +727,4 @@ | ||
// Experimental Data Fetching | ||
export function defineLoader< | ||
@@ -716,4 +737,4 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded<Name>) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export function defineLoader< | ||
@@ -724,4 +745,11 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export { | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
} | ||
@@ -746,7 +774,6 @@ | ||
// src/codegen/vueRouterModule.ts | ||
function generateVueRouterProxy(routesModule, { dataFetching }) { | ||
function generateVueRouterProxy(routesModule, options) { | ||
return ` | ||
import { routes } from '${routesModule}' | ||
import { createRouter as _createRouter } from 'vue-router' | ||
${dataFetching ? `import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'` : ``} | ||
@@ -756,2 +783,6 @@ export * from 'vue-router' | ||
_defineLoader as defineLoader, | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
@@ -766,5 +797,3 @@ | ||
)) | ||
${dataFetching ? ` | ||
_setupDataFetchingGuard(router) | ||
` : ``} | ||
return router | ||
@@ -786,6 +815,76 @@ } | ||
// src/core/definePage.ts | ||
var import_common = require("@vue-macros/common"); | ||
var import_ast_walker_scope = require("ast-walker-scope"); | ||
var MACRO_DEFINE_PAGE = "definePage"; | ||
function definePageTransform({ | ||
code, | ||
id | ||
}) { | ||
if (!code.includes(MACRO_DEFINE_PAGE)) | ||
return; | ||
const sfc = (0, import_common.parseSFC)(code, id); | ||
if (!sfc.scriptSetup) | ||
return; | ||
const { script, scriptSetup, scriptCompiled } = sfc; | ||
const definePageNodes = scriptCompiled.scriptSetupAst.map((node) => { | ||
if (node.type === "ExpressionStatement") | ||
node = node.expression; | ||
return (0, import_common.isCallOf)(node, MACRO_DEFINE_PAGE) ? node : null; | ||
}).filter((node) => !!node); | ||
if (!definePageNodes.length) { | ||
return; | ||
} else if (definePageNodes.length > 1) { | ||
throw new SyntaxError(`duplicate definePage() call`); | ||
} | ||
const definePageNode = definePageNodes[0]; | ||
const setupOffset = scriptSetup.loc.start.offset; | ||
if (id.includes(MACRO_DEFINE_PAGE)) { | ||
const s = new import_common.MagicString(code); | ||
const routeRecord = definePageNode.arguments[0]; | ||
const scriptBindings = sfc.scriptCompiled.scriptSetupAst ? getIdentifiers(sfc.scriptCompiled.scriptSetupAst) : []; | ||
(0, import_common.checkInvalidScopeReference)(routeRecord, MACRO_DEFINE_PAGE, scriptBindings); | ||
s.remove(setupOffset + routeRecord.end, code.length); | ||
s.remove(0, setupOffset + routeRecord.start); | ||
s.prepend(`export default `); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} else { | ||
const s = new import_common.MagicString(code); | ||
s.remove( | ||
setupOffset + definePageNode.start, | ||
setupOffset + definePageNode.end | ||
); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} | ||
} | ||
var getIdentifiers = (stmts) => { | ||
let ids = []; | ||
(0, import_ast_walker_scope.walkAST)( | ||
{ | ||
type: "Program", | ||
body: stmts, | ||
directives: [], | ||
sourceType: "module", | ||
sourceFile: "" | ||
}, | ||
{ | ||
enter(node) { | ||
if (node.type === "BlockStatement") { | ||
this.skip(); | ||
} | ||
}, | ||
leave(node) { | ||
if (node.type !== "Program") | ||
return; | ||
ids = Object.keys(this.scope); | ||
} | ||
} | ||
); | ||
return ids; | ||
}; | ||
// src/core/context.ts | ||
function createRoutesContext(options) { | ||
const { dts: preferDTS, root, routesFolder } = options; | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe.resolve)(root, "typed-router.d.ts") : (0, import_pathe.resolve)(root, preferDTS); | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe2.resolve)(root, "typed-router.d.ts") : (0, import_pathe2.resolve)(root, preferDTS); | ||
const routeTree = createPrefixTree(options); | ||
@@ -798,8 +897,2 @@ const routeMap = /* @__PURE__ */ new Map(); | ||
} | ||
const resolvedRoutesFolders = normalizeRoutesFolderOption(routesFolder).map( | ||
(routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
}) | ||
); | ||
const watchers = []; | ||
@@ -817,3 +910,3 @@ async function scanPages() { | ||
await Promise.all( | ||
resolvedRoutesFolders.map((folder) => { | ||
routesFolder.map((folder) => { | ||
const watcher = new RoutesFolderWatcher(folder, options); | ||
@@ -825,3 +918,3 @@ setupWatcher(watcher); | ||
ignore: options.exclude | ||
}).then((files) => files.map((file) => (0, import_pathe.resolve)(folder.src, file))).then( | ||
}).then((files) => files.map((file) => (0, import_pathe2.resolve)(folder.src, file))).then( | ||
(files) => Promise.all( | ||
@@ -847,3 +940,3 @@ files.map( | ||
routePath, | ||
(0, import_pathe.resolve)(root, path) | ||
(0, import_pathe2.resolve)(root, path) | ||
); | ||
@@ -853,2 +946,4 @@ node.setCustomRouteBlock(path, routeBlock); | ||
routeMap.set(path, node); | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
} | ||
@@ -862,2 +957,4 @@ async function updatePage({ filePath: path, routePath }) { | ||
} | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
node.setCustomRouteBlock(path, await getRouteBlock(path, options)); | ||
@@ -885,7 +982,22 @@ node.value.includeLoaderGuard = options.dataFetching && await hasNamedExports(path); | ||
function generateRoutes() { | ||
const imports = options.dataFetching ? `import { _LoaderSymbol } from 'unplugin-vue-router/runtime' | ||
` : ``; | ||
return `${imports}export const routes = ${generateRouteRecord(routeTree)} | ||
const importList = /* @__PURE__ */ new Map(); | ||
const routesExport = `export const routes = ${generateRouteRecord( | ||
routeTree, | ||
options, | ||
importList | ||
)}`; | ||
let imports = ""; | ||
if (options.dataFetching) { | ||
imports += `import { _HasDataLoaderMeta, _mergeRouteRecord } from 'unplugin-vue-router/runtime' | ||
`; | ||
} | ||
for (const [path, name] of importList) { | ||
imports += `import ${name} from '${path}' | ||
`; | ||
} | ||
if (imports) { | ||
imports += "\n"; | ||
} | ||
return `${imports}${routesExport} | ||
`; | ||
} | ||
@@ -931,6 +1043,48 @@ function generateDTS2() { | ||
generateRoutes, | ||
generateVueRouterProxy: generateVueRouterProxy2 | ||
generateVueRouterProxy: generateVueRouterProxy2, | ||
definePageTransform(code, id) { | ||
return definePageTransform({ | ||
code, | ||
id | ||
}); | ||
} | ||
}; | ||
} | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
var import_pathe3 = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe3.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// src/core/vite/index.ts | ||
@@ -961,4 +1115,6 @@ function createViteContext(server) { | ||
// src/index.ts | ||
var import_pluginutils = require("@rollup/pluginutils"); | ||
var import_pathe4 = require("pathe"); | ||
var src_default = (0, import_unplugin.createUnplugin)((opt, meta) => { | ||
const options = { ...DEFAULT_OPTIONS, ...opt }; | ||
const options = resolveOptions(opt); | ||
const ctx = createRoutesContext(options); | ||
@@ -975,2 +1131,12 @@ function getVirtualId2(id) { | ||
} | ||
const pageFilePattern = `**/*` + (options.extensions.length === 1 ? options.extensions[0] : `.{${options.extensions.map((extension) => extension.replace(".", "")).join(",")}}`); | ||
const filterPageComponents = (0, import_pluginutils.createFilter)( | ||
[ | ||
...options.routesFolder.map( | ||
(routeOption) => (0, import_pathe4.join)(routeOption.src, pageFilePattern) | ||
), | ||
/definePage\&vue$/ | ||
], | ||
options.exclude | ||
); | ||
return { | ||
@@ -989,3 +1155,2 @@ name: "unplugin-vue-router", | ||
} | ||
return null; | ||
}, | ||
@@ -1001,2 +1166,8 @@ buildStart() { | ||
}, | ||
transformInclude(id) { | ||
return filterPageComponents(id); | ||
}, | ||
transform(code, id) { | ||
return ctx.definePageTransform(code, id); | ||
}, | ||
load(id) { | ||
@@ -1016,3 +1187,2 @@ const resolvedId = getVirtualId2(id); | ||
} | ||
return null; | ||
}, | ||
@@ -1019,0 +1189,0 @@ vite: { |
import * as unplugin from 'unplugin'; | ||
import { R as ResolvedOptions, S as ServerContext, T as TreeLeaf } from './options-7cf6c9a2.js'; | ||
export { O as Options, T as TreeLeaf, c as createPrefixTree } from './options-7cf6c9a2.js'; | ||
import { R as ResolvedOptions, S as ServerContext, O as Options } from './options-66491ed4.js'; | ||
export { O as Options, T as TreeNode, b as TreeNodeValueParam, d as TreeNodeValueStatic, c as createPrefixTree, a as createTreeNodeValue } from './options-66491ed4.js'; | ||
import { L as LiteralStringUnion } from './defineLoader-e49c7239.js'; | ||
export { b as _DataLoader, D as _DefineLoaderOptions, g as getFileBasedRouteName, a as getPascalCaseRouteName } from './defineLoader-e49c7239.js'; | ||
import { RouteParamsRaw, RouteParams, RouteMeta, RouteLocationNormalized, RouteRecordName, RouteLocationNormalizedLoaded, RouteQueryAndHash, RouteLocationOptions, RouteLocation, NavigationGuardNext, NavigationFailure, Router, RouteLocationRaw, RouterLinkProps as RouterLinkProps$1 } from 'vue-router'; | ||
import { Ref, AllowedComponentProps, ComponentCustomProps, VNodeProps, UnwrapRef, VNode, ComputedRef } from 'vue'; | ||
export { a as DataLoader, D as DefineLoaderOptions } from './defineLoader-68ee3023.js'; | ||
@@ -15,21 +16,5 @@ declare function createRoutesContext(options: ResolvedOptions): { | ||
generateVueRouterProxy: () => string; | ||
definePageTransform(code: string, id: string): unplugin.Thenable<unplugin.TransformResult>; | ||
}; | ||
declare type LiteralStringUnion<LiteralType, BaseType extends string = string> = LiteralType | (BaseType & Record<never, never>); | ||
/** | ||
* Creates a name based of the node path segments. | ||
* | ||
* @param node - the node to get the path from | ||
* @param parent - the parent node | ||
* @returns a route name | ||
*/ | ||
declare function getPascalCaseRouteName(node: TreeLeaf): string; | ||
/** | ||
* Joins the path segments of a node into a name that corresponds to the filepath represented by the node. | ||
* | ||
* @param node - the node to get the path from | ||
* @returns a route name | ||
*/ | ||
declare function getFileBasedRouteName(node: TreeLeaf): string; | ||
interface RouteRecordInfo<Name extends string = string, Path extends string = string, ParamsRaw extends RouteParamsRaw = RouteParamsRaw, Params extends RouteParams = RouteParams, Meta extends RouteMeta = RouteMeta> { | ||
@@ -169,7 +154,23 @@ name: Name; | ||
declare const _default: unplugin.UnpluginInstance<Partial<ResolvedOptions>>; | ||
declare const _default: unplugin.UnpluginInstance<Options>; | ||
declare const VueRouterExports: string[]; | ||
declare const RuntimeExports: string[][]; | ||
/** | ||
* @deprecated use `VueRouterAutoImports` instead | ||
*/ | ||
declare const VueRouterExports: Array<string | [string, string]>; | ||
/** | ||
* Adds useful auto imports to the AutoImport config: | ||
* @example | ||
* ```js | ||
* import { VueRouterAutoImports } from 'unplugin-vue-router' | ||
* | ||
* AutoImport({ | ||
* imports: [VueRouterAutoImports], | ||
* }), | ||
* ``` | ||
*/ | ||
declare const VueRouterAutoImports: { | ||
'vue-router/auto': (string | [string, string])[]; | ||
}; | ||
export { NavigationGuard, ParamValue, ParamValueOneOrMore, ParamValueZeroOrMore, ParamValueZeroOrOne, RouteLocationAsPathTyped, RouteLocationAsPathTypedList, RouteLocationAsRelativeTyped, RouteLocationAsRelativeTypedList, RouteLocationAsString, RouteLocationNormalizedLoadedTyped, RouteLocationNormalizedLoadedTypedList, RouteLocationNormalizedTyped, RouteLocationNormalizedTypedList, RouteLocationResolvedTyped, RouteLocationResolvedTypedList, RouteLocationTyped, RouteLocationTypedList, RouteRecordInfo, RouterLinkTyped, RuntimeExports, UseLinkFnTyped, VueRouterExports, _RouteMapGeneric, _RouterTyped, _UseLinkReturnTyped, createRoutesContext, _default as default, getFileBasedRouteName, getPascalCaseRouteName }; | ||
export { NavigationGuard, ParamValue, ParamValueOneOrMore, ParamValueZeroOrMore, ParamValueZeroOrOne, RouteLocationAsPathTyped, RouteLocationAsPathTypedList, RouteLocationAsRelativeTyped, RouteLocationAsRelativeTypedList, RouteLocationAsString, RouteLocationNormalizedLoadedTyped, RouteLocationNormalizedLoadedTypedList, RouteLocationNormalizedTyped, RouteLocationNormalizedTypedList, RouteLocationResolvedTyped, RouteLocationResolvedTypedList, RouteLocationTyped, RouteLocationTypedList, RouteRecordInfo, RouterLinkTyped, UseLinkFnTyped, VueRouterAutoImports, VueRouterExports, _RouteMapGeneric, _RouterTyped, _UseLinkReturnTyped, createRoutesContext, _default as default }; |
@@ -29,7 +29,10 @@ "use strict"; | ||
__export(src_exports, { | ||
RuntimeExports: () => RuntimeExports, | ||
TreeLeaf: () => TreeLeaf, | ||
TreeNode: () => TreeNode, | ||
TreeNodeValueParam: () => TreeNodeValueParam, | ||
TreeNodeValueStatic: () => TreeNodeValueStatic, | ||
VueRouterAutoImports: () => VueRouterAutoImports, | ||
VueRouterExports: () => VueRouterExports, | ||
createPrefixTree: () => createPrefixTree, | ||
createRoutesContext: () => createRoutesContext, | ||
createTreeNodeValue: () => createTreeNodeValue, | ||
default: () => src_default, | ||
@@ -42,5 +45,2 @@ getFileBasedRouteName: () => getFileBasedRouteName, | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
// src/core/utils.ts | ||
@@ -179,24 +179,6 @@ var import_scule = require("scule"); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
// src/core/treeLeafValue.ts | ||
var _TreeLeafValueBase = class { | ||
// src/core/treeNodeValue.ts | ||
var _TreeNodeValueBase = class { | ||
constructor(rawSegment, parent, pathSegment = rawSegment, subSegments = [rawSegment]) { | ||
@@ -232,3 +214,3 @@ this._overrides = /* @__PURE__ */ new Map(); | ||
}; | ||
var TreeLeafValueStatic = class extends _TreeLeafValueBase { | ||
var TreeNodeValueStatic = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, pathSegment = rawSegment) { | ||
@@ -239,3 +221,3 @@ super(rawSegment, parent, pathSegment); | ||
}; | ||
var TreeLeafValueParam = class extends _TreeLeafValueBase { | ||
var TreeNodeValueParam = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, params, pathSegment, subSegments) { | ||
@@ -247,9 +229,9 @@ super(rawSegment, parent, pathSegment, subSegments); | ||
}; | ||
function createTreeLeafValue(segment, parent) { | ||
function createTreeNodeValue(segment, parent) { | ||
if (!segment || segment === "index") { | ||
return new TreeLeafValueStatic("", parent); | ||
return new TreeNodeValueStatic("", parent); | ||
} | ||
const [pathSegment, params, subSegments] = parseSegment(segment); | ||
if (params.length) { | ||
return new TreeLeafValueParam( | ||
return new TreeNodeValueParam( | ||
segment, | ||
@@ -262,3 +244,3 @@ parent, | ||
} | ||
return new TreeLeafValueStatic(segment, parent, pathSegment); | ||
return new TreeNodeValueStatic(segment, parent, pathSegment); | ||
} | ||
@@ -347,8 +329,9 @@ function parseSegment(segment) { | ||
// src/core/tree.ts | ||
var TreeLeaf = class { | ||
var TreeNode = class { | ||
constructor(options, filePath, parent) { | ||
this.children = /* @__PURE__ */ new Map(); | ||
this.hasDefinePage = false; | ||
this.options = options; | ||
this.parent = parent; | ||
this.value = createTreeLeafValue(filePath, parent == null ? void 0 : parent.value); | ||
this.value = createTreeNodeValue(filePath, parent == null ? void 0 : parent.value); | ||
} | ||
@@ -358,3 +341,3 @@ insert(path, filePath = path) { | ||
if (!this.children.has(segment)) { | ||
this.children.set(segment, new TreeLeaf(this.options, segment, this)); | ||
this.children.set(segment, new TreeNode(this.options, segment, this)); | ||
} | ||
@@ -432,7 +415,7 @@ const child = this.children.get(segment); | ||
toString() { | ||
return `${this.value}${this.value.filePaths.size ? ` \u{1F4C4} (${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}`; | ||
return `${this.value}${this.value.filePaths.size > 1 || this.value.filePaths.size === 1 && !this.value.filePaths.get("default") ? ` \u2388(${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}${this.hasDefinePage ? " \u2691 definePage()" : ""}`; | ||
} | ||
}; | ||
function createPrefixTree(options) { | ||
return new TreeLeaf(options, ""); | ||
return new TreeNode(options, ""); | ||
} | ||
@@ -500,6 +483,6 @@ function splitFilePath(filePath) { | ||
// src/codegen/generateRouteRecords.ts | ||
function generateRouteRecord(node, indent = 0) { | ||
function generateRouteRecord(node, options, importList, indent = 0) { | ||
if (node.value.path === "/" && indent === 0) { | ||
return `[ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 1)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 1)).join(",\n")} | ||
]`; | ||
@@ -509,18 +492,55 @@ } | ||
const indentStr = " ".repeat((indent + 1) * 2); | ||
return `${startIndent}{ | ||
const routeRecord = `${startIndent}{ | ||
${indentStr}path: '${node.path}', | ||
${indentStr}${node.value.filePaths.size ? `name: '${node.name}',` : "/* no name */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent(node, indentStr) : "/* no component */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent( | ||
node, | ||
indentStr, | ||
options.importMode, | ||
importList | ||
) : "/* no component */"} | ||
${indentStr}${node.value.overrides.props != null ? `props: ${node.value.overrides.props},` : "/* no props */"} | ||
${indentStr}${node.children.size > 0 ? `children: [ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 2)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 2)).join(",\n")} | ||
${indentStr}],` : "/* no children */"}${formatMeta(node, indentStr)} | ||
${startIndent}}`; | ||
if (node.hasDefinePage) { | ||
const definePageDataList = []; | ||
for (const [name, filePath] of node.value.filePaths) { | ||
const definePageData = `_definePage_${name}_${importList.size}`; | ||
definePageDataList.push(definePageData); | ||
importList.set(`${filePath}?definePage&vue`, definePageData); | ||
} | ||
if (definePageDataList.length) { | ||
return ` _mergeRouteRecord( | ||
${routeRecord}, | ||
${definePageDataList.join(",\n")} | ||
)`; | ||
} | ||
} | ||
return routeRecord; | ||
} | ||
function generateRouteRecordComponent(node, indentStr) { | ||
function generateRouteRecordComponent(node, indentStr, importMode, importList) { | ||
const files = Array.from(node.value.filePaths); | ||
const isDefaultExport = files.length === 1 && files[0][0] === "default"; | ||
return isDefaultExport ? `component: () => import('${files[0][1]}'),` : `components: { | ||
${files.map(([key, path]) => `${indentStr + " "}'${key}': () => import('${path}')`).join(",\n")} | ||
return isDefaultExport ? `component: ${generatePageImport(files[0][1], importMode, importList)},` : `components: { | ||
${files.map( | ||
([key, path]) => `${indentStr + " "}'${key}': ${generatePageImport( | ||
path, | ||
importMode, | ||
importList | ||
)}` | ||
).join(",\n")} | ||
${indentStr}},`; | ||
} | ||
function generatePageImport(filepath, importMode, importList) { | ||
const mode = typeof importMode === "function" ? importMode(filepath) : importMode; | ||
if (mode === "async") { | ||
return `() => import('${filepath}')`; | ||
} else { | ||
const importName = `_page_${filepath.replace(/[\/\.]/g, "_")}`; | ||
importList.set(filepath, importName); | ||
return importName; | ||
} | ||
} | ||
function generateImportList(node, indentStr) { | ||
@@ -538,3 +558,3 @@ const files = Array.from(node.value.filePaths); | ||
LOADER_GUARD_RE, | ||
"[_LoaderSymbol]: " + generateImportList(node, indent + " ") + "," | ||
"[_HasDataLoaderMeta]: " + generateImportList(node, indent + " ") + "," | ||
) | ||
@@ -547,3 +567,3 @@ ).join("\n"); | ||
var import_fast_glob = __toESM(require("fast-glob")); | ||
var import_pathe = require("pathe"); | ||
var import_pathe2 = require("pathe"); | ||
@@ -610,2 +630,3 @@ // src/core/customBlock.ts | ||
var import_chokidar = __toESM(require("chokidar")); | ||
var import_pathe = require("pathe"); | ||
var RoutesFolderWatcher = class { | ||
@@ -627,2 +648,3 @@ constructor(routesFolder, options) { | ||
this.watcher.on(event, (filePath) => { | ||
filePath = (0, import_pathe.normalize)(filePath); | ||
if (this.options.extensions.every( | ||
@@ -679,4 +701,4 @@ (extension) => !filePath.endsWith(extension) | ||
// data fetching | ||
DataLoader, | ||
DefineLoaderOptions, | ||
_DataLoader, | ||
_DefineLoaderOptions, | ||
} from 'unplugin-vue-router' | ||
@@ -733,2 +755,4 @@ | ||
// Experimental Data Fetching | ||
export function defineLoader< | ||
@@ -741,4 +765,4 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded<Name>) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export function defineLoader< | ||
@@ -749,4 +773,11 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export { | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
} | ||
@@ -771,7 +802,6 @@ | ||
// src/codegen/vueRouterModule.ts | ||
function generateVueRouterProxy(routesModule, { dataFetching }) { | ||
function generateVueRouterProxy(routesModule, options) { | ||
return ` | ||
import { routes } from '${routesModule}' | ||
import { createRouter as _createRouter } from 'vue-router' | ||
${dataFetching ? `import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'` : ``} | ||
@@ -781,2 +811,6 @@ export * from 'vue-router' | ||
_defineLoader as defineLoader, | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
@@ -791,5 +825,3 @@ | ||
)) | ||
${dataFetching ? ` | ||
_setupDataFetchingGuard(router) | ||
` : ``} | ||
return router | ||
@@ -811,6 +843,76 @@ } | ||
// src/core/definePage.ts | ||
var import_common = require("@vue-macros/common"); | ||
var import_ast_walker_scope = require("ast-walker-scope"); | ||
var MACRO_DEFINE_PAGE = "definePage"; | ||
function definePageTransform({ | ||
code, | ||
id | ||
}) { | ||
if (!code.includes(MACRO_DEFINE_PAGE)) | ||
return; | ||
const sfc = (0, import_common.parseSFC)(code, id); | ||
if (!sfc.scriptSetup) | ||
return; | ||
const { script, scriptSetup, scriptCompiled } = sfc; | ||
const definePageNodes = scriptCompiled.scriptSetupAst.map((node) => { | ||
if (node.type === "ExpressionStatement") | ||
node = node.expression; | ||
return (0, import_common.isCallOf)(node, MACRO_DEFINE_PAGE) ? node : null; | ||
}).filter((node) => !!node); | ||
if (!definePageNodes.length) { | ||
return; | ||
} else if (definePageNodes.length > 1) { | ||
throw new SyntaxError(`duplicate definePage() call`); | ||
} | ||
const definePageNode = definePageNodes[0]; | ||
const setupOffset = scriptSetup.loc.start.offset; | ||
if (id.includes(MACRO_DEFINE_PAGE)) { | ||
const s = new import_common.MagicString(code); | ||
const routeRecord = definePageNode.arguments[0]; | ||
const scriptBindings = sfc.scriptCompiled.scriptSetupAst ? getIdentifiers(sfc.scriptCompiled.scriptSetupAst) : []; | ||
(0, import_common.checkInvalidScopeReference)(routeRecord, MACRO_DEFINE_PAGE, scriptBindings); | ||
s.remove(setupOffset + routeRecord.end, code.length); | ||
s.remove(0, setupOffset + routeRecord.start); | ||
s.prepend(`export default `); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} else { | ||
const s = new import_common.MagicString(code); | ||
s.remove( | ||
setupOffset + definePageNode.start, | ||
setupOffset + definePageNode.end | ||
); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} | ||
} | ||
var getIdentifiers = (stmts) => { | ||
let ids = []; | ||
(0, import_ast_walker_scope.walkAST)( | ||
{ | ||
type: "Program", | ||
body: stmts, | ||
directives: [], | ||
sourceType: "module", | ||
sourceFile: "" | ||
}, | ||
{ | ||
enter(node) { | ||
if (node.type === "BlockStatement") { | ||
this.skip(); | ||
} | ||
}, | ||
leave(node) { | ||
if (node.type !== "Program") | ||
return; | ||
ids = Object.keys(this.scope); | ||
} | ||
} | ||
); | ||
return ids; | ||
}; | ||
// src/core/context.ts | ||
function createRoutesContext(options) { | ||
const { dts: preferDTS, root, routesFolder } = options; | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe.resolve)(root, "typed-router.d.ts") : (0, import_pathe.resolve)(root, preferDTS); | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe2.resolve)(root, "typed-router.d.ts") : (0, import_pathe2.resolve)(root, preferDTS); | ||
const routeTree = createPrefixTree(options); | ||
@@ -823,8 +925,2 @@ const routeMap = /* @__PURE__ */ new Map(); | ||
} | ||
const resolvedRoutesFolders = normalizeRoutesFolderOption(routesFolder).map( | ||
(routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
}) | ||
); | ||
const watchers = []; | ||
@@ -842,3 +938,3 @@ async function scanPages() { | ||
await Promise.all( | ||
resolvedRoutesFolders.map((folder) => { | ||
routesFolder.map((folder) => { | ||
const watcher = new RoutesFolderWatcher(folder, options); | ||
@@ -850,3 +946,3 @@ setupWatcher(watcher); | ||
ignore: options.exclude | ||
}).then((files) => files.map((file) => (0, import_pathe.resolve)(folder.src, file))).then( | ||
}).then((files) => files.map((file) => (0, import_pathe2.resolve)(folder.src, file))).then( | ||
(files) => Promise.all( | ||
@@ -872,3 +968,3 @@ files.map( | ||
routePath, | ||
(0, import_pathe.resolve)(root, path) | ||
(0, import_pathe2.resolve)(root, path) | ||
); | ||
@@ -878,2 +974,4 @@ node.setCustomRouteBlock(path, routeBlock); | ||
routeMap.set(path, node); | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
} | ||
@@ -887,2 +985,4 @@ async function updatePage({ filePath: path, routePath }) { | ||
} | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
node.setCustomRouteBlock(path, await getRouteBlock(path, options)); | ||
@@ -910,7 +1010,22 @@ node.value.includeLoaderGuard = options.dataFetching && await hasNamedExports(path); | ||
function generateRoutes() { | ||
const imports = options.dataFetching ? `import { _LoaderSymbol } from 'unplugin-vue-router/runtime' | ||
` : ``; | ||
return `${imports}export const routes = ${generateRouteRecord(routeTree)} | ||
const importList = /* @__PURE__ */ new Map(); | ||
const routesExport = `export const routes = ${generateRouteRecord( | ||
routeTree, | ||
options, | ||
importList | ||
)}`; | ||
let imports = ""; | ||
if (options.dataFetching) { | ||
imports += `import { _HasDataLoaderMeta, _mergeRouteRecord } from 'unplugin-vue-router/runtime' | ||
`; | ||
} | ||
for (const [path, name] of importList) { | ||
imports += `import ${name} from '${path}' | ||
`; | ||
} | ||
if (imports) { | ||
imports += "\n"; | ||
} | ||
return `${imports}${routesExport} | ||
`; | ||
} | ||
@@ -956,6 +1071,48 @@ function generateDTS2() { | ||
generateRoutes, | ||
generateVueRouterProxy: generateVueRouterProxy2 | ||
generateVueRouterProxy: generateVueRouterProxy2, | ||
definePageTransform(code, id) { | ||
return definePageTransform({ | ||
code, | ||
id | ||
}); | ||
} | ||
}; | ||
} | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
var import_pathe3 = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe3.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// src/core/vite/index.ts | ||
@@ -986,4 +1143,6 @@ function createViteContext(server) { | ||
// src/index.ts | ||
var import_pluginutils = require("@rollup/pluginutils"); | ||
var import_pathe4 = require("pathe"); | ||
var src_default = (0, import_unplugin.createUnplugin)((opt, meta) => { | ||
const options = { ...DEFAULT_OPTIONS, ...opt }; | ||
const options = resolveOptions(opt); | ||
const ctx = createRoutesContext(options); | ||
@@ -1000,2 +1159,12 @@ function getVirtualId2(id) { | ||
} | ||
const pageFilePattern = `**/*` + (options.extensions.length === 1 ? options.extensions[0] : `.{${options.extensions.map((extension) => extension.replace(".", "")).join(",")}}`); | ||
const filterPageComponents = (0, import_pluginutils.createFilter)( | ||
[ | ||
...options.routesFolder.map( | ||
(routeOption) => (0, import_pathe4.join)(routeOption.src, pageFilePattern) | ||
), | ||
/definePage\&vue$/ | ||
], | ||
options.exclude | ||
); | ||
return { | ||
@@ -1014,3 +1183,2 @@ name: "unplugin-vue-router", | ||
} | ||
return null; | ||
}, | ||
@@ -1026,2 +1194,8 @@ buildStart() { | ||
}, | ||
transformInclude(id) { | ||
return filterPageComponents(id); | ||
}, | ||
transform(code, id) { | ||
return ctx.definePageTransform(code, id); | ||
}, | ||
load(id) { | ||
@@ -1041,3 +1215,2 @@ const resolvedId = getVirtualId2(id); | ||
} | ||
return null; | ||
}, | ||
@@ -1054,14 +1227,20 @@ vite: { | ||
"useRouter", | ||
"defineLoader" | ||
"defineLoader", | ||
"definePage" | ||
]; | ||
var RuntimeExports = [["_defineLoader", "defineLoader"]]; | ||
var VueRouterAutoImports = { | ||
"vue-router/auto": VueRouterExports | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
RuntimeExports, | ||
TreeLeaf, | ||
TreeNode, | ||
TreeNodeValueParam, | ||
TreeNodeValueStatic, | ||
VueRouterAutoImports, | ||
VueRouterExports, | ||
createPrefixTree, | ||
createRoutesContext, | ||
createTreeNodeValue, | ||
getFileBasedRouteName, | ||
getPascalCaseRouteName | ||
}); |
@@ -1,2 +0,2 @@ | ||
export { D as DEFAULT_OPTIONS, O as Options, R as ResolvedOptions, b as RoutesFolder, a as RoutesFolderOption, S as ServerContext, _ as _RoutesFolder, n as normalizeRoutesFolderOption } from './options-7cf6c9a2.js'; | ||
export { D as DEFAULT_OPTIONS, O as Options, R as ResolvedOptions, f as RoutesFolder, e as RoutesFolderOption, S as ServerContext, g as _OptionsImportMode, _ as _RoutesFolder, r as resolveOptions } from './options-66491ed4.js'; | ||
import 'vue-router'; |
@@ -24,3 +24,3 @@ "use strict"; | ||
DEFAULT_OPTIONS: () => DEFAULT_OPTIONS, | ||
normalizeRoutesFolderOption: () => normalizeRoutesFolderOption | ||
resolveOptions: () => resolveOptions | ||
}); | ||
@@ -38,4 +38,6 @@ module.exports = __toCommonJS(options_exports); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var import_pathe = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
@@ -48,2 +50,3 @@ extensions: [".vue"], | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
@@ -59,6 +62,20 @@ dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
DEFAULT_OPTIONS, | ||
normalizeRoutesFolderOption | ||
resolveOptions | ||
}); |
import * as unplugin from 'unplugin'; | ||
import { R as ResolvedOptions } from './options-7cf6c9a2.js'; | ||
import { O as Options } from './options-66491ed4.js'; | ||
import 'vue-router'; | ||
declare const _default: (options?: Partial<ResolvedOptions> | undefined) => unplugin.RollupPlugin; | ||
declare const _default: (options: Options) => unplugin.RollupPlugin; | ||
export { _default as default }; |
@@ -36,5 +36,2 @@ "use strict"; | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
// src/core/utils.ts | ||
@@ -154,24 +151,6 @@ var import_scule = require("scule"); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
// src/core/treeLeafValue.ts | ||
var _TreeLeafValueBase = class { | ||
// src/core/treeNodeValue.ts | ||
var _TreeNodeValueBase = class { | ||
constructor(rawSegment, parent, pathSegment = rawSegment, subSegments = [rawSegment]) { | ||
@@ -207,3 +186,3 @@ this._overrides = /* @__PURE__ */ new Map(); | ||
}; | ||
var TreeLeafValueStatic = class extends _TreeLeafValueBase { | ||
var TreeNodeValueStatic = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, pathSegment = rawSegment) { | ||
@@ -214,3 +193,3 @@ super(rawSegment, parent, pathSegment); | ||
}; | ||
var TreeLeafValueParam = class extends _TreeLeafValueBase { | ||
var TreeNodeValueParam = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, params, pathSegment, subSegments) { | ||
@@ -222,9 +201,9 @@ super(rawSegment, parent, pathSegment, subSegments); | ||
}; | ||
function createTreeLeafValue(segment, parent) { | ||
function createTreeNodeValue(segment, parent) { | ||
if (!segment || segment === "index") { | ||
return new TreeLeafValueStatic("", parent); | ||
return new TreeNodeValueStatic("", parent); | ||
} | ||
const [pathSegment, params, subSegments] = parseSegment(segment); | ||
if (params.length) { | ||
return new TreeLeafValueParam( | ||
return new TreeNodeValueParam( | ||
segment, | ||
@@ -237,3 +216,3 @@ parent, | ||
} | ||
return new TreeLeafValueStatic(segment, parent, pathSegment); | ||
return new TreeNodeValueStatic(segment, parent, pathSegment); | ||
} | ||
@@ -322,8 +301,9 @@ function parseSegment(segment) { | ||
// src/core/tree.ts | ||
var TreeLeaf = class { | ||
var TreeNode = class { | ||
constructor(options, filePath, parent) { | ||
this.children = /* @__PURE__ */ new Map(); | ||
this.hasDefinePage = false; | ||
this.options = options; | ||
this.parent = parent; | ||
this.value = createTreeLeafValue(filePath, parent == null ? void 0 : parent.value); | ||
this.value = createTreeNodeValue(filePath, parent == null ? void 0 : parent.value); | ||
} | ||
@@ -333,3 +313,3 @@ insert(path, filePath = path) { | ||
if (!this.children.has(segment)) { | ||
this.children.set(segment, new TreeLeaf(this.options, segment, this)); | ||
this.children.set(segment, new TreeNode(this.options, segment, this)); | ||
} | ||
@@ -407,7 +387,7 @@ const child = this.children.get(segment); | ||
toString() { | ||
return `${this.value}${this.value.filePaths.size ? ` \u{1F4C4} (${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}`; | ||
return `${this.value}${this.value.filePaths.size > 1 || this.value.filePaths.size === 1 && !this.value.filePaths.get("default") ? ` \u2388(${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}${this.hasDefinePage ? " \u2691 definePage()" : ""}`; | ||
} | ||
}; | ||
function createPrefixTree(options) { | ||
return new TreeLeaf(options, ""); | ||
return new TreeNode(options, ""); | ||
} | ||
@@ -475,6 +455,6 @@ function splitFilePath(filePath) { | ||
// src/codegen/generateRouteRecords.ts | ||
function generateRouteRecord(node, indent = 0) { | ||
function generateRouteRecord(node, options, importList, indent = 0) { | ||
if (node.value.path === "/" && indent === 0) { | ||
return `[ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 1)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 1)).join(",\n")} | ||
]`; | ||
@@ -484,18 +464,55 @@ } | ||
const indentStr = " ".repeat((indent + 1) * 2); | ||
return `${startIndent}{ | ||
const routeRecord = `${startIndent}{ | ||
${indentStr}path: '${node.path}', | ||
${indentStr}${node.value.filePaths.size ? `name: '${node.name}',` : "/* no name */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent(node, indentStr) : "/* no component */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent( | ||
node, | ||
indentStr, | ||
options.importMode, | ||
importList | ||
) : "/* no component */"} | ||
${indentStr}${node.value.overrides.props != null ? `props: ${node.value.overrides.props},` : "/* no props */"} | ||
${indentStr}${node.children.size > 0 ? `children: [ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 2)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 2)).join(",\n")} | ||
${indentStr}],` : "/* no children */"}${formatMeta(node, indentStr)} | ||
${startIndent}}`; | ||
if (node.hasDefinePage) { | ||
const definePageDataList = []; | ||
for (const [name, filePath] of node.value.filePaths) { | ||
const definePageData = `_definePage_${name}_${importList.size}`; | ||
definePageDataList.push(definePageData); | ||
importList.set(`${filePath}?definePage&vue`, definePageData); | ||
} | ||
if (definePageDataList.length) { | ||
return ` _mergeRouteRecord( | ||
${routeRecord}, | ||
${definePageDataList.join(",\n")} | ||
)`; | ||
} | ||
} | ||
return routeRecord; | ||
} | ||
function generateRouteRecordComponent(node, indentStr) { | ||
function generateRouteRecordComponent(node, indentStr, importMode, importList) { | ||
const files = Array.from(node.value.filePaths); | ||
const isDefaultExport = files.length === 1 && files[0][0] === "default"; | ||
return isDefaultExport ? `component: () => import('${files[0][1]}'),` : `components: { | ||
${files.map(([key, path]) => `${indentStr + " "}'${key}': () => import('${path}')`).join(",\n")} | ||
return isDefaultExport ? `component: ${generatePageImport(files[0][1], importMode, importList)},` : `components: { | ||
${files.map( | ||
([key, path]) => `${indentStr + " "}'${key}': ${generatePageImport( | ||
path, | ||
importMode, | ||
importList | ||
)}` | ||
).join(",\n")} | ||
${indentStr}},`; | ||
} | ||
function generatePageImport(filepath, importMode, importList) { | ||
const mode = typeof importMode === "function" ? importMode(filepath) : importMode; | ||
if (mode === "async") { | ||
return `() => import('${filepath}')`; | ||
} else { | ||
const importName = `_page_${filepath.replace(/[\/\.]/g, "_")}`; | ||
importList.set(filepath, importName); | ||
return importName; | ||
} | ||
} | ||
function generateImportList(node, indentStr) { | ||
@@ -513,3 +530,3 @@ const files = Array.from(node.value.filePaths); | ||
LOADER_GUARD_RE, | ||
"[_LoaderSymbol]: " + generateImportList(node, indent + " ") + "," | ||
"[_HasDataLoaderMeta]: " + generateImportList(node, indent + " ") + "," | ||
) | ||
@@ -522,3 +539,3 @@ ).join("\n"); | ||
var import_fast_glob = __toESM(require("fast-glob")); | ||
var import_pathe = require("pathe"); | ||
var import_pathe2 = require("pathe"); | ||
@@ -585,2 +602,3 @@ // src/core/customBlock.ts | ||
var import_chokidar = __toESM(require("chokidar")); | ||
var import_pathe = require("pathe"); | ||
var RoutesFolderWatcher = class { | ||
@@ -602,2 +620,3 @@ constructor(routesFolder, options) { | ||
this.watcher.on(event, (filePath) => { | ||
filePath = (0, import_pathe.normalize)(filePath); | ||
if (this.options.extensions.every( | ||
@@ -654,4 +673,4 @@ (extension) => !filePath.endsWith(extension) | ||
// data fetching | ||
DataLoader, | ||
DefineLoaderOptions, | ||
_DataLoader, | ||
_DefineLoaderOptions, | ||
} from 'unplugin-vue-router' | ||
@@ -708,2 +727,4 @@ | ||
// Experimental Data Fetching | ||
export function defineLoader< | ||
@@ -716,4 +737,4 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded<Name>) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export function defineLoader< | ||
@@ -724,4 +745,11 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export { | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
} | ||
@@ -746,7 +774,6 @@ | ||
// src/codegen/vueRouterModule.ts | ||
function generateVueRouterProxy(routesModule, { dataFetching }) { | ||
function generateVueRouterProxy(routesModule, options) { | ||
return ` | ||
import { routes } from '${routesModule}' | ||
import { createRouter as _createRouter } from 'vue-router' | ||
${dataFetching ? `import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'` : ``} | ||
@@ -756,2 +783,6 @@ export * from 'vue-router' | ||
_defineLoader as defineLoader, | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
@@ -766,5 +797,3 @@ | ||
)) | ||
${dataFetching ? ` | ||
_setupDataFetchingGuard(router) | ||
` : ``} | ||
return router | ||
@@ -786,6 +815,76 @@ } | ||
// src/core/definePage.ts | ||
var import_common = require("@vue-macros/common"); | ||
var import_ast_walker_scope = require("ast-walker-scope"); | ||
var MACRO_DEFINE_PAGE = "definePage"; | ||
function definePageTransform({ | ||
code, | ||
id | ||
}) { | ||
if (!code.includes(MACRO_DEFINE_PAGE)) | ||
return; | ||
const sfc = (0, import_common.parseSFC)(code, id); | ||
if (!sfc.scriptSetup) | ||
return; | ||
const { script, scriptSetup, scriptCompiled } = sfc; | ||
const definePageNodes = scriptCompiled.scriptSetupAst.map((node) => { | ||
if (node.type === "ExpressionStatement") | ||
node = node.expression; | ||
return (0, import_common.isCallOf)(node, MACRO_DEFINE_PAGE) ? node : null; | ||
}).filter((node) => !!node); | ||
if (!definePageNodes.length) { | ||
return; | ||
} else if (definePageNodes.length > 1) { | ||
throw new SyntaxError(`duplicate definePage() call`); | ||
} | ||
const definePageNode = definePageNodes[0]; | ||
const setupOffset = scriptSetup.loc.start.offset; | ||
if (id.includes(MACRO_DEFINE_PAGE)) { | ||
const s = new import_common.MagicString(code); | ||
const routeRecord = definePageNode.arguments[0]; | ||
const scriptBindings = sfc.scriptCompiled.scriptSetupAst ? getIdentifiers(sfc.scriptCompiled.scriptSetupAst) : []; | ||
(0, import_common.checkInvalidScopeReference)(routeRecord, MACRO_DEFINE_PAGE, scriptBindings); | ||
s.remove(setupOffset + routeRecord.end, code.length); | ||
s.remove(0, setupOffset + routeRecord.start); | ||
s.prepend(`export default `); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} else { | ||
const s = new import_common.MagicString(code); | ||
s.remove( | ||
setupOffset + definePageNode.start, | ||
setupOffset + definePageNode.end | ||
); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} | ||
} | ||
var getIdentifiers = (stmts) => { | ||
let ids = []; | ||
(0, import_ast_walker_scope.walkAST)( | ||
{ | ||
type: "Program", | ||
body: stmts, | ||
directives: [], | ||
sourceType: "module", | ||
sourceFile: "" | ||
}, | ||
{ | ||
enter(node) { | ||
if (node.type === "BlockStatement") { | ||
this.skip(); | ||
} | ||
}, | ||
leave(node) { | ||
if (node.type !== "Program") | ||
return; | ||
ids = Object.keys(this.scope); | ||
} | ||
} | ||
); | ||
return ids; | ||
}; | ||
// src/core/context.ts | ||
function createRoutesContext(options) { | ||
const { dts: preferDTS, root, routesFolder } = options; | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe.resolve)(root, "typed-router.d.ts") : (0, import_pathe.resolve)(root, preferDTS); | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe2.resolve)(root, "typed-router.d.ts") : (0, import_pathe2.resolve)(root, preferDTS); | ||
const routeTree = createPrefixTree(options); | ||
@@ -798,8 +897,2 @@ const routeMap = /* @__PURE__ */ new Map(); | ||
} | ||
const resolvedRoutesFolders = normalizeRoutesFolderOption(routesFolder).map( | ||
(routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
}) | ||
); | ||
const watchers = []; | ||
@@ -817,3 +910,3 @@ async function scanPages() { | ||
await Promise.all( | ||
resolvedRoutesFolders.map((folder) => { | ||
routesFolder.map((folder) => { | ||
const watcher = new RoutesFolderWatcher(folder, options); | ||
@@ -825,3 +918,3 @@ setupWatcher(watcher); | ||
ignore: options.exclude | ||
}).then((files) => files.map((file) => (0, import_pathe.resolve)(folder.src, file))).then( | ||
}).then((files) => files.map((file) => (0, import_pathe2.resolve)(folder.src, file))).then( | ||
(files) => Promise.all( | ||
@@ -847,3 +940,3 @@ files.map( | ||
routePath, | ||
(0, import_pathe.resolve)(root, path) | ||
(0, import_pathe2.resolve)(root, path) | ||
); | ||
@@ -853,2 +946,4 @@ node.setCustomRouteBlock(path, routeBlock); | ||
routeMap.set(path, node); | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
} | ||
@@ -862,2 +957,4 @@ async function updatePage({ filePath: path, routePath }) { | ||
} | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
node.setCustomRouteBlock(path, await getRouteBlock(path, options)); | ||
@@ -885,7 +982,22 @@ node.value.includeLoaderGuard = options.dataFetching && await hasNamedExports(path); | ||
function generateRoutes() { | ||
const imports = options.dataFetching ? `import { _LoaderSymbol } from 'unplugin-vue-router/runtime' | ||
` : ``; | ||
return `${imports}export const routes = ${generateRouteRecord(routeTree)} | ||
const importList = /* @__PURE__ */ new Map(); | ||
const routesExport = `export const routes = ${generateRouteRecord( | ||
routeTree, | ||
options, | ||
importList | ||
)}`; | ||
let imports = ""; | ||
if (options.dataFetching) { | ||
imports += `import { _HasDataLoaderMeta, _mergeRouteRecord } from 'unplugin-vue-router/runtime' | ||
`; | ||
} | ||
for (const [path, name] of importList) { | ||
imports += `import ${name} from '${path}' | ||
`; | ||
} | ||
if (imports) { | ||
imports += "\n"; | ||
} | ||
return `${imports}${routesExport} | ||
`; | ||
} | ||
@@ -931,6 +1043,48 @@ function generateDTS2() { | ||
generateRoutes, | ||
generateVueRouterProxy: generateVueRouterProxy2 | ||
generateVueRouterProxy: generateVueRouterProxy2, | ||
definePageTransform(code, id) { | ||
return definePageTransform({ | ||
code, | ||
id | ||
}); | ||
} | ||
}; | ||
} | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
var import_pathe3 = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe3.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// src/core/vite/index.ts | ||
@@ -961,4 +1115,6 @@ function createViteContext(server) { | ||
// src/index.ts | ||
var import_pluginutils = require("@rollup/pluginutils"); | ||
var import_pathe4 = require("pathe"); | ||
var src_default = (0, import_unplugin.createUnplugin)((opt, meta) => { | ||
const options = { ...DEFAULT_OPTIONS, ...opt }; | ||
const options = resolveOptions(opt); | ||
const ctx = createRoutesContext(options); | ||
@@ -975,2 +1131,12 @@ function getVirtualId2(id) { | ||
} | ||
const pageFilePattern = `**/*` + (options.extensions.length === 1 ? options.extensions[0] : `.{${options.extensions.map((extension) => extension.replace(".", "")).join(",")}}`); | ||
const filterPageComponents = (0, import_pluginutils.createFilter)( | ||
[ | ||
...options.routesFolder.map( | ||
(routeOption) => (0, import_pathe4.join)(routeOption.src, pageFilePattern) | ||
), | ||
/definePage\&vue$/ | ||
], | ||
options.exclude | ||
); | ||
return { | ||
@@ -989,3 +1155,2 @@ name: "unplugin-vue-router", | ||
} | ||
return null; | ||
}, | ||
@@ -1001,2 +1166,8 @@ buildStart() { | ||
}, | ||
transformInclude(id) { | ||
return filterPageComponents(id); | ||
}, | ||
transform(code, id) { | ||
return ctx.definePageTransform(code, id); | ||
}, | ||
load(id) { | ||
@@ -1016,3 +1187,2 @@ const resolvedId = getVirtualId2(id); | ||
} | ||
return null; | ||
}, | ||
@@ -1019,0 +1189,0 @@ vite: { |
@@ -1,7 +0,8 @@ | ||
import { a as DataLoader } from './defineLoader-68ee3023.js'; | ||
export { a as DataLoader, D as DefineLoaderOptions, d as _defineLoader, s as _stopScope } from './defineLoader-68ee3023.js'; | ||
import { Router } from 'vue-router'; | ||
import { Router, RouteLocationNormalized, RouteRecordRaw } from 'vue-router'; | ||
import { b as DataLoader, A as Awaitable } from './defineLoader-e49c7239.js'; | ||
export { b as DataLoader, D as DefineLoaderOptions, d as _defineLoader, s as _stopDataFetchingScope } from './defineLoader-e49c7239.js'; | ||
import './options-66491ed4.js'; | ||
import 'vue'; | ||
declare const LoaderSymbol: unique symbol; | ||
declare const HasDataLoaderMeta: unique symbol; | ||
declare module 'vue-router' { | ||
@@ -13,7 +14,31 @@ interface RouteMeta { | ||
*/ | ||
[LoaderSymbol]?: Array<() => Promise<Record<string, DataLoader<unknown> | unknown>>>; | ||
[HasDataLoaderMeta]?: Array<() => Promise<Record<string, DataLoader<unknown> | unknown>>>; | ||
} | ||
} | ||
declare function setupDataFetchingGuard(router: Router, initialState?: Record<string, unknown>): Record<string, unknown> | null | undefined; | ||
declare type NavigationResult = any; | ||
interface SetupDataFetchingGuardOptions { | ||
/** | ||
* Initial data to skip the initial data loaders. This is useful for SSR and should be set only on client side. | ||
*/ | ||
initialData?: Record<string, unknown>; | ||
/** | ||
* Hook that is called before each data loader is called. Can return a promise to delay the data loader call. | ||
*/ | ||
beforeLoad?: (route: RouteLocationNormalized) => Promise<unknown>; | ||
/** | ||
* Called if any data loader returns a `NavigationResult` with an array of them. Should decide what is the outcome of | ||
* the data fetching guard. Note this isn't called if no data loaders return a `NavigationResult`. | ||
*/ | ||
selectNavigationResult?: (results: NavigationResult[]) => Awaitable<NavigationResult | undefined | void>; | ||
} | ||
declare function setupDataFetchingGuard(router: Router, { initialData }?: SetupDataFetchingGuardOptions): Record<string, unknown> | null | undefined; | ||
export { LoaderSymbol as _LoaderSymbol, setupDataFetchingGuard as _setupDataFetchingGuard }; | ||
/** | ||
* Defines properties of the route for the current page component. | ||
* | ||
* @param route - route information to be added to this page | ||
*/ | ||
declare function _definePage(route: Partial<Omit<RouteRecordRaw, 'children' | 'components' | 'component'>>): void; | ||
declare function _mergeRouteRecord(main: RouteRecordRaw, ...routeRecords: Partial<RouteRecordRaw>[]): RouteRecordRaw; | ||
export { HasDataLoaderMeta as _HasDataLoaderMeta, _definePage, _mergeRouteRecord, setupDataFetchingGuard as _setupDataFetchingGuard }; |
@@ -23,6 +23,8 @@ "use strict"; | ||
__export(runtime_exports, { | ||
_LoaderSymbol: () => LoaderSymbol, | ||
_HasDataLoaderMeta: () => HasDataLoaderMeta, | ||
_defineLoader: () => defineLoader, | ||
_definePage: () => _definePage, | ||
_mergeRouteRecord: () => _mergeRouteRecord, | ||
_setupDataFetchingGuard: () => setupDataFetchingGuard, | ||
_stopScope: () => stopScope | ||
_stopDataFetchingScope: () => stopScope | ||
}); | ||
@@ -42,3 +44,3 @@ module.exports = __toCommonJS(runtime_exports); | ||
} | ||
function createDataCacheEntry(options, initialState) { | ||
function createDataCacheEntry(options, initialData) { | ||
return withinScope(() => ({ | ||
@@ -49,3 +51,3 @@ pending: (0, import_vue.ref)(false), | ||
loaders: /* @__PURE__ */ new Set(), | ||
data: (0, import_vue.ref)(initialState), | ||
data: (0, import_vue.ref)(initialData), | ||
params: {}, | ||
@@ -82,2 +84,21 @@ query: {}, | ||
// src/data-fetching/locationUtils.ts | ||
function includesParams(outer, inner) { | ||
for (const key in inner) { | ||
const innerValue = inner[key]; | ||
const outerValue = outer[key]; | ||
if (typeof innerValue === "string") { | ||
if (innerValue !== outerValue) | ||
return false; | ||
} else if (!innerValue || !outerValue) { | ||
if (innerValue !== outerValue) | ||
return false; | ||
} else { | ||
if (!Array.isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i])) | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
// src/data-fetching/defineLoader.ts | ||
@@ -131,5 +152,5 @@ var DEFAULT_DEFINE_LOADER_OPTIONS = { | ||
const pendingLoad = () => pendingPromise; | ||
function load(route, router, parent, initialState) { | ||
function load(route, router, parent, initialRootData) { | ||
const hasCacheEntry = cache.has(router); | ||
const initialData = initialState && initialState[options.key]; | ||
const initialData = initialRootData && initialRootData[options.key]; | ||
if (!hasCacheEntry) { | ||
@@ -189,19 +210,2 @@ cache.set(router, createDataCacheEntry(options, initialData)); | ||
} | ||
function includesParams(outer, inner) { | ||
for (const key in inner) { | ||
const innerValue = inner[key]; | ||
const outerValue = outer[key]; | ||
if (typeof innerValue === "string") { | ||
if (innerValue !== outerValue) | ||
return false; | ||
} else if (!innerValue || !outerValue) { | ||
if (innerValue !== outerValue) | ||
return false; | ||
} else { | ||
if (!Array.isArray(outerValue) || outerValue.length !== innerValue.length || innerValue.some((value, i) => value !== outerValue[i])) | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
var IsLoader = Symbol(); | ||
@@ -243,17 +247,25 @@ function isDataLoader(loader) { | ||
// src/core/utils.ts | ||
var import_scule = require("scule"); | ||
var isArray = Array.isArray; | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/data-fetching/dataFetchingGuard.ts | ||
var LoaderSymbol = Symbol(); | ||
var HasDataLoaderMeta = Symbol(); | ||
var ADDED_SYMBOL = Symbol(); | ||
function setupDataFetchingGuard(router, initialState) { | ||
if (ADDED_SYMBOL in router) { | ||
console.warn( | ||
"[vue-router]: Data fetching guard added twice. Make sure to remove the extra call." | ||
); | ||
return; | ||
function setupDataFetchingGuard(router, { initialData } = {}) { | ||
if (__DEV__) { | ||
if (ADDED_SYMBOL in router) { | ||
console.warn( | ||
"[vue-router]: Data fetching guard added twice. Make sure to remove the extra call." | ||
); | ||
return; | ||
} | ||
router[ADDED_SYMBOL] = true; | ||
} | ||
router[ADDED_SYMBOL] = true; | ||
const fetchedState = {}; | ||
let isFetched; | ||
router.beforeEach((to) => { | ||
return Promise.all( | ||
to.matched.flatMap((route) => route.meta[LoaderSymbol]).filter((moduleImport) => moduleImport).map( | ||
to.matched.flatMap((route) => route.meta[HasDataLoaderMeta]).filter((moduleImport) => moduleImport).map( | ||
(moduleImport) => moduleImport().then((mod) => { | ||
@@ -271,8 +283,9 @@ const loaders = Object.keys(mod).filter((exportName) => isDataLoader(mod[exportName])).map((loaderName) => mod[loaderName]); | ||
void 0, | ||
initialState | ||
initialData | ||
).then(() => { | ||
if (!initialState) { | ||
if (!initialData) { | ||
if (key) { | ||
fetchedState[key] = cache.get(router).data.value; | ||
} | ||
} else if (__DEV__ && !key && !isFetched) { | ||
} | ||
@@ -285,13 +298,28 @@ }); | ||
).then(() => { | ||
initialState = void 0; | ||
initialData = void 0; | ||
isFetched = true; | ||
}); | ||
}); | ||
return initialState ? null : fetchedState; | ||
return initialData ? null : fetchedState; | ||
} | ||
// src/runtime.ts | ||
function _definePage(route) { | ||
} | ||
function _mergeRouteRecord(main, ...routeRecords) { | ||
return routeRecords.reduce((acc, routeRecord) => { | ||
const meta = Object.assign({}, acc.meta, routeRecord.meta); | ||
Object.assign(acc, routeRecord); | ||
acc.meta = meta; | ||
return acc; | ||
}, main); | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
_LoaderSymbol, | ||
_HasDataLoaderMeta, | ||
_defineLoader, | ||
_definePage, | ||
_mergeRouteRecord, | ||
_setupDataFetchingGuard, | ||
_stopScope | ||
_stopDataFetchingScope | ||
}); |
import * as vite from 'vite'; | ||
import { R as ResolvedOptions } from './options-7cf6c9a2.js'; | ||
import { O as Options } from './options-66491ed4.js'; | ||
import 'vue-router'; | ||
declare const _default: (options?: Partial<ResolvedOptions> | undefined) => vite.Plugin; | ||
declare const _default: (options: Options) => vite.Plugin; | ||
export { _default as default }; |
318
dist/vite.js
@@ -36,5 +36,2 @@ "use strict"; | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
// src/core/utils.ts | ||
@@ -154,24 +151,6 @@ var import_scule = require("scule"); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
// src/core/treeLeafValue.ts | ||
var _TreeLeafValueBase = class { | ||
// src/core/treeNodeValue.ts | ||
var _TreeNodeValueBase = class { | ||
constructor(rawSegment, parent, pathSegment = rawSegment, subSegments = [rawSegment]) { | ||
@@ -207,3 +186,3 @@ this._overrides = /* @__PURE__ */ new Map(); | ||
}; | ||
var TreeLeafValueStatic = class extends _TreeLeafValueBase { | ||
var TreeNodeValueStatic = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, pathSegment = rawSegment) { | ||
@@ -214,3 +193,3 @@ super(rawSegment, parent, pathSegment); | ||
}; | ||
var TreeLeafValueParam = class extends _TreeLeafValueBase { | ||
var TreeNodeValueParam = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, params, pathSegment, subSegments) { | ||
@@ -222,9 +201,9 @@ super(rawSegment, parent, pathSegment, subSegments); | ||
}; | ||
function createTreeLeafValue(segment, parent) { | ||
function createTreeNodeValue(segment, parent) { | ||
if (!segment || segment === "index") { | ||
return new TreeLeafValueStatic("", parent); | ||
return new TreeNodeValueStatic("", parent); | ||
} | ||
const [pathSegment, params, subSegments] = parseSegment(segment); | ||
if (params.length) { | ||
return new TreeLeafValueParam( | ||
return new TreeNodeValueParam( | ||
segment, | ||
@@ -237,3 +216,3 @@ parent, | ||
} | ||
return new TreeLeafValueStatic(segment, parent, pathSegment); | ||
return new TreeNodeValueStatic(segment, parent, pathSegment); | ||
} | ||
@@ -322,8 +301,9 @@ function parseSegment(segment) { | ||
// src/core/tree.ts | ||
var TreeLeaf = class { | ||
var TreeNode = class { | ||
constructor(options, filePath, parent) { | ||
this.children = /* @__PURE__ */ new Map(); | ||
this.hasDefinePage = false; | ||
this.options = options; | ||
this.parent = parent; | ||
this.value = createTreeLeafValue(filePath, parent == null ? void 0 : parent.value); | ||
this.value = createTreeNodeValue(filePath, parent == null ? void 0 : parent.value); | ||
} | ||
@@ -333,3 +313,3 @@ insert(path, filePath = path) { | ||
if (!this.children.has(segment)) { | ||
this.children.set(segment, new TreeLeaf(this.options, segment, this)); | ||
this.children.set(segment, new TreeNode(this.options, segment, this)); | ||
} | ||
@@ -407,7 +387,7 @@ const child = this.children.get(segment); | ||
toString() { | ||
return `${this.value}${this.value.filePaths.size ? ` \u{1F4C4} (${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}`; | ||
return `${this.value}${this.value.filePaths.size > 1 || this.value.filePaths.size === 1 && !this.value.filePaths.get("default") ? ` \u2388(${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}${this.hasDefinePage ? " \u2691 definePage()" : ""}`; | ||
} | ||
}; | ||
function createPrefixTree(options) { | ||
return new TreeLeaf(options, ""); | ||
return new TreeNode(options, ""); | ||
} | ||
@@ -475,6 +455,6 @@ function splitFilePath(filePath) { | ||
// src/codegen/generateRouteRecords.ts | ||
function generateRouteRecord(node, indent = 0) { | ||
function generateRouteRecord(node, options, importList, indent = 0) { | ||
if (node.value.path === "/" && indent === 0) { | ||
return `[ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 1)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 1)).join(",\n")} | ||
]`; | ||
@@ -484,18 +464,55 @@ } | ||
const indentStr = " ".repeat((indent + 1) * 2); | ||
return `${startIndent}{ | ||
const routeRecord = `${startIndent}{ | ||
${indentStr}path: '${node.path}', | ||
${indentStr}${node.value.filePaths.size ? `name: '${node.name}',` : "/* no name */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent(node, indentStr) : "/* no component */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent( | ||
node, | ||
indentStr, | ||
options.importMode, | ||
importList | ||
) : "/* no component */"} | ||
${indentStr}${node.value.overrides.props != null ? `props: ${node.value.overrides.props},` : "/* no props */"} | ||
${indentStr}${node.children.size > 0 ? `children: [ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 2)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 2)).join(",\n")} | ||
${indentStr}],` : "/* no children */"}${formatMeta(node, indentStr)} | ||
${startIndent}}`; | ||
if (node.hasDefinePage) { | ||
const definePageDataList = []; | ||
for (const [name, filePath] of node.value.filePaths) { | ||
const definePageData = `_definePage_${name}_${importList.size}`; | ||
definePageDataList.push(definePageData); | ||
importList.set(`${filePath}?definePage&vue`, definePageData); | ||
} | ||
if (definePageDataList.length) { | ||
return ` _mergeRouteRecord( | ||
${routeRecord}, | ||
${definePageDataList.join(",\n")} | ||
)`; | ||
} | ||
} | ||
return routeRecord; | ||
} | ||
function generateRouteRecordComponent(node, indentStr) { | ||
function generateRouteRecordComponent(node, indentStr, importMode, importList) { | ||
const files = Array.from(node.value.filePaths); | ||
const isDefaultExport = files.length === 1 && files[0][0] === "default"; | ||
return isDefaultExport ? `component: () => import('${files[0][1]}'),` : `components: { | ||
${files.map(([key, path]) => `${indentStr + " "}'${key}': () => import('${path}')`).join(",\n")} | ||
return isDefaultExport ? `component: ${generatePageImport(files[0][1], importMode, importList)},` : `components: { | ||
${files.map( | ||
([key, path]) => `${indentStr + " "}'${key}': ${generatePageImport( | ||
path, | ||
importMode, | ||
importList | ||
)}` | ||
).join(",\n")} | ||
${indentStr}},`; | ||
} | ||
function generatePageImport(filepath, importMode, importList) { | ||
const mode = typeof importMode === "function" ? importMode(filepath) : importMode; | ||
if (mode === "async") { | ||
return `() => import('${filepath}')`; | ||
} else { | ||
const importName = `_page_${filepath.replace(/[\/\.]/g, "_")}`; | ||
importList.set(filepath, importName); | ||
return importName; | ||
} | ||
} | ||
function generateImportList(node, indentStr) { | ||
@@ -513,3 +530,3 @@ const files = Array.from(node.value.filePaths); | ||
LOADER_GUARD_RE, | ||
"[_LoaderSymbol]: " + generateImportList(node, indent + " ") + "," | ||
"[_HasDataLoaderMeta]: " + generateImportList(node, indent + " ") + "," | ||
) | ||
@@ -522,3 +539,3 @@ ).join("\n"); | ||
var import_fast_glob = __toESM(require("fast-glob")); | ||
var import_pathe = require("pathe"); | ||
var import_pathe2 = require("pathe"); | ||
@@ -585,2 +602,3 @@ // src/core/customBlock.ts | ||
var import_chokidar = __toESM(require("chokidar")); | ||
var import_pathe = require("pathe"); | ||
var RoutesFolderWatcher = class { | ||
@@ -602,2 +620,3 @@ constructor(routesFolder, options) { | ||
this.watcher.on(event, (filePath) => { | ||
filePath = (0, import_pathe.normalize)(filePath); | ||
if (this.options.extensions.every( | ||
@@ -654,4 +673,4 @@ (extension) => !filePath.endsWith(extension) | ||
// data fetching | ||
DataLoader, | ||
DefineLoaderOptions, | ||
_DataLoader, | ||
_DefineLoaderOptions, | ||
} from 'unplugin-vue-router' | ||
@@ -708,2 +727,4 @@ | ||
// Experimental Data Fetching | ||
export function defineLoader< | ||
@@ -716,4 +737,4 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded<Name>) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export function defineLoader< | ||
@@ -724,4 +745,11 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export { | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
} | ||
@@ -746,7 +774,6 @@ | ||
// src/codegen/vueRouterModule.ts | ||
function generateVueRouterProxy(routesModule, { dataFetching }) { | ||
function generateVueRouterProxy(routesModule, options) { | ||
return ` | ||
import { routes } from '${routesModule}' | ||
import { createRouter as _createRouter } from 'vue-router' | ||
${dataFetching ? `import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'` : ``} | ||
@@ -756,2 +783,6 @@ export * from 'vue-router' | ||
_defineLoader as defineLoader, | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
@@ -766,5 +797,3 @@ | ||
)) | ||
${dataFetching ? ` | ||
_setupDataFetchingGuard(router) | ||
` : ``} | ||
return router | ||
@@ -786,6 +815,76 @@ } | ||
// src/core/definePage.ts | ||
var import_common = require("@vue-macros/common"); | ||
var import_ast_walker_scope = require("ast-walker-scope"); | ||
var MACRO_DEFINE_PAGE = "definePage"; | ||
function definePageTransform({ | ||
code, | ||
id | ||
}) { | ||
if (!code.includes(MACRO_DEFINE_PAGE)) | ||
return; | ||
const sfc = (0, import_common.parseSFC)(code, id); | ||
if (!sfc.scriptSetup) | ||
return; | ||
const { script, scriptSetup, scriptCompiled } = sfc; | ||
const definePageNodes = scriptCompiled.scriptSetupAst.map((node) => { | ||
if (node.type === "ExpressionStatement") | ||
node = node.expression; | ||
return (0, import_common.isCallOf)(node, MACRO_DEFINE_PAGE) ? node : null; | ||
}).filter((node) => !!node); | ||
if (!definePageNodes.length) { | ||
return; | ||
} else if (definePageNodes.length > 1) { | ||
throw new SyntaxError(`duplicate definePage() call`); | ||
} | ||
const definePageNode = definePageNodes[0]; | ||
const setupOffset = scriptSetup.loc.start.offset; | ||
if (id.includes(MACRO_DEFINE_PAGE)) { | ||
const s = new import_common.MagicString(code); | ||
const routeRecord = definePageNode.arguments[0]; | ||
const scriptBindings = sfc.scriptCompiled.scriptSetupAst ? getIdentifiers(sfc.scriptCompiled.scriptSetupAst) : []; | ||
(0, import_common.checkInvalidScopeReference)(routeRecord, MACRO_DEFINE_PAGE, scriptBindings); | ||
s.remove(setupOffset + routeRecord.end, code.length); | ||
s.remove(0, setupOffset + routeRecord.start); | ||
s.prepend(`export default `); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} else { | ||
const s = new import_common.MagicString(code); | ||
s.remove( | ||
setupOffset + definePageNode.start, | ||
setupOffset + definePageNode.end | ||
); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} | ||
} | ||
var getIdentifiers = (stmts) => { | ||
let ids = []; | ||
(0, import_ast_walker_scope.walkAST)( | ||
{ | ||
type: "Program", | ||
body: stmts, | ||
directives: [], | ||
sourceType: "module", | ||
sourceFile: "" | ||
}, | ||
{ | ||
enter(node) { | ||
if (node.type === "BlockStatement") { | ||
this.skip(); | ||
} | ||
}, | ||
leave(node) { | ||
if (node.type !== "Program") | ||
return; | ||
ids = Object.keys(this.scope); | ||
} | ||
} | ||
); | ||
return ids; | ||
}; | ||
// src/core/context.ts | ||
function createRoutesContext(options) { | ||
const { dts: preferDTS, root, routesFolder } = options; | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe.resolve)(root, "typed-router.d.ts") : (0, import_pathe.resolve)(root, preferDTS); | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe2.resolve)(root, "typed-router.d.ts") : (0, import_pathe2.resolve)(root, preferDTS); | ||
const routeTree = createPrefixTree(options); | ||
@@ -798,8 +897,2 @@ const routeMap = /* @__PURE__ */ new Map(); | ||
} | ||
const resolvedRoutesFolders = normalizeRoutesFolderOption(routesFolder).map( | ||
(routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
}) | ||
); | ||
const watchers = []; | ||
@@ -817,3 +910,3 @@ async function scanPages() { | ||
await Promise.all( | ||
resolvedRoutesFolders.map((folder) => { | ||
routesFolder.map((folder) => { | ||
const watcher = new RoutesFolderWatcher(folder, options); | ||
@@ -825,3 +918,3 @@ setupWatcher(watcher); | ||
ignore: options.exclude | ||
}).then((files) => files.map((file) => (0, import_pathe.resolve)(folder.src, file))).then( | ||
}).then((files) => files.map((file) => (0, import_pathe2.resolve)(folder.src, file))).then( | ||
(files) => Promise.all( | ||
@@ -847,3 +940,3 @@ files.map( | ||
routePath, | ||
(0, import_pathe.resolve)(root, path) | ||
(0, import_pathe2.resolve)(root, path) | ||
); | ||
@@ -853,2 +946,4 @@ node.setCustomRouteBlock(path, routeBlock); | ||
routeMap.set(path, node); | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
} | ||
@@ -862,2 +957,4 @@ async function updatePage({ filePath: path, routePath }) { | ||
} | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
node.setCustomRouteBlock(path, await getRouteBlock(path, options)); | ||
@@ -885,7 +982,22 @@ node.value.includeLoaderGuard = options.dataFetching && await hasNamedExports(path); | ||
function generateRoutes() { | ||
const imports = options.dataFetching ? `import { _LoaderSymbol } from 'unplugin-vue-router/runtime' | ||
` : ``; | ||
return `${imports}export const routes = ${generateRouteRecord(routeTree)} | ||
const importList = /* @__PURE__ */ new Map(); | ||
const routesExport = `export const routes = ${generateRouteRecord( | ||
routeTree, | ||
options, | ||
importList | ||
)}`; | ||
let imports = ""; | ||
if (options.dataFetching) { | ||
imports += `import { _HasDataLoaderMeta, _mergeRouteRecord } from 'unplugin-vue-router/runtime' | ||
`; | ||
} | ||
for (const [path, name] of importList) { | ||
imports += `import ${name} from '${path}' | ||
`; | ||
} | ||
if (imports) { | ||
imports += "\n"; | ||
} | ||
return `${imports}${routesExport} | ||
`; | ||
} | ||
@@ -931,6 +1043,48 @@ function generateDTS2() { | ||
generateRoutes, | ||
generateVueRouterProxy: generateVueRouterProxy2 | ||
generateVueRouterProxy: generateVueRouterProxy2, | ||
definePageTransform(code, id) { | ||
return definePageTransform({ | ||
code, | ||
id | ||
}); | ||
} | ||
}; | ||
} | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
var import_pathe3 = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe3.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// src/core/vite/index.ts | ||
@@ -961,4 +1115,6 @@ function createViteContext(server) { | ||
// src/index.ts | ||
var import_pluginutils = require("@rollup/pluginutils"); | ||
var import_pathe4 = require("pathe"); | ||
var src_default = (0, import_unplugin.createUnplugin)((opt, meta) => { | ||
const options = { ...DEFAULT_OPTIONS, ...opt }; | ||
const options = resolveOptions(opt); | ||
const ctx = createRoutesContext(options); | ||
@@ -975,2 +1131,12 @@ function getVirtualId2(id) { | ||
} | ||
const pageFilePattern = `**/*` + (options.extensions.length === 1 ? options.extensions[0] : `.{${options.extensions.map((extension) => extension.replace(".", "")).join(",")}}`); | ||
const filterPageComponents = (0, import_pluginutils.createFilter)( | ||
[ | ||
...options.routesFolder.map( | ||
(routeOption) => (0, import_pathe4.join)(routeOption.src, pageFilePattern) | ||
), | ||
/definePage\&vue$/ | ||
], | ||
options.exclude | ||
); | ||
return { | ||
@@ -989,3 +1155,2 @@ name: "unplugin-vue-router", | ||
} | ||
return null; | ||
}, | ||
@@ -1001,2 +1166,8 @@ buildStart() { | ||
}, | ||
transformInclude(id) { | ||
return filterPageComponents(id); | ||
}, | ||
transform(code, id) { | ||
return ctx.definePageTransform(code, id); | ||
}, | ||
load(id) { | ||
@@ -1016,3 +1187,2 @@ const resolvedId = getVirtualId2(id); | ||
} | ||
return null; | ||
}, | ||
@@ -1019,0 +1189,0 @@ vite: { |
import * as webpack from 'webpack'; | ||
import { R as ResolvedOptions } from './options-7cf6c9a2.js'; | ||
import { O as Options } from './options-66491ed4.js'; | ||
import 'vue-router'; | ||
declare const _default: (options?: Partial<ResolvedOptions> | undefined) => webpack.WebpackPluginInstance; | ||
declare const _default: (options: Options) => webpack.WebpackPluginInstance; | ||
export { _default as default }; |
@@ -36,5 +36,2 @@ "use strict"; | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
// src/core/utils.ts | ||
@@ -154,24 +151,6 @@ var import_scule = require("scule"); | ||
} | ||
var __DEV__ = process.env.NODE_ENV !== "production"; | ||
// src/options.ts | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
// src/core/treeLeafValue.ts | ||
var _TreeLeafValueBase = class { | ||
// src/core/treeNodeValue.ts | ||
var _TreeNodeValueBase = class { | ||
constructor(rawSegment, parent, pathSegment = rawSegment, subSegments = [rawSegment]) { | ||
@@ -207,3 +186,3 @@ this._overrides = /* @__PURE__ */ new Map(); | ||
}; | ||
var TreeLeafValueStatic = class extends _TreeLeafValueBase { | ||
var TreeNodeValueStatic = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, pathSegment = rawSegment) { | ||
@@ -214,3 +193,3 @@ super(rawSegment, parent, pathSegment); | ||
}; | ||
var TreeLeafValueParam = class extends _TreeLeafValueBase { | ||
var TreeNodeValueParam = class extends _TreeNodeValueBase { | ||
constructor(rawSegment, parent, params, pathSegment, subSegments) { | ||
@@ -222,9 +201,9 @@ super(rawSegment, parent, pathSegment, subSegments); | ||
}; | ||
function createTreeLeafValue(segment, parent) { | ||
function createTreeNodeValue(segment, parent) { | ||
if (!segment || segment === "index") { | ||
return new TreeLeafValueStatic("", parent); | ||
return new TreeNodeValueStatic("", parent); | ||
} | ||
const [pathSegment, params, subSegments] = parseSegment(segment); | ||
if (params.length) { | ||
return new TreeLeafValueParam( | ||
return new TreeNodeValueParam( | ||
segment, | ||
@@ -237,3 +216,3 @@ parent, | ||
} | ||
return new TreeLeafValueStatic(segment, parent, pathSegment); | ||
return new TreeNodeValueStatic(segment, parent, pathSegment); | ||
} | ||
@@ -322,8 +301,9 @@ function parseSegment(segment) { | ||
// src/core/tree.ts | ||
var TreeLeaf = class { | ||
var TreeNode = class { | ||
constructor(options, filePath, parent) { | ||
this.children = /* @__PURE__ */ new Map(); | ||
this.hasDefinePage = false; | ||
this.options = options; | ||
this.parent = parent; | ||
this.value = createTreeLeafValue(filePath, parent == null ? void 0 : parent.value); | ||
this.value = createTreeNodeValue(filePath, parent == null ? void 0 : parent.value); | ||
} | ||
@@ -333,3 +313,3 @@ insert(path, filePath = path) { | ||
if (!this.children.has(segment)) { | ||
this.children.set(segment, new TreeLeaf(this.options, segment, this)); | ||
this.children.set(segment, new TreeNode(this.options, segment, this)); | ||
} | ||
@@ -407,7 +387,7 @@ const child = this.children.get(segment); | ||
toString() { | ||
return `${this.value}${this.value.filePaths.size ? ` \u{1F4C4} (${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}`; | ||
return `${this.value}${this.value.filePaths.size > 1 || this.value.filePaths.size === 1 && !this.value.filePaths.get("default") ? ` \u2388(${Array.from(this.value.filePaths.keys()).join(", ")})` : ""}${this.hasDefinePage ? " \u2691 definePage()" : ""}`; | ||
} | ||
}; | ||
function createPrefixTree(options) { | ||
return new TreeLeaf(options, ""); | ||
return new TreeNode(options, ""); | ||
} | ||
@@ -475,6 +455,6 @@ function splitFilePath(filePath) { | ||
// src/codegen/generateRouteRecords.ts | ||
function generateRouteRecord(node, indent = 0) { | ||
function generateRouteRecord(node, options, importList, indent = 0) { | ||
if (node.value.path === "/" && indent === 0) { | ||
return `[ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 1)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 1)).join(",\n")} | ||
]`; | ||
@@ -484,18 +464,55 @@ } | ||
const indentStr = " ".repeat((indent + 1) * 2); | ||
return `${startIndent}{ | ||
const routeRecord = `${startIndent}{ | ||
${indentStr}path: '${node.path}', | ||
${indentStr}${node.value.filePaths.size ? `name: '${node.name}',` : "/* no name */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent(node, indentStr) : "/* no component */"} | ||
${indentStr}${node.value.filePaths.size ? generateRouteRecordComponent( | ||
node, | ||
indentStr, | ||
options.importMode, | ||
importList | ||
) : "/* no component */"} | ||
${indentStr}${node.value.overrides.props != null ? `props: ${node.value.overrides.props},` : "/* no props */"} | ||
${indentStr}${node.children.size > 0 ? `children: [ | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, indent + 2)).join(",\n")} | ||
${node.getSortedChildren().map((child) => generateRouteRecord(child, options, importList, indent + 2)).join(",\n")} | ||
${indentStr}],` : "/* no children */"}${formatMeta(node, indentStr)} | ||
${startIndent}}`; | ||
if (node.hasDefinePage) { | ||
const definePageDataList = []; | ||
for (const [name, filePath] of node.value.filePaths) { | ||
const definePageData = `_definePage_${name}_${importList.size}`; | ||
definePageDataList.push(definePageData); | ||
importList.set(`${filePath}?definePage&vue`, definePageData); | ||
} | ||
if (definePageDataList.length) { | ||
return ` _mergeRouteRecord( | ||
${routeRecord}, | ||
${definePageDataList.join(",\n")} | ||
)`; | ||
} | ||
} | ||
return routeRecord; | ||
} | ||
function generateRouteRecordComponent(node, indentStr) { | ||
function generateRouteRecordComponent(node, indentStr, importMode, importList) { | ||
const files = Array.from(node.value.filePaths); | ||
const isDefaultExport = files.length === 1 && files[0][0] === "default"; | ||
return isDefaultExport ? `component: () => import('${files[0][1]}'),` : `components: { | ||
${files.map(([key, path]) => `${indentStr + " "}'${key}': () => import('${path}')`).join(",\n")} | ||
return isDefaultExport ? `component: ${generatePageImport(files[0][1], importMode, importList)},` : `components: { | ||
${files.map( | ||
([key, path]) => `${indentStr + " "}'${key}': ${generatePageImport( | ||
path, | ||
importMode, | ||
importList | ||
)}` | ||
).join(",\n")} | ||
${indentStr}},`; | ||
} | ||
function generatePageImport(filepath, importMode, importList) { | ||
const mode = typeof importMode === "function" ? importMode(filepath) : importMode; | ||
if (mode === "async") { | ||
return `() => import('${filepath}')`; | ||
} else { | ||
const importName = `_page_${filepath.replace(/[\/\.]/g, "_")}`; | ||
importList.set(filepath, importName); | ||
return importName; | ||
} | ||
} | ||
function generateImportList(node, indentStr) { | ||
@@ -513,3 +530,3 @@ const files = Array.from(node.value.filePaths); | ||
LOADER_GUARD_RE, | ||
"[_LoaderSymbol]: " + generateImportList(node, indent + " ") + "," | ||
"[_HasDataLoaderMeta]: " + generateImportList(node, indent + " ") + "," | ||
) | ||
@@ -522,3 +539,3 @@ ).join("\n"); | ||
var import_fast_glob = __toESM(require("fast-glob")); | ||
var import_pathe = require("pathe"); | ||
var import_pathe2 = require("pathe"); | ||
@@ -585,2 +602,3 @@ // src/core/customBlock.ts | ||
var import_chokidar = __toESM(require("chokidar")); | ||
var import_pathe = require("pathe"); | ||
var RoutesFolderWatcher = class { | ||
@@ -602,2 +620,3 @@ constructor(routesFolder, options) { | ||
this.watcher.on(event, (filePath) => { | ||
filePath = (0, import_pathe.normalize)(filePath); | ||
if (this.options.extensions.every( | ||
@@ -654,4 +673,4 @@ (extension) => !filePath.endsWith(extension) | ||
// data fetching | ||
DataLoader, | ||
DefineLoaderOptions, | ||
_DataLoader, | ||
_DefineLoaderOptions, | ||
} from 'unplugin-vue-router' | ||
@@ -708,2 +727,4 @@ | ||
// Experimental Data Fetching | ||
export function defineLoader< | ||
@@ -716,4 +737,4 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded<Name>) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export function defineLoader< | ||
@@ -724,4 +745,11 @@ P extends Promise<any>, | ||
loader: (route: RouteLocationNormalizedLoaded) => P, | ||
options?: DefineLoaderOptions<isLazy>, | ||
): DataLoader<Awaited<P>, isLazy> | ||
options?: _DefineLoaderOptions<isLazy>, | ||
): _DataLoader<Awaited<P>, isLazy> | ||
export { | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
} | ||
@@ -746,7 +774,6 @@ | ||
// src/codegen/vueRouterModule.ts | ||
function generateVueRouterProxy(routesModule, { dataFetching }) { | ||
function generateVueRouterProxy(routesModule, options) { | ||
return ` | ||
import { routes } from '${routesModule}' | ||
import { createRouter as _createRouter } from 'vue-router' | ||
${dataFetching ? `import { _setupDataFetchingGuard } from 'unplugin-vue-router/runtime'` : ``} | ||
@@ -756,2 +783,6 @@ export * from 'vue-router' | ||
_defineLoader as defineLoader, | ||
_definePage as definePage, | ||
_HasDataLoaderMeta as HasDataLoaderMeta, | ||
_setupDataFetchingGuard as setupDataFetchingGuard, | ||
_stopDataFetchingScope as stopDataFetchingScope, | ||
} from 'unplugin-vue-router/runtime' | ||
@@ -766,5 +797,3 @@ | ||
)) | ||
${dataFetching ? ` | ||
_setupDataFetchingGuard(router) | ||
` : ``} | ||
return router | ||
@@ -786,6 +815,76 @@ } | ||
// src/core/definePage.ts | ||
var import_common = require("@vue-macros/common"); | ||
var import_ast_walker_scope = require("ast-walker-scope"); | ||
var MACRO_DEFINE_PAGE = "definePage"; | ||
function definePageTransform({ | ||
code, | ||
id | ||
}) { | ||
if (!code.includes(MACRO_DEFINE_PAGE)) | ||
return; | ||
const sfc = (0, import_common.parseSFC)(code, id); | ||
if (!sfc.scriptSetup) | ||
return; | ||
const { script, scriptSetup, scriptCompiled } = sfc; | ||
const definePageNodes = scriptCompiled.scriptSetupAst.map((node) => { | ||
if (node.type === "ExpressionStatement") | ||
node = node.expression; | ||
return (0, import_common.isCallOf)(node, MACRO_DEFINE_PAGE) ? node : null; | ||
}).filter((node) => !!node); | ||
if (!definePageNodes.length) { | ||
return; | ||
} else if (definePageNodes.length > 1) { | ||
throw new SyntaxError(`duplicate definePage() call`); | ||
} | ||
const definePageNode = definePageNodes[0]; | ||
const setupOffset = scriptSetup.loc.start.offset; | ||
if (id.includes(MACRO_DEFINE_PAGE)) { | ||
const s = new import_common.MagicString(code); | ||
const routeRecord = definePageNode.arguments[0]; | ||
const scriptBindings = sfc.scriptCompiled.scriptSetupAst ? getIdentifiers(sfc.scriptCompiled.scriptSetupAst) : []; | ||
(0, import_common.checkInvalidScopeReference)(routeRecord, MACRO_DEFINE_PAGE, scriptBindings); | ||
s.remove(setupOffset + routeRecord.end, code.length); | ||
s.remove(0, setupOffset + routeRecord.start); | ||
s.prepend(`export default `); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} else { | ||
const s = new import_common.MagicString(code); | ||
s.remove( | ||
setupOffset + definePageNode.start, | ||
setupOffset + definePageNode.end | ||
); | ||
return (0, import_common.getTransformResult)(s, id); | ||
} | ||
} | ||
var getIdentifiers = (stmts) => { | ||
let ids = []; | ||
(0, import_ast_walker_scope.walkAST)( | ||
{ | ||
type: "Program", | ||
body: stmts, | ||
directives: [], | ||
sourceType: "module", | ||
sourceFile: "" | ||
}, | ||
{ | ||
enter(node) { | ||
if (node.type === "BlockStatement") { | ||
this.skip(); | ||
} | ||
}, | ||
leave(node) { | ||
if (node.type !== "Program") | ||
return; | ||
ids = Object.keys(this.scope); | ||
} | ||
} | ||
); | ||
return ids; | ||
}; | ||
// src/core/context.ts | ||
function createRoutesContext(options) { | ||
const { dts: preferDTS, root, routesFolder } = options; | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe.resolve)(root, "typed-router.d.ts") : (0, import_pathe.resolve)(root, preferDTS); | ||
const dts = preferDTS === false ? false : preferDTS === true ? (0, import_pathe2.resolve)(root, "typed-router.d.ts") : (0, import_pathe2.resolve)(root, preferDTS); | ||
const routeTree = createPrefixTree(options); | ||
@@ -798,8 +897,2 @@ const routeMap = /* @__PURE__ */ new Map(); | ||
} | ||
const resolvedRoutesFolders = normalizeRoutesFolderOption(routesFolder).map( | ||
(routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe.resolve)(root, routeOption.src) | ||
}) | ||
); | ||
const watchers = []; | ||
@@ -817,3 +910,3 @@ async function scanPages() { | ||
await Promise.all( | ||
resolvedRoutesFolders.map((folder) => { | ||
routesFolder.map((folder) => { | ||
const watcher = new RoutesFolderWatcher(folder, options); | ||
@@ -825,3 +918,3 @@ setupWatcher(watcher); | ||
ignore: options.exclude | ||
}).then((files) => files.map((file) => (0, import_pathe.resolve)(folder.src, file))).then( | ||
}).then((files) => files.map((file) => (0, import_pathe2.resolve)(folder.src, file))).then( | ||
(files) => Promise.all( | ||
@@ -847,3 +940,3 @@ files.map( | ||
routePath, | ||
(0, import_pathe.resolve)(root, path) | ||
(0, import_pathe2.resolve)(root, path) | ||
); | ||
@@ -853,2 +946,4 @@ node.setCustomRouteBlock(path, routeBlock); | ||
routeMap.set(path, node); | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
} | ||
@@ -862,2 +957,4 @@ async function updatePage({ filePath: path, routePath }) { | ||
} | ||
const content = await import_fs3.promises.readFile(path, "utf8"); | ||
node.hasDefinePage = content.includes("definePage"); | ||
node.setCustomRouteBlock(path, await getRouteBlock(path, options)); | ||
@@ -885,7 +982,22 @@ node.value.includeLoaderGuard = options.dataFetching && await hasNamedExports(path); | ||
function generateRoutes() { | ||
const imports = options.dataFetching ? `import { _LoaderSymbol } from 'unplugin-vue-router/runtime' | ||
` : ``; | ||
return `${imports}export const routes = ${generateRouteRecord(routeTree)} | ||
const importList = /* @__PURE__ */ new Map(); | ||
const routesExport = `export const routes = ${generateRouteRecord( | ||
routeTree, | ||
options, | ||
importList | ||
)}`; | ||
let imports = ""; | ||
if (options.dataFetching) { | ||
imports += `import { _HasDataLoaderMeta, _mergeRouteRecord } from 'unplugin-vue-router/runtime' | ||
`; | ||
} | ||
for (const [path, name] of importList) { | ||
imports += `import ${name} from '${path}' | ||
`; | ||
} | ||
if (imports) { | ||
imports += "\n"; | ||
} | ||
return `${imports}${routesExport} | ||
`; | ||
} | ||
@@ -931,6 +1043,48 @@ function generateDTS2() { | ||
generateRoutes, | ||
generateVueRouterProxy: generateVueRouterProxy2 | ||
generateVueRouterProxy: generateVueRouterProxy2, | ||
definePageTransform(code, id) { | ||
return definePageTransform({ | ||
code, | ||
id | ||
}); | ||
} | ||
}; | ||
} | ||
// src/options.ts | ||
var import_local_pkg = require("local-pkg"); | ||
var import_pathe3 = require("pathe"); | ||
var DEFAULT_OPTIONS = { | ||
extensions: [".vue"], | ||
exclude: [], | ||
routesFolder: "src/pages", | ||
routeBlockLang: "json5", | ||
getRouteName: getFileBasedRouteName, | ||
dataFetching: false, | ||
importMode: "async", | ||
root: process.cwd(), | ||
dts: (0, import_local_pkg.isPackageExists)("typescript"), | ||
logs: false, | ||
_inspect: false | ||
}; | ||
function normalizeRoutesFolderOption(routesFolder) { | ||
return (isArray(routesFolder) ? routesFolder : [routesFolder]).map( | ||
(routeOption) => typeof routeOption === "string" ? { src: routeOption } : routeOption | ||
); | ||
} | ||
function resolveOptions(options) { | ||
const root = options.root || DEFAULT_OPTIONS.root; | ||
const routesFolder = normalizeRoutesFolderOption( | ||
options.routesFolder || DEFAULT_OPTIONS.routesFolder | ||
).map((routeOption) => ({ | ||
...routeOption, | ||
src: (0, import_pathe3.resolve)(root, routeOption.src) | ||
})); | ||
return { | ||
...DEFAULT_OPTIONS, | ||
...options, | ||
routesFolder | ||
}; | ||
} | ||
// src/core/vite/index.ts | ||
@@ -961,4 +1115,6 @@ function createViteContext(server) { | ||
// src/index.ts | ||
var import_pluginutils = require("@rollup/pluginutils"); | ||
var import_pathe4 = require("pathe"); | ||
var src_default = (0, import_unplugin.createUnplugin)((opt, meta) => { | ||
const options = { ...DEFAULT_OPTIONS, ...opt }; | ||
const options = resolveOptions(opt); | ||
const ctx = createRoutesContext(options); | ||
@@ -975,2 +1131,12 @@ function getVirtualId2(id) { | ||
} | ||
const pageFilePattern = `**/*` + (options.extensions.length === 1 ? options.extensions[0] : `.{${options.extensions.map((extension) => extension.replace(".", "")).join(",")}}`); | ||
const filterPageComponents = (0, import_pluginutils.createFilter)( | ||
[ | ||
...options.routesFolder.map( | ||
(routeOption) => (0, import_pathe4.join)(routeOption.src, pageFilePattern) | ||
), | ||
/definePage\&vue$/ | ||
], | ||
options.exclude | ||
); | ||
return { | ||
@@ -989,3 +1155,2 @@ name: "unplugin-vue-router", | ||
} | ||
return null; | ||
}, | ||
@@ -1001,2 +1166,8 @@ buildStart() { | ||
}, | ||
transformInclude(id) { | ||
return filterPageComponents(id); | ||
}, | ||
transform(code, id) { | ||
return ctx.definePageTransform(code, id); | ||
}, | ||
load(id) { | ||
@@ -1016,3 +1187,2 @@ const resolvedId = getVirtualId2(id); | ||
} | ||
return null; | ||
}, | ||
@@ -1019,0 +1189,0 @@ vite: { |
{ | ||
"name": "unplugin-vue-router", | ||
"version": "0.1.2", | ||
"packageManager": "pnpm@7.9.0", | ||
"version": "0.2.0", | ||
"packageManager": "pnpm@7.9.3", | ||
"description": "File based typed routing for Vue Router", | ||
@@ -79,2 +79,6 @@ "keywords": [ | ||
"dependencies": { | ||
"@babel/types": "^7.18.13", | ||
"@rollup/pluginutils": "^4.2.1", | ||
"@vue-macros/common": "^0.10.0", | ||
"ast-walker-scope": "^0.2.1", | ||
"chokidar": "^3.5.3", | ||
@@ -84,6 +88,6 @@ "fast-glob": "^3.2.11", | ||
"local-pkg": "^0.4.2", | ||
"mlly": "^0.5.7", | ||
"pathe": "^0.3.3", | ||
"mlly": "^0.5.13", | ||
"pathe": "^0.3.5", | ||
"scule": "^0.3.2", | ||
"unplugin": "^0.9.0", | ||
"unplugin": "^0.9.4", | ||
"yaml": "^2.1.1" | ||
@@ -112,10 +116,10 @@ }, | ||
"rimraf": "^3.0.2", | ||
"rollup": "^2.77.2", | ||
"rollup": "^2.78.1", | ||
"semver": "^7.3.7", | ||
"ts-expect": "^1.3.0", | ||
"tsup": "^6.2.1", | ||
"tsup": "^6.2.2", | ||
"typescript": "^4.7.4", | ||
"unplugin-auto-import": "^0.11.1", | ||
"vite": "^3.0.4", | ||
"vitest": "^0.21.0", | ||
"unplugin-auto-import": "^0.11.2", | ||
"vite": "^3.0.9", | ||
"vitest": "^0.22.1", | ||
"vue": "^3.2.37", | ||
@@ -122,0 +126,0 @@ "vue-router": "^4.1.3", |
@@ -23,2 +23,4 @@ # unplugin-vue-router | ||
Add VueRouter plugin **before** Vue plugin: | ||
<details> | ||
@@ -36,2 +38,4 @@ <summary>Vite</summary><br> | ||
}), | ||
// ⚠️ Vue must be placed after VueRouter() | ||
Vue(), | ||
], | ||
@@ -57,2 +61,4 @@ }) | ||
}), | ||
// ⚠️ Vue must be placed after VueRouter() | ||
Vue(), | ||
], | ||
@@ -166,3 +172,3 @@ } | ||
import AutoImport from 'unplugin-auto-import/vite' | ||
+import { VueRouterExports } from 'unplugin-vue-router' | ||
+import { VueRouterAutoImports } from 'unplugin-vue-router' | ||
@@ -175,3 +181,3 @@ export default defineConfig({ | ||
- 'vue-router', | ||
+ { 'vue-router/auto': VueRouterExports }, | ||
+ VueRouterAutoImports, | ||
], | ||
@@ -215,2 +221,6 @@ }), | ||
routeBlockLang: 'json5', | ||
// Change the import mode of page components. Can be 'async', 'sync', or a function with the following signature: | ||
// (filepath: string) => 'async' | 'sync' | ||
importMode: 'async', | ||
}) | ||
@@ -298,3 +308,2 @@ ``` | ||
├── users/ | ||
│ ├── index.vue | ||
│ ├── [id].vue | ||
@@ -305,2 +314,21 @@ │ └── index.vue | ||
If you want to add a new route `/users/create` you could add a new file `src/pages/users/create.vue` but that would nest the `create.vue` component within the `users.vue` component. To avoid this you can instead create a file `src/pages/users.create.vue`. The `.` will become a `/` when generating the routes: | ||
```js | ||
const routes = [ | ||
{ | ||
path: '/users', | ||
component: () => import('src/pages/users.vue'), | ||
children: [ | ||
{ path: '', component: () => import('src/pages/users/index.vue') }, | ||
{ path: ':id', component: () => import('src/pages/users/[id].vue') }, | ||
], | ||
}, | ||
{ | ||
path: '/users/create', | ||
component: () => import('src/pages/users.create.vue'), | ||
}, | ||
] | ||
``` | ||
### Named routes | ||
@@ -307,0 +335,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
292412
38
8113
541
14
26
+ Added@babel/types@^7.18.13
+ Added@rollup/pluginutils@^4.2.1
+ Added@vue-macros/common@^0.10.0
+ Addedast-walker-scope@^0.2.1
+ Added@rollup/pluginutils@4.2.1(transitive)
+ Added@vue-macros/common@0.10.0(transitive)
+ Addedast-walker-scope@0.2.3(transitive)
+ Addedmagic-string@0.26.7(transitive)
+ Addedsourcemap-codec@1.4.8(transitive)
Updatedmlly@^0.5.13
Updatedpathe@^0.3.5
Updatedunplugin@^0.9.4