1- import glob from 'fast-glob'
2- import fs from 'fs-extra'
3- import { dirname , join } from 'node:path'
4- import { HtmlTagDescriptor , Plugin , normalizePath } from 'vite'
1+ import type { OutputOptions } from 'rollup'
2+ import { HtmlTagDescriptor , Plugin } from 'vite'
53
6- interface ImportMapSource {
4+ interface VendorLibrary {
75 name : string
8- pattern : string | RegExp
9- entry : string
10- recursiveDependence ?: boolean
11- override ?: Record < string , Partial < ImportMapSource > >
12- }
13-
14- const parseDeps = ( root : string , pkg : string ) => {
15- const pkgPath = join ( root , 'node_modules' , pkg , 'package.json' )
16- if ( fs . existsSync ( pkgPath ) ) {
17- const content = fs . readFileSync ( pkgPath , 'utf-8' )
18- const pkg = JSON . parse ( content )
19- return Object . keys ( pkg . dependencies || { } )
20- }
21- return [ ]
6+ pattern : RegExp
227}
238
249/**
@@ -38,89 +23,53 @@ const parseDeps = (root: string, pkg: string) => {
3823 * @returns {Plugin } A Vite plugin that generates and injects an import map
3924 */
4025export function generateImportMapPlugin (
41- importMapSources : ImportMapSource [ ]
26+ vendorLibraries : VendorLibrary [ ]
4227) : Plugin {
4328 const importMapEntries : Record < string , string > = { }
44- const resolvedImportMapSources : Map < string , ImportMapSource > = new Map ( )
45- const assetDir = 'assets/lib'
46- let root : string
4729
4830 return {
4931 name : 'generate-import-map-plugin' ,
5032
5133 // Configure manual chunks during the build process
5234 configResolved ( config ) {
53- root = config . root
54-
5535 if ( config . build ) {
5636 // Ensure rollupOptions exists
5737 if ( ! config . build . rollupOptions ) {
5838 config . build . rollupOptions = { }
5939 }
6040
61- for ( const source of importMapSources ) {
62- resolvedImportMapSources . set ( source . name , source )
63- if ( source . recursiveDependence ) {
64- const deps = parseDeps ( root , source . name )
65-
66- while ( deps . length ) {
67- const dep = deps . shift ( ) !
68- const depSource = Object . assign ( { } , source , {
69- name : dep ,
70- pattern : dep ,
71- ...source . override ?. [ dep ]
72- } )
73- resolvedImportMapSources . set ( depSource . name , depSource )
74-
75- const _deps = parseDeps ( root , depSource . name )
76- deps . unshift ( ..._deps )
41+ const outputOptions : OutputOptions = {
42+ manualChunks : ( id : string ) => {
43+ for ( const lib of vendorLibraries ) {
44+ if ( lib . pattern . test ( id ) ) {
45+ return `vendor-${ lib . name } `
46+ }
7747 }
78- }
79- }
80-
81- const external : ( string | RegExp ) [ ] = [ ]
82- for ( const [ , source ] of resolvedImportMapSources ) {
83- external . push ( source . pattern )
48+ return null
49+ } ,
50+ // Disable minification of internal exports to preserve function names
51+ minifyInternalExports : false
8452 }
85- config . build . rollupOptions . external = external
53+ config . build . rollupOptions . output = outputOptions
8654 }
8755 } ,
8856
89- generateBundle ( _options ) {
90- for ( const [ , source ] of resolvedImportMapSources ) {
91- if ( source . entry ) {
92- const moduleFile = join ( source . name , source . entry )
93- const sourceFile = join ( root , 'node_modules' , moduleFile )
94- const targetFile = join ( root , 'dist' , assetDir , moduleFile )
95-
96- importMapEntries [ source . name ] =
97- './' + normalizePath ( join ( assetDir , moduleFile ) )
98-
99- const targetDir = dirname ( targetFile )
100- if ( ! fs . existsSync ( targetDir ) ) {
101- fs . mkdirSync ( targetDir , { recursive : true } )
102- }
103- fs . copyFileSync ( sourceFile , targetFile )
104- }
105-
106- if ( source . recursiveDependence ) {
107- const files = glob . sync ( [ '**/*.{js,mjs}' ] , {
108- cwd : join ( root , 'node_modules' , source . name )
109- } )
110-
111- for ( const file of files ) {
112- const moduleFile = join ( source . name , file )
113- const sourceFile = join ( root , 'node_modules' , moduleFile )
114- const targetFile = join ( root , 'dist' , assetDir , moduleFile )
115-
116- importMapEntries [ normalizePath ( join ( source . name , dirname ( file ) ) ) ] =
117- './' + normalizePath ( join ( assetDir , moduleFile ) )
118-
119- const targetDir = dirname ( targetFile )
120- if ( ! fs . existsSync ( targetDir ) ) {
121- fs . mkdirSync ( targetDir , { recursive : true } )
122- }
123- fs . copyFileSync ( sourceFile , targetFile )
57+ generateBundle ( _options , bundle ) {
58+ for ( const fileName in bundle ) {
59+ const chunk = bundle [ fileName ]
60+ if ( chunk . type === 'chunk' && ! chunk . isEntry ) {
61+ // Find matching vendor library by chunk name
62+ const vendorLib = vendorLibraries . find (
63+ ( lib ) => chunk . name === `vendor-${ lib . name } `
64+ )
65+
66+ if ( vendorLib ) {
67+ const relativePath = `./${ chunk . fileName . replace ( / \\ / g, '/' ) } `
68+ importMapEntries [ vendorLib . name ] = relativePath
69+
70+ console . log (
71+ `[ImportMap Plugin] Found chunk: ${ chunk . name } -> Mapped '${ vendorLib . name } ' to '${ relativePath } '`
72+ )
12473 }
12574 }
12675 }
0 commit comments