Skip to content
6 changes: 5 additions & 1 deletion packages/vite/src/node/plugins/importMetaGlob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ export function importGlobPlugin(config: ResolvedConfig): Plugin {
const affirmed: string[] = []
const negated: string[] = []
for (const glob of globs) {
;(glob[0] === '!' ? negated : affirmed).push(glob)
if (glob[0] === '!') {
negated.push(glob.slice(1))
} else {
affirmed.push(glob)
}
}
const affirmedMatcher = picomatch(affirmed)
const negatedMatcher = picomatch(negated)
Expand Down
66 changes: 53 additions & 13 deletions playground/glob-import/__tests__/glob-import.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,40 @@ if (!isBuild) {
.poll(async () => JSON.parse(await resultElement.textContent()))
.toStrictEqual(['/pkg-pages/foo.js'])
})

test('hmr for adding/removing files with array patterns and exclusions', async () => {
const resultElement = page.locator('.array-result')
await expect
.poll(async () => JSON.parse(await resultElement.textContent()))
.toStrictEqual({
'./array-test-dir/included.js': 'included',
})

addFile('array-test-dir/new-file.js', 'export default "new"')
await expect
.poll(async () => JSON.parse(await resultElement.textContent()))
.toStrictEqual({
'./array-test-dir/included.js': 'included',
'./array-test-dir/new-file.js': 'new',
})

removeFile('array-test-dir/new-file.js')
await expect
.poll(async () => JSON.parse(await resultElement.textContent()))
.toStrictEqual({
'./array-test-dir/included.js': 'included',
})
})
}

test('array pattern with exclusions', async () => {
await expect
.poll(async () => JSON.parse(await page.textContent('.array-result')))
.toStrictEqual({
'./array-test-dir/included.js': 'included',
})
})

test('tree-shake eager css', async () => {
expect(await page.textContent('.no-tree-shake-eager-css-result')).toMatch(
'.no-tree-shake-eager-css',
Expand All @@ -237,26 +269,34 @@ test('escapes special chars in globs without mangling user supplied glob suffix'
.filter((f) => f.isDirectory())
.map((f) => `/escape/${f.name}/glob.js`)
.sort()
const foundRelativeNames = (await page.textContent('.escape-relative'))
.split('\n')
.sort()
expect(expectedNames).toEqual(foundRelativeNames)
const foundAliasNames = (await page.textContent('.escape-alias'))
.split('\n')
.sort()
expect(expectedNames).toEqual(foundAliasNames)
await expect
.poll(async () => {
const text = await page.textContent('.escape-relative')
return text.split('\n').sort()
})
.toEqual(expectedNames)
await expect
.poll(async () => {
const text = await page.textContent('.escape-alias')
return text.split('\n').sort()
})
.toEqual(expectedNames)
})

test('subpath imports', async () => {
expect(await page.textContent('.subpath-imports')).toMatch('bar foo')
await expect
.poll(async () => await page.textContent('.subpath-imports'))
.toMatch('bar foo')
})

test('#alias imports', async () => {
expect(await page.textContent('.hash-alias-imports')).toMatch('bar foo')
await expect
.poll(async () => 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),
)
await expect
.poll(async () => await page.textContent('.result-base'))
.toBe(JSON.stringify(baseRawResult, null, 2))
})
1 change: 1 addition & 0 deletions playground/glob-import/array-test-dir/excluded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'excluded'
1 change: 1 addition & 0 deletions playground/glob-import/array-test-dir/included.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'included'
18 changes: 18 additions & 0 deletions playground/glob-import/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,21 @@ <h2>Base</h2>
2,
)
</script>

<h2>Array Pattern with Exclusions</h2>
<pre class="array-result"></pre>

<script type="module">
const arrayModules = import.meta.glob(
['./array-test-dir/*.js', '!./array-test-dir/excluded.js'],
{
eager: true,
import: 'default',
},
)
document.querySelector('.array-result').textContent = JSON.stringify(
arrayModules,
null,
2,
)
</script>