Skip to content

Commit

Permalink
feat: add importPath option to specify import absolute path or rela…
Browse files Browse the repository at this point in the history
…tive path (#493)
  • Loading branch information
GoodbyeNJN authored Jun 25, 2024
1 parent 86641c6 commit 640a3a6
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 7 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,32 @@ function App() {
}
```

### importPath

- **Type:** `'absolute' | 'relative'`
- **Default:** `'relative'`

Import page components from absolute or relative paths. The default behavior is to import from relative paths, but in some special cases, it can be set to `'absolute'` to import from absolute paths.

For example, if your page components are located in the `app/pages` directory and you have set `base: /app/` in your `vite.config.js`, you should set `importPath` to `'absolute'` in order to correctly import the page components.

```js
// vite.config.js
export default {
base: '/app/',
plugins: [
Pages({
dirs: 'app/pages',

// It should be set to 'absolute' in this case.
importPath: 'absolute',
}),
],
}
```

See [#492](https://github.com/hannoeru/vite-plugin-pages/issues/492) for more details.

### routeBlockLang

- **Type:** `string`
Expand Down
3 changes: 3 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export function resolveOptions(userOptions: UserOptions, viteRoot?: string): Res

const importMode = userOptions.importMode || (syncIndex ? syncIndexResolver : 'async')

const importPath = userOptions.importPath || 'relative'

const resolver = getResolver(userOptions.resolver)

const extensions = userOptions.extensions || resolver.resolveExtensions()
Expand All @@ -90,6 +92,7 @@ export function resolveOptions(userOptions: UserOptions, viteRoot?: string): Res
root,
extensions,
importMode,
importPath,
exclude,
caseSensitive,
resolver,
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function prepareRoutes(
}

async function computeReactRoutes(ctx: PageContext): Promise<ReactRoute[]> {
const { routeStyle, caseSensitive } = ctx.options
const { routeStyle, caseSensitive, importPath } = ctx.options
const nuxtStyle = routeStyle === 'nuxt'

const pageRoutes = [...ctx.pageRouteMap.values()]
Expand All @@ -54,7 +54,7 @@ async function computeReactRoutes(ctx: PageContext): Promise<ReactRoute[]> {

pageRoutes.forEach((page) => {
const pathNodes = page.route.split('/')
const element = page.path.replace(ctx.root, '')
const element = importPath === 'relative' ? page.path.replace(ctx.root, '') : page.path
let parentRoutes = routes

for (let i = 0; i < pathNodes.length; i++) {
Expand Down
6 changes: 3 additions & 3 deletions src/resolvers/solid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function prepareRoutes(
}

async function computeSolidRoutes(ctx: PageContext): Promise<SolidRoute[]> {
const { routeStyle, caseSensitive } = ctx.options
const { routeStyle, caseSensitive, importPath } = ctx.options
const nuxtStyle = routeStyle === 'nuxt'

const pageRoutes = [...ctx.pageRouteMap.values()]
Expand All @@ -54,8 +54,8 @@ async function computeSolidRoutes(ctx: PageContext): Promise<SolidRoute[]> {
pageRoutes.forEach((page) => {
const pathNodes = page.route.split('/')

const component = page.path.replace(ctx.root, '')
const element = page.path.replace(ctx.root, '')
const component = importPath === 'relative' ? page.path.replace(ctx.root, '') : page.path
const element = importPath === 'relative' ? page.path.replace(ctx.root, '') : page.path

let parentRoutes = routes

Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function prepareRoutes(
}

async function computeVueRoutes(ctx: PageContext, customBlockMap: Map<string, CustomBlock>): Promise<VueRoute[]> {
const { routeStyle, caseSensitive, routeNameSeparator } = ctx.options
const { routeStyle, caseSensitive, importPath, routeNameSeparator } = ctx.options

const pageRoutes = [...ctx.pageRouteMap.values()]
// sort routes for HMR
Expand All @@ -73,7 +73,7 @@ async function computeVueRoutes(ctx: PageContext, customBlockMap: Map<string, Cu
const pathNodes = page.route.split('/')

// add leading slash to component path if not already there
const component = page.path.replace(ctx.root, '')
const component = importPath === 'relative' ? page.path.replace(ctx.root, '') : page.path
const customBlock = customBlockMap.get(page.path)

const route: VueRouteBase = {
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ interface Options {
* @default 'root index file => "sync", others => "async"'
*/
importMode: ImportMode | ImportModeResolver
/**
* Import page components from absolute or relative paths.
* @default 'relative'
*/
importPath: 'absolute' | 'relative'
/**
* Sync load top level index file
* @default true
Expand Down
139 changes: 139 additions & 0 deletions test/__snapshots__/generate.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,145 @@ exports[`generate routes > vue - async mode match snapshot > routes 1`] = `
]
`;

exports[`generate routes > vue - import absolute path match snapshot > client code 1`] = `
"const __pages_import_0__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/[...all].vue");
const __pages_import_1__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/[sensor].vue");
const __pages_import_2__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/[sensor]/current.vue");
const __pages_import_3__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/about.vue");
const __pages_import_4__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id].vue");
const __pages_import_5__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id]/more.vue");
const __pages_import_6__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id]/nested.vue");
const __pages_import_7__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/index.vue");
const __pages_import_8__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/[id].vue");
const __pages_import_9__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/index.vue");
const __pages_import_10__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/today/[...all].vue");
const __pages_import_11__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/today/index.vue");
const __pages_import_12__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/components.vue");
const __pages_import_13__ = () => import("/mock/fs/vite-plugin-pages/examples/vue/src/pages/index.vue");
const routes = [{"name":"all","path":"/:all(.*)*","component":__pages_import_0__,"props":true},{"name":"sensor","path":"/:sensor","component":__pages_import_1__,"children":[{"name":"sensor-current","path":"current","component":__pages_import_2__,"props":true}],"props":true},{"path":"/about","component":__pages_import_3__,"children":[{"name":"about-user-id","path":":id","component":__pages_import_4__,"children":[{"name":"about-id-more","path":"more","component":__pages_import_5__,"props":true},{"name":"about-id-nested","path":"nested","component":__pages_import_6__,"props":true}],"props":true,"meta":{"requiresAuth":true}},{"name":"about","path":"","component":__pages_import_7__,"props":true}],"props":true,"meta":{"lang":"yml"}},{"name":"blog-id","path":"/blog/:id","component":__pages_import_8__,"props":true,"meta":{"requiresAuth":false}},{"name":"blog","path":"/blog","component":__pages_import_9__,"props":true},{"name":"blog-today-all","path":"/blog/today/:all(.*)","component":__pages_import_10__,"props":true},{"name":"blog-today","path":"/blog/today","component":__pages_import_11__,"props":true},{"name":"components","path":"/components","component":__pages_import_12__,"props":true,"meta":{"lang":"yaml"}},{"name":"homepage","path":"/","component":__pages_import_13__,"props":true,"meta":{"requiresAuth":false}}];
export default routes;"
`;

exports[`generate routes > vue - import absolute path match snapshot > routes 1`] = `
[
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/[...all].vue",
"customBlock": undefined,
"name": "all",
"path": "/:all(.*)*",
"props": true,
},
{
"children": [
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/[sensor]/current.vue",
"customBlock": undefined,
"name": "sensor-current",
"path": "current",
"props": true,
},
],
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/[sensor].vue",
"customBlock": undefined,
"name": "sensor",
"path": "/:sensor",
"props": true,
},
{
"children": [
{
"children": [
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id]/more.vue",
"customBlock": undefined,
"name": "about-id-more",
"path": "more",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id]/nested.vue",
"customBlock": undefined,
"name": "about-id-nested",
"path": "nested",
"props": true,
},
],
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/[id].vue",
"meta": {
"requiresAuth": true,
},
"name": "about-user-id",
"path": ":id",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/about/index.vue",
"customBlock": undefined,
"name": "about",
"path": "",
"props": true,
},
],
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/about.vue",
"meta": {
"lang": "yml",
},
"path": "/about",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/[id].vue",
"meta": {
"requiresAuth": false,
},
"name": "blog-id",
"path": "/blog/:id",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/index.vue",
"customBlock": undefined,
"name": "blog",
"path": "/blog",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/today/[...all].vue",
"customBlock": undefined,
"name": "blog-today-all",
"path": "/blog/today/:all(.*)",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/blog/today/index.vue",
"customBlock": undefined,
"name": "blog-today",
"path": "/blog/today",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/components.vue",
"meta": {
"lang": "yaml",
},
"name": "components",
"path": "/components",
"props": true,
},
{
"component": "/mock/fs/vite-plugin-pages/examples/vue/src/pages/index.vue",
"meta": {
"requiresAuth": false,
},
"name": "homepage",
"path": "/",
"props": true,
},
]
`;

exports[`generate routes > vue - sync mode match snapshot > client code 1`] = `
"import __pages_import_0__ from "/examples/vue/src/pages/[...all].vue";
import __pages_import_1__ from "/examples/vue/src/pages/[sensor].vue";
Expand Down
4 changes: 4 additions & 0 deletions test/__snapshots__/options.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ exports[`options resolve > react 1`] = `
],
"extensionsRE": /\\\\\\.\\(tsx\\|jsx\\|ts\\|js\\)\\$/,
"importMode": [Function],
"importPath": "relative",
"moduleIds": [
"~react-pages",
"virtual:generated-pages-react",
Expand Down Expand Up @@ -70,6 +71,7 @@ exports[`options resolve > solid 1`] = `
],
"extensionsRE": /\\\\\\.\\(tsx\\|jsx\\|ts\\|js\\)\\$/,
"importMode": [Function],
"importPath": "relative",
"moduleIds": [
"~solid-pages",
],
Expand Down Expand Up @@ -114,6 +116,7 @@ exports[`options resolve > vue - custom module id 1`] = `
],
"extensionsRE": /\\\\\\.\\(vue\\|ts\\|js\\)\\$/,
"importMode": [Function],
"importPath": "relative",
"moduleIds": [
"~vue-pages",
],
Expand Down Expand Up @@ -159,6 +162,7 @@ exports[`options resolve > vue 1`] = `
],
"extensionsRE": /\\\\\\.\\(vue\\|ts\\|js\\)\\$/,
"importMode": [Function],
"importPath": "relative",
"moduleIds": [
"~pages",
"pages-generated",
Expand Down
30 changes: 30 additions & 0 deletions test/generate.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { slash } from '@antfu/utils'

import { PageContext } from '../src/context'

const sensitivity = process.platform === 'win32' ? 'base' : 'variant'
Expand Down Expand Up @@ -51,6 +53,34 @@ describe('generate routes', () => {
expect(routes).toMatchSnapshot('client code')
})

it('vue - import absolute path match snapshot', async () => {
const root = slash(process.cwd())
const mock = `/mock/fs/vite-plugin-pages${root.endsWith('/') ? '/' : ''}`
const ctx = new PageContext({
dirs: 'examples/vue/src/pages',
importPath: 'absolute',
extendRoute(route) {
if (route.component) {
route.component = route.component.replace(root, mock)
}
if (route.element) {
route.element = route.element.replace(root, mock)
}

return route
},
onRoutesGenerated(routes) {
routes = deepSortArray(routes)
expect(routes).toMatchSnapshot('routes')
return routes
},
}, root)
await ctx.searchGlob()
const routes = await ctx.resolveRoutes()

expect(routes).toMatchSnapshot('client code')
})

it('react - match snapshot', async () => {
const ctx = new PageContext({
dirs: 'examples/react/src/pages',
Expand Down

0 comments on commit 640a3a6

Please sign in to comment.