<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valor-software-tech</title>
    <description>The latest articles on DEV Community by Valor-software-tech (@valorsoftwaretech).</description>
    <link>https://dev.to/valorsoftwaretech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F596621%2Fc77055d9-9be2-4474-922c-bc94bfaeec1f.jpg</url>
      <title>DEV Community: Valor-software-tech</title>
      <link>https://dev.to/valorsoftwaretech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/valorsoftwaretech"/>
    <language>en</language>
    <item>
      <title>Medusa Resources Overlimit in Realtime Notification</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Fri, 06 Jan 2023 18:03:24 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/medusa-resources-overlimit-in-realtime-notification-1ee4</link>
      <guid>https://dev.to/valorsoftwaretech/medusa-resources-overlimit-in-realtime-notification-1ee4</guid>
      <description>&lt;p&gt;&lt;strong&gt;Medusa Dashboard&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue
&lt;/h2&gt;

&lt;p&gt;**&lt;br&gt;
A user has a "Free Subscription" price plan with some limited resource usage. Currently, it looks like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F511tcvucwmr87szaw6yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F511tcvucwmr87szaw6yw.png" alt="Image description" width="478" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Let’s play with builds now.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user builds his application on his own (an application is connected to Medusa via tokens and medusa-plugin), &lt;strong&gt;medusa-plugin&lt;/strong&gt; makes an API call to Medusa Server with a request to update application builds inside Medusa Dashboard, it creates some records in the database and you can manage and use those builds in the Dashboard then.&lt;br&gt;
At the current moment, we don’t have any restrictions for build amount and usage according to the Price Plan so users can easily get a quote over the limit like for usage of 130 builds with 100 builds in the Plan.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s1658ys900t1l02z2ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1s1658ys900t1l02z2ub.png" alt="Image description" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The task sounds like "&lt;strong&gt;Restrict overlimit usage of Medusa Resources according to Quota&lt;/strong&gt;". Sounds like a five-minute task, just insert a checker before business logic. If the check is positive – go further, if negative – stop action.&lt;br&gt;
Okay, it’s done. Even works. But there’s another issue – it will look for a User like a bug. No… like &lt;strong&gt;a BUG&lt;/strong&gt;. As all things, described above, are under-the-hood processes, the user cannot know at that moment that he got overlimit, so we have to notify the user somehow in some way. &lt;/p&gt;

&lt;p&gt;We don’t have any real-time solutions implemented inside yet, so it seems that, easy from first sight, the task becomes a task of implementing real-time technology. Okay, what do we know about it? Web Sockets – cool, but they are unidirectional, we do not need them. In addition, we might have an issue if the load balancer doesn’t support WebSockets (like a basic AWS Load Balancer).&lt;/p&gt;

&lt;h2&gt;
  
  
  What else?
&lt;/h2&gt;

&lt;p&gt;SSE – Server-Sent-Events. Technology, which might cover a lot of cases where people use WebSockets. In addition, it brings less headache with integration as it uses HTTP protocol only. &lt;br&gt;
Some words of difference between WebSockets and SSE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Okay, we said it, we did it!&lt;/strong&gt;&lt;br&gt;
On the Back End side, we use NestJS, Front End is NextJS (for a non-native speaker, it’s quite difficult and funny to try to pronounce them instantly one by one :) ).&lt;/p&gt;

&lt;p&gt;Let’s start. NestJS documentation has some words about the implementation of SSE. So it looks easy to do, it has simple examples, and it works… But in our case, not always and not everywhere.&lt;/p&gt;

&lt;p&gt;There are a few issues I have faced during implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 1
&lt;/h2&gt;

&lt;p&gt;An example in NestJS documentation is related to &lt;code&gt;interval&lt;/code&gt; usage and sends messages once a second. We do not need that way, we need to send messages at the moment we want, and only to users whom this message concerns. &lt;br&gt;
So we had to alter the event emitter to send messages only at that moment we need. &lt;br&gt;
It was done.&lt;/p&gt;

&lt;p&gt;@Injectable()&lt;br&gt;
export class ServerEventsService {&lt;br&gt;
 private readonly emitter: EventEmitter;&lt;/p&gt;

&lt;p&gt;constructor() {&lt;br&gt;
   this.emitter = new EventEmitter();&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;subscribe(userId: string): Observable {&lt;br&gt;
   return fromEvent(this.emitter, userId);&lt;br&gt;
 }&lt;/p&gt;

&lt;p&gt;emit(userId: string, data?: SseEventMessage): void {&lt;br&gt;
   this.emitter.emit(userId, { data });&lt;br&gt;
 }&lt;br&gt;
}&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 2
&lt;/h2&gt;

&lt;p&gt;As we are using NextJS, it means that most pages are SSR (Server Side Rendered). That means, in addition, that we cannot create the EventSource instance anywhere we want. So we have to initialize the eventsource after the component has been rendered in the browser. &lt;/p&gt;

&lt;p&gt;Firstly, we need to receive messages and show them globally, it should not be related to a certain page. Another thing is how to make it work in our case of SSR.&lt;/p&gt;

&lt;p&gt;We just need to do that in &lt;code&gt;useEffect&lt;/code&gt;, to make it start working in a Browser already. So we created a Global Modal with some inputs, integrated our solution and it worked. Cool, we are so happy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue 3
&lt;/h2&gt;

&lt;p&gt;Our solution worked well in the case of real-time processes, but what if Medusa Dashboard was closed? We need to notify a user that he has some issues with using Medusa because of quota overlimit. Easy, just make a check. The thing is that we need to make an async call in useEffect and linter tells us that we are incorrect with that decision… But, there’s a workaround. We need to wrap the async function into the self-invoking unnamed function. &lt;/p&gt;

&lt;p&gt;(async () =&amp;gt; {&lt;br&gt;
  await task();&lt;br&gt;
})();&lt;/p&gt;

&lt;p&gt;Issue 4&lt;br&gt;
It’s a bad thing to have a checker on the Back End side for the under-the-hood process and the same checker on the Front End side, so on a Front End we just make an API call without using a response. On the server side, we check all related data, and in case the checker responds negatively, we emit a new message from Server to UI.&lt;br&gt;
But it didn’t work.&lt;/p&gt;

&lt;p&gt;Under-the-hood things emitted the message from one controller, check by demand the emitted message from another controller. &lt;/p&gt;

&lt;p&gt;What is the issue? Why doesn't it work? I’m emitting a message, and it emits but the UI doesn't get it…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;I checked if my emitters have listeners. One of them had one, and another one – did not. &lt;br&gt;
Whaaat?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have created an SSE Service and injected that as a provider into the App Module, then into another Module. It’s not directly said anywhere in the documentation that by doing things in this way, we will get different multiple instances of Services. Hmmm… Okay. &lt;br&gt;
Creating a separate module with a separate service, then injecting modules into other modules – saved me… The Next JS modules are Singletons, so now I have only one instance of the SSE part and really can use this service everywhere in the Server and emit messages to a certain channel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvppk2rx6mev2mtny6fu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvppk2rx6mev2mtny6fu3.png" alt="Image description" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it. We have integrated SSE into the System, it works great and this is a base to develop that further.&lt;/p&gt;

&lt;p&gt;Now we can notify a user if something is happening under the hood and the user should be aware of it. Great!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://t2674704.p.clickup-attachments.com/t2674704/186d6f2b-3b58-49c4-8e93-7db736b0ab5e/medusa_sse.mp4?view=open" rel="noopener noreferrer"&gt;WATCH ME&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Video Plan:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Who we are and what we are doing? What do we need now? What is the issue? What are we going to do and how are we going to resolve this?****&lt;/p&gt;

&lt;p&gt;We are Valor Software, an international company, created by the Developer for Developers. &lt;br&gt;
We are fans and sponsors of NestJS and NativeScript and do a lot of awesome things by ourselves, like ngx-bootstrap, and a current one called Medusa. &lt;br&gt;
Medusa is a kind of Dashboard and management system for Module Federation. With Medusa, you can finally have visibility into your Module Federation-powered applications. See what versions are deployed, their underlying dependencies and relationships, and which teams are committing to them. That’s in general about Medusa evolving all the time, development moving further and further.&lt;/p&gt;

&lt;p&gt;Today we have to resolve the following thing:&lt;/p&gt;

&lt;p&gt;When a user is building his connected application on his own, medusa-plugin makes an API call to Medusa Dashboard with the request to update application builds inside Medusa Dashboard, it does some logic and creates a few records in the database so then you can manage and use those builds in the Dashboard then.&lt;br&gt;
At the current moment, we don’t have any restrictions for builds' amount and usage according to the Price Plan so users can easily get a quote over the limit, like for using 130 builds with 100 builds limit in the Plan.&lt;/p&gt;

&lt;p&gt;The task sounds like "&lt;strong&gt;Restrict overlimit usage of Medusa Resources according to Quota&lt;/strong&gt;". Sounds like a five-minute task, just insert a checker before business logic. If the check is positive – go further, if negative – stop action.&lt;br&gt;
&lt;strong&gt;2. Add a checker&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;3. Add Stripe data to the checker to check the user payment method&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;4. Add a checker for quotas&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;5. Make it reusable&lt;/strong&gt;&lt;br&gt;
Okay, it’s done. Even works. But there’s another issue – it will look for the User like a bug. No… like &lt;strong&gt;a BUG&lt;/strong&gt;. As all things, described above, are under-the-hood processes, the user cannot know at that moment that he got overlimit, so we have to notify the user somehow in some way. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Add SSE Service, tell that it should be a Singleton as it’s important and nobody tells that.&lt;/strong&gt;&lt;br&gt;
We don’t have any real-time solutions implemented inside yet, so it seems that, easy from first sight, the task becomes a task of implementing real-time technology. Okay, what do we know about it? Web Sockets – cool, but they are unidirectional, we do not need them. In addition, we might have an issue if the load balancer doesn’t support WebSockets (like a basic AWS Load Balancer).&lt;br&gt;
&lt;strong&gt;What else?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SSE – Server-Sent-Events. Technology, which might cover a lot of cases where people use WebSockets. In addition, it brings less headache with integration as it uses HTTP protocol only. &lt;br&gt;
Some words of difference between WebSockets and SSE.&lt;/p&gt;

&lt;p&gt;On the Back End side, we use NestJS, Front End is NextJS (for a non-native speaker, it’s quite difficult and funny to try to pronounce them instantly one by one :) ).&lt;/p&gt;

&lt;p&gt;Let’s start. NestJS documentation has some words about the implementation of SSE. So it looks easy to do, and it has simple examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Say that the EventSource listener should be fully FE and as we use NextJS – should be in useEffect.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;8. Check that it works, and set the channel based on UserId.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;9. Check that it works for app builds and on login, remove redundant code.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>Module Federation in mobile apps powered by NativeScript</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Fri, 06 Jan 2023 16:56:49 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/module-federation-in-mobile-apps-powered-by-nativescript-5id</link>
      <guid>https://dev.to/valorsoftwaretech/module-federation-in-mobile-apps-powered-by-nativescript-5id</guid>
      <description>&lt;p&gt;Module federation has been one of the most popular topics in development lately. People love the way it allows teams to develop applications independently and integrate them all into a single final application. While that seems good for the web, how could Module Federation look in a mobile native application?&lt;/p&gt;

&lt;p&gt;Let’s get the elephant out of the room first. The whole point of module federation is that teams can deploy their applications independently, but native apps have their bundles and code shipped holistically with the app. Even if they didn’t, having the user wait or be unable to load your app in bad or no connectivity would lead to terrible UX. Before going down this path, you need careful thought and a really good reason.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KV10hqRc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9j14b9kljgx9qjij4pr6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KV10hqRc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9j14b9kljgx9qjij4pr6.gif" alt="Image description" width="480" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let’s start with a use case. One of our large enterprise clients has a WYSIWYG editor for NativeScript, complete with their own native components library. They have their own SSO and app “shell” that is common to all of their apps, but their users are able to customize the content, including pushing changes only to specific screens. To generate this they needed to be able to generate bundles dynamically and push them to the application so they could easily switch between apps, and update only the user’s bundle.&lt;/p&gt;

&lt;p&gt;This application highlights one of the beauties of NativeScript. The users don’t need to have knowledge of native code at all, and if they need to extend something, they can do it directly in JavaScript or TypeScript, while also allowing them to add native code once they feel like they need it.&lt;/p&gt;

&lt;p&gt;Now back to the application. This was initially built before bundlers were widely used, and once bundlers became the norm, it became a tricky situation where they’d need to map the available modules and override the require functions to provide the user code with the expected module. A mess. Enter Webpack Module Federation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exposing an application&lt;/strong&gt;&lt;br&gt;
For this example, I’ve decided to use Angular as it’s one of the frameworks officially supported by NativeScript. So first we create our app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, NgModule, NO_ERRORS_SCHEMA } from "@angular/core";
import { RouterModule } from "@angular/router";
import { NativeScriptCommonModule } from "@nativescript/angular";
import { timer } from "rxjs";

@Component({
  template: `&amp;lt;Label&amp;gt;Hello from wmf! Here's a counter: {{ timer | async }}&amp;lt;/Label&amp;gt;`,
})
export class MyComponent {
  timer = timer(0, 1000);
}

@NgModule({
  declarations: [MyComponent],
  imports: [NativeScriptCommonModule, RouterModule.forChild([{ path: "", component: MyComponent }])],
  schemas: [NO_ERRORS_SCHEMA]
})
export class FederatedModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we’ll need to download all the JS files anyway, for testing purposes I’ve made it all compile to a single chunk and discard the non-remote entrypoint. To do this I used the default NativeScript webpack config and augmented with a few details to build it directly to my current app’s assets directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webpack = require("@nativescript/webpack");
const coreWebpack = require('webpack');
const path = require(`path`);
const NoEmitPlugin = require('no-emit-webpack-plugin');

module.exports = (env) =&amp;gt; {
  webpack.init(env);

  const packageJson = require('./package.json');

  // Learn how to customize:
  // &amp;lt;https://docs.nativescript.org/webpack&amp;gt;

  webpack.chainWebpack((config, env) =&amp;gt; {
    config.entryPoints.clear();
    config.resolve.alias.set('~', path.join(__dirname, 'federated-src'));
    config.resolve.alias.set('@', path.join(__dirname, 'federated-src'));
    config.plugins.delete('CopyWebpackPlugin');
    config.output.path(path.join(__dirname, 'src', 'assets'));
    config.optimization.runtimeChunk(true);
    config.module.delete('bundle');
    config.plugin('NoEmitPlugin').use(NoEmitPlugin, ['dummy.js']);
    config.plugin('MaxChunks').use(coreWebpack.optimize.LimitChunkCountPlugin, [{ maxChunks: 1 }]);
    config.plugin('WebpackModuleFederationPlugin').use(coreWebpack.container.ModuleFederationPlugin, [{
      name: 'federated',
      exposes: {
        './federated.module': './federated-src/federated.module.ts'
      },
      library: {
        type: 'commonjs'
      },
      shared: {
        '@nativescript/core': { eager: true, singleton: true, requiredVersion: "*", import: false },
        '@nativescript/angular': { eager: true, singleton: true, requiredVersion: "*", import: false },
        '@angular/core': { eager: true, singleton: true, requiredVersion: "*", import: false },
        '@angular/router': { eager: true, singleton: true, requiredVersion: "*", import: false },      }
    }]);
  });

  const config = webpack.resolveConfig();
  config.entry = { 'dummy': './federated-src/federated.module.ts' };
  return config;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Loading the remote entrypoint&lt;/strong&gt;&lt;br&gt;
One of the tricky parts of this whole process is that we can’t download the app piece by piece, as underneath we’re using commonjs (node’s require) to evaluate and load the modules into memory. To do this we need to download all of the output into the application and then we can load it.&lt;br&gt;
As a POC, we can start with a simple remote configuration which allows us to load the entrypoint as a normal module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// federated webpack config
{
  name: 'federated',
  exposes: {
    './federated.module': './federated-src/federated.module.ts'
  },
  library: {
    type: 'commonjs'
  },
}

// host config

{
  remoteType: "commonjs",
  remotes: {
    "federated": "~/assets/federated.js"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the import it as a route like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  path: 'federated', loadChildren: () =&amp;gt;  import('federated/federated.module').then((m) =&amp;gt; m.FederatedModule),
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, we’d have to have all the federated modules shipped in the final application, so to load things dynamically, we should instead use the following code to load arbitrary entrypoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// &amp;lt;reference path="../../node_modules/webpack/module.d.ts" /&amp;gt;

type Factory = () =&amp;gt; any;
type ShareScope = typeof __webpack_share_scopes__[string];

interface Container {
  init(shareScope: ShareScope): void;

  get(module: string): Factory;
}

export enum FileType {
  Component = "Component",
  Module = "Module",
  Css = "CSS",
  Html = "Html",
}

export interface LoadRemoteFileOptions {
  // actual file being imported
  remoteEntry: string;
  // used as a "key" to store the file in the cache
  remoteName: string;
  // what file to import
  // must match the "exposes" property of the federated bundle
  // Example:
  // exposes: {'.': './file.ts', './otherFile': './some/path/otherFile.ts'}
  // calling this function with '.' will import './file.ts'
  // calling this function with './otherFile' will import './some/path/otherFile.ts'
  exposedFile: string;
  // mostly unused for the moment, just use Module
  // can be used in the future to change how to load specific files
  exposeFileType: FileType;
}

export class MfeUtil {
  // holds list of loaded script
  private fileMap: Record&amp;lt;string, boolean&amp;gt; = {};
  private moduleMap: Record&amp;lt;string, Container&amp;gt; = {};

  findExposedModule = async &amp;lt;T&amp;gt;(
    uniqueName: string,
    exposedFile: string
  ): Promise&amp;lt;T | undefined&amp;gt; =&amp;gt; {
    let Module: T | undefined;
    // Initializes the shared scope. Fills it with known provided modules from this build and all remotes
    await __webpack_init_sharing__("default");
    const container = this.moduleMap[uniqueName];
    // Initialize the container, it may provide shared modules
    await container.init(__webpack_share_scopes__.default);
    const factory = await container.get(exposedFile);
    Module = factory();
    return Module;
  };

  public loadRootFromFile(filePath: string) {
    return this.loadRemoteFile({
      exposedFile: ".",
      exposeFileType: FileType.Module,
      remoteEntry: filePath,
      remoteName: filePath,
    });
  }

  public loadRemoteFile = async (
    loadRemoteModuleOptions: LoadRemoteFileOptions
  ): Promise&amp;lt;any&amp;gt; =&amp;gt; {
    await this.loadRemoteEntry(
      loadRemoteModuleOptions.remoteEntry,
      loadRemoteModuleOptions.remoteName
    );
    return await this.findExposedModule&amp;lt;any&amp;gt;(
      loadRemoteModuleOptions.remoteName,
      loadRemoteModuleOptions.exposedFile
    );
  };

  private loadRemoteEntry = async (
    remoteEntry: string,
    uniqueName?: string
  ): Promise&amp;lt;void&amp;gt; =&amp;gt; {
    return new Promise&amp;lt;void&amp;gt;((resolve, reject) =&amp;gt; {
      if (this.fileMap[remoteEntry]) {
        resolve();
        return;
      }

      this.fileMap[remoteEntry] = true;

      const required = __non_webpack_require__(remoteEntry);
      this.moduleMap[uniqueName] = required as Container;
      resolve();
      return;
    });
  };
}

export const moduleFederationImporter = new MfeUtil();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;export const moduleFederationImporter = new MfeUtil();&lt;br&gt;
This code is able to load any .js file on the device, so it can be used in conjunction with a download strategy to download the files and then load them dynamically. For example, we can first download the full file, and then load it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 path: "federated",
 loadChildren: async () =&amp;gt; {
   const file = await Http.getFile('http://127.0.0.1:3000/federated.js');

   return (await moduleFederationImporter
     .loadRemoteFile({
       exposedFile: "./federated.module",
       exposeFileType: FileType.Module,
       remoteEntry: file.path,
       remoteName: "federated",
     })).FederatedModule;
 },
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, we could also download it as a zip and extract, or you could, theoretically, override the way that webpack loads the chunks in the federated module to download them piece by piece as needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sharing the common modules&lt;/strong&gt;&lt;br&gt;
The complexity of sharing modules cannot be understated. The initial Webpack Module Federation PR (&lt;a href="https://github.com/webpack/webpack/pull/10838"&gt;https://github.com/webpack/webpack/pull/10838&lt;/a&gt;) that provided the full container and consumer API is smaller then the PR that introduced version shared dependencies (&lt;a href="https://github.com/webpack/webpack/pull/10960"&gt;https://github.com/webpack/webpack/pull/10960&lt;/a&gt;).&lt;br&gt;
A native app is not just a webpage, but the full browser itself. While the web provides a lot of APIs directly, NativeScript provides a lot of them through the @nativescript/core package so that’s one dependency that has to be a singleton and we can’t under any circumstance have multiple versions of it. In this example we’re also using angular, so let’s share that as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shared: {
  '@nativescript/core': { eager: true, singleton: true, requiredVersion: "*" },
  '@nativescript/angular': { eager: true, singleton: true, requiredVersion: "*" },
  '@angular/core': { eager: true, singleton: true, requiredVersion: "*" },
  '@angular/router': { eager: true, singleton: true, requiredVersion: "*" },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we also share them as eager, since those packages are critical to the bootstrap of the application. For example, @nativescript/core is responsible for calling UIApplicationMain on iOS, so if you fail to call it, the app will instantly close.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;br&gt;
First, we create a simple standalone component that will show a Label and a nested page which will be loaded asynchronous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, NO_ERRORS_SCHEMA } from "@angular/core";
import {
 NativeScriptCommonModule,
 NativeScriptRouterModule,
} from "@nativescript/angular";

@Component({
 standalone: true,
 template: `&amp;lt;StackLayout&amp;gt;
   &amp;lt;Label&amp;gt;Hello from standalone component&amp;lt;/Label&amp;gt;
   &amp;lt;GridLayout&amp;gt;&amp;lt;page-router-outlet&amp;gt;&amp;lt;/page-router-outlet&amp;gt;&amp;lt;/GridLayout&amp;gt;
 &amp;lt;/StackLayout&amp;gt;`,
 schemas: [NO_ERRORS_SCHEMA],
 imports: [NativeScriptCommonModule, NativeScriptRouterModule],
})
export class ShellComponent {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Then we can define the Federated Module:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
 template: `&amp;lt;Label&amp;gt;Hello from wmf! Here's a counter: {{ timer | async }}&amp;lt;/Label&amp;gt;`,
})
export class MyComponent {
 timer = timer(0, 1000);
}

@NgModule({
 declarations: [MyComponent],
 imports: [NativeScriptCommonModule, RouterModule.forChild([{ path: "", component: MyComponent }])],
 schemas: [NO_ERRORS_SCHEMA]
})
export class FederatedModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;And finally, we can setup the routing:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NgModule } from "@angular/core";
import { Routes } from "@angular/router";
import { NativeScriptRouterModule } from "@nativescript/angular";
import { FileType, moduleFederationImporter } from "./mfe.utils";
import { Http } from "@nativescript/core";
import { ShellComponent } from "./shell.component";

const routes: Routes = [
 { path: "", redirectTo: "/shell", pathMatch: "full" },
 {
   path: "shell",
   component: ShellComponent,
   loadChildren: async () =&amp;gt; {
     const file = await Http.getFile("http://127.0.0.1:3000/federated.js");

     return (
       await moduleFederationImporter.loadRemoteFile({
         exposedFile: "./federated.module",
         exposeFileType: FileType.Module,
         remoteEntry: file.path,
         remoteName: "federated",
       })
     ).FederatedModule;
   },
 },
];

@NgModule({
 imports: [NativeScriptRouterModule.forRoot(routes), ShellComponent],
 exports: [NativeScriptRouterModule],
})
export class AppRoutingModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Which results in the following screen, fully working module federation in NativeScript!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N5UI3_E4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xy3zmwu46pr4xh3avfry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N5UI3_E4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xy3zmwu46pr4xh3avfry.png" alt="Image description" width="880" height="1906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br&gt;
Although Module Federations is still limited on the native application side, we’re already exploring possibilities on how to import modules from the web directly, instead of having to download them manually, giving it first class support and allowing full code splitted remote modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const entry = await import('https://example.com/remoteEntry.js');
entry.get(...)
// entry magically fetches https://example.com/chunk.0.js if needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Module Federation is very promising for creating distribution of efforts and on demand releases without having to go through the pain of constant app store approval processes. While not for everyone it is a very exciting opportunity for large teams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need help?&lt;/strong&gt;&lt;br&gt;
Valor Software is both an official partner of both the NativeScript organization and Module Federation organization. If you're looking at using Module Federation with your NativeScript application and would like some help. Reach out to our team, &lt;a href="mailto:sales@valor-software.com"&gt;sales@valor-software.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nativescript</category>
      <category>modulefederatio</category>
      <category>mobile</category>
      <category>valorsoftware</category>
    </item>
    <item>
      <title>Nx, Next.js, and Module Federation</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Wed, 20 Jul 2022 20:50:00 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/nx-nextjs-and-module-federation-40mp</link>
      <guid>https://dev.to/valorsoftwaretech/nx-nextjs-and-module-federation-40mp</guid>
      <description>&lt;p&gt;&lt;strong&gt;Table of Contents:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;About the author&lt;/li&gt;
&lt;li&gt;Micro Frontends, Nx, and monorepos&lt;/li&gt;
&lt;li&gt;Next.js, Nx + Next.js&lt;/li&gt;
&lt;li&gt;Module Federation, Next.js + Module Federation&lt;/li&gt;
&lt;li&gt;Starting the project&lt;/li&gt;
&lt;li&gt;Generating new pages and new applications&lt;/li&gt;
&lt;li&gt;Running in the development environment&lt;/li&gt;
&lt;li&gt;Generating new components&lt;/li&gt;
&lt;li&gt;Installing nextjs-mf&lt;/li&gt;
&lt;li&gt;Creating hooks&lt;/li&gt;
&lt;li&gt;Deploying projects on Vercel + private dependencies with Vercel&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The author
&lt;/h2&gt;

&lt;p&gt;Bruno Silva, the Next.js developer of Valor Software with the team's support, has created the solution described below and this material which was originally published on the &lt;a href="https://valor-software.com/articles^" rel="noopener noreferrer"&gt;Valor's blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The article is also available in Portuguese: &lt;a href="https://valor-software.com/articles/nx-next-js-e-module-federation" rel="noopener noreferrer"&gt;https://valor-software.com/articles/nx-next-js-e-module-federation&lt;/a&gt;. Enjoy the reading and the dev experience :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Micro Frontends
&lt;/h2&gt;

&lt;p&gt;You’ve probably heard about microservices and the number of benefits they bring to both the scalability of a backend application and the team that develops it. Now imagine if these same advantages could be brought to the frontend. Well, that’s what we’re going to talk about today.&lt;br&gt;
First, let’s talk about what a micro frontend is and what are its benefits. Micro frontends are a way to organize both an application and the team that develops it. Think about the following: a web application is usually composed of several resources, and depending on the size of the application it depends on certain synchrony between the teams that develop it so that new versions are released for production. Let’s take an example: Imagine that we have an online course sales website and that website has the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Institutional page (landing page/marketing)&lt;/li&gt;
&lt;li&gt;Catalog / advanced search&lt;/li&gt;
&lt;li&gt;Checkout&lt;/li&gt;
&lt;li&gt;Courses player page&lt;/li&gt;
&lt;li&gt;Upload page&lt;/li&gt;
&lt;li&gt;Forum (for students to interact with tutors)&lt;/li&gt;
&lt;li&gt;Account Settings pages (for students and tutors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine that each of these features can be easily split into microservices when it comes to the backend, but most of the time the frontend ends up being a kind of “monolith” containing a single stack and forcing the entire team to stay in sync at all times. that a new feature goes into production. Can you see this? Clearly, we could split each part of this eCommerce into distinct applications for smaller teams with unique responsibilities and possibly different stacks. Think about it, the team responsible for the checkout could work 100% focused on improving the user’s shopping experience flow, reducing noise that made them give up on the purchase, or for example the catalog and institutional team (landing page) that could work on different marketing fronts, as well as the team responsible for the video area of the platform, which would be focused on ensuring speed / high quality in the delivery of classes to students.&lt;/p&gt;

&lt;p&gt;Anyway, there are many examples that we could cite about the use of micro frontends, but as the purpose of this article is to be a little more practical, let’s skip this part and if you are more interested in understanding the advantages of using micro frontends, I suggest you read more about it in &lt;a href="https://micro-frontends.org/^" rel="noopener noreferrer"&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Nx and monorepos
&lt;/h2&gt;

&lt;p&gt;Well, as we saw earlier it is possible to divide some web applications into microfrontends which, initially, may bring you some questions such as: “But then I need to divide all applications into separate repositories? Imagine the headache it will be to test all this!” and that’s where we’ll talk about mono repositories. Mono repository or Monorepo is a single git repository that seeks to manage all the source code of an application, this brings us a series of advantages and some disadvantages, here are some of them:&lt;/p&gt;
&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Standardization (lint) of the code for the entire team&lt;/li&gt;
&lt;li&gt;Test management in one place&lt;/li&gt;
&lt;li&gt;Centralization of dependency management&lt;/li&gt;
&lt;li&gt;Code reuse between applications due to dependency centralization&lt;/li&gt;
&lt;li&gt;Transparency as we can see all code from a single workspace&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;.git folder can end up getting big due to a high number of contributions, because the whole team is contributing commits in the same project&lt;/li&gt;
&lt;li&gt;Increase of build time of some applications depending on the dependency level and size of shared files/data&lt;/li&gt;
&lt;li&gt;No permission granularity, since the entire team needs to have access to the monorepo, the power to restrict the access of certain users to certain parts of the application is lost Looking at the benefits and the context, I saw that it would be an excellent opportunity to use Nx as a manager for our project. &lt;a href="https://nx.dev/^" rel="noopener noreferrer"&gt;Nx&lt;/a&gt; is a monorepo manager with a huge range of &lt;a href="https://nx.dev/community#create-nx-plugin^" rel="noopener noreferrer"&gt;plugins&lt;/a&gt; to facilitate the creation of new applications, libraries, tests, build execution, lint standardization, centralization, dependency management, and many other features.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Next.js
&lt;/h2&gt;

&lt;p&gt;It is indisputable that currently &lt;a href="https://nextjs.org/^" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; is one of the web frameworks that has been gaining more and more adoption in recent times and all this is due to the range of features such as server-side rendering, static optimization, file-system routing, API routes and &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/overview^" rel="noopener noreferrer"&gt;data-fetching&lt;/a&gt; strategies he proposes. Next.js is an awesome tool, but we’ll assume you already know it and skip to the next part.&lt;/p&gt;
&lt;h2&gt;
  
  
  Nx + Next.js
&lt;/h2&gt;

&lt;p&gt;According to the Nx team, their development philosophy is very similar to Visual Studio Code’s, in which they focus on maintaining a powerful and generic tool, while extensions, or plugins, are fundamental for increasing your productivity with it. As such, &lt;a href="https://nx.dev/packages/next^" rel="noopener noreferrer"&gt;@nrwl/next&lt;/a&gt; is the plugin that we will use to create and manage our applications with Next.js within our Nx workspace.&lt;/p&gt;
&lt;h2&gt;
  
  
  Module Federation
&lt;/h2&gt;

&lt;p&gt;Module Federation is a &lt;a href="https://webpack.js.org/concepts/module-federation^" rel="noopener noreferrer"&gt;Webpack 5&lt;/a&gt; feature that has arrived to make it possible to share parts of an application to another at runtime. This makes it possible for multiple applications compiled with webpack to repurpose parts of their code as the user interacts with them, which takes us to the next step.&lt;/p&gt;
&lt;h2&gt;
  
  
  Next.js + Module Federation
&lt;/h2&gt;

&lt;p&gt;Let’s start with our first example of this article where we talk about an eCommerce application, now imagine that our marketing team decides to create a mega Black Friday campaign and decides to change several parts of our application by inserting different components with dynamic banners, carousels, countdowns, themed offers, etc… this would probably be a headache for all teams responsible for our microfrontend applications since each one would have to implement the new requirements of the marketing team in their projects and that would have to be very well tested and synchronized so that everything went right and nothing could be released ahead of time… Anyway, all this could easily generate a lot of work and a lot of headache for the team, but that’s where the very powerful Module Federation comes in.&lt;/p&gt;

&lt;p&gt;Thanks to it, only one team would be in responsible for developing the new components along with their respective logic, and the rest of the team would only be responsible for implementing the use of these new complements, which could bring with them, hooks, components in React, among others.&lt;/p&gt;

&lt;p&gt;Unfortunately, implementing and using the Module Federation features of Webpack with Next.js is not that easy, as you would need to deeply understand how both tools work to be able to create a solution that facilitates the integration between the two. Fortunately, there is already a solution and has several features including support for SSR (server-side rendering), these tools are called &lt;a href="https://app.privjs.com/package?pkg=@module-federation/nextjs-mf^" rel="noopener noreferrer"&gt;nextjs-mf&lt;/a&gt; and &lt;a href="https://app.privjs.com/package?pkg=@module-federation/nextjs-ssr^" rel="noopener noreferrer"&gt;nextjs-ssr&lt;/a&gt; and together we are going to explore a proof-of-concept application that I created to show you the power of these tools together.&lt;/p&gt;

&lt;p&gt;⚠️ Attention: for the application to work with Module Federation features you need to have access to the &lt;a href="https://app.privjs.com/package?pkg=@module-federation/nextjs-mf^" rel="noopener noreferrer"&gt;nextjs-mf &lt;/a&gt;or &lt;a href="https://app.privjs.com/package?pkg=@module-federation/nextjs-ssr^" rel="noopener noreferrer"&gt;nextjs-ssr&lt;/a&gt; plugin which currently requires a paid license!&lt;/p&gt;
&lt;h2&gt;
  
  
  About the project
&lt;/h2&gt;

&lt;p&gt;This project will show, how to create the basis for a fully scalable application both in production and in development. In it, we will see some small examples of how the tools mentioned above can be used.&lt;/p&gt;
&lt;h2&gt;
  
  
  Starting the project
&lt;/h2&gt;

&lt;p&gt;Initially, we will need to install Nx in our environment to handle the commands needed to manage our monorepo. To do this, open a terminal and run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm i -g nx&lt;/code&gt;&lt;br&gt;
Once this is done, navigate to a directory where you want to create the project and run the command below, this command will use &lt;a href="https://nx.dev/packages/next^" rel="noopener noreferrer"&gt;@nrwl/next&lt;/a&gt; to create our workspace (monorepo) and our first application:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-nx-workspace@latest --preset=next&lt;/code&gt;&lt;br&gt;
An interactive terminal will guide you through the creation process, you can follow as I did below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9du1gec1x52pkfqgl8y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi9du1gec1x52pkfqgl8y.png" alt="Terminal guide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once this is done, you must wait for the workspace (monorepo) to be created and the project’s dependencies to be downloaded after that you can open vscode in the workspace root, in my case:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;code ./nextjs-nx-module-federation&lt;/code&gt;&lt;br&gt;
Looking at the file explorer you can see that the project has a structure similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── apps
│   ├── store (...)
│   └── store-e2e (...)
├── babel.config.json
├── jest.config.ts
├── jest.preset.js
├── libs
├── nx.json
├── package.json
├── package-lock.json
├── README.md
├── tools
│   ├── generators (...)
│   └── tsconfig.tools.json
├── tsconfig.base.json
└── workspace.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ℹ️ Note that our application in Next.js is inside the "apps" folder, this folder will contain all the other applications you are going to create, we can also see other configuration files of our workspace. It is important to note that there is only one "node_modules" folder in the entire project, this happens because all dependencies will be in one place, at the root of the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating new pages
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://nx.dev/packages/next^" rel="noopener noreferrer"&gt;@nrwl/next plugin&lt;/a&gt; has several &lt;a href="https://nx.dev/packages/next#generators^" rel="noopener noreferrer"&gt;generators&lt;/a&gt;, and commands that serve to automate the creation of pages, components, and other common structures in the project.&lt;/p&gt;

&lt;p&gt;Knowing this we will create our first page using a generator called "page" for this run the following command in the terminal&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx g @nrwl/next:page home --project=store&lt;/code&gt;&lt;br&gt;
ℹ️ Note that we use the --project flag to indicate to the generator in which project the new page should be created.&lt;/p&gt;

&lt;p&gt;This will generate a page called "home" which will be located at&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apps/store/pages/home/index.tsx&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating new applications
&lt;/h2&gt;

&lt;p&gt;Now we will need to create another application, which we will call "checkout". Unlike the first application we created together with the workspace, we will need to use the following command to create a new Next.js application in the current workspace:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx g @nrwl/next:app checkout&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Your "apps" folder should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── apps
│   ├── checkout (...)
│   ├── checkout-e2e (...)
│   ├── store (...)
│   └── store-e2e (...)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running in the development environment
&lt;/h2&gt;

&lt;p&gt;To see our changes running, we will need to run the following command in the terminal:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx serve store&lt;/code&gt;&lt;br&gt;
ℹ️ serve is an executor command&lt;/p&gt;

&lt;p&gt;Also, we can run all applications at the same time using:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx run-many --target=serve --all&lt;/code&gt;&lt;br&gt;
ℹ️ Note that we use the --target flag to indicate to nx which executor we want to run on all projects.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generating new components
&lt;/h2&gt;

&lt;p&gt;As we saw earlier, we have the possibility to create structures in our application using the Nx CLI tool, now we are going to create a simple button component in the "checkout" project, that execute the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx g @nrwl/next:component buy-button --project=checkout&lt;/code&gt;&lt;br&gt;
Now let’s edit the component in the directory below so that it looks like &lt;a href="https://github.com/BrunoS3D/nextjs-nx-module-federation/blob/main/apps/checkout/components/buy-button/buy-button.tsx^" rel="noopener noreferrer"&gt;this&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;apps/checkout/components/buy-button/buy-button.tsx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We’ll use this simple app "checkout" component in the app "store" to exemplify code sharing with Module Federation and that takes us to the next step.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing nextjs-mf
&lt;/h2&gt;

&lt;p&gt;⚠️ Attention: for the application to work with Module Federation features you need to have access to the &lt;a href="https://app.privjs.com/package?pkg=@module-federation/nextjs-mf%5B%5Bnextjs-ssr%5E" rel="noopener noreferrer"&gt;https://app.privjs.com/package?pkg=@module-federation/nextjs-mf[[nextjs-ssr^&lt;/a&gt;] plugin which currently requires a paid license!&lt;/p&gt;

&lt;p&gt;To install the tool, we need to login to [PrivJs}(&lt;a href="https://privjs.com/%5E" rel="noopener noreferrer"&gt;https://privjs.com/^&lt;/a&gt;) using npm, to do so, run the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm login --registry &amp;lt;https://r.privjs.com&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once this is done a file containing your credentials will be saved in ~/.npmrc. Now you can install nextjs-mf using the command below:&lt;br&gt;
npm install @module-federation/nextjs-mf --registry &lt;a href="https://r.privjs.com^" rel="noopener noreferrer"&gt;https://r.privjs.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will need to modify our "next.config.js" file in both projects so that the installed plugin can work, for that open the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;apps/store/next.config.js&lt;/li&gt;
&lt;li&gt;apps/checkout/next.config.js You will see that in them we have an Nx plugin being used, we will need to maintain it, for that, make the files of each project similar to these:&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/BrunoS3D/nextjs-nx-module-federation/blob/b20485c501c8c8353aca9b7a2b0bbf376c43348d/apps/store/next.config.js^" rel="noopener noreferrer"&gt;store/next.config.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/BrunoS3D/nextjs-nx-module-federation/blob/b20485c501c8c8353aca9b7a2b0bbf376c43348d/apps/checkout/next.config.js^" rel="noopener noreferrer"&gt;checkout/next.config.js&lt;/a&gt; You will notice that we have two environment variables being used in this file, we will need to define them in each project so create a ".env.development.local" file in each project and leave each file with the following values:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NEXT_PUBLIC_CHECKOUT_URL=http://localhost:4200
NEXT_PUBLIC_STORE_URL=http://localhost:4300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So far no new changes can be noticed, but we can already use the Module Federation resources, but before that, we will make some modifications in our development environment so that applications can communicate without generating warnings in the console by local port collision, to this open and edit the following files:&lt;/p&gt;

&lt;p&gt;"apps/store/project.json"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  // ...
  "targets": {
    // ...
    "serve": {
      // ...
      "options": {
        "buildTarget": "checkout:build",
        "dev": true,
        "port": 4300
      },
      // ...
    },
    // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"apps/checkout/project.json"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  // ...
  "targets": {
    // ...
    "serve": {
      // ...
      "options": {
        "buildTarget": "checkout:build",
        "dev": true,
        "port": 4200
      },
      // ...
    },
    // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order for the component to be federated, we must add it to the "next.config.js" file, open the file and add a new entry in the "exposes" object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = withFederatedSidecar({
  // ...
  exposes: {
    './buy-button': './components/buy-button/buy-button.tsx',
  },
  // ...
})(nxNextConfig);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now with everything configured, we must restart any next process that is running and we are going to import the button component that we created in the "checkout" project in the "store" project using the Module Federation resources, for that open the "home" page that we created in the "store" project and import the Next.js &lt;a href="https://nextjs.org/docs/advanced-features/dynamic-import^" rel="noopener noreferrer"&gt;dynamic&lt;/a&gt; function as shown below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;import dynamic from 'next/dynamic';&lt;/code&gt;&lt;br&gt;
This function will help us to import the component only on the client-side, so add the following code snippet on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const BuyButton = dynamic(
  async () =&amp;gt; import('checkout/buy-button'),
  {
    ssr: false,
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we can use the component in the page content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function Page() {
  return (
    &amp;lt;div className={styles['container']}&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to Store!&amp;lt;/h1&amp;gt;
      &amp;lt;BuyButton onClick={() =&amp;gt; alert('Hello, Module Federation!')}&amp;gt;Add to Cart&amp;lt;/BuyButton&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see the following result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7c1c2wsu8gf2y0xjles.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7c1c2wsu8gf2y0xjles.png" alt="Welcome to store!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating hooks
&lt;/h2&gt;

&lt;p&gt;One of the powers of nextjs-mf is the federation of functions, including hooks. An important detail is that we cannot import hooks asynchronously, which leads us to adopt a solution where we import functions using "require" and the page or component that uses the hook being loaded lazily/asynchronously, what we call "top-level-await".&lt;/p&gt;

&lt;p&gt;First, we will need to create a hook, for that, we are going to make a simple state function. Create a file in the "checkout" app in "apps/checkout/hooks/useAddToCart.ts" and insert the code below in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from 'react';

export default function useAddToCartHook() {
  const [itemsCount, setItemsCount] = useState&amp;lt;number&amp;gt;(0);
  return {
    itemsCount,
    addToCart: () =&amp;gt; setItemsCount((i) =&amp;gt; i + 1),
    clearCart: () =&amp;gt; setItemsCount(0),
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is done, add the file to the list of modules exposed in the "next.config.js" file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = withFederatedSidecar({
  // ...
  exposes: {
    './buy-button': './components/buy-button/buy-button.tsx',
        './useAddToCartHook': './hooks/useAddToCart.ts'
  },
  // ...
})(nxNextConfig);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To import the hook, let’s create a new page that will be imported asynchronously, for that create a new folder in the store app called async-pages. Create a custom-hook.tsx file that will be our page inside the async-pages folder, then add the following code to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// typing for the hook
type UseAddToCartHookType = () =&amp;gt; UseAddToCartHookResultType;

// hook function return typing
type UseAddToCartHookResultType = {
  itemsCount: number;
  addToCart: () =&amp;gt; void;
  clearCart: () =&amp;gt; void;
};

// hook default value
let useAddToCartHook = (() =&amp;gt; ({})) as UseAddToCartHookType;

// import the hook only on the client-side
if (process.browser) {
  useAddToCartHook = require('checkout/useAddToCartHook').default;
}

export function Page() {
    // on server side extracts the values as undefined
    // on the client side extracts the hook values
  const { itemsCount, addToCart, clearCart } =
    useAddToCartHook() as UseAddToCartHookResultType;

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to Custom Hook!&amp;lt;/h1&amp;gt;

      &amp;lt;p&amp;gt;
        Item Count: &amp;lt;strong&amp;gt;{itemsCount}&amp;lt;/strong&amp;gt;
      &amp;lt;/p&amp;gt;
      &amp;lt;button onClick={addToCart}&amp;gt;Add to Cart&amp;lt;/button&amp;gt;
      &amp;lt;button onClick={clearCart}&amp;gt;Clear Cart&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// here you can use the getInitialProps function normally
// it will be called on both server-side and client-side
Page.getInitialProps = async (/*ctx*/) =&amp;gt; {
  return {};
};

export default Page;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to create a page in the "pages" folder that loads our page asynchronously, for that use the command below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nx g @nrwl/next:page custom-hook --project=store&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now open the newly created page file and add the following code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import dynamic from 'next/dynamic';
import type { NextPage, NextPageContext } from 'next';

// import functions from page in synchronously way
const page = import('../../async-pages/custom-hook');

// lazy import the page component
const Page = dynamic(
  () =&amp;gt; import('../../async-pages/custom-hook')
) as NextPage;

Page.getInitialProps = async (ctx: NextPageContext) =&amp;gt; {
    // capture the getInitialProps function from the page
  const getInitialProps = ((await page).default as NextPage)?.getInitialProps;
  if (getInitialProps) {
        // if the function exists, call the function on server-side and client-side
    return getInitialProps(ctx);
  }
  return {};
};

export default Page;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can see the following result&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o8lkw4ca2la8dsfcds7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o8lkw4ca2la8dsfcds7.gif" alt="Welcome to cutom hook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some errors at the time of writing this article may be occurring, so if in doubt, consider looking at &lt;a href="https://github.com/BrunoS3D/nextjs-nx-module-federation^" rel="noopener noreferrer"&gt;this project&lt;/a&gt; I created as a proof of concept, I’m actively working with Zackary to make it up to date and functional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying projects on Vercel
&lt;/h2&gt;

&lt;p&gt;The procedure that we are going to perform now will be done at &lt;a href="https://vercel.com/^" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;, but we can replicate it without much difficulty on other serverless hosting platforms such as &lt;a href="https://www.netlify.com/^" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;, &lt;a href="https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/^" rel="noopener noreferrer"&gt;AWS Amplify&lt;/a&gt;, and Serverless with a &lt;a href="https://www.serverless.com/plugins/serverless-nextjs-plugin^" rel="noopener noreferrer"&gt;plugin&lt;/a&gt; for Next.js or even in a &lt;a href="https://en.wikipedia.org/wiki/Self-hosting_(web_services)^" rel="noopener noreferrer"&gt;self-hosted&lt;/a&gt; way using Docker with a private server.&lt;br&gt;
We can carry out the process in two ways: by &lt;a href="https://vercel.com/new^" rel="noopener noreferrer"&gt;interface&lt;/a&gt; or by &lt;a href="https://vercel.com/cli^" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;, but to facilitate the process we will do it by the interface, you just need to host the project on GitHub so that we can import it in a few clicks, once the project is on &lt;a href="https://github.com/^" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; you can open &lt;a href="https://vercel.com/new^" rel="noopener noreferrer"&gt;this page&lt;/a&gt; on Vercel to deploy the first application… exactly, although it’s a monorepo, we’re going to configure everything so that separate deployments are made.&lt;/p&gt;

&lt;p&gt;First, we will deploy the "checkout" app because it has fewer dependencies, for that select the repository as in the following image and click on the button to import it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqwl98xwxolxj9bc3bqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnqwl98xwxolxj9bc3bqf.png" alt="Import Git repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose a name for the application on the screen that opens but remember that we are still going to do the same step for the app "store" so define a different name for each project. We must change some commands for the project build in the "Build and Output Settings" tab, for this, check the override option and leave the fields as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe18xb4kiwi0vqzzwlhwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe18xb4kiwi0vqzzwlhwf.png" alt="Build output settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build command (checkout)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx nx build checkout --prod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Output directory (checkout)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dist/apps/checkout/.next&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For now, let’s skip the environment variables section, as we don’t have the URLs where the applications will be hosted, we can click on the "Deploy" button. You may notice that we may have an error during the build, but don’t worry if that happens, we’ll solve this soon. Now we are going to deploy our app "store" and we are going to do the same steps as before, just changing some fields on the "Build and Output Settings" tab. Build command (store)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx nx build store --prod&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Output directory (store)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dist/apps/store/.next&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once that’s done, we can click on the "Deploy" button. Again, you’ll notice that the build resulted in an error, but that doesn’t matter, the important thing is that we now have the two URLs of the two projects and we can use them to configure our environment. Now go to the settings panel of each application and set the following environment variables&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyba9ztsmao1ph70udcja.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyba9ztsmao1ph70udcja.png" alt="Environment variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that I am using a URL of the “deployment” that I made of my app store, you must do it with the URL that Vercel generated for yours, remember to define the two environment variables "NEXT_PUBLIC_CHECKOUT_URL" and "NEXT_PUBLIC_STORE_URL" each with its respective URL of production.&lt;/p&gt;
&lt;h2&gt;
  
  
  Private dependencies with Vercel
&lt;/h2&gt;

&lt;p&gt;If you open the project build logs, you will notice that in both the error is the same, probably something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm ERR! 403 403 Forbidden - GET &amp;lt;https://r.privjs.com/@module-federation%2fnextjs-mf/-/nextjs-mf-3.5.0.tgz&amp;gt; - You must be logged in to install/publish packages.
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy, or
npm ERR! 403 on a server you do not have access to.
npm ERR! A complete log of this run can be found in:
npm ERR!     /vercel/.npm/_logs/2022-06-24T21_11_19_939Z-debug-0.log
Error: Command "npm install" exited with 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This happens because Vercel does not have the necessary credentials to access a package that is in a private repository, to give access to the repository we need to configure an environment variable called "NPM_RC", the value of this variable must be the same as what is inside the "~/.npmrc" file which was created when we used the "npm login" command.&lt;/p&gt;

&lt;p&gt;To do so, just create a new variable in Vercel’s environment variables settings panel called "NPM_RC" and insert the entire contents of the "~/.npmrc" file, if you have any doubts read &lt;a href="https://vercel.com/support/articles/using-private-dependencies-with-vercel^" rel="noopener noreferrer"&gt;this document&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, you can open the “Deployments” tab and “Redeploy” your application!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dhmqkct5r51odyn2ijk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dhmqkct5r51odyn2ijk.png" alt="deployments redeploy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigating to the application "store" URL you can see the button whose source code is in the "checkout" project being "federated" to our site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.thoughtworks.com/radar/techniques/micro-frontends^" rel="noopener noreferrer"&gt;Thoughtworks - Micro frontends&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/localizalabs/module-federation-o-futuro-do-microfrontend-4fed87983ec2^" rel="noopener noreferrer"&gt;Module Federation — O futuro do microfrontend&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://micro-frontends.org/^" rel="noopener noreferrer"&gt;What are Micro Frontends?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-ei6RqZilYI^" rel="noopener noreferrer"&gt;Webpack 5 Module Federation - Zack Jackson - CityJS Conf 2020&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://betterprogramming.pub/the-pros-and-cons-monorepos-explained-f86c998392e1^" rel="noopener noreferrer"&gt;The Pros and Cons of Monorepos, Explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/module-federation/module-federation-examples/tree/master/nextjs^" rel="noopener noreferrer"&gt;Next.js with Module Federation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/support/articles/using-private-dependencies-with-vercel^" rel="noopener noreferrer"&gt;How do I use private dependencies with Vercel?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nx.dev/packages/next^" rel="noopener noreferrer"&gt;Nx with Next.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>modulefederation</category>
      <category>nx</category>
      <category>microfrontends</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Debugging NgRx in NativeScript with Redux DevTools</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Wed, 08 Jun 2022 11:33:00 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/debugging-ngrx-in-nativescript-with-redux-devtools-50fg</link>
      <guid>https://dev.to/valorsoftwaretech/debugging-ngrx-in-nativescript-with-redux-devtools-50fg</guid>
      <description>&lt;p&gt;The solution and the story were kindly provided by Eduardo Speroni, a NativeScript developer at Valor Software, a talented open-source activist and contributor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rmu28gHM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yi6njstpjdr6kehx754u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rmu28gHM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yi6njstpjdr6kehx754u.png" alt="Image description" width="592" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intro&lt;/strong&gt;&lt;br&gt;
NgRx needs practically no introduction in the current state of Angular applications. It allows you to manage your app’s state easily and make your UI react to the changes seamlessly. This tool is not exclusively for the web, so we can expect many NativeScript Angular applications to use it quite extensively.&lt;/p&gt;

&lt;p&gt;Although NgRx is amazing, it still adds certain complexity to your application that is often harder to debug. For such cases, using Redux DevTools becomes indispensable in the debugging process, as it allows you to have a clear view of your state and how it changes over time. Those features, alongside time travel and custom action dispatch, make it a very powerful tool.&lt;/p&gt;

&lt;p&gt;Many stacks have to implement their own way of integrating NgRx with Redux DevTools, for example, with Ionic, as Zack Barbuto describes in &lt;a href="https://medium.com/nextfaze/remote-debugging-ngrx-store-with-ionic-74e367316193"&gt;his article about remote debugging&lt;/a&gt;. Also, thanks to our recent efforts on &lt;a&gt;WebSockets for NativeScript&lt;/a&gt; (find the creation story &lt;a href="https://valor-software.com/articles/implementing-websockets-plugin-for-nativescript.html"&gt;on the blog&lt;/a&gt;) and the chain webpack configuration added in @nativescript/webpack 5+, you can debug NgRx in NativeScript with ease. In this article I’ll tell you about our implementation details and how you can start using it right away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Table of Contents:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Intro&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connecting Redux DevTools with NgRx for NativeScript&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overriding the way NgRx fetches the Redux extension implementation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nativescript-ngrx-devtools plugin: features review&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to use the Plugin, steps to reproduce for debugging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Caveats&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Useful Links&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Connecting Redux DevTools with NgRx for NativeScript&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;NgRx relies on the Redux DevTools Extension to be defined in the window and implement a specific (and relatively simple) interface. Redux Remote DevTools provides an option to connect to it remotely through SocketCluster, which uses WebSockets. Thankfully, we can now use &lt;a href="https://www.npmjs.com/package/@valor/nativescript-websockets"&gt;the WebSockets plugin&lt;/a&gt; to polyfill them.&lt;/p&gt;

&lt;p&gt;This approach is not new, and part of our implementation can be credited to &lt;a href="https://github.com/zalmoxisus"&gt;Zalmoxis&lt;/a&gt; and &lt;a href="https://github.com/zalmoxisus/remotedev"&gt;his remote debugging method&lt;/a&gt;. Not all node or browser libraries support NativeScript, but we can make most of them work with it. Since NS isn’t either “node” or “browser” but a combination of multiple APIs common to both, libraries that support both platforms might be usable here. SocketCluster is one of those libraries that work perfectly with NativeScript as long as we use the browser implementation. As a result, we implemented &lt;a href="https://github.com/valor-software/nativescript-plugins/blob/3e6bb3ae819b697e78f299e1c2f891b15944316f/packages/nativescript-ngrx-devtools/package-alias-plugin.js"&gt;a custom way&lt;/a&gt; of reading &lt;a href="https://github.com/defunctzombie/package-browser-field-spec"&gt;the browser field spec&lt;/a&gt;, which is also nicely &lt;a href="https://docs.npmjs.com/cli/v8/configuring-npm/package-json#browser"&gt;described on npm&lt;/a&gt; and applied the required file substitutions individually for the required libraries. This means we can now use the web version of SocketCluster freely in our implementation without fear that it’ll break existing applications.&lt;/p&gt;

&lt;p&gt;Taking inspiration from previously mentioned implementations of the extension interface, we built our own interface focusing on reliability and small footprint. This was done by converting it fully to RxJS, adding error handling, retrying failed connections, trying to connect to multiple default debugging IPs periodically, and making it all highly configurable. The result was a robust bridge between your application and the remote Redux DevTools so that you can focus less on the details and more on developing your application faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overriding the Way NgRx Fetches the Redux Extension Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once we finished writing the Redux DevTools Extension interface, we needed to provide it to NgRx. Unfortunately, NgRx gets this information from the [‘&lt;strong&gt;REDUX_DEVTOOLS_EXTENSION&lt;/strong&gt;’] window, which isn’t available in NativeScript. Polyfilling “window” is not the best approach either, as it could also lead to unintended side effects due to many libraries checking if a window exists to determine if they’re running in a browser environment or not. With &lt;a href="https://github.com/ngrx/platform/pull/3338"&gt;a PR to NgRx&lt;/a&gt;, we were able to export the required symbol to override the way NgRx fetches the extension implementation.&lt;/p&gt;

&lt;p&gt;As a side note, this change isn’t retroactive, but the plugin code has a workaround for cases when this symbol is not defined, so you can use it with older versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nativescript-ngrx-devtools Plugin: Features Review&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below is the overview of key plugin features, so you get to know it better before the installation.&lt;/p&gt;

&lt;p&gt;The beginning of work with the plugin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gXkzw6xh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amekp2rwrru1xbg7j7fw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gXkzw6xh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/amekp2rwrru1xbg7j7fw.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plugin replays the state after skipping actions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YvNW0_6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8k91hyvmvekn9dcoj1zz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YvNW0_6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8k91hyvmvekn9dcoj1zz.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qN4eVJuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d82ddgi02n93si15qns2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qN4eVJuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d82ddgi02n93si15qns2.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;br&gt;
The increment with delay:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lMR7XbOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zynzurc6gaywe2vcapyt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lMR7XbOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zynzurc6gaywe2vcapyt.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;br&gt;
Dispatching a custom action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qcHWdVfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc3cws113lqrff21abl9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qcHWdVfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc3cws113lqrff21abl9.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Use the Plugin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To start using the plugin, first ensure to install both: it and our WebSockets Polyfill:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://market.nativescript.org/plugins/@valor/nativescript-ngrx-devtools/"&gt;npm i @valor/nativescript-ngrx-devtools&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@valor/nativescript-websockets"&gt;@valor/nativescript-websockets&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your polyfills.ts, ensure that websockets is properly polyfilled after nativescript’s globals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * NativeScript Polyfills
 */
// Install @nativescript/core polyfills (XHR, setTimeout, requestAnimationFrame)
import '@nativescript/core/globals';
import '@valor/nativescript-websockets'; // add this line!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then import the modules of your application and start using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@NgModule({
 imports: [
   NativeScriptModule,
   StoreModule.forRoot(
     {
       counter: reducer,
     },
     {
       initialState: {
         counter: initialState,
       },
     }
   ),
   ...(__DEV__ ? [ // ensure this code is tree shaken in prod
         StoreDevtoolsModule.instrument(), 
         NativeScriptNgRxDevtoolsModule.forRoot()
      ] : []),

 ],
 declarations: [AppComponent],
 bootstrap: [AppComponent],
 schemas: [NO_ERRORS_SCHEMA],
})
export class AppModule {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the plugin will attempt to connect to many IP addresses that NativeScript automatically detects from &lt;strong&gt;NS_DEV_HOST_IPS&lt;/strong&gt; on port 8000, but those can be configured in the options object in NativeScriptNgRxDevtoolsModule.forRoot(options).&lt;/p&gt;

&lt;p&gt;After configuring our remote devtools, you can just start debugging!&lt;/p&gt;

&lt;p&gt;Steps to Reproduce for Debugging:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;npm i -g @redux-devtools/cli‍&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Then&lt;br&gt;
‍&lt;br&gt;
&lt;code&gt;redux-devtools — open‍&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open ‘Settings’ in the redux-devtools UI and ensure ‘connect local’ is checked and you’re going to use port 8000 which is default, then save those settings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run a NativeScript app and start debugging.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Caveats&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Redux DevTools already has a couple of caveats on the web, like having it crash by storing certain kinds of non-serializable objects. This also applies to NativeScript, and the fact that ignoring those caveats can also crash your app makes them even worse. Here’s an example from one of the projects we’re working on now. When testing the plugin on a large mobile app that has modals with high-definition images, we noticed that the app would crash due to a memory lack. The issue was that the action that was sent to the DevTools, contained a reference to the modal itself, so it was never garbage collected, and every time it opened, the memory would increase. Connecting to the DevTools also made the app take a performance hit as it was trying to serialize massive objects.&lt;/p&gt;

&lt;p&gt;The solution, in this case, is to use actionSanitizer and stateSanitizer to make sure your state and actions contain only serializable data.&lt;/p&gt;

&lt;p&gt;How it works with the plugin:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b7MvOedj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bv33ot98haojxrl215jp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b7MvOedj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bv33ot98haojxrl215jp.gif" alt="Image description" width="880" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Find more on this topic from the &lt;a href="https://dev.to/migsarnavarro/use-sanitizers-to-avoid-redux-devtools-crash-67p"&gt;Use sanitizers to avoid Redux Devtools crash&lt;/a&gt; article by Migzar Navarro and the &lt;a href="https://v7.ngrx.io/guide/store-devtools/config"&gt;NgRx official guide&lt;/a&gt;. Also worth mentioning that it’s critical to ensure you’re using webpack flags, not to bundle the DevTools in production. As they have a memory overhead you don’t want in production apps.&lt;/p&gt;

&lt;p&gt;That’s all I wanted to tell in this article. Hope, it was useful, and you’ll enjoy using the plugin!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@valor/nativescript-websockets"&gt;nativescript-websockets&lt;/a&gt; plugin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@valor/nativescript-ngrx-devtools"&gt;nativescript-ngrx-devtools&lt;/a&gt; plugin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/valor-software/nativescript-plugins/blob/3e6bb3ae819b697e78f299e1c2f891b15944316f/packages/nativescript-ngrx-devtools/package-alias-plugin.js"&gt;package-alias-plugin.js&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://medium.com/nextfaze/remote-debugging-ngrx-store-with-ionic-74e367316193"&gt;Remote Debugging @ngrx/store with Ionic&lt;/a&gt; article by Zack Barbuto&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/zalmoxisus/remotedev"&gt;Remote debugging method&lt;/a&gt; by Zalmoxis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.npmjs.com/cli/v8/configuring-npm/package-json#browser"&gt;Configuring npm — package-json&lt;/a&gt; documentation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/defunctzombie/package-browser-field-spec"&gt;The browser field when packaging modules for client side use&lt;/a&gt; spec&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ngrx</category>
      <category>ns</category>
      <category>nativescript</category>
      <category>redux</category>
    </item>
    <item>
      <title>Performance Testing via Artillery.io - user guide</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Wed, 09 Mar 2022 12:33:50 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/performance-testing-via-artilleryio-user-guide-3pod</link>
      <guid>https://dev.to/valorsoftwaretech/performance-testing-via-artilleryio-user-guide-3pod</guid>
      <description>&lt;p&gt;Valor's Head of QA Dmitry has shared his experience using Artillery.io including tips and tricks for beginners. The following story is on his behalf, and the original material was published on &lt;a href="https://valor-software.com/articles/performance-testing-via-artillery-io.html"&gt;the company's blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Today, I’m going to tell you all about setting up and using &lt;a href="https://artillery.io/"&gt;Artillery.io&lt;/a&gt; on your projects. We have a lot of popular testing tools like JMeter, Gatling, LoadNinja, etc. So you might be wondering why I’ve chosen Artillery. Well, I’m going to show its advantages and share handy usage tips later in the article.&lt;br&gt;
‍&lt;br&gt;
‌Artillery.io is a modern performance testing software that is powerful yet quite simple to navigate. It suits different types of performance testing, on local machines and as part of &lt;a href="https://en.wikipedia.org/wiki/Continuous_integration"&gt;CI&lt;/a&gt;. What’s even better? – Artillery provides &lt;a href="https://www.artillery.io/pricing"&gt;a free ‘Dev’ option&lt;/a&gt; if you want to test the waters before diving in. So, let's make some exploration!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Artillery.io?
&lt;/h2&gt;

&lt;p&gt;Artillery offers many services that make performance and load testing faster and more reliable. Now let me outline a few reasons why I choose to use it over the better-known software.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Node.js tool&lt;br&gt;
Java-based tools can be complicated and time-consuming to work with. Artillery.io is a Node.js tool with a basic СLI, which is a far simpler way to run performance tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Broad support of protocols, frameworks, and libraries&lt;br&gt;
Out of the box, Artillery.io will support:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.artillery.io/docs/guides/guides/http-reference"&gt;HTTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.artillery.io/docs/guides/guides/socketio-reference"&gt;Socket.IO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.artillery.io/docs/guides/guides/ws-reference"&gt;WebSocket&lt;/a&gt;&lt;br&gt;
However, you can use Artillery.io to test any stack, thanks to the plugin interface. Here are a few examples:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apache Kafka&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon Kinesis&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.artillery.io/docs/guides/plugins/plugin-hls"&gt;HLS&lt;/a&gt; (HTTP Live Streaming)‌&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;YAML format&lt;br&gt;
Unlike popular competitors’ testing tools, Artillery.io writes tests in YAML format which makes them readable and easy to understand. Artillery also supports a JSON format for testing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Accessible scenarios&lt;br&gt;
With Artillery's scenarios and phases, you can build more flexible tests and cover multiple use cases in parallel. Also, it takes you just a few steps and conditions to set up tests for complex user behaviours. Finally, it's easy to reuse scenarios for comparison and future testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easy integration&lt;br&gt;
Artillery.io seamlessly integrates with CI (for example, check &lt;a href="https://artillery.io/docs/guides/integration-guides/github-actions.html"&gt;the integration guide for GitHub Actions&lt;/a&gt;), making the process very organized. It also &lt;a href="https://artillery.io/docs/guides/guides/docker.html"&gt;works with Docker&lt;/a&gt;, so you can run your Artillery tests inside a Docker container.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detailed reports&lt;br&gt;
After running tests, you can create a JSON report through the --output flag. Also, you can generate an HTML report out of JSON to save it as a file or export it to your browser. Find details on reporting in the Scenario section below.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Artillery Docs&lt;br&gt;
Artillery provides &lt;a href="https://artillery.io/docs/guides/overview/welcome.html"&gt;numerous documents&lt;/a&gt; to browse for instructions and other useful info. This helps you get the performance testing software up and running much smoother than with other similar tools. Also, you can look up support from other developers on &lt;a href="https://github.com/artilleryio/artillery/discussions"&gt;community forums&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G4EldFc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s88f6p7zky1ap20j7xn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G4EldFc8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s88f6p7zky1ap20j7xn6.png" alt="Image description" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How does Artillery.io work?
&lt;/h2&gt;

&lt;p&gt;I’m going to walk you through some basic commands to get started with Artillery.io using &lt;a href="https://valor-software.com/ngx-bootstrap/#/"&gt;ngx-bootstrap&lt;/a&gt; in my examples. Ngx-bootstrap, together with other community libraries, were created by &lt;a href="https://valor-software.com/"&gt;Valor Software&lt;/a&gt;, the company where I’m working. And as we have hundreds of thousands of engineers using our products monthly, we need scalable performance testing to make sure everything runs smoothly. So, let’s get started!&lt;/p&gt;

&lt;p&gt;First, you need to install the latest version of the software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;
To install the latest version, enter:&lt;br&gt;
&lt;code&gt;npm install -g artillery@latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fast test&lt;/strong&gt;&lt;br&gt;
To run a fast test, enter:&lt;br&gt;
&lt;code&gt;artillery quick --count 15 -n 30 https://valor-software.com/ngx-bootstrap/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With this command, the test will run 15 virtual users with each of them making 30 HTTP GET requests to the URL address that you specified.‌&lt;/p&gt;

&lt;p&gt;This command also supports other flags to configure your fast tests:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A8_pv_-T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/geb82bf05wunp49f870w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A8_pv_-T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/geb82bf05wunp49f870w.png" alt="Image description" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is a list of possible configurations of the run command:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--24MbYuZH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l4ttiuprlhrqhv3cehs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--24MbYuZH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l4ttiuprlhrqhv3cehs5.png" alt="Image description" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Config&lt;br&gt;
For standard test scenarios, you should create a ‘my.yml’ file with config.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ABLASPq9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k6gigbngiodg0n69k125.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ABLASPq9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k6gigbngiodg0n69k125.png" alt="Image description" width="880" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The my.yml file should contain ‘config:’ paired with the target URL. To set up environments for your tests, you can write environments into the command after the target URL has been entered.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6IbKX9lv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kff05qltnvm7vfuuqmjd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6IbKX9lv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kff05qltnvm7vfuuqmjd.png" alt="Image description" width="880" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phases in the config&lt;/strong&gt;&lt;br&gt;
Artillery.io allows you to enter multiple sequential load options for the application. The testing phase consists of several aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;duration: the time of one phase;&lt;/li&gt;
&lt;li&gt;arrivalRate: the number of users added each second;&lt;/li&gt;
&lt;li&gt;rampTo: up to how many users per second the load will grow by;&lt;/li&gt;
&lt;li&gt;name: a name of the phases.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r1h9WOaE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/diagwqenw78jk2wu7qex.png" alt="Image description" width="880" height="450"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only have one target URL, the different phases of the performance testing are placed right after it. If there are multiple environments, then you should add phases to each environment variable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plugins&lt;/strong&gt;&lt;br&gt;
In the Artillery npm utility, you can find &lt;a href="https://www.npmjs.com/search?q=artillery-plugin-&amp;amp;page=0&amp;amp;perPage=20"&gt;lots of plugins&lt;/a&gt; that can help you in your performance testing. Install &lt;a href="https://www.npmjs.com/package/artillery-plugin-expect"&gt;artillery-plugin-expect&lt;/a&gt; to compare the expected result with the actually received result.&lt;/p&gt;

&lt;p&gt;Then, after the phases inside the config, enter:&lt;br&gt;
&lt;code&gt;plugins:&lt;br&gt;
   expect: {}&lt;/code&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V-d2uhoI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5bue1uwi6g93oalkwn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V-d2uhoI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5bue1uwi6g93oalkwn6.png" alt="Image description" width="880" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, with the config completed, we can finally write some tests!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;br&gt;
All tests should be written in the &lt;code&gt;scenarios&lt;/code&gt; section and should contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET, POST, PUT, DELETE, and some other commands;&lt;/li&gt;
&lt;li&gt;a URL for every endpoint;&lt;/li&gt;
&lt;li&gt;the body text in JSON format;&lt;/li&gt;
&lt;li&gt;all checks you want to run.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WSTlrcPQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x1mvdne038vksxu2z0g2.png" alt="Image description" width="880" height="817"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run tests, you should enter:&lt;br&gt;
&lt;code&gt;artillery run my.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To run a test and then generate a report in a .txt file, run:&lt;br&gt;
&lt;code&gt;artillery run -o first.txt my.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After generating a .txt report, to generate a second report in HTML, run the command:&lt;br&gt;
&lt;code&gt;artillery report first.txt&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here's the report example:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7oWcWwGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmupyebb5o01au5auoub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7oWcWwGZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmupyebb5o01au5auoub.png" alt="Image description" width="880" height="1128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;&lt;br&gt;
With Artillery.io, you can use basic authentication or get authorized by tokens uploading CSV with your credentials. Just pick an option that suits your project best.&lt;/p&gt;

&lt;p&gt;Check their &lt;a href="https://artillery.io/docs/guides/guides/http-reference.html#Basic-Authentication"&gt;official documentation&lt;/a&gt; to find information on authentication and many other aspects of Artillery.io.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_n_UWs1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/km1rl4kya5lf2wgzml0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_n_UWs1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/km1rl4kya5lf2wgzml0r.png" alt="Image description" width="880" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's first revise how you can get authorized by tokens. To upload a CSV file with credentials, you should add the following lines into the config file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;payload – to use the payload functionality;&lt;/li&gt;
&lt;li&gt;path – to write a path for the CSV file that Artillery needs to use;&lt;/li&gt;
&lt;li&gt;fields – names of fields that you need to use.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Aky9j4f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zh3j4vj4rsephj5q2erz.png" alt="Image description" width="880" height="599"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See an example with a CSV file:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VqdHl253--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4b03vkcvyjuo4yfwc66n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VqdHl253--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4b03vkcvyjuo4yfwc66n.png" alt="Image description" width="880" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second way to get authorized is through environment variables. And we have several options for this. The first one is to execute an export command in your console as below:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0f1V5DdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idpscavzgskdfqhl61kk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0f1V5DdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idpscavzgskdfqhl61kk.png" alt="Image description" width="880" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And after it's done, you can use your variable inside your yml file:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--unHeQASq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e12488bygprnifi65hki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--unHeQASq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e12488bygprnifi65hki.png" alt="Image description" width="880" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another option is to write a new script with an environment variable in your package.json file to execute your tests without typing the export variable in the terminal each time. It will look like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9fBQ3tzo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onpjnvgu8gzanf7j4fdt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9fBQ3tzo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onpjnvgu8gzanf7j4fdt.png" alt="Image description" width="880" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then all you need to do is run this script in the terminal:&lt;br&gt;
&lt;code&gt;npm run artillery:run&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, you can upload CSV to pass parameters for your test requests: GET, POST, PUT, etc.&lt;br&gt;
Check an example with POST:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xda6uh1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb2wa8og00905mjcef7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xda6uh1q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb2wa8og00905mjcef7w.png" alt="Image description" width="880" height="1017"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Final thoughts&lt;/strong&gt;&lt;br&gt;
Artillery.io is an accessible and comprehensive tool that I use and can surely recommend for performance testing.&lt;/p&gt;

&lt;p&gt;With a free &lt;a href="https://artillery.io/docs/guides/getting-started/installing-artillery.html"&gt;Artillery Core&lt;/a&gt; version, you can run tests from a local or virtual machine. And by switching to &lt;a href="https://artillery.io/docs/guides/getting-started/installing-artillery-pro.html"&gt;Artillery Pro&lt;/a&gt;, you're getting a self-hosted AWS performance testing platform.&lt;/p&gt;

&lt;p&gt;Other features of Artillery Pro include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runs millions of tests per second across 13 geographical regions;&lt;/li&gt;
&lt;li&gt;works with existing security systems;&lt;/li&gt;
&lt;li&gt;no repeat charges or paid maintenance;&lt;/li&gt;
&lt;li&gt;VPC internal test services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this article has given you some clarity on Artillery’s software, and helped you make a choice regarding the performance testing tool you want to work with. ‌‍&lt;/p&gt;

&lt;p&gt;In case you’re looking for help in software testing, or your project needs an advanced quality assurance pipeline – &lt;a href="https://valor-software.com/contact.html"&gt;drop us a line&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.artillery.io/docs/guides/getting-started/installing-artillery"&gt;Installation through npm utility guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://artillery.io/docs/guides/overview/welcome.html"&gt;Artillery docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/search?q=artillery-plugin-&amp;amp;page=0&amp;amp;perPage=20"&gt;Artillery plugins on npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>artilleryio</category>
      <category>testing</category>
      <category>automation</category>
      <category>loadtesting</category>
    </item>
    <item>
      <title>How to deploy Firebase Preview Channels on Travis CI</title>
      <dc:creator>Valor-software-tech</dc:creator>
      <pubDate>Thu, 22 Jul 2021 14:53:00 +0000</pubDate>
      <link>https://dev.to/valorsoftwaretech/how-to-deploy-firebase-preview-channels-on-travis-ci-3pa4</link>
      <guid>https://dev.to/valorsoftwaretech/how-to-deploy-firebase-preview-channels-on-travis-ci-3pa4</guid>
      <description>&lt;p&gt;Nikita Glukhi, Software Engineer at Valor Software, kindly provided this story and the solution.&lt;br&gt;
Firebase has released the long-awaited Preview channel functionality, which allows for the testing of updates. All Firebase (not Firestore!) users can benefit from this hosting feature. And you may be asking what about Travis CI or other hosting users? Can they use preview channels as well?&lt;br&gt;
At the time of this article’s publication, GitHub Actions does not yet natively provide automated procedures for Travis CI from GitHub. Below is a solution to use preview channels by Firebase with your existing &lt;a href="https://travis-ci.org/"&gt;Travis CI&lt;/a&gt; deployment environment.&lt;/p&gt;
&lt;h3&gt;
  
  
  Check updates with no risk for users’ experience
&lt;/h3&gt;

&lt;p&gt;Let’s face the truth, to check the behavior of your polished and tested updates on production, you had to actually push them to production. Then, in case something fails, — get back to a previous version. Application users might have noticed inappropriate system behavior, which is a pity. To get rid of this kind of working situation, we can now use preview channels. Apply this new Firebase feature to automatically deploy updates and see how they behave, with no risk for real users’ experience. Also, you can comfortably leave comments for your updates, and amend them with your team. The best thing is that this temporary storage will remove itself after a preview channel link expires. No storage place taken!&lt;/p&gt;
&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need to know Travis CI and have experience with the config file.&lt;/li&gt;
&lt;li&gt;You need to know how to write Bash scripts and know the right stage to run the Bash script for preview channels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Steps to reproduce:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a new local repository.&lt;/li&gt;
&lt;li&gt;Create a new GitHub repository.&lt;/li&gt;
&lt;li&gt;Run the ‘git remote add’ command to connect your local repository to the GitHub repository.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://firebase.google.com/docs/web/setup"&gt;Set up Firebase project&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.travis-ci.com/user/tutorial/#to-get-started-with-travis-ci-using-github"&gt;Set up Travis CI&lt;/a&gt; for GitHub repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set up configuration variables — add &lt;a href="https://docs.travis-ci.com/user/environment-variables/"&gt;environment variables in Travis CI&lt;/a&gt;. The variables that you need to set up are the two access tokens to work with Firebase and GitHub:&lt;br&gt;
• To get FIREBASE_TOKEN, use the command: firebase login:ci&lt;br&gt;
If the command doesn’t work, that’s probably because you don’t have firebase-tools&lt;br&gt;
installed. For installation, run the following command: npm i -g firebase-tools, or curl -sL &lt;a href="https://valorsoftware.medium.com/how-to-deploy-firebase-preview-channels-on-travis-ci-f97ae6bd8d5b#:~:text=https%3A//firebase.tools"&gt;https://firebase.tools&lt;/a&gt; | bash&lt;br&gt;
Then — run a firebase login command, then — firebase login:ci. The latter command gives you a Firebase access token that you want to use as a value for this step (To get FIREBASE_TOKEN…).&lt;br&gt;
• Get GITHUB_TOKEN using this link: &lt;a href="https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token"&gt;Creating a personal access token&lt;/a&gt;&lt;br&gt;
Then, apply this value for the GITHUB_TOKEN variable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your local repository, run the ‘firebase init hosting’ command, choose your Firebase project from the list of already existed projects, and &lt;a href="https://firebase.google.com/docs/hosting/full-config"&gt;configure firebase.json file&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create .travis.yml file in your local repository.&lt;/li&gt;
&lt;li&gt;Create a Bash script — &lt;a href="https://devdocs.io/bash/"&gt;https://devdocs.io/bash/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add job to the .travis.yml file that should call the script that we’ve created as step 8.
The job you need to insert into the .travis.yml file:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stages:
 - name: "Deploy to Firebase preview channel"
   if: branch = master AND type = pull_request
jobs:
 include:
 - stage: "Deploy to Firebase preview channel"
   skip_cleanup: true
   provider: firebase
   project: fir-project-dc47e
   before_script:
     - sudo apt-get install jq
     - npm install firebase-tools -g
     - npm run build:prod
   script: bash deploy-to-firebase-preview-channels.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here fir-project-dc47e — an ID of your Firebase project&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push changes to GitHub and create a pull request.
Now, back to solving our Travis CI issue and enabling its usage with the Preview channel Firebase functionality. Find the solution I came up with in the repository: &lt;a href="https://github.com/NikitaGlukhi/travis-ci-and-firebase-preview-channels"&gt;Travis CI and Firebase preview channels solution&lt;/a&gt;.
Or a brief version on gist: &lt;a href="https://gist.github.com/NikitaGlukhi/f094a6a8e6812d104d779e37d6560705"&gt;.travis.yml: preview channels deployment&lt;/a&gt;.
I’ll separate the script into pieces and describe every step below. To deploy successfully, please, follow my guidelines step by step.
I start with a deployment to a preview channel:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash
DEPLOY_TO_PREVIEW_CHANNEL_RESULT=$(firebase hosting:channel:deploy pr-$TRAVIS_PULL_REQUEST --expires 30d --token $FIREBASE_TOKEN --json)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After running the deploy command, I get a response with an object containing data, and I have the following as a result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "status": "success",
 "result": {
   "fir-project-dc47e": {
     "site": "fir-project-dc47e",
     "url": "https://fir-project-dc47e--pr-1-t36vykr3.web.app",
     "expireTime": "2021-01-08T09:27:24.847798020Z"
   }
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here fir-project-dc47e — an ID of your Firebase project&lt;br&gt;
I add this object to the DEPLOY_TO_PREVIEW_CHANNEL_RESULT variable. This object has a .result parameter containing all the data needed for future operations.&lt;br&gt;
Next, I select data from the .result parameter and add it to a separate variable that corresponds to the parameter name. This variable will contain an object with a key of ngx-bootstrap-demo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RESULT=`echo ${DEPLOY_TO_PREVIEW_CHANNEL_RESULT} | jq -r '.result'`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following goes to RESULT_DATA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
     "site": "fir-project-dc47e",
     "url": "https://fir-project-dc47e--pr-1-t36vykr3.web.app",
     "expireTime": "2021-01-08T09:27:24.847798020Z"
   }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, I extract a website name from the RESULT_DATA variable. The result will go to the SITE variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SITE=`echo ${RESULT_DATA} | jq -r '."site"'`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I extract a preview channel URL from RESULT_DATA variable, and the result goes to the URL variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;URL=`echo ${RESULT_DATA} | jq -r '."url"'`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then — extracting data with the expiration time from the RESULT_DATA variable. And, I write it down to the EXPIRE_TIME_UTC variable. UTC format is a default one, so I bring it to the needed format which is GMT, in my case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPIRE_TIME_UTC=`echo ${RESULT_DATA} | jq -r .expireTime`
EXPIRE_TIME=$(TZ='GMT' date -d $EXPIRE_TIME_UTC +%c)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The NEW_COMMENT variable creates a text with a project name, link to a preview channel, and its life duration. I’ll add this text of the comment to a pull request later (TRAVIS_PULL_REQUEST/comments).&lt;br&gt;
Then, I extract all the comments from the pull request I want to work on, using the request to GitHub API. The result goes to the COMMENTS variable. The Objects array will have a description for each comment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;COMMENTS=$(curl -H "Authorization: token $GITHUB_TOKEN" -X GET "https://api.github.com/repos/$TRAVIS_REPO_SLUG/issues/$TRAVIS_PULL_REQUEST/comments")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I declare variables for test cycles. Using the SUBSTRING variable, I search for a comment that might have been added before to replace it with the latest one.&lt;br&gt;
COMMENT_ID equals -1 by default. In the future, I’ll assign a comment ID that I find to it. In case of no overlaps appeared, the value stays as default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SUBSTRING="Project: fir-project-dc47e"
COMMENT_ID=-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this cycle, I sort out the COMMENTS array, and extract the body of each comment — its text, and search for a substring in this body. If an overlap is detected, I take the comment ID and assign it to the COMMENT_ID variable. If no overlaps are detected, then nothing is assigned, the loop just runs as before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for row in $(echo "${COMMENTS}" | jq -r '.[] | @base64'); do
echo ${row}
  _jq() {
     echo ${row} | base64 --decode | jq -r ${1}
  }
  BODY=$(_jq '.body')  if [[ ${BODY} == *"$SUBSTRING"* ]]; then
    COMMENT_ID=$(_jq '.id')
  fi
done
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I run a COMMENT_ID test, if it equals 0 or is more than 0, it means a comment like this exists, and I need to refresh it. Then, I refer to GitHub API (GITHUB_TOKEN). If there’s no comment — the command creates a new comment in a pull request (GitHub API, as well).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [[ ${COMMENT_ID} -ge 0 ]];
 then
   curl -H "Authorization: token $GITHUB_TOKEN" -X PATCH -d "{\"body\": \"$NEW_COMMENT\"}" "https://api.github.com/repos/${TRAVIS_REPO_SLUG}/issues/comments/${COMMENT_ID}"
 else
   curl -H "Authorization: token $GITHUB_TOKEN" -X POST -d "{\"body\": \"$NEW_COMMENT\"}" "https://api.github.com/repos/${TRAVIS_REPO_SLUG}/issues/${TRAVIS_PULL_REQUEST}/comments"
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result, I get the link with the comment to a preview channel. And, the comment we get from the previous operation comes from the person which token we use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VG-awAZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93tv18r8jrm2ghjlbfco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VG-awAZm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93tv18r8jrm2ghjlbfco.png" alt="Preview Channel Link"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Any questions?
&lt;/h3&gt;

&lt;p&gt;Feel free to contact me if you have any questions or troubles with deploying the script: &lt;a href="mailto:nikita.glukhi@valor-software.com"&gt;nikita.glukhi@valor-software.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful links:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.github.com/v3/issues/comments/#list-issue-comments-for-a-repository"&gt;Issue Comments for a repository&lt;/a&gt; — extract all the comments for a repository (as well as for a preview channel, but there’s no example in the doc)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/free-pro-team@latest/rest/reference/issues#create-an-issue-comment"&gt;Create an issue comment&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/free-pro-team@latest/rest/reference/issues#update-an-issue-comment"&gt;Update an issue comment&lt;/a&gt; — refresh an existing comment&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firebase</category>
      <category>travisci</category>
      <category>previewchannels</category>
      <category>previewchannel</category>
    </item>
  </channel>
</rss>
