Skip to content

Commit e6913d1

Browse files
bluwyeasymikeysapphi-red
authored
fix: backport to 5.2 (#17411)
Co-authored-by: Mikhail Avdeev <[email protected]> Co-authored-by: 翠 / green <[email protected]>
1 parent e861168 commit e6913d1

File tree

3 files changed

+116
-4
lines changed

3 files changed

+116
-4
lines changed

packages/vite/src/node/__tests__/plugins/css.spec.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
cssUrlRE,
1010
getEmptyChunkReplacer,
1111
hoistAtRules,
12+
preprocessCSS,
1213
} from '../../plugins/css'
1314

1415
describe('search css url function', () => {
@@ -65,6 +66,7 @@ background: #f0f;
6566
}`,
6667
},
6768
{
69+
configFile: false,
6870
resolve: {
6971
alias: [
7072
{
@@ -101,6 +103,7 @@ position: fixed;
101103

102104
test('custom generateScopedName', async () => {
103105
const { transform, resetMock } = await createCssPluginTransform(undefined, {
106+
configFile: false,
104107
css: {
105108
modules: {
106109
generateScopedName: 'custom__[hash:base64:5]',
@@ -338,3 +341,50 @@ require("other-module");`
338341
)
339342
})
340343
})
344+
345+
describe('preprocessCSS', () => {
346+
test('works', async () => {
347+
const resolvedConfig = await resolveConfig({ configFile: false }, 'serve')
348+
const result = await preprocessCSS(
349+
`\
350+
.foo {
351+
color:red;
352+
background: url(./foo.png);
353+
}`,
354+
'foo.css',
355+
resolvedConfig,
356+
)
357+
expect(result.code).toMatchInlineSnapshot(`
358+
".foo {
359+
color:red;
360+
background: url(./foo.png);
361+
}"
362+
`)
363+
})
364+
365+
test('works with lightningcss', async () => {
366+
const resolvedConfig = await resolveConfig(
367+
{
368+
configFile: false,
369+
css: { transformer: 'lightningcss' },
370+
},
371+
'serve',
372+
)
373+
const result = await preprocessCSS(
374+
`\
375+
.foo {
376+
color: red;
377+
background: url(./foo.png);
378+
}`,
379+
'foo.css',
380+
resolvedConfig,
381+
)
382+
expect(result.code).toMatchInlineSnapshot(`
383+
".foo {
384+
color: red;
385+
background: url("./foo.png");
386+
}
387+
"
388+
`)
389+
})
390+
})

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ import {
8282
import type { ESBuildOptions } from './esbuild'
8383
import { getChunkOriginalFileName } from './manifest'
8484

85+
const decoder = new TextDecoder()
8586
// const debug = createDebugger('vite:css')
8687

8788
export interface CSSOptions {
@@ -1808,8 +1809,12 @@ async function minifyCSS(
18081809
),
18091810
)
18101811
}
1812+
1813+
// NodeJS res.code = Buffer
1814+
// Deno res.code = Uint8Array
1815+
// For correct decode compiled css need to use TextDecoder
18111816
// LightningCSS output does not return a linebreak at the end
1812-
return code.toString() + (inlined ? '' : '\n')
1817+
return decoder.decode(code) + (inlined ? '' : '\n')
18131818
}
18141819
try {
18151820
const { code, warnings } = await transform(css, {
@@ -2698,8 +2703,6 @@ function isPreProcessor(lang: any): lang is PreprocessLang {
26982703
}
26992704

27002705
const importLightningCSS = createCachedImport(() => import('lightningcss'))
2701-
2702-
const decoder = new TextDecoder()
27032706
async function compileLightningCSS(
27042707
id: string,
27052708
src: string,
@@ -2780,6 +2783,8 @@ async function compileLightningCSS(
27802783
if (urlReplacer) {
27812784
const replaceUrl = await urlReplacer(dep.url, id)
27822785
css = css.replace(dep.placeholder, () => replaceUrl)
2786+
} else {
2787+
css = css.replace(dep.placeholder, () => dep.url)
27832788
}
27842789
break
27852790
default:

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

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,64 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
318318
},
319319

320320
generateBundle({ format }, bundle) {
321-
if (format !== 'es' || ssr || isWorker) {
321+
if (format !== 'es') {
322+
return
323+
}
324+
325+
if (ssr || isWorker) {
326+
const removedPureCssFiles = removedPureCssFilesCache.get(config)
327+
if (removedPureCssFiles && removedPureCssFiles.size > 0) {
328+
for (const file in bundle) {
329+
const chunk = bundle[file]
330+
if (chunk.type === 'chunk' && chunk.code.includes('import')) {
331+
const code = chunk.code
332+
let imports!: ImportSpecifier[]
333+
try {
334+
imports = parseImports(code)[0].filter((i) => i.d > -1)
335+
} catch (e: any) {
336+
const loc = numberToPos(code, e.idx)
337+
this.error({
338+
name: e.name,
339+
message: e.message,
340+
stack: e.stack,
341+
cause: e.cause,
342+
pos: e.idx,
343+
loc: { ...loc, file: chunk.fileName },
344+
frame: generateCodeFrame(code, loc),
345+
})
346+
}
347+
348+
for (const imp of imports) {
349+
const {
350+
n: name,
351+
s: start,
352+
e: end,
353+
ss: expStart,
354+
se: expEnd,
355+
} = imp
356+
let url = name
357+
if (!url) {
358+
const rawUrl = code.slice(start, end)
359+
if (rawUrl[0] === `"` && rawUrl[rawUrl.length - 1] === `"`)
360+
url = rawUrl.slice(1, -1)
361+
}
362+
if (!url) continue
363+
364+
const normalizedFile = path.posix.join(
365+
path.posix.dirname(chunk.fileName),
366+
url,
367+
)
368+
if (removedPureCssFiles.has(normalizedFile)) {
369+
// remove with Promise.resolve({}) while preserving source map location
370+
chunk.code =
371+
chunk.code.slice(0, expStart) +
372+
`Promise.resolve({${''.padEnd(expEnd - expStart - 19, ' ')}})` +
373+
chunk.code.slice(expEnd)
374+
}
375+
}
376+
}
377+
}
378+
}
322379
return
323380
}
324381

0 commit comments

Comments
 (0)