@@ -5,9 +5,7 @@ import { Buffer } from 'node:buffer'
55import * as mrmime from 'mrmime'
66import type {
77 NormalizedOutputOptions ,
8- OutputOptions ,
98 PluginContext ,
10- PreRenderedAsset ,
119 RenderedChunk
1210} from 'rollup'
1311import MagicString from 'magic-string'
@@ -29,10 +27,15 @@ const urlRE = /(\?|&)url(?:&|$)/
2927const assetCache = new WeakMap < ResolvedConfig , Map < string , string > > ( )
3028
3129// chunk.name is the basename for the asset ignoring the directory structure
32- // For the manifest, we need to preserve the original file path
30+ // For the manifest, we need to preserve the original file path and isEntry
31+ // for CSS assets. We keep a map from referenceId to this information.
32+ export interface GeneratedAssetMeta {
33+ originalName : string
34+ isEntry ?: boolean
35+ }
3336export const generatedAssets = new WeakMap <
3437 ResolvedConfig ,
35- Map < string , { originalName : string } >
38+ Map < string , GeneratedAssetMeta >
3639> ( )
3740
3841// add own dictionary entry by directly assigning mrmime
@@ -248,120 +251,6 @@ export function getPublicAssetFilename(
248251 return publicAssetUrlCache . get ( config ) ?. get ( hash )
249252}
250253
251- export function resolveAssetFileNames (
252- config : ResolvedConfig
253- ) : string | ( ( chunkInfo : PreRenderedAsset ) => string ) {
254- const output = config . build ?. rollupOptions ?. output
255- const defaultAssetFileNames = path . posix . join (
256- config . build . assetsDir ,
257- '[name].[hash][extname]'
258- )
259- // Steps to determine which assetFileNames will be actually used.
260- // First, if output is an object or string, use assetFileNames in it.
261- // And a default assetFileNames as fallback.
262- let assetFileNames : Exclude < OutputOptions [ 'assetFileNames' ] , undefined > =
263- ( output && ! Array . isArray ( output ) ? output . assetFileNames : undefined ) ??
264- defaultAssetFileNames
265- if ( output && Array . isArray ( output ) ) {
266- // Second, if output is an array, adopt assetFileNames in the first object.
267- assetFileNames = output [ 0 ] . assetFileNames ?? assetFileNames
268- }
269- return assetFileNames
270- }
271-
272- /**
273- * converts the source filepath of the asset to the output filename based on the assetFileNames option. \
274- * this function imitates the behavior of rollup.js. \
275- * https://rollupjs.org/guide/en/#outputassetfilenames
276- *
277- * @example
278- * ```ts
279- * const content = Buffer.from('text');
280- * const fileName = assetFileNamesToFileName(
281- * 'assets/[name].[hash][extname]',
282- * '/path/to/file.txt',
283- * getHash(content),
284- * content
285- * )
286- * // fileName: 'assets/file.982d9e3e.txt'
287- * ```
288- *
289- * @param assetFileNames filename pattern. e.g. `'assets/[name].[hash][extname]'`
290- * @param file filepath of the asset
291- * @param contentHash hash of the asset. used for `'[hash]'` placeholder
292- * @param content content of the asset. passed to `assetFileNames` if `assetFileNames` is a function
293- * @returns output filename
294- */
295- export function assetFileNamesToFileName (
296- assetFileNames : Exclude < OutputOptions [ 'assetFileNames' ] , undefined > ,
297- file : string ,
298- contentHash : string ,
299- content : string | Buffer
300- ) : string {
301- const basename = path . basename ( file )
302-
303- // placeholders for `assetFileNames`
304- // `hash` is slightly different from the rollup's one
305- const extname = path . extname ( basename )
306- const ext = extname . substring ( 1 )
307- const name = basename . slice ( 0 , - extname . length )
308- const hash = contentHash
309-
310- if ( typeof assetFileNames === 'function' ) {
311- assetFileNames = assetFileNames ( {
312- name : file ,
313- source : content ,
314- type : 'asset'
315- } )
316- if ( typeof assetFileNames !== 'string' ) {
317- throw new TypeError ( 'assetFileNames must return a string' )
318- }
319- } else if ( typeof assetFileNames !== 'string' ) {
320- throw new TypeError ( 'assetFileNames must be a string or a function' )
321- }
322-
323- const fileName = assetFileNames . replace (
324- / \[ \w + \] / g,
325- ( placeholder : string ) : string => {
326- switch ( placeholder ) {
327- case '[ext]' :
328- return ext
329-
330- case '[extname]' :
331- return extname
332-
333- case '[hash]' :
334- return hash
335-
336- case '[name]' :
337- return sanitizeFileName ( name )
338- }
339- throw new Error (
340- `invalid placeholder ${ placeholder } in assetFileNames "${ assetFileNames } "`
341- )
342- }
343- )
344-
345- return fileName
346- }
347-
348- // taken from https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/utils/sanitizeFileName.ts
349- // https://datatracker.ietf.org/doc/html/rfc2396
350- // eslint-disable-next-line no-control-regex
351- const INVALID_CHAR_REGEX = / [ \x00 - \x1F \x7F < > * # " { } | ^ [ \] ` ; ? : & = + $ , ] / g
352- const DRIVE_LETTER_REGEX = / ^ [ a - z ] : / i
353- function sanitizeFileName ( name : string ) : string {
354- const match = DRIVE_LETTER_REGEX . exec ( name )
355- const driveLetter = match ? match [ 0 ] : ''
356-
357- // A `:` is only allowed as part of a windows drive letter (ex: C:\foo)
358- // Otherwise, avoid them because they can refer to NTFS alternate data streams.
359- return (
360- driveLetter +
361- name . substr ( driveLetter . length ) . replace ( INVALID_CHAR_REGEX , '_' )
362- )
363- }
364-
365254export const publicAssetUrlCache = new WeakMap <
366255 ResolvedConfig ,
367256 // hash -> url
0 commit comments