Skip to content

Commit d199621

Browse files
committed
fix: differentiate between rel=preload and rel=stylesheet for CSS files
1 parent 82dea8e commit d199621

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

packages/vite/src/node/plugins/importAnalysisBuild.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,7 @@ function preload(
6565
return baseModule()
6666
}
6767

68-
const absoluteUrls = new Set<string>()
6968
const links = document.getElementsByTagName('link')
70-
for (let i = links.length - 1; i >= 0; i--) {
71-
// The `links[i].href` is an absolute URL thanks to browser doing the work
72-
// for us. See https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-domstring-5
73-
absoluteUrls.add(links[i].href)
74-
}
7569

7670
return Promise.all(
7771
deps.map((dep) => {
@@ -89,7 +83,14 @@ function preload(
8983
if (isBaseRelative) {
9084
// When isBaseRelative is true then we have `importerUrl` and `dep` is
9185
// already converted to an absolute URL by the `assetsURL` function
92-
if (absoluteUrls.has(dep)) return
86+
for (let i = links.length - 1; i >= 0; i--) {
87+
const link = links[i]
88+
// The `links[i].href` is an absolute URL thanks to browser doing the work
89+
// for us. See https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-domstring-5
90+
if (link.href === dep && (!isCss || link.rel === 'stylesheet')) {
91+
return
92+
}
93+
}
9394
} else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) {
9495
return
9596
}

playground/css-dynamic-import/__tests__/css-dynamic-import.spec.ts

+50-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const getConfig = (base: string): InlineConfig => ({
1212
base,
1313
root: rootDir,
1414
logLevel: 'silent',
15-
preview: { port: ports['css/dynamic-import'] }
15+
preview: { port: ports['css/dynamic-import'] },
16+
build: { assetsInlineLimit: 0 }
1617
})
1718

1819
async function withBuild(base: string, fn: () => Promise<void>) {
@@ -42,14 +43,17 @@ async function withServe(base: string, fn: () => Promise<void>) {
4243
}
4344
}
4445

45-
async function getChunks() {
46+
async function getLinks() {
4647
const links = await page.$$('link')
47-
const hrefs = await Promise.all(links.map((l) => l.evaluate((el) => el.href)))
48-
return hrefs.map((href) => {
49-
// drop hash part from the file name
50-
const [_, name, ext] = href.match(/assets\/([a-z]+)\..*?\.(.*)$/)
51-
return `${name}.${ext}`
52-
})
48+
return await Promise.all(
49+
links.map((handle) => {
50+
return handle.evaluate((link) => ({
51+
pathname: new URL(link.href).pathname,
52+
rel: link.rel,
53+
as: link.as
54+
}))
55+
})
56+
)
5357
}
5458

5559
baseOptions.forEach(({ base, label }) => {
@@ -60,12 +64,37 @@ baseOptions.forEach(({ base, label }) => {
6064
await page.waitForSelector('.loaded', { state: 'attached' })
6165

6266
expect(await getColor('.css-dynamic-import')).toBe('green')
63-
expect(await getChunks()).toEqual([
64-
'index.css',
65-
'dynamic.js',
66-
'dynamic.css',
67-
'static.js',
68-
'index.js'
67+
expect(await getLinks()).toEqual([
68+
{
69+
pathname: expect.stringMatching(/^\/assets\/index\..+\.css$/),
70+
rel: 'stylesheet',
71+
as: ''
72+
},
73+
{
74+
pathname: expect.stringMatching(/^\/assets\/dynamic\..+\.css$/),
75+
rel: 'preload',
76+
as: 'style'
77+
},
78+
{
79+
pathname: expect.stringMatching(/^\/assets\/dynamic\..+\.js$/),
80+
rel: 'modulepreload',
81+
as: 'script'
82+
},
83+
{
84+
pathname: expect.stringMatching(/^\/assets\/dynamic\..+\.css$/),
85+
rel: 'stylesheet',
86+
as: ''
87+
},
88+
{
89+
pathname: expect.stringMatching(/^\/assets\/static\..+\.js$/),
90+
rel: 'modulepreload',
91+
as: 'script'
92+
},
93+
{
94+
pathname: expect.stringMatching(/^\/assets\/index\..+\.js$/),
95+
rel: 'modulepreload',
96+
as: 'script'
97+
}
6998
])
7099
})
71100
}
@@ -79,7 +108,13 @@ baseOptions.forEach(({ base, label }) => {
79108

80109
expect(await getColor('.css-dynamic-import')).toBe('green')
81110
// in serve there is no preloading
82-
expect(await getChunks()).toEqual([])
111+
expect(await getLinks()).toEqual([
112+
{
113+
pathname: '/dynamic.css',
114+
rel: 'preload',
115+
as: 'style'
116+
}
117+
])
83118
})
84119
}
85120
)
+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import './static.js'
22

3+
const link = document.head.appendChild(document.createElement('link'))
4+
link.rel = 'preload'
5+
link.as = 'style'
6+
link.href = new URL('./dynamic.css', import.meta.url).href
7+
38
import('./dynamic.js').then(async ({ lazyLoad }) => {
49
await lazyLoad()
510
})

0 commit comments

Comments
 (0)