Wanted to use WebPack 5’s Module Federation feature, so decided to upgrade the existing VUE-CLI 4.x project.

Module Federation can be found on the official website. The main thing I want to use is component libraries as containers.

Remote App exports a component that the host app wants to use. It is important to note that the Host App is a sub-application that will be invoked online by the corresponding base project.

Upgrade procedure :(use vue-cli to complete the upgrade)

npm install -g @vue/cli@next
# OR
yarn global add @vue/cli@next
Copy the code
vue upgrade --next
Copy the code

The command line will have a series of prompts, follow the prompts to proceed. Upgrade completed after the start of the running code, as expected a bunch of errors.

  • Polyfill the Node module

    Webpack5 will no longer automatically add node polyfill to the path module. Resolve. Fallback will need to be added manually if this is used in our code.

    Resolve. Fallback can be updated in fallback. Make changes accordingly. Here we are using path, so modify webpack.config.js as follows:

    module.exports = {
        // ...
        resolve: {
            fallback: {
                path: require.resolve('path-browserify'),
                buffer: require.resolve(' ')}}// ...
    }
    Copy the code
  • PreloadPLugin abandoned

    Vue-cli 5.x is no longer configured with PreloadPLugin. Remove this configuration.

  • Url-loader /raw-loader/file-loader is no longer available. Asset Modules is used as the resource module.

  • Output no longer has jsonpFunction, instead chunkLoadingGlobal

  • Modified the wenpack-dev-server upgrade

    You can refer to changLog to change the corresponding fields.

    DisableHostCheck disableHostCheck: allowedHosts: “all”.

    Devserver discards before and replaces it with onBeforeSetupMiddleware

  • Another reason for this project was that the version numbers of core-js and HTML-webpack-plugin were written to the console, which caused an error. These two packages were removed and reinstalled. By now, all errors were resolved and the project ran perfectly.

  • Use of Module Federation

    To move on, we want to use the Module Federation configuration to modify webpack.config.js as follows

    // remote app config
    const {  ModuleFederationPlugin } = require('webpack').container
    module.exports = {
        // ...
        configureWebpack(config) {
            return {
              resolve: {
                alias: {
                  The '@': resolve('src'),},fallback: {
                  "path": require.resolve("path-browserify"),
                  "buffer": require.resolve("buffer"),}},plugins: [
                new ModuleFederationPlugin({
                 // name is globally unique
                  name: 'remote_sjms_customer'.filename: 'remoteEntry.js'.exposes: {
                      // Components that need to be exposed
                    './customerDialog': './src/views/customer/components/dialog-form.vue'}}}),]; },// ...
    }
    Copy the code

    After the operation, we can see the file to https://localhost:9091/remoteEntry.js.

    Then we started to configure webpack.config.js for the Host app

    // host app config
    const = __publicPath__ = process.env.NODE_ENV === 'development' ? ' ' : '/xxx/'
    module.exports = {
        publicPath: __publicPath__,
        configureWebpack: (config) = > {
            return {
                resolve: {
                    alias: {
                      The '@': resolve('src'),},// Webpack5 no longer automatically adds Node Polyfill
                    fallback: {
                      path: require.resolve('path-browserify'),
                      buffer: require.resolve('buffer'),}},output: {
                    libraryTarget: 'window'.library: packageObj.name,
                    // jsonpFunction is deprecated
                    chunkLoadingGlobal: `webpackJsonp_${packageObj.name}`,},plugins: [
                    new ModuleFederationPlugin({
                      name: 'host_customer'.filename: 'host_customer.js'.remotes: {
                         // The name of the remote is the same as that of the remote
                        'remote_sjms_customer': 'remote_sjms_customer@//localhost.longfor.com:9091/remoteEntry.js',},})]}}}/ / application
    import AddCompany from 'remote_sjms_customer/customerDialog'
    Copy the code

Everything was ready and ready to use. When we opened the Qiankun sub-application (host application) separately, the console reported error ScriptExternalLoadError: Loading Script failed.

However, the request for remoteentry.js can be seen in the Network.

I couldn’t find the corresponding script when I read the newspaper, so I went to the example on the official website and found the vuE-cli3-demo (ORIGINALLY I watched vue-CLI), but later I realized that the CLI had been upgraded to 5.x, so I should go to vue3 demo. We saw that the corresponding configuration set splitChunks to false, so we changed the configuration of our remote app

const {  ModuleFederationPlugin } = require('webpack').container
    module.exports = {
        // ...
        configureWebpack(config) {
            return {
              // VuE-CLI5 requires this configuration
              optimization: {
                  splitChunks: false,},resolve: {
                alias: {
                  The '@': resolve('src'),},fallback: {
                  "path": require.resolve("path-browserify"),
                  "buffer": require.resolve("buffer"),}},plugins: [
                new ModuleFederationPlugin({
                 // name is globally unique
                  name: 'remote_sjms_customer'.filename: 'remoteEntry.js'.exposes: {
                      // Components that need to be exposed
                    './customerDialog': './src/views/customer/components/dialog-form.vue'}}}),]; },// ...
Copy the code

Rerun our host project, and we have successfully seen the remote components we need loaded correctly. But our Host App is an qiankun sub-app that will be called by the base.

Then when we accessed the dock, the same error occurred:

As expected, it did not go so smoothly. With the experience of the error last time, I guess I still could not find the JS file loaded. Qiankun could do nothing more than sandbox mechanism, originally wanted to dynamically modify the value of __webpack_public_path__, but the manual modification did not take effect. The sandbox mechanism of Qiankun failed to find the remote_sjMS_customer module, so we needed to add the library configuration for ModuleFederationPlugin and modify the configuration of remote App as follows:

// remote app config
module.exports = {
    // ...
    configureWebpack(config) {
    return {
      optimization: {
        splitChunks: false,},// provide the app's title in webpack's name field, so that
      // it can be accessed in index.html to inject the correct title.
      name: APP_NAME,
      resolve: {
        alias: {
          The '@': resolve('src'),},fallback: {
          "path": require.resolve("path-browserify"),
          "buffer": require.resolve("buffer"),}},plugins: [
        new ModuleFederationPlugin({
          name: 'remote_sjms_customer'.filename: 'remoteEntry.js'.// Add library, make sure type is window
          library: { type: "window".name: "remote_sjms_customer" },
          exposes: {
            './customerDialog': './src/views/customer/components/dialog-form.vue'}}}),]; },// ...
}
Copy the code

The ModuleFederationPlugin defaults to {type: ‘var’, name: Name}, but here we need to expose the remote_sjMS_customer module globally, so change type to Window.

When accessed through the dock again, our remote components are shared, and we’re done