11/* eslint-disable jest/no-export */
2+ // eslint-disable @typescript-eslint/no-unsafe-call
23import path from "path" ;
34import fs from "fs-extra" ;
4- import { InputOptions , OutputOptions } from "rollup " ;
5+ import { InputOptions , OutputOptions , rolldown } from "rolldown " ;
56
67import { Options } from "../../src/types" ;
78
8- import { rolldown } from ' rolldown'
9- import nodePolyfills from '@ rolldown/plugin-node-polyfills'
9+ import nodePolyfills from "@ rolldown/plugin-node-polyfills" ;
10+ import type { OutputChunk , OutputAsset } from " rolldown" ;
1011
1112export interface WriteData {
1213 input : string | string [ ] ;
@@ -17,77 +18,140 @@ export interface WriteData {
1718 outputOpts ?: OutputOptions ;
1819}
1920
20- export interface WriteResult {
21+ interface WriteResult {
2122 js : ( ) => Promise < string [ ] > ;
2223 css : ( ) => Promise < string [ ] > ;
23- isCss : ( ) => Promise < boolean > ;
24+ isCss : ( ) => Promise < boolean [ ] > ;
2425 map : ( ) => Promise < string [ ] > ;
25- isMap : ( ) => Promise < boolean > ;
26+ isMap : ( ) => Promise < boolean [ ] > ;
2627 isFile : ( file : string ) => Promise < boolean > ;
2728}
2829
29- async function pathExistsAll ( files : string [ ] ) : Promise < boolean > {
30- if ( files . length === 0 ) return false ;
31- for await ( const file of files ) {
32- const exists = await fs . pathExists ( file ) ;
33- if ( ! exists ) return false ;
34- }
35- return true ;
30+ async function pathExistsAll ( paths : string [ ] ) : Promise < boolean [ ] > {
31+ return Promise . all (
32+ paths . map ( async p =>
33+ fs
34+ . access ( p )
35+ . then ( ( ) => true )
36+ . catch ( ( ) => false ) ,
37+ ) ,
38+ ) ;
39+ }
40+ // Process output files
41+ function isChunk ( f : OutputChunk | OutputAsset ) : f is OutputChunk {
42+ return f . type === "chunk" ;
3643}
3744
38- export const fixture = ( ...args : string [ ] ) : string =>
39- path . normalize ( path . join ( __dirname , ".." , "fixtures" , ...args ) ) ;
45+ function isCssAsset ( f : OutputAsset ) : boolean {
46+ return f . fileName . endsWith ( ".css" ) ;
47+ }
4048
41- export async function write ( data : WriteData ) : Promise < WriteResult > {
42- const outDir = fixture ( "dist" , data . outDir ?? data . title ?? " ") ;
43- const input = Array . isArray ( data . input ) ? data . input . map ( i => fixture ( i ) ) : fixture ( data . input ) ;
49+ function isSourceMap ( f : OutputAsset ) : boolean {
50+ return f . fileName . endsWith ( ".css.map ") ;
51+ }
4452
53+ export async function write ( data : {
54+ input : string | string [ ] ;
55+ outDir ?: string ;
56+ title ?: string ;
57+ inputOpts ?: Partial < InputOptions > ;
58+ outputOpts ?: Partial < OutputOptions > ;
59+ } ) : Promise < WriteResult > {
60+ const outDir = path . join ( "dist" , data . outDir ?? data . title ?? "" ) ;
61+ const input = Array . isArray ( data . input )
62+ ? data . input . map ( i => path . join ( i ) )
63+ : path . join ( data . input ) ;
64+
65+ // Rolldown-specific configuration
4566 const bundle = await rolldown ( {
46- // ... other config
4767 input,
68+ platform : "node" ,
69+ // Merged configuration
70+ ...data . inputOpts ,
71+ // Rolldown-native options
72+ resolve : {
73+ mainFields : [ "module" , "main" ] ,
74+ extensions : [ ".mjs" , ".js" , ".ts" , ".json" , ".node" ] ,
75+ } ,
4876 plugins : [
49- nodePolyfills ( {
50- // Optional configuration
51- include : [ 'fs' , 'path' ] , // Only polyfill specific modules
52- exclude : [ 'crypto' ] , // Exclude modules from polyfilling
53- } ) ,
54- // ... other plugins
77+ {
78+ name : "json-handler" ,
79+ transform ( code : string , id : string ) {
80+ if ( id . endsWith ( ".json" ) ) {
81+ return `export default ${ code } ` ;
82+ }
83+ } ,
84+ } ,
85+ {
86+ name : "node-resolve" ,
87+ resolveId ( source : string ) {
88+ if ( source === "vue" || source . startsWith ( "@vue/" ) ) {
89+ return { id : source , external : true } ;
90+ }
91+ } ,
92+ } ,
93+ {
94+ name : "css-extract" ,
95+ transform ( code : string , id : string ) {
96+ if ( id . endsWith ( ".css" ) ) {
97+ return `export default ${ JSON . stringify ( code ) } ` ;
98+ }
99+ } ,
100+ } ,
101+ nodePolyfills ( ) ,
55102 ] ,
56- platform : 'node' // Important for Node.js polyfilling
57- } )
58- const { output } = await bundle . write ( {
59- ...data . outputOpts ,
60- dir : data . outputOpts ?. file ? undefined : outDir ,
61- file : data . outputOpts ?. file && path . join ( outDir , data . outputOpts . file ) ,
103+
104+ treeshake : {
105+ moduleSideEffects : ( id : string ) =>
106+ id . includes ( ".css" ) || id . includes ( ".vue" ) || id . includes ( ".json" ) ,
107+ } ,
62108 } ) ;
63109
64- const js = output
65- . filter ( f => f . type === "chunk" )
110+ // Output handling
111+ const outputConfig = {
112+ dir : outDir ,
113+ format : "es" as const ,
114+ ...( data . outputOpts ?? { } ) ,
115+ } ;
116+
117+ if ( data . outputOpts ?. file ) {
118+ const { ...rest } = outputConfig ;
119+ outputConfig . file = path . join ( outDir , data . outputOpts . file ) ;
120+ Object . assign ( outputConfig , rest ) ;
121+ }
122+
123+ const { output } = await bundle . write ( outputConfig ) ;
124+
125+ const jsFiles = output
126+ . filter ( ( f ) : f is OutputChunk => isChunk ( f ) )
66127 . map ( f => path . join ( outDir , f . fileName ) )
67128 . sort ( ) ;
68129
69- const css = output
70- . filter ( f => f . type === "asset" && f . fileName . endsWith ( ".css" ) )
130+ const cssFiles = output
131+ . filter ( ( f ) : f is OutputAsset => ! isChunk ( f ) && isCssAsset ( f ) )
71132 . map ( f => path . join ( outDir , f . fileName ) )
72133 . sort ( ) ;
73134
74- const map = output
75- . filter ( f => f . type === "asset" && f . fileName . endsWith ( ".css.map" ) )
135+ const mapFiles = output
136+ . filter ( ( f ) : f is OutputAsset => ! isChunk ( f ) && isSourceMap ( f ) )
76137 . map ( f => path . join ( outDir , f . fileName ) )
77138 . sort ( ) ;
78139
79- const res : WriteResult = {
80- js : async ( ) => Promise . all ( js . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
81- css : async ( ) => Promise . all ( css . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
82- isCss : async ( ) => pathExistsAll ( css ) ,
83- map : async ( ) => Promise . all ( map . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
84- isMap : async ( ) => pathExistsAll ( map ) ,
85- isFile : async file => fs . pathExists ( path . join ( outDir , file ) ) ,
140+ return {
141+ js : async ( ) => Promise . all ( jsFiles . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
142+ css : async ( ) => Promise . all ( cssFiles . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
143+ isCss : async ( ) => pathExistsAll ( cssFiles ) ,
144+ map : async ( ) => Promise . all ( mapFiles . map ( async f => fs . readFile ( f , "utf8" ) ) ) ,
145+ isMap : async ( ) => pathExistsAll ( mapFiles ) ,
146+ isFile : async ( file : string ) =>
147+ fs
148+ . access ( path . join ( outDir , file ) )
149+ . then ( ( ) => true )
150+ . catch ( ( ) => false ) ,
86151 } ;
87-
88- return res ;
89152}
90153
154+ /////
91155export interface TestData extends WriteData {
92156 title : string ;
93157 files ?: string [ ] ;
@@ -99,11 +163,25 @@ export function validate(data: TestData): void {
99163 test ( data . title , async ( ) => {
100164 if ( data . shouldFail ) {
101165 // eslint-disable-next-line jest/no-conditional-expect -- helper utility
102- await expect ( write ( data ) ) . rejects . toThrowErrorMatchingSnapshot ( ) ;
166+ await expect (
167+ write ( {
168+ input : data . input ,
169+ outDir : data . outDir ,
170+ title : data . title ,
171+ inputOpts : data . inputOpts as Partial < InputOptions > ,
172+ outputOpts : data . outputOpts as Partial < OutputOptions > ,
173+ } ) ,
174+ ) . rejects . toThrowErrorMatchingSnapshot ( ) ;
103175 return ;
104176 }
105177
106- const res = await write ( data ) ;
178+ const res = await write ( {
179+ input : data . input ,
180+ outDir : data . outDir ,
181+ title : data . title ,
182+ inputOpts : data . inputOpts as Partial < InputOptions > ,
183+ outputOpts : data . outputOpts as Partial < OutputOptions > ,
184+ } ) ;
107185
108186 for ( const f of await res . js ( ) ) expect ( f ) . toMatchSnapshot ( "js" ) ;
109187
0 commit comments