SOURCE

// main.js
/*
import * as Vue from 'vue';
import * as echarts from 'echarts';
window.Vue = Vue;
window.Echarts = echarts;
*/

// 远程组件加载示例
{/* 
<template>
  <component: is="componentKey" ></component>
</template >
  <script>
    import {
      defineComponent,
      defineAsyncComponent
    } from "vue";

    export default defineComponent({
      setup(props) {
    const componentKey =  defineAsyncComponent(
      () =>
    new Promise(
          (resolve, reject) => {            
      if (window.__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER) {
        resolve(window.__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER);
      }
      // 注意url需要转防xss安全处理:如下处理方法
      const strReplaceXss = (str) => {
          const specailToStr = {
              '&': '&amp;',
              '<': '&lt;',
              '>': '&gt;',
              '"': '&quot;',
              "'": '&#x27',
              ',': '&#44',
              ';': '&#59',
              '(': '&#40',
              ')': '&#41',
          };
          return (str || '').replace(/[&<>"',;()]/g, (val) => specailToStr[val]);
      };
      encodeURI(strReplaceXss(url));
      // 注意url需要转防xss安全处理
      fetch('/CommonComponentFront/satisfaction_table_selection_transfer.0.0.1.umd.js', {
        method: 'GET',
        mode: 'cors',
      })
        .then(response => response.text())
        .then(text => {
          const script = document.createElement('script');
          script.text = text;
          document.body.appendChild(script);
          resolve(window.__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER);
        })
        .catch(reject);
          }
    ),
    );
    return {
      componentKey
    }
  },
});
  </script> */}

// 语法糖形式
{/*
 <script setup>
import { ref,toRefs, markRaw, unref, watch } from 'vue';
defineOptions({
  inheritAttrs: false,
});
const props = defineProps({
  url:{
    type: String,
    default: '/CommonComponentFront/satisfaction_remote_component_table_selection_transfer.0.0.1.umd.js?name=__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER'
  }
});
const { url } = toRefs(props);
const componentKey = ref(null);

// 特殊字符转义
const strReplaceXss = (str) => {
  const specailToStr = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27',
    ',': '&#44',
    ';': '&#59',
    '(': '&#40',
    ')': '&#41',
  };
  return (str || '').replace(/[&<>"',;()]/g, (val) => specailToStr[val]);
};

const loadScript = (url) => {
  const str = unref(url);
  // url编码后参数name提取
  const params = new URLSearchParams(`?${encodeURI(strReplaceXss(str).split('.js?')[1] || '')}`);
  const name = params.get('name');
  if (!name) {
    return;
  }
  if (window[name]) {
    componentKey.value = markRaw(window[name]);
  } else {
    fetch(str, {
      method: 'GET',
      mode: 'cors',
    }).then((res) => {
      if (res.status === 200) {
        res.text().then((code) => {
          const script = document.createElement('script');
          script.text = code;
          document.body.appendChild(script);
          componentKey.value = markRaw(window[name]);
        });
      }
    });
  }
  return;
};

watch(
  () => url,
  (val) => {
    loadScript(val);
  },
  { deep: true, immediate: true }
);
</script> 
*/}


//将name直接配置在url参数上的方案代码:
/**********开始**********
url = /CommonComponentFront/famliyPorutin__selection_transfer.0.0.1.umd.js?name=__FMAILYPORUTIN_GROUP_SELFTEST_ECHARTS

const params = new URLSearchParams(`?${encodeURI(strReplaceXss(url).split('.js?')[1] || '')}`);
const name = params.get('name');
if (!name) {
  return;
}
if (window[name]) {
  mode.value = markRaw(window[name]);
} else {
    fetch(url, {
        method: 'GET',
        mode: 'cors',
    }).then(response => response.text()).then(text => {        
        const script = document.createElement('script');
        script.text = text;
        document.body.appendChild(script);
        resolve(window[name]);
    });
}
**********结束**********/



// vite.config.js配置
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { resolve } from 'path';
import pkg from './package.json';


export default defineConfig({
  define: {
    'process.env.NODE_ENV': '"production"'
  },
  build: {
    cssCodeSplit: true,
    reportCompressedSize: false,
    // minify: 'terser',
    // terserOptions: {
    //   compress: {
    //     drop_console: true,
    //     drop_debugger: true,
    //   },
    // },
    outDir: 'CommonComponentFront',
    lib: {
      target: 'esnext',
      formats: ['es', 'umd'],
      entry: resolve(__dirname, 'src/components/remote/BaseTableSelectionTransfer.vue'),
      name: '__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER',
      fileName: (format) => `satisfaction_table_selection_transfer.${pkg.version}.${format}.js`
    },
    rollupOptions: {
      external: ['vue', 'elementPlus', 'echarts'],
      output: {
        globals: {
          vue: 'Vue',
          elementPlus: 'ElementPlus',
          echarts: 'Echarts'
        }
      }
    }
  },
  plugins: [vue(), vueJsx()],
  resolve: {
    alias: {
      '@': resolve(__dirname, './src')
    }
  }
});

/*********************************************************************************/

// package.json
{
  "name": "satisfaction_remote_component_table_selection_transfer",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "axios": "1.6.1",
    "echarts": "5.4.2",
    "element-plus": "2.3.12",
    "vue": "3.3.4",
    "vue-router": "4.2.4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.2.3",
    "@vitejs/plugin-vue-jsx": "^3.1.0",
    "@vue/compiler-sfc": "^3.1.1",
    "less": "^4.1.3",
    "postcss-import": "^15.1.0",
    "postcss-url": "^10.1.3",
    "vite": "^4.3.5"
  }
}


// vite.config.js配置
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { resolve } from 'path';
import pkg from './package.json';


export default defineConfig({
  define: {
    'process.env.NODE_ENV': '"production"'
  },
  build: {
    cssCodeSplit: true,
    outDir: 'CommonComponentFront',
    reportCompressedSize: false,
    lib: {
      target: 'esnext',
      formats: ['es', 'umd'],
      entry: resolve(__dirname, 'src/components/index.vue'),
      name: `__${pkg.name.toLocaleUpperCase()}`,
      fileName: (format) => `${pkg.name}.${pkg.version}.${format}.js`
    },
    rollupOptions: {
      external: ['vue', 'elementPlus', 'echarts'],
      output: {
        globals: {
          vue: 'Vue',
          elementPlus: 'ElementPlus',
          echarts: 'Echarts'
        }
      }
    }
  },
  plugins: [vue(), vueJsx()],
  resolve: {
    alias: {
      '@': resolve(__dirname, './src')
    }
  }
})

// App.vue
<template>
    <component :is="mode" ></component>
</template>
<script setup>
import { ref,toRefs, markRaw, unref, watch } from 'vue';
defineOptions({
  inheritAttrs: false,
});
const props = defineProps({
  // 远程js地址
  url:{
    type: String,
    default: '/CommonComponentFront/satisfaction_remote_component_table_selection_transfer.0.0.1.umd.js?name=__SATISFACTION_REMOTE_COMPONENT_TABLE_SELECTION_TRANSFER'
  }
});
const { url } = toRefs(props);
const mode = ref(null);

// 特殊字符转义
const strReplaceXss = (str) => {
  const specailToStr = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27',
    ',': '&#44',
    ';': '&#59',
    '(': '&#40',
    ')': '&#41',
  };
  return (str || '').replace(/[&<>"',;()]/g, (val) => specailToStr[val]);
};

// 加载远程js
const loadScript = (url) => {
  const str = unref(url);
  // url编码后参数name提取
  const params = new URLSearchParams(`?${encodeURI(strReplaceXss(str).split('.js?')[1] || '')}`);
  const name = params.get('name');
  if (!name) {
    return;
  }
  if (window[name]) {
    mode.value = markRaw(window[name]);
  } else {
    fetch(str, {
      method: 'GET',
      mode: 'cors',
    }).then((res) => {
      if (res.status === 200) {
        res.text().then((code) => {
          const script = document.createElement('script');
          script.text = code;
          document.body.appendChild(script);
          mode.value = markRaw(window[name]);
        });
      }
    });
  }
  return;
};

watch(
  () => url,
  (val) => {
    loadScript(val);
  },
  { deep: true, immediate: true }
);
</script> 

<style lang="less">
#app,body,html{
  width: 100%;
  height: 100%;
}
</style>


// main.js
import { createApp } from 'vue';
import * as Vue from 'vue';
import * as echarts from 'echarts';
import App from './App.vue';
import ElementPlus from 'element-plus';
import zhCn from 'element-plus/dist/locale/zh-cn.mjs';
import 'element-plus/dist/index.css';

window.Vue = Vue;
window.Echarts = echarts;

const app = createApp(App);

app.use(ElementPlus, {
  locale: zhCn
});

app.mount('#app');

/*********************************************************************************/
console 命令行工具 X clear

                    
>
console