vuejs / vitepress

Vite & Vue powered static site generator.
https://vitepress.dev
MIT License
13.02k stars 2.1k forks source link

Site config and data loaders don't support subpath imports #4173

Open rileychh opened 2 months ago

rileychh commented 2 months ago

Describe the bug

Subpath imports configured in package.json are not resolved in .vitepress/config.ts and *.data.ts.

Reproduction

StackBlitz

  1. Configure subpath imports in package.json

    "imports": {
    "#*": "./*"
    }
  2. Create a module exporting data in the project root

    // sharedData.ts
    export default {
    siteTitle: 'Shared site title',
    };
  3. Import the module

    in .vitepress/config.ts
    import { defineConfig } from 'vitepress';
    import sharedData from '#sharedData';
    export default defineConfig({
    title: sharedData.siteTitle,
    });
    
    in a data loader
    import { defineLoader } from 'vitepress';
    import sharedData from '#sharedData';
    export default defineLoader({
    watch: ['./sharedData.ts'],
    load: () => sharedData,
    });
    

Expected behavior

import sharedData from '#sharedData'

should work identically to

import sharedData from '../../sharedData'

and set the site title to Shared site title.

System Info

System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    vitepress: latest => 1.3.4

Additional context

Running VitePress with Bun (bun --bun run docs:dev) or tsx tsx node_modules/vitepress/bin/vitepress.js works around the issue.

Validations

brc-dd commented 2 months ago

I don't think node supports that. You'll need to change it to "#*": "./*.js" and use js for it to work.

esbuild doesn't transform that while importing. So, it's whatever node supports. Intermediate code:

image

\ bun and tsx have very lax resolution algorithms and support extension-less imports in ESM and TS.

rileychh commented 2 months ago

I tried the following configurations:

  1. import sharedData from '#sharedData.js' with imports set to "#*": "./*.js":
    Cannot find module '/home/projects/vitepress-subpath-imports/sharedData.js.js'
  2. import sharedData from '#sharedData' with imports set to "#*": "./*":
    Cannot find module '/home/projects/vitepress-subpath-imports/sharedData.js'
  3. import sharedData from '#sharedData.js' with imports set to "#*": "./*":
    Cannot find module '/home/projects/vitepress-subpath-imports/sharedData.js'

Unfortunately none of the configuration worked.

esbuild doesn't transform that while importing.

It's interesting that the second configuration throws an error with sharedData.js, even when no extensions are specified. Why does this happen?

brc-dd commented 2 months ago

I meant try this:

import sharedData from '#sharedData'
"#*": "./*.js"
// sharedData.js

export stuff ...

It's not specific to vitepress. Create a normal foo.js file and add the import there and run it with node foo.js.

https://stackblitz.com/edit/node-u1evg5?file=index.js

rileychh commented 2 months ago

Thank you for pointing that out! I hadn't tried that specific configuration before.

While your solution works perfectly for JavaScript files, I noticed that it doesn't seem to work for TypeScript files. Do you have any suggestions on how to make this work with TypeScript as well?

Edit: "#*": "./*" also works for JavaScript files.

brc-dd commented 2 months ago

Do you have any suggestions on how to make this work with TypeScript as well?

Ah, currently no. You'll need to use tsx, or switch completely to bun. Newer node versions have added an experimental strip types flag that might also work in certain cases. But even then updates in that subpath imported file won't be tracked and config won't auto-reload. You'll need to manually restart your server every time you change that file.