Need help with single-spa-vue and webpack5
r4m-davronu opened this issue · comments
Davron Usmonov commented
I have 2 applications for my single-spa
First application webpack.config.js:
{
mode: vars.webpackMode,
entry: options.webpackEntries,
experiments: {
outputModule: true,
},
output: {
path: path.resolve(options.appPath, buildDirectory, vars.publicSubDir),
publicPath: vars.publicPath,
filename: vars.prodBuild ? '[name].[contenthash:8].js' : 'js/[name].js',
module: true
},
cache: vars.prodBuild ? false : {
type: 'memory',
cacheUnaffected: true,
},
snapshot: {
managedPaths: [/^(.+?[\\/]node_modules)[\\/]((?!@route4me)).*[\\/]*/],
},
target: ['web', 'browserslist'],
externals: { ...options.webpackExternal },
resolve: {
alias: options.webpackAliases,
extensions: [
'.ts',
'.js',
'.vue',
'.json',
],
},
module: {
rules: [
// es
{
test: /\.m?js$/,
exclude(modulePath) {
const es6sourcesRegExpArray = [
/r4m-shared-ui[\\/]src/,
/node_modules[\\/]vuetify/,
];
if (es6sourcesRegExpArray.filter(es6path => es6path.test(modulePath)).length > 0) {
return false;
}
return /(node_modules|\.min\.)/.test(modulePath);
},
use: [
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
],
],
plugins: [
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-parameters',
],
cacheDirectory: true,
},
},
],
},
{
test: /\.(ts)$/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
allowTsInNodeModules: true,
context: path.resolve(options.appPath),
compilerOptions: {
outDir: path.resolve(options.appPath, buildDirectory, vars.publicSubDir),
},
},
},
// VUE
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loader: {
scss: 'vue-style-loader!css-loader!sass-loader',
},
},
},
// CSS & SCSS
{
test: /\.(css|scss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
require('autoprefixer'),
],
},
},
},
{
loader: 'sass-loader',
options: sassLoaderOptions,
},
],
},
// WOFF FONTS
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
options: {
name: vars.prodBuild ? '[name].[contenthash:8].[ext]' : '[name].[ext]',
outputPath: 'fonts/',
},
},
// IMAGES
{
test: /\.(png|svg|jpe?g|gif)$/,
loader: 'file-loader',
options: {
name: vars.prodBuild ? '[name].[hash].[ext]' : '[name].[ext]',
outputPath: 'img/',
// publicPath: 'img/', // don't override, it's ok for referencing from CSS/SCSS ONLY! Not JS/Vue!
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: vars.prodBuild ? '[name].[contenthash:8].css' : '[name].css',
// chunkFilename: vars.prodBuild ? '[id].[contenthash:8].css' : '[id].css',
}),
new VueLoaderPlugin({
optimizeSSR: false,
}),
new VuetifyLoaderPlugin(),
new AssetsPlugin({
path: path.resolve(options.appPath, 'storage', 'json'),
filename: 'assets.json',
prettyPrint: true,
entrypoints: true,
}),
vars.prodBuild && new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: path.resolve(options.appPath, 'bundle_report.html'),
openAnalyzer: false,
}),
vars.hmr ? new webpack.HotModuleReplacementPlugin() : undefined,
].filter(Boolean),
devtool: vars.prodBuild ? 'nosources-source-map' : 'eval-source-map',
devServer: {
static: {
directory: options.appPath,
},
devMiddleware: {
writeToDisk: true,
},
server: vars.wdsUrl.match(/https:/i) ? {
type: 'https',
options: {
cert: './ssl.crt',
key: './ssl.key',
},
} : false,
allowedHosts: "all",
port: vars.wdsPort,
compress: true,
client: {
overlay: false,
},
headers: {
'Access-Control-Allow-Origin': vars.appUrl,
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
'Access-Control-Allow-Credentials': 'true',
},
}
}
First application main.js:
const vueLifecycles = singleSpaVue({
Vue,
appOptions: {
render: (h) => h(App),
},
});
export const bootstrap = vueLifecycles.bootstrap;
export const mount = vueLifecycles.mount;
export const unmount = vueLifecycles.unmount;```
First application package.json:
{
"private": false,
"scripts": {
"start": "npm run serve",
"build": "webpack",
"serve": "webpack-dev-server",
"create_env_webpack": "echo \"No need\" && exit 0",
"test": "echo \"Error: no test specified\" && exit 1",
"translate": "node node_modules/r4m-shared-ui/src/utils/translate-json.js",
"lint": "eslint \"src/**/*.{js,vue}\" --fix"
},
"engines": {
"node": ">=14.0.0 <15.0.0",
"npm": ">=6.0.0 <7.0.0",
"yarn": "forbidden"
},
"author": "",
"license": "license.md",
"dependencies": {
"@mdi/font": "^5.9.55",
"@mdi/js": "^5.9.55",
"@vue/composition-api": "^1.7.2",
"axios": "^0.26.1",
"dayjs": "^1.11.10",
"laravel-echo": "^1.8.1",
"lodash": "^4.17.21",
"promise-polyfill": "^8.1.3",
"pusher-js": "^7.0.0",
"qs": "^6.9.4",
"single-spa": "^6.0.1",
"sweetalert2": "^8.16.3",
"systemjs-webpack-interop": "^2.3.7",
"throttle-debounce": "^5.0.0",
"vue": "2.6.14",
"vue-axios": "^2.1.5",
"vue-class-component": "^7.2.6",
"vue-i18n": "^8.28.2",
"vue-property-decorator": "^8.5.1",
"vue2-perfect-scrollbar": "^1.5.56",
"vuetify": "^2.1.9",
"ws": "^8.16.0"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.5.5",
"@types/lodash": "^4.14.150",
"@types/node": "^16.9.2",
"@types/throttle-debounce": "^5.0.2",
"@typescript-eslint/eslint-plugin": "^2.34.0",
"@typescript-eslint/parser": "^2.34.0",
"@vue/eslint-config-typescript": "^5.1.0",
"assets-webpack-plugin": "^7.1.1",
"autoprefixer": "^9.7.3",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"browserslist": "^4.23.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^2.1.1",
"css-minimizer-webpack-plugin": "^6.0.0",
"dotenv-flow": "^3.1.0",
"eslint": "^5.16.0",
"eslint-config-airbnb-base": "^13.2.0",
"eslint-config-vuetify": "^0.4.0",
"eslint-import-resolver-webpack": "^0.11.1",
"eslint-loader": "^2.2.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-vue": "^5.2.3",
"eslint-plugin-vuetify": "^1.0.0-beta.5",
"file-loader": "^4.2.0",
"fs": "0.0.1-security",
"html-webpack-plugin": "^5.6.0",
"mini-css-extract-plugin": "^0.7.0",
"node-fetch": "^2.6.7",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"sass": "~1.32.0",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"terser-webpack-plugin": "^5.3.10",
"ts-loader": "^9.5.1",
"typescript": "^4.9.5",
"url-loader": "^1.1.2",
"v-mask": "^2.3.0",
"vue-eslint-parser": "^6.0.4",
"vue-loader": "15.9.2",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "2.6.14",
"vuetify-loader": "1.5.0",
"webpack": "^5.90.3",
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.2"
},
"babel": {
"presets": [
"@babel/preset-env"
]
}
}
bootstrap, mount, unmount - exists on main.ts at all.
But when i add this application to single-spa like this:
<script type="systemjs-importmap">
{
"imports": {
...
"app1": "http://localhost:9000/js/app.js",
...
}
}
</script>
...
...
...
singleSpa.registerApplication(
'app1',
async () => {
const sc = await System.import('app1');
console.log('first application', sc)
return System.import('app1')
},
location => true
)
console returns me not Module, only error:
Uncaught app1: Application 'app1' died in status LOADING_SOURCE_CODE: "does not export an unmount function or array of functions"
Second application with boilerplate vue-cli works perfectly.
How to fix my application on webpack?
Davron Usmonov commented
Davron Usmonov commented
@joeldenning look please