这两天在折腾singlespa 集成 vue3.0, 折腾了许久, 结果如下:
主项目访问子项目:
子项目单独起:
直接上代码:
子项目
vite.js
import {fileURLToPath, URL} from 'node:url'
// import createVitePlugins from './vite/plugins'
import {defineConfig, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
const StatsPlugin = require('stats-webpack-plugin')
const path = require('path')
import htmlPlugin from 'vite-plugin-index-html';
const selectorNamespace = require("postcss-selector-namespace");
// https://vitejs.dev/config/
export default defineConfig(({mode, command}) => {
const {VITE_APP_ENV, VITE_APP_MODULE_NAME} = loadEnv(mode, process.cwd())
console.log("ssss:", VITE_APP_MODULE_NAME, mode)
return {
base: 'http://localhost:3002/vue3/',
// base: VITE_APP_ENV == 'development' ? `http://localhost:3002/${VITE_APP_MODULE_NAME}/` : '/' + VITE_APP_MODULE_NAME + '/',
plugins: [
vue({
template: {
transformAssetUrls: {
base: '/src'
}
}
}),
vueJsx(),
],
resolve: {
alias: {
// '@': fileURLToPath(new URL('./src', import.meta.url))
'@': path.resolve(__dirname, './src')
},
// https://cn.vitejs.dev/config/#resolve-extensions
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue', '.svg']
},
build: {
manifest: true,
target: 'modules',
outDir: 'vue3', //指定输出路径
assetsDir: 'assets', // 指定生成静态资源的存放路径
minify: 'terser', // 混淆器,terser构建后文件体积更小
lib: {
name: 'lib',
entry: path.resolve(__dirname, 'src/main.js'),
formats: ['es'],
},
rollupOptions: {
input: 'src/main.js',
format: 'system',
preserveEntrySignatures: true
},
},
// 强制预构建插件包
optimizeDeps: {
// include: ['axios'],
},
rollupOptions: {
input: 'src/main.js',
format: 'system',
preserveEntrySignatures: true
},
server: {
port: 3002,
host: true,
open: true,
proxy: {
// https://cn.vitejs.dev/config/#server-proxy
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/api/, '')
}
}
},
//fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file
css: {
postcss: {
plugins: [
selectorNamespace({
namespace(css) {
/* 无需添加的样式 */
if (css.includes("element-variables.scss")) return "";
return "#app-vue3";
}
}),
require('autoprefixer')({
overrideBrowserslist: [
'Android 4.1',
'iOS 7.1',
'Chrome > 31',
'ff > 31',
'ie >= 8',
'> 1%',
],
grid: true,
}),
require('postcss-flexbugs-fixes'),
{
postcssPlugin: 'internal:charset-removal',
AtRule: {
charset: (atRule) => {
if (atRule.name === 'charset') {
atRule.remove();
}
}
}
}
]
}
}
}
}
)
main.js
import { createApp,h } from 'vue'
import { createPinia } from 'pinia'
import singleSpaVue from 'single-spa-vue'
import App from './App.vue'
import router from './router'
import './assets/main.css'
const app = createApp(App)
//
app.use(createPinia())
app.use(router)
if (!window.singleSpaNavigate) {
// delete vueOptions.el
app.mount('#app-vue3')
}
const vueLifecycles = singleSpaVue({
createApp,
appOptions: {
el: '#app-vue3',
render() {
return h(App, {
props: {
// single-spa props are available on the "this" object. Forward them to your component as needed.
// https://single-spa.js.org/docs/building-applications#lifecyle-props
name: this.name,
mountParcel: this.mountParcel,
singleSpa: this.singleSpa,
},
});
},
},
handleInstance: (app) => {
app.use(router);
app.use(createPinia())
}
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;
主项目
singleSpa.registerApplication({
name: "@org/vite-example",
app: () =>
import(
/* webpackIgnore: true */
//"http://localhost:3000/src/main.js"
"http://localhost:3002/vue3/src/main.js"
),
activeWhen: ["#/vue3"],
});