import * as path from 'path' ; import { getModuleMarker , normalizePath , parseExposeOptions } from '../utils' ; import { builderInfo , DYNAMIC_LOADING_CSS , DYNAMIC_LOADING_CSS_PREFIX , EXPOSES_MAP , EXTERNALS , parsedOptions , SHARED } from '../public' ; import { AcornNode } from 'rollup' ; import { VitePluginFederationOptions } from 'types' ; import { PluginHooks } from '../../types/pluginHooks' ; import MagicString from 'magic-string' ; import { walk } from 'estree-walker' ; export function prodExposePlugin ( options ) { let moduleMap = '' ; parsedOptions . prodExpose = parseExposeOptions ( options ) ; for ( const item of parsedOptions . prodExpose ) { const moduleName = getModuleMarker ( `\${${ item [ 0 ] }}` , SHARED ) ; EXTERNALS . push ( moduleName ) ; const exposeFilepath = normalizePath ( path . resolve ( item [ 1 ] . import ) ) ; EXPOSES_MAP . set ( item [ 0 ] , exposeFilepath ) ; item [ 1 ] . id = exposeFilepath ; moduleMap += `\n"${ item [ 0 ] }":()=>{
      ${ DYNAMIC_LOADING_CSS }('${ DYNAMIC_LOADING_CSS_PREFIX }${ exposeFilepath }')
      return __federation_import('\${__federation_expose_${ item [ 0 ] }}').then(module=>()=>module)
    },` ; } let remoteEntryChunk ; return { name : 'originjs:expose-production' , virtualFile : { __remoteEntryHelper__ : `let moduleMap = {${ moduleMap }}
    export const ${ DYNAMIC_LOADING_CSS } = (cssFilePath) => {
      const metaUrl = import.meta.url
      if (typeof metaUrl == 'undefined') {
        console.warn('The remote style takes effect only when the build.target option in the vite.config.ts file is higher than that of "es2020".')
        return
      }
      const curUrl = metaUrl.substring(0, metaUrl.lastIndexOf('${ options . filename }'))
      const element = document.head.appendChild(document.createElement('link'))
      element.href = curUrl + cssFilePath
      element.rel = 'stylesheet'
    };
    async function __federation_import(name) {
        return import(name);
    };
    export const get =(module) => {
        return moduleMap[module]();
    };
    export const init =(shareScope) => {
      globalThis.__federation_shared__= globalThis.__federation_shared__|| {};
      Object.entries(shareScope).forEach(([key, value]) => {
        const versionKey = Object.keys(value)[0];
        const versionValue = Object.values(value)[0];
        const scope = versionValue.scope || 'default'
        globalThis.__federation_shared__[scope] = globalThis.__federation_shared__[scope] || {};
        const shared= globalThis.__federation_shared__[scope];
        (shared[key] = shared[key]||{})[versionKey] = versionValue;
      });
    }` } , options ( ) { return null ; } , buildStart ( ) { if ( parsedOptions . prodExpose . length > 0 ) { this . emitFile ( { fileName : `${ builderInfo . assetsDir ? builderInfo . assetsDir + '/' : '' }${ options . filename }` , type : 'chunk' , id : '__remoteEntryHelper__' , preserveSignature : 'strict' } ) ; } } , renderChunk ( code , chunk ) { if ( chunk . facadeModuleId === '\0virtual:__remoteEntryHelper__' ) { remoteEntryChunk = chunk ; } return null ; } , generateBundle ( _options , bundle ) { const moduleCssFileMap = getChunkCssRelation ( bundle ) ; for ( const file in bundle ) { const chunk = bundle [ file ] ; if ( chunk . type === 'chunk' && chunk . isEntry ) { if ( ! remoteEntryChunk && chunk . fileName === options . filename ) { remoteEntryChunk = chunk ; } } } if ( remoteEntryChunk ) { const item = remoteEntryChunk ; moduleCssFileMap . forEach ( ( value , key ) => { item . code = item . code . replace ( `${ DYNAMIC_LOADING_CSS_PREFIX }${ key }` , `./${ path . basename ( value ) }` ) ; } ) ; let ast = null ; try { ast = this . parse ( item . code ) ; } catch ( err ) { console . error ( err ) ; } if ( ! ast ) { return ; } const magicString = new MagicString ( item . code ) ; walk ( ast , { enter ( node ) { if ( node . type === 'CallExpression' && typeof node ?. arguments [ 0 ] ?. value === 'string' && node ?. arguments [ 0 ] ?. value . indexOf ( `${ DYNAMIC_LOADING_CSS_PREFIX }` ) > - 1 ) { magicString . remove ( node . start , node . end + 1 ) ; } } } ) ; item . code = magicString . toString ( ) ; } } } ; param bundle returns function getChunkCssRelation ( bundle ) { const cssFileMap = new Map ( ) ; const moduleCssFileMap = new Map ( ) ; for ( const file in bundle ) { if ( path . extname ( file ) === '.css' ) { cssFileMap . set ( getOriginalFileName ( file ) , file ) ; } } for ( const file in bundle ) { let name = getOriginalFileName ( file ) ; if ( cssFileMap . get ( name ) != null && path . extname ( file ) !== '.css' ) { moduleCssFileMap . set ( bundle [ file ] . facadeModuleId , cssFileMap . get ( name ) ) ; continue ; } const chunk = bundle [ file ] ; if ( chunk ?. modules != undefined && Object . keys ( chunk ?. modules ) ?. length === 0 ) { name = getOriginalFileName ( chunk . imports [ 0 ] ) ; if ( cssFileMap . get ( name ) != null ) { moduleCssFileMap . set ( chunk . facadeModuleId , cssFileMap . get ( name ) ) ; } } } if ( moduleCssFileMap . size === 0 ) { for ( const file in bundle ) { cssFileMap . forEach ( function ( css ) { moduleCssFileMap . set ( bundle [ file ] . facadeModuleId , css ) ; } ) ; } } return moduleCssFileMap ; function getOriginalFileName ( file ) { return path . parse ( path . parse ( file ) . name ) . name ; } } }