Skip to content

Commit f01cddd

Browse files
committed
feat(loaders): change experimental option to match only specific folders
1 parent 952561a commit f01cddd

File tree

4 files changed

+61
-21
lines changed

4 files changed

+61
-21
lines changed

playground/vite.config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export default defineConfig({
3030
VueRouter({
3131
extensions: ['.page.vue', '.vue'],
3232
importMode: 'async',
33-
experimental: { autoExportsDataLoaders: true },
33+
experimental: {
34+
autoExportsDataLoaders: ['src/loaders/**/*', '@/loaders/**/*'],
35+
},
3436
extendRoute(route) {
3537
route.params.forEach((param, i) => {
3638
// transform kebab-case to camelCase

src/data-loaders/auto-exports.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
import { createFilter } from '@rollup/pluginutils'
22
import MagicString from 'magic-string'
33
import { findStaticImports, parseStaticImport } from 'mlly'
4+
import { join, resolve } from 'pathe'
45
import { type UnpluginOptions } from 'unplugin'
56

6-
const ignoredSpecifiers = ['vue', 'vue-router', 'pinia']
7-
8-
export function extractLoadersToExport(code: string): string[] {
7+
export function extractLoadersToExport(
8+
code: string,
9+
filterPaths: (id: string) => boolean,
10+
root: string
11+
): string[] {
912
const imports = findStaticImports(code)
1013
const importNames = imports.flatMap((i) => {
1114
const parsed = parseStaticImport(i)
1215

13-
// bail out faster for anything that is not a data loader
14-
if (
15-
// NOTE: move out to a regexp if the option is exposed
16-
parsed.specifier.startsWith('@vueuse/') &&
17-
ignoredSpecifiers.includes(parsed.specifier)
16+
// since we run post-post, vite will add a leading slash to the specifier
17+
const specifier = resolve(
18+
root,
19+
parsed.specifier.startsWith('/')
20+
? parsed.specifier.slice(1)
21+
: parsed.specifier
1822
)
19-
return []
23+
console.log('🔍', specifier)
24+
25+
// bail out faster for anything that is not a data loader
26+
if (!filterPaths(specifier)) return []
2027

2128
return [
2229
parsed.defaultImport,
@@ -27,11 +34,17 @@ export function extractLoadersToExport(code: string): string[] {
2734
return importNames
2835
}
2936

30-
export function createAutoExportPlugin(): UnpluginOptions {
31-
const filterVueComponents = createFilter(
32-
[/\.vue$/, /\.vue\?vue/, /\.vue\?v=/]
33-
// [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/]
34-
)
37+
export function createAutoExportPlugin({
38+
filterPageComponents,
39+
loadersPathsGlobs,
40+
root,
41+
}: {
42+
filterPageComponents: (id: string) => boolean
43+
loadersPathsGlobs: string | string[]
44+
root: string
45+
}): UnpluginOptions {
46+
console.log('Creating auto-export plugin', loadersPathsGlobs)
47+
const filterPaths = createFilter(loadersPathsGlobs)
3548

3649
return {
3750
name: 'unplugin-vue-router:data-loaders-auto-export',
@@ -40,11 +53,18 @@ export function createAutoExportPlugin(): UnpluginOptions {
4053
transform: {
4154
order: 'post',
4255
handler(code, id) {
43-
if (!filterVueComponents(id)) {
56+
// strip query to also match .vue?vue&lang=ts etc
57+
const queryIndex = id.indexOf('?')
58+
const idWithoutQuery = queryIndex >= 0 ? id.slice(0, queryIndex) : id
59+
if (!filterPageComponents(idWithoutQuery)) {
4460
return
4561
}
4662

47-
const loadersToExports = extractLoadersToExport(code)
63+
const loadersToExports = extractLoadersToExport(
64+
code,
65+
filterPaths,
66+
root
67+
)
4868

4969
if (loadersToExports.length <= 0) return
5070

src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,15 @@ export default createUnplugin<Options | undefined>((opt = {}, _meta) => {
188188
},
189189
]
190190

191+
// Experimental options
191192
if (options.experimental.autoExportsDataLoaders) {
192-
plugins.push(createAutoExportPlugin())
193+
plugins.push(
194+
createAutoExportPlugin({
195+
filterPageComponents,
196+
loadersPathsGlobs: options.experimental.autoExportsDataLoaders,
197+
root: options.root,
198+
})
199+
)
193200
}
194201

195202
return plugins

src/options.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,12 @@ export interface Options {
216216
*/
217217
experimental?: {
218218
/**
219-
* Automatically export data loaders in vue components. This allows you to not
219+
* (Vite only). File paths or globs where loaders are exported. This will be used to filter out imported loaders and
220+
* automatically re export them in page components. You can for example set this to `'src/loaders/**\/*'` (without
221+
* the backslash) to automatically re export any imported variable from files in the `src/loaders` folder within a
222+
* page component.
220223
*/
221-
autoExportsDataLoaders?: boolean
224+
autoExportsDataLoaders?: string | string[]
222225
}
223226
}
224227

@@ -239,7 +242,7 @@ export const DEFAULT_OPTIONS = {
239242
},
240243
watch: !process.env.CI,
241244
experimental: {
242-
autoExportsDataLoaders: false,
245+
autoExportsDataLoaders: 'src/loaders/**/*',
243246
},
244247
} satisfies Options
245248

@@ -299,6 +302,14 @@ export function resolveOptions(options: Options) {
299302
src: resolve(root, routeOption.src),
300303
}))
301304

305+
if (options.experimental?.autoExportsDataLoaders) {
306+
options.experimental.autoExportsDataLoaders = (
307+
Array.isArray(options.experimental.autoExportsDataLoaders)
308+
? options.experimental.autoExportsDataLoaders
309+
: [options.experimental.autoExportsDataLoaders]
310+
).map((path) => resolve(root, path))
311+
}
312+
302313
if (options.extensions) {
303314
options.extensions = options.extensions
304315
// ensure that extensions start with a dot or warn the user

0 commit comments

Comments
 (0)