Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need help with single-spa-vue and webpack5 #116

Open
r4m-davronu opened this issue May 2, 2024 · 2 comments
Open

Need help with single-spa-vue and webpack5 #116

r4m-davronu opened this issue May 2, 2024 · 2 comments

Comments

@r4m-davronu
Copy link

r4m-davronu commented May 2, 2024

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?

@r4m-davronu
Copy link
Author

image
look at screen (don't pay attention to the app name)

@r4m-davronu
Copy link
Author

@joeldenning look please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant