@@ -11,7 +11,6 @@ import type { NodeLoaderOptions, WebpackAssetRelocatorLoader } from './types'
1111import { COLOURS } from 'vite-plugin-utils/function'
1212import {
1313 type NativeRecord ,
14- type NativeRecordType ,
1514 createCjs ,
1615 ensureDir ,
1716 getInteropSnippet ,
@@ -22,8 +21,13 @@ import {
2221export interface NativeOptions {
2322 /** @default 'node_natives' */
2423 assetsDir ?: string
25- /** By default native modules are automatically detected if this option is not explicitly configure by the user. */
24+ /**
25+ * By default native modules are automatically detected if this option is not explicitly configure by the user.
26+ * @deprecated use `ignore` option instead
27+ */
2628 natives ?: string [ ] | ( ( natives : string [ ] ) => string [ ] )
29+ /** Ignore the specified native module. */
30+ ignore ?: ( name : string ) => boolean | undefined
2731 /** Enable and configure webpack. */
2832 webpack ?: {
2933 config ?: ( config : Configuration ) => Configuration | undefined | Promise < Configuration | undefined >
@@ -44,8 +48,7 @@ const nativesMap = new Map<string, {
4448 status : 'built' | 'resolved'
4549 nativeFilename : string
4650 interopFilename : string
47- type : NativeRecordType
48- nodeFiles : string [ ]
51+ native : NativeRecord
4952} >
5053
5154export default function native ( options : NativeOptions ) : Plugin {
@@ -61,21 +64,16 @@ export default function native(options: NativeOptions): Plugin {
6164 const outDir = config . build ?. outDir ?? 'dist'
6265 output = normalizePath ( path . join ( resolvedRoot , outDir , assetsDir ) )
6366
64- const depsNativeRecord = await getDependenciesNatives ( resolvedRoot )
65- const depsNatives = [ ...depsNativeRecord . keys ( ) ]
67+ let nativeRecord = await getDependenciesNatives ( resolvedRoot )
6668
6769 if ( options . natives ) {
6870 const natives = Array . isArray ( options . natives )
6971 ? options . natives
70- : options . natives ( depsNatives )
72+ : options . natives ( [ ... nativeRecord . keys ( ) ] )
7173 // TODO: bundle modules based on `natives`.
7274 }
7375
7476 const withDistAssetBase = ( p : string ) => ( assetsDir && p ) ? `${ assetsDir } /${ p } ` : p
75-
76- let detectedNativeRecord : NativeRecord = new Map
77- let detectedNatives : string [ ] = [ ]
78-
7977 const alias : Alias = {
8078 find : / ( .* ) / ,
8179 // Keep `customResolver` receive original source.
@@ -85,54 +83,51 @@ export default function native(options: NativeOptions): Plugin {
8583 if ( ! importer ) return
8684 if ( ! bareImportRE . test ( source ) ) return
8785
88- if ( ! depsNativeRecord . has ( source ) ) {
89- // Auto detection.
86+ if ( ! nativeRecord . has ( source ) ) {
87+ // Dynamic deep detection.
9088 // e.g. serialport -> @serialport/bindings-cpp
91- const nativeRecord = await resolveNativeRecord ( source , importer )
92- if ( nativeRecord ) {
93- detectedNativeRecord = new Map ( [ ...detectedNativeRecord , ...nativeRecord ] )
94- detectedNatives = [ ...depsNativeRecord . keys ( ) ]
95- }
89+ nativeRecord = new Map ( [ ...nativeRecord , ...( await resolveNativeRecord ( source , importer ) ?? [ ] ) ] )
9690 }
9791
98- if ( [ ...depsNatives , ...detectedNatives ] . includes ( source ) ) {
99- const nativeFilename = path . join ( output , source + NativeExt )
100- const interopFilename = path . join ( output , source + InteropExt )
92+ const nativeItem = nativeRecord . get ( source )
93+ if ( ! nativeItem ) return
10194
102- if ( ! nativesMap . get ( source ) ) {
103- ensureDir ( output )
95+ if ( options . ignore ?.( source ) === false ) {
96+ nativeItem . ignore = true
97+ return
98+ }
10499
105- // Generate Vite and Webpack interop file.
106- fs . writeFileSync (
107- interopFilename ,
108- getInteropSnippet ( source , `./${ withDistAssetBase ( source + NativeExt ) } ` ) ,
109- )
100+ const nativeFilename = path . join ( output , source + NativeExt )
101+ const interopFilename = path . join ( output , source + InteropExt )
110102
111- // We did not immediately call the `webpackBundle()` build here
112- // because `build.emptyOutDir = true` will cause the built file to be removed.
103+ if ( ! nativesMap . get ( source ) ) {
104+ ensureDir ( output )
113105
114- const isDetected = detectedNativeRecord . has ( source )
106+ // Generate Vite and Webpack interop file.
107+ fs . writeFileSync (
108+ interopFilename ,
109+ getInteropSnippet ( source , `./${ withDistAssetBase ( source + NativeExt ) } ` ) ,
110+ )
115111
116- // Collect modules that are explicitly used.
117- nativesMap . set ( source , {
118- status : 'resolved' ,
119- nativeFilename,
120- interopFilename,
121- type : isDetected ? 'detected' : 'dependencies' ,
122- nodeFiles : isDetected
123- ? detectedNativeRecord . get ( source ) ?. nativeFiles !
124- : depsNativeRecord . get ( source ) ?. nativeFiles ! ,
125- } )
126- }
112+ // We did not immediately call the `webpackBundle()` build here
113+ // because `build.emptyOutDir = true` will cause the built file to be removed.
127114
128- return { id : interopFilename }
115+ // Collect modules that are explicitly used.
116+ nativesMap . set ( source , {
117+ status : 'resolved' ,
118+ nativeFilename,
119+ interopFilename,
120+ native : nativeItem ,
121+ } )
129122 }
123+
124+ return { id : interopFilename }
130125 } ,
131126 }
132127
133128 modifyAlias ( config , [ alias ] )
134129 // Run build are not necessary.
135- modifyOptimizeDeps ( config , [ ...depsNatives , ... detectedNatives ] )
130+ modifyOptimizeDeps ( config , [ ...nativeRecord . keys ( ) ] )
136131 } ,
137132 async buildEnd ( error ) {
138133 if ( error ) return
@@ -258,3 +253,7 @@ async function webpackBundle(
258253 } )
259254 } )
260255}
256+
257+ async function ensureNodeFiles ( ) {
258+
259+ }
0 commit comments