Skip to content

Commit

Permalink
refactor(css): make getEmptyChunkReplacer for unit test (#14528)
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Co-authored-by: bluwy <bjornlu.dev@gmail.com>
  • Loading branch information
susnux and bluwy committed Oct 10, 2023
1 parent a3b6d8d commit 18900fd
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 14 deletions.
55 changes: 55 additions & 0 deletions packages/vite/src/node/__tests__/plugins/css.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
convertTargets,
cssPlugin,
cssUrlRE,
getEmptyChunkReplacer,
hoistAtRules,
} from '../../plugins/css'

Expand Down Expand Up @@ -258,3 +259,57 @@ describe('convertTargets', () => {
})
})
})

describe('getEmptyChunkReplacer', () => {
test('replaces import call', () => {
const code = `\
import "some-module";
import "pure_css_chunk.js";
import "other-module";`

const replacer = getEmptyChunkReplacer(['pure_css_chunk.js'], 'es')
const replaced = replacer(code)
expect(replaced.length).toBe(code.length)
expect(replaced).toMatchInlineSnapshot(`
"import \\"some-module\\";
/* empty css */import \\"other-module\\";"
`)
})

test('replaces import call without new lines', () => {
const code = `import "some-module";import "pure_css_chunk.js";import "other-module";`

const replacer = getEmptyChunkReplacer(['pure_css_chunk.js'], 'es')
const replaced = replacer(code)
expect(replaced.length).toBe(code.length)
expect(replaced).toMatchInlineSnapshot(
'"import \\"some-module\\";/* empty css */import \\"other-module\\";"',
)
})

test('replaces require call', () => {
const code = `\
require("some-module");
require("pure_css_chunk.js");
require("other-module");`

const replacer = getEmptyChunkReplacer(['pure_css_chunk.js'], 'cjs')
const replaced = replacer(code)
expect(replaced.length).toBe(code.length)
expect(replaced).toMatchInlineSnapshot(`
"require(\\"some-module\\");
/* empty css */require(\\"other-module\\");"
`)
})

test('replaces require call in minified code without new lines', () => {
const code = `require("some-module");require("pure_css_chunk.js");require("other-module");`

const replacer = getEmptyChunkReplacer(['pure_css_chunk.js'], 'cjs')
const replaced = replacer(code)
expect(replaced.length).toBe(code.length)
expect(replaced).toMatchInlineSnapshot(
'"require(\\"some-module\\");/* empty css */require(\\"other-module\\");"',
)
})
})
50 changes: 36 additions & 14 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import glob from 'fast-glob'
import postcssrc from 'postcss-load-config'
import type {
ExistingRawSourceMap,
ModuleFormat,
OutputChunk,
RenderedChunk,
RollupError,
Expand Down Expand Up @@ -735,16 +736,11 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
(pureCssChunk) => prelimaryNameToChunkMap[pureCssChunk.fileName],
)

const emptyChunkFiles = pureCssChunkNames
.map((file) => path.basename(file))
.join('|')
.replace(/\./g, '\\.')
const emptyChunkRE = new RegExp(
opts.format === 'es'
? `\\bimport\\s*["'][^"']*(?:${emptyChunkFiles})["'];\n?`
: `\\brequire\\(\\s*["'][^"']*(?:${emptyChunkFiles})["']\\);\n?`,
'g',
const replaceEmptyChunk = getEmptyChunkReplacer(
pureCssChunkNames,
opts.format,
)

for (const file in bundle) {
const chunk = bundle[file]
if (chunk.type === 'chunk') {
Expand All @@ -766,13 +762,10 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
}
return true
})
chunk.code = chunk.code.replace(
emptyChunkRE,
// remove css import while preserving source map location
(m) => `/* empty css ${''.padEnd(m.length - 15)}*/`,
)
chunk.code = replaceEmptyChunk(chunk.code)
}
}

const removedPureCssFiles = removedPureCssFilesCache.get(config)!
pureCssChunkNames.forEach((fileName) => {
removedPureCssFiles.set(fileName, bundle[fileName] as RenderedChunk)
Expand Down Expand Up @@ -818,6 +811,35 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
}
}

/**
* Create a replacer function that takes code and replaces given pure CSS chunk imports
* @param pureCssChunkNames The chunks that only contain pure CSS and should be replaced
* @param outputFormat The module output format to decide whether to replace `import` or `require`
*/
export function getEmptyChunkReplacer(
pureCssChunkNames: string[],
outputFormat: ModuleFormat,
): (code: string) => string {
const emptyChunkFiles = pureCssChunkNames
.map((file) => path.basename(file))
.join('|')
.replace(/\./g, '\\.')

const emptyChunkRE = new RegExp(
outputFormat === 'es'
? `\\bimport\\s*["'][^"']*(?:${emptyChunkFiles})["'];\n?`
: `\\brequire\\(\\s*["'][^"']*(?:${emptyChunkFiles})["']\\);\n?`,
'g',
)

return (code: string) =>
code.replace(
emptyChunkRE,
// remove css import while preserving source map location
(m) => `/* empty css ${''.padEnd(m.length - 15)}*/`,
)
}

interface CSSAtImportResolvers {
css: ResolveFn
sass: ResolveFn
Expand Down

0 comments on commit 18900fd

Please sign in to comment.