From fd262c0acbd802812aba55ba681374a0de3789e8 Mon Sep 17 00:00:00 2001 From: hakshu25 Date: Tue, 29 Oct 2024 22:34:00 +0900 Subject: [PATCH 01/20] feat: parse base path in import.meta.glob --- .../plugins/importGlob/parse.spec.ts | 35 +++++++++++++++++++ .../vite/src/node/plugins/importMetaGlob.ts | 8 ++++- packages/vite/types/importGlob.d.ts | 4 +++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts index bb1304076661bc..d74b9372d754c3 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts @@ -141,6 +141,28 @@ describe('parse positives', async () => { `) }) + it('options with base', async () => { + expect( + await run(` + import.meta.glob('**/dir/*.md', { + base: './path/to/base' + }) + `), + ).toMatchInlineSnapshot(` + [ + { + "globs": [ + "**/dir/*.md", + ], + "options": { + "base": "./path/to/base", + }, + "start": 5, + }, + ] + `) + }) + it('object properties - 1', async () => { expect( await run(` @@ -376,4 +398,17 @@ describe('parse negatives', async () => { '[Error: Vite is unable to parse the glob options as the value is not static]', ) }) + + it('options base', async () => { + expect( + await runError('import.meta.glob("./*.js", { base: 1 })'), + ).toMatchInlineSnapshot( + '[Error: Expected glob option "base" to be of type string, but got number]', + ) + expect( + await runError('import.meta.glob("./*.js", { base: "foo" })'), + ).toMatchInlineSnapshot( + '[Error: Invalid glob: "foo/*.js" (resolved: "foo/*.js"). It must start with \'/\' or \'./\']', + ) + }) }) diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index 13d2afbe071628..5aa2008fc1fe73 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -117,6 +117,7 @@ const knownOptions = { import: ['string'], exhaustive: ['boolean'], query: ['object', 'string'], + base: ['string'], } const forceDefaultAs = ['raw', 'url'] @@ -306,7 +307,9 @@ export async function parseImportGlob( } const globsResolved = await Promise.all( - globs.map((glob) => toAbsoluteGlob(glob, root, importer, resolveId)), + globs.map((glob) => + toAbsoluteGlob(glob, root, importer, resolveId, options.base), + ), ) const isRelative = globs.every((i) => '.!'.includes(i[0])) @@ -544,6 +547,7 @@ export async function toAbsoluteGlob( root: string, importer: string | undefined, resolveId: IdResolver, + base?: string, ): Promise { let pre = '' if (glob[0] === '!') { @@ -552,6 +556,8 @@ export async function toAbsoluteGlob( } root = globSafePath(root) const dir = importer ? globSafePath(dirname(importer)) : root + if (base && base.startsWith('./')) return pre + posix.join(dir, base, glob) + glob = base ? posix.join(base, glob) : glob if (glob[0] === '/') return pre + posix.join(root, glob.slice(1)) if (glob.startsWith('./')) return pre + posix.join(dir, glob.slice(2)) if (glob.startsWith('../')) return pre + posix.join(dir, glob) diff --git a/packages/vite/types/importGlob.d.ts b/packages/vite/types/importGlob.d.ts index e0167531d6d9ad..40535340b9ea9b 100644 --- a/packages/vite/types/importGlob.d.ts +++ b/packages/vite/types/importGlob.d.ts @@ -28,6 +28,10 @@ export interface ImportGlobOptions< * @default false */ exhaustive?: boolean + /** + * Base path to resolve relative paths. + */ + base?: string } export type GeneralImportGlobOptions = ImportGlobOptions From 09a3e9cab6315d9ae178154eb1c7b591f06f6b86 Mon Sep 17 00:00:00 2001 From: hakshu25 Date: Tue, 29 Oct 2024 23:21:53 +0900 Subject: [PATCH 02/20] feat: add support for custom base path in import.meta.glob --- .../importGlob/__snapshots__/fixture.spec.ts.snap | 2 ++ .../__tests__/plugins/importGlob/fixture-a/index.ts | 2 ++ packages/vite/src/node/plugins/importMetaGlob.ts | 11 ++++++++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap index f187b9e0ab0a03..3daf451dd40ee6 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap +++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap @@ -52,6 +52,7 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => }); +export const customBase = /* #__PURE__ */ Object.assign({"fixture-a/modules/a.ts": () => import("./modules/a.ts"),"fixture-a/modules/b.ts": () => import("./modules/b.ts"),"fixture-a/modules/index.ts": () => import("./modules/index.ts"),"fixture-a/sibling.ts": () => import("./sibling.ts")}); " `; @@ -107,6 +108,7 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => }); +export const customBase = /* #__PURE__ */ Object.assign({"fixture-a/modules/a.ts": () => import("./modules/a.ts"),"fixture-a/modules/b.ts": () => import("./modules/b.ts"),"fixture-a/modules/index.ts": () => import("./modules/index.ts"),"fixture-a/sibling.ts": () => import("./sibling.ts")}); " `; diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts index 8a2311051a8d09..7404ab82a914e3 100644 --- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts +++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts @@ -67,3 +67,5 @@ export const cleverCwd2 = import.meta.glob([ '../fixture-b/*.ts', '!**/index.ts', ]) + +export const customBase = import.meta.glob('**/*.ts', { base: './' }) diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts index 5aa2008fc1fe73..91160da3d60882 100644 --- a/packages/vite/src/node/plugins/importMetaGlob.ts +++ b/packages/vite/src/node/plugins/importMetaGlob.ts @@ -419,15 +419,20 @@ export async function transformGlobImport( throw new Error( "In virtual modules, all globs must start with '/'", ) - const filePath = `/${relative(root, file)}` - return { filePath, importPath: filePath } + const importPath = `/${relative(root, file)}` + const filePath = options.base + ? `${relative(posix.join(root, options.base), file)}` + : importPath + return { filePath, importPath } } let importPath = relative(dir, file) if (importPath[0] !== '.') importPath = `./${importPath}` let filePath: string - if (isRelative) { + if (options.base) { + filePath = relative(posix.join(root, options.base), file) + } else if (isRelative) { filePath = importPath } else { filePath = relative(root, file) From 6b17fd72774aced2f7394f66153c97b9b1a4c90d Mon Sep 17 00:00:00 2001 From: hakshu25 Date: Tue, 29 Oct 2024 23:57:52 +0900 Subject: [PATCH 03/20] test: add integration test for base option of glob-import --- .../glob-import/__tests__/glob-import.spec.ts | 12 +++++++++++ playground/glob-import/index.html | 20 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/playground/glob-import/__tests__/glob-import.spec.ts b/playground/glob-import/__tests__/glob-import.spec.ts index bdfb4e92119c23..5c3acd70983f77 100644 --- a/playground/glob-import/__tests__/glob-import.spec.ts +++ b/playground/glob-import/__tests__/glob-import.spec.ts @@ -83,6 +83,12 @@ const relativeRawResult = { }, } +const baseRawResult = { + 'baz.json': { + msg: 'baz', + }, +} + test('should work', async () => { await withRetry(async () => { const actual = await page.textContent('.result') @@ -247,3 +253,9 @@ test('subpath imports', async () => { test('#alias imports', async () => { expect(await page.textContent('.hash-alias-imports')).toMatch('bar foo') }) + +test('import base glob raw', async () => { + expect(await page.textContent('.result-base')).toBe( + JSON.stringify(baseRawResult, null, 2), + ) +}) diff --git a/playground/glob-import/index.html b/playground/glob-import/index.html index 8f8d833b56625b..d2f5b790499550 100644 --- a/playground/glob-import/index.html +++ b/playground/glob-import/index.html @@ -27,6 +27,8 @@

#alias imports


 

In package


+

Base

+

 
 
 
+
+

From ae89d14861d35f81a512a27e82b0ea87b53a793a Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Wed, 30 Oct 2024 23:13:30 +0900
Subject: [PATCH 04/20] feat: add validation to check if the base option
 doesn't start with '!'

---
 .../vite/src/node/__tests__/plugins/importGlob/parse.spec.ts  | 3 +++
 packages/vite/src/node/plugins/importMetaGlob.ts              | 4 ++++
 2 files changed, 7 insertions(+)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
index d74b9372d754c3..420ac60d7d0f6c 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
@@ -410,5 +410,8 @@ describe('parse negatives', async () => {
     ).toMatchInlineSnapshot(
       '[Error: Invalid glob: "foo/*.js" (resolved: "foo/*.js"). It must start with \'/\' or \'./\']',
     )
+    expect(
+      await runError('import.meta.glob("./*.js", { base: "!/foo" })'),
+    ).toMatchInlineSnapshot('[Error: Option "base" cannot start with "!"]')
   })
 })
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 91160da3d60882..59de12f7bb5b2d 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -163,6 +163,10 @@ function parseGlobOptions(
     }
   }
 
+  if (opts.base && opts.base[0] === '!') {
+    throw err('Option "base" cannot start with "!"', optsStartIndex)
+  }
+
   if (typeof opts.query === 'object') {
     for (const key in opts.query) {
       const value = opts.query[key]

From 5db0640b20913245a861dad03d2e31529d127bf2 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Thu, 31 Oct 2024 23:51:43 +0900
Subject: [PATCH 05/20] fix: resolved relative paths to options.base

---
 .../importGlob/__snapshots__/fixture.spec.ts.snap      | 10 ++++++++--
 .../__tests__/plugins/importGlob/fixture-a/index.ts    |  4 ++++
 packages/vite/src/node/plugins/importMetaGlob.ts       |  6 +++++-
 3 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
index 3daf451dd40ee6..a533cee9bb52ad 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
@@ -52,7 +52,10 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 
 });
-export const customBase = /* #__PURE__ */ Object.assign({"fixture-a/modules/a.ts": () => import("./modules/a.ts"),"fixture-a/modules/b.ts": () => import("./modules/b.ts"),"fixture-a/modules/index.ts": () => import("./modules/index.ts"),"fixture-a/sibling.ts": () => import("./sibling.ts")});
+export const customBase = /* #__PURE__ */ Object.assign({"modules/a.ts": () => import("./modules/a.ts"),"modules/b.ts": () => import("./modules/b.ts"),"modules/index.ts": () => import("./modules/index.ts"),"sibling.ts": () => import("./sibling.ts")});
+export const customRootBase = /* #__PURE__ */ Object.assign({"a.ts": () => import("../fixture-b/a.ts"),"b.ts": () => import("../fixture-b/b.ts"),"index.ts": () => import("../fixture-b/index.ts")
+
+});
 "
 `;
 
@@ -108,7 +111,10 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 
 });
-export const customBase = /* #__PURE__ */ Object.assign({"fixture-a/modules/a.ts": () => import("./modules/a.ts"),"fixture-a/modules/b.ts": () => import("./modules/b.ts"),"fixture-a/modules/index.ts": () => import("./modules/index.ts"),"fixture-a/sibling.ts": () => import("./sibling.ts")});
+export const customBase = /* #__PURE__ */ Object.assign({"modules/a.ts": () => import("./modules/a.ts"),"modules/b.ts": () => import("./modules/b.ts"),"modules/index.ts": () => import("./modules/index.ts"),"sibling.ts": () => import("./sibling.ts")});
+export const customRootBase = /* #__PURE__ */ Object.assign({"a.ts": () => import("../fixture-b/a.ts"),"b.ts": () => import("../fixture-b/b.ts"),"index.ts": () => import("../fixture-b/index.ts")
+
+});
 "
 `;
 
diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
index 7404ab82a914e3..52b52950c5fb62 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
@@ -69,3 +69,7 @@ export const cleverCwd2 = import.meta.glob([
 ])
 
 export const customBase = import.meta.glob('**/*.ts', { base: './' })
+
+export const customRootBase = import.meta.glob('**/*.ts', {
+  base: '/fixture-b',
+})
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 59de12f7bb5b2d..610ca6fd967ce9 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -435,7 +435,11 @@ export async function transformGlobImport(
 
             let filePath: string
             if (options.base) {
-              filePath = relative(posix.join(root, options.base), file)
+              const resolvedBasePath = options.base[0] === '/' ? root : dir
+              filePath = relative(
+                posix.join(resolvedBasePath, options.base),
+                file,
+              )
             } else if (isRelative) {
               filePath = importPath
             } else {

From f6d73df72b326f8a9cce6e822a846bc6e1c32094 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Fri, 1 Nov 2024 00:10:46 +0900
Subject: [PATCH 06/20] docs: add usage of base path for glob import

---
 docs/guide/features.md | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/docs/guide/features.md b/docs/guide/features.md
index dfd8c57f715ded..8166fb7f9cb58c 100644
--- a/docs/guide/features.md
+++ b/docs/guide/features.md
@@ -537,6 +537,33 @@ const modules = import.meta.glob('./dir/*.js', {
 })
 ```
 
+#### Base Path
+
+You can also use the `base` option to provide base path for the imports:
+
+```ts twoslash
+import 'vite/client'
+// ---cut---
+const moduleRelativeBase = import.meta.glob('**/*.js', {
+  base: './base',
+})
+const moduleRootBase = import.meta.glob('**/*.js', {
+  base: '/base',
+})
+```
+
+```ts
+// code produced by vite:
+const moduleRelativeBase = {
+  'dir/foo.js': () => import('./dir/foo.js'),
+  'dir/bar.js': () => import('./dir/bar.js'),
+}
+const moduleRootBase = {
+  'other_dir/foo.js': () => import('../other_dir/foo.js'),
+  'other_dir/bar.js': () => import('../other_dir/bar.js'),
+}
+```
+
 ### Glob Import Caveats
 
 Note that:

From f2066092f22a292c5ffc7e37283760ae9c25db0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=BF=A0=20/=20green?= 
Date: Fri, 1 Nov 2024 12:34:46 +0900
Subject: [PATCH 07/20] docs: remove one example

---
 docs/guide/features.md | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/docs/guide/features.md b/docs/guide/features.md
index 8166fb7f9cb58c..4616af98971c57 100644
--- a/docs/guide/features.md
+++ b/docs/guide/features.md
@@ -544,24 +544,17 @@ You can also use the `base` option to provide base path for the imports:
 ```ts twoslash
 import 'vite/client'
 // ---cut---
-const moduleRelativeBase = import.meta.glob('**/*.js', {
+const moduleBase = import.meta.glob('**/*.js', {
   base: './base',
 })
-const moduleRootBase = import.meta.glob('**/*.js', {
-  base: '/base',
-})
 ```
 
 ```ts
 // code produced by vite:
-const moduleRelativeBase = {
+const moduleBase = {
   'dir/foo.js': () => import('./dir/foo.js'),
   'dir/bar.js': () => import('./dir/bar.js'),
 }
-const moduleRootBase = {
-  'other_dir/foo.js': () => import('../other_dir/foo.js'),
-  'other_dir/bar.js': () => import('../other_dir/bar.js'),
-}
 ```
 
 ### Glob Import Caveats

From 7f0f5e754142871a9bc0431264fd04ab19cb56a1 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Sat, 2 Nov 2024 22:25:51 +0900
Subject: [PATCH 08/20] fix: ensure glob import keys start with './' when using
 base option

---
 docs/guide/features.md                                    | 4 ++--
 .../plugins/importGlob/__snapshots__/fixture.spec.ts.snap | 8 ++++----
 packages/vite/src/node/plugins/importMetaGlob.ts          | 1 +
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/docs/guide/features.md b/docs/guide/features.md
index 4616af98971c57..035887b5f75fdf 100644
--- a/docs/guide/features.md
+++ b/docs/guide/features.md
@@ -552,8 +552,8 @@ const moduleBase = import.meta.glob('**/*.js', {
 ```ts
 // code produced by vite:
 const moduleBase = {
-  'dir/foo.js': () => import('./dir/foo.js'),
-  'dir/bar.js': () => import('./dir/bar.js'),
+  './dir/foo.js': () => import('./dir/foo.js'),
+  './dir/bar.js': () => import('./dir/bar.js'),
 }
 ```
 
diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
index a533cee9bb52ad..c7c55ad0cbe043 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
@@ -52,8 +52,8 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 
 });
-export const customBase = /* #__PURE__ */ Object.assign({"modules/a.ts": () => import("./modules/a.ts"),"modules/b.ts": () => import("./modules/b.ts"),"modules/index.ts": () => import("./modules/index.ts"),"sibling.ts": () => import("./sibling.ts")});
-export const customRootBase = /* #__PURE__ */ Object.assign({"a.ts": () => import("../fixture-b/a.ts"),"b.ts": () => import("../fixture-b/b.ts"),"index.ts": () => import("../fixture-b/index.ts")
+export const customBase = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts"),"./sibling.ts": () => import("./sibling.ts")});
+export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("../fixture-b/a.ts"),"./b.ts": () => import("../fixture-b/b.ts"),"./index.ts": () => import("../fixture-b/index.ts")
 
 });
 "
@@ -111,8 +111,8 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 
 });
-export const customBase = /* #__PURE__ */ Object.assign({"modules/a.ts": () => import("./modules/a.ts"),"modules/b.ts": () => import("./modules/b.ts"),"modules/index.ts": () => import("./modules/index.ts"),"sibling.ts": () => import("./sibling.ts")});
-export const customRootBase = /* #__PURE__ */ Object.assign({"a.ts": () => import("../fixture-b/a.ts"),"b.ts": () => import("../fixture-b/b.ts"),"index.ts": () => import("../fixture-b/index.ts")
+export const customBase = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts"),"./sibling.ts": () => import("./sibling.ts")});
+export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("../fixture-b/a.ts"),"./b.ts": () => import("../fixture-b/b.ts"),"./index.ts": () => import("../fixture-b/index.ts")
 
 });
 "
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 610ca6fd967ce9..1419064b9c20d5 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -440,6 +440,7 @@ export async function transformGlobImport(
                 posix.join(resolvedBasePath, options.base),
                 file,
               )
+              if (filePath[0] !== '.') filePath = `./${filePath}`
             } else if (isRelative) {
               filePath = importPath
             } else {

From 1cd16f3723d83f7a25c2b56fde32e25590f19300 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Sat, 2 Nov 2024 22:43:03 +0900
Subject: [PATCH 09/20] docs: fix glob import paths to use base directory

---
 docs/guide/features.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/guide/features.md b/docs/guide/features.md
index 035887b5f75fdf..fe749df1d9a181 100644
--- a/docs/guide/features.md
+++ b/docs/guide/features.md
@@ -552,8 +552,8 @@ const moduleBase = import.meta.glob('**/*.js', {
 ```ts
 // code produced by vite:
 const moduleBase = {
-  './dir/foo.js': () => import('./dir/foo.js'),
-  './dir/bar.js': () => import('./dir/bar.js'),
+  './dir/foo.js': () => import('./base/dir/foo.js'),
+  './dir/bar.js': () => import('./base/dir/bar.js'),
 }
 ```
 

From 51e76be61adb05c660a0394ba22faac9c809e655 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Sat, 2 Nov 2024 23:00:52 +0900
Subject: [PATCH 10/20] fix: ensure glob import keys start with './' for base
 directory in glob-import.spec.ts

---
 playground/glob-import/__tests__/glob-import.spec.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/playground/glob-import/__tests__/glob-import.spec.ts b/playground/glob-import/__tests__/glob-import.spec.ts
index 5c3acd70983f77..96e3d5d3fce696 100644
--- a/playground/glob-import/__tests__/glob-import.spec.ts
+++ b/playground/glob-import/__tests__/glob-import.spec.ts
@@ -84,7 +84,7 @@ const relativeRawResult = {
 }
 
 const baseRawResult = {
-  'baz.json': {
+  './baz.json': {
     msg: 'baz',
   },
 }

From b07d814c850d11ee2eaa2839383e613f79b56040 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Tue, 5 Nov 2024 23:08:38 +0900
Subject: [PATCH 11/20] feat: support alias in glob with options.base

---
 .../importGlob/__snapshots__/fixture.spec.ts.snap     | 10 ++++++++--
 .../__tests__/plugins/importGlob/fixture-a/index.ts   |  4 ++++
 packages/vite/src/node/plugins/importMetaGlob.ts      | 11 ++++++++++-
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
index c7c55ad0cbe043..285ad9041f5793 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
@@ -53,7 +53,10 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 });
 export const customBase = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts"),"./sibling.ts": () => import("./sibling.ts")});
-export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("../fixture-b/a.ts"),"./b.ts": () => import("../fixture-b/b.ts"),"./index.ts": () => import("../fixture-b/index.ts")
+export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("/fixture-b/a.ts"),"./b.ts": () => import("/fixture-b/b.ts"),"./index.ts": () => import("/fixture-b/index.ts")
+
+});
+export const aliasBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("/fixture-a/modules/a.ts"),"./b.ts": () => import("/fixture-a/modules/b.ts"),"./index.ts": () => import("/fixture-a/modules/index.ts")
 
 });
 "
@@ -112,7 +115,10 @@ export const cleverCwd2 = /* #__PURE__ */ Object.assign({"./modules/a.ts": () =>
 
 });
 export const customBase = /* #__PURE__ */ Object.assign({"./modules/a.ts": () => import("./modules/a.ts"),"./modules/b.ts": () => import("./modules/b.ts"),"./modules/index.ts": () => import("./modules/index.ts"),"./sibling.ts": () => import("./sibling.ts")});
-export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("../fixture-b/a.ts"),"./b.ts": () => import("../fixture-b/b.ts"),"./index.ts": () => import("../fixture-b/index.ts")
+export const customRootBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("/fixture-b/a.ts"),"./b.ts": () => import("/fixture-b/b.ts"),"./index.ts": () => import("/fixture-b/index.ts")
+
+});
+export const aliasBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("/fixture-a/modules/a.ts"),"./b.ts": () => import("/fixture-a/modules/b.ts"),"./index.ts": () => import("/fixture-a/modules/index.ts")
 
 });
 "
diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
index 52b52950c5fb62..9780b02e36bcd4 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
@@ -73,3 +73,7 @@ export const customBase = import.meta.glob('**/*.ts', { base: './' })
 export const customRootBase = import.meta.glob('**/*.ts', {
   base: '/fixture-b',
 })
+
+export const aliasBase = import.meta.glob('@modules/*.ts', {
+  base: '/fixture-a/modules',
+})
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 1419064b9c20d5..4d6bf2776f260b 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -441,6 +441,9 @@ export async function transformGlobImport(
                 file,
               )
               if (filePath[0] !== '.') filePath = `./${filePath}`
+              if (options.base[0] === '/') {
+                importPath = `/${relative(root, file)}`
+              }
             } else if (isRelative) {
               filePath = importPath
             } else {
@@ -570,7 +573,13 @@ export async function toAbsoluteGlob(
   }
   root = globSafePath(root)
   const dir = importer ? globSafePath(dirname(importer)) : root
-  if (base && base.startsWith('./')) return pre + posix.join(dir, base, glob)
+  if (base) {
+    if (base.startsWith('./')) return pre + posix.join(dir, base, glob)
+    if (glob[0] === '@') {
+      const withoutAlias = /\/.+$/.exec(glob)?.[0]
+      return pre + posix.join(root, base, withoutAlias || glob)
+    }
+  }
   glob = base ? posix.join(base, glob) : glob
   if (glob[0] === '/') return pre + posix.join(root, glob.slice(1))
   if (glob.startsWith('./')) return pre + posix.join(dir, glob.slice(2))

From 2ec1175391ae4d4324870cc43fdbf1fff081a979 Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Tue, 5 Nov 2024 23:33:25 +0900
Subject: [PATCH 12/20] feat: support relative glob in virtual modules

---
 .../plugins/importGlob/__snapshots__/fixture.spec.ts.snap  | 3 ++-
 .../src/node/__tests__/plugins/importGlob/fixture.spec.ts  | 1 +
 packages/vite/src/node/plugins/importMetaGlob.ts           | 7 +++++--
 3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
index 285ad9041f5793..4caf501500b2a9 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/__snapshots__/fixture.spec.ts.snap
@@ -126,5 +126,6 @@ export const aliasBase = /* #__PURE__ */ Object.assign({"./a.ts": () => import("
 
 exports[`fixture > virtual modules 1`] = `
 "/* #__PURE__ */ Object.assign({"/modules/a.ts": () => import("/modules/a.ts"),"/modules/b.ts": () => import("/modules/b.ts"),"/modules/index.ts": () => import("/modules/index.ts")})
-/* #__PURE__ */ Object.assign({"/../fixture-b/a.ts": () => import("/../fixture-b/a.ts"),"/../fixture-b/b.ts": () => import("/../fixture-b/b.ts"),"/../fixture-b/index.ts": () => import("/../fixture-b/index.ts")})"
+/* #__PURE__ */ Object.assign({"/../fixture-b/a.ts": () => import("/../fixture-b/a.ts"),"/../fixture-b/b.ts": () => import("/../fixture-b/b.ts"),"/../fixture-b/index.ts": () => import("/../fixture-b/index.ts")})
+/* #__PURE__ */ Object.assign({"./a.ts": () => import("/modules/a.ts"),"./b.ts": () => import("/modules/b.ts"),"./index.ts": () => import("/modules/index.ts")})"
 `;
diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture.spec.ts
index 62eb06581531a7..8276ddc8e1b553 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture.spec.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture.spec.ts
@@ -45,6 +45,7 @@ describe('fixture', async () => {
     const code = [
       "import.meta.glob('/modules/*.ts')",
       "import.meta.glob(['/../fixture-b/*.ts'])",
+      "import.meta.glob(['./*.ts'], { base: '/modules' })",
     ].join('\n')
     expect(
       (
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 4d6bf2776f260b..766ea32d9c9d35 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -419,14 +419,17 @@ export async function transformGlobImport(
 
           const resolvePaths = (file: string) => {
             if (!dir) {
-              if (isRelative)
+              if (!options.base && isRelative)
                 throw new Error(
                   "In virtual modules, all globs must start with '/'",
                 )
               const importPath = `/${relative(root, file)}`
-              const filePath = options.base
+              let filePath = options.base
                 ? `${relative(posix.join(root, options.base), file)}`
                 : importPath
+              if (options.base && filePath[0] !== '.') {
+                filePath = `./${filePath}`
+              }
               return { filePath, importPath }
             }
 

From 76dc01e92a5adc3af45606a74fa34dee96bf405b Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Wed, 6 Nov 2024 23:12:47 +0900
Subject: [PATCH 13/20] test: fix test to treat as base instead of prefix

---
 .../src/node/__tests__/plugins/importGlob/fixture-a/index.ts  | 4 ++--
 .../vite/src/node/__tests__/plugins/importGlob/parse.spec.ts  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
index 9780b02e36bcd4..1c48aaa78ac59e 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/fixture-a/index.ts
@@ -68,9 +68,9 @@ export const cleverCwd2 = import.meta.glob([
   '!**/index.ts',
 ])
 
-export const customBase = import.meta.glob('**/*.ts', { base: './' })
+export const customBase = import.meta.glob('./**/*.ts', { base: './' })
 
-export const customRootBase = import.meta.glob('**/*.ts', {
+export const customRootBase = import.meta.glob('./**/*.ts', {
   base: '/fixture-b',
 })
 
diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
index 420ac60d7d0f6c..da1b30620ded7b 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
@@ -144,7 +144,7 @@ describe('parse positives', async () => {
   it('options with base', async () => {
     expect(
       await run(`
-    import.meta.glob('**/dir/*.md', {
+    import.meta.glob('./**/dir/*.md', {
       base: './path/to/base'
     })
     `),
@@ -152,7 +152,7 @@ describe('parse positives', async () => {
       [
         {
           "globs": [
-            "**/dir/*.md",
+            "./**/dir/*.md",
           ],
           "options": {
             "base": "./path/to/base",

From 500cb145d9f3bc947387bb0c286cd0f427effc9f Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Wed, 6 Nov 2024 23:13:31 +0900
Subject: [PATCH 14/20] docs: fix glob import example to treat as base instead
 of prefix

---
 docs/guide/features.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/guide/features.md b/docs/guide/features.md
index fe749df1d9a181..f8229db426be7e 100644
--- a/docs/guide/features.md
+++ b/docs/guide/features.md
@@ -544,7 +544,7 @@ You can also use the `base` option to provide base path for the imports:
 ```ts twoslash
 import 'vite/client'
 // ---cut---
-const moduleBase = import.meta.glob('**/*.js', {
+const moduleBase = import.meta.glob('./**/*.js', {
   base: './base',
 })
 ```

From f6c657d0275fc0299b142d0a8f682b1c09d4c82f Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Thu, 7 Nov 2024 23:13:28 +0900
Subject: [PATCH 15/20] fix: changed to update dir to glob to act as base
 instead of prefix

---
 .../plugins/importGlob/parse.spec.ts          |  2 +-
 .../vite/src/node/plugins/importMetaGlob.ts   | 36 ++++++++++++++-----
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
index da1b30620ded7b..3be198b1282977 100644
--- a/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
+++ b/packages/vite/src/node/__tests__/plugins/importGlob/parse.spec.ts
@@ -408,7 +408,7 @@ describe('parse negatives', async () => {
     expect(
       await runError('import.meta.glob("./*.js", { base: "foo" })'),
     ).toMatchInlineSnapshot(
-      '[Error: Invalid glob: "foo/*.js" (resolved: "foo/*.js"). It must start with \'/\' or \'./\']',
+      "[Error: Option \"base\" must start with '/', './' or '../', but got \"foo\"]",
     )
     expect(
       await runError('import.meta.glob("./*.js", { base: "!/foo" })'),
diff --git a/packages/vite/src/node/plugins/importMetaGlob.ts b/packages/vite/src/node/plugins/importMetaGlob.ts
index 766ea32d9c9d35..ffaf2d81afc09d 100644
--- a/packages/vite/src/node/plugins/importMetaGlob.ts
+++ b/packages/vite/src/node/plugins/importMetaGlob.ts
@@ -163,8 +163,19 @@ function parseGlobOptions(
     }
   }
 
-  if (opts.base && opts.base[0] === '!') {
-    throw err('Option "base" cannot start with "!"', optsStartIndex)
+  if (opts.base) {
+    if (opts.base[0] === '!') {
+      throw err('Option "base" cannot start with "!"', optsStartIndex)
+    } else if (
+      opts.base[0] !== '/' &&
+      !opts.base.startsWith('./') &&
+      !opts.base.startsWith('../')
+    ) {
+      throw err(
+        `Option "base" must start with '/', './' or '../', but got "${opts.base}"`,
+        optsStartIndex,
+      )
+    }
   }
 
   if (typeof opts.query === 'object') {
@@ -575,15 +586,24 @@ export async function toAbsoluteGlob(
     glob = glob.slice(1)
   }
   root = globSafePath(root)
-  const dir = importer ? globSafePath(dirname(importer)) : root
+  let dir
   if (base) {
-    if (base.startsWith('./')) return pre + posix.join(dir, base, glob)
-    if (glob[0] === '@') {
-      const withoutAlias = /\/.+$/.exec(glob)?.[0]
-      return pre + posix.join(root, base, withoutAlias || glob)
+    if (base.startsWith('/')) {
+      dir = posix.join(root, base)
+    } else {
+      dir = posix.resolve(
+        importer ? globSafePath(dirname(importer)) : root,
+        base,
+      )
     }
+  } else {
+    dir = importer ? globSafePath(dirname(importer)) : root
+  }
+
+  if (base && glob[0] === '@') {
+    const withoutAlias = /\/.+$/.exec(glob)?.[0]
+    return pre + posix.join(root, base, withoutAlias || glob)
   }
-  glob = base ? posix.join(base, glob) : glob
   if (glob[0] === '/') return pre + posix.join(root, glob.slice(1))
   if (glob.startsWith('./')) return pre + posix.join(dir, glob.slice(2))
   if (glob.startsWith('../')) return pre + posix.join(dir, glob)

From 1a260721827daf317c697815fc3e293e8ace33cf Mon Sep 17 00:00:00 2001
From: hakshu25 
Date: Fri, 8 Nov 2024 10:54:09 +0900
Subject: [PATCH 16/20] test: fix e2e test glob in base option of import glob

---
 playground/glob-import/index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/playground/glob-import/index.html b/playground/glob-import/index.html
index d2f5b790499550..69f9f2854d5012 100644
--- a/playground/glob-import/index.html
+++ b/playground/glob-import/index.html
@@ -171,7 +171,7 @@ 

Base