<?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>Forem: Zack Jackson</title>
    <description>The latest articles on Forem by Zack Jackson (@scriptedalchemy).</description>
    <link>https://forem.com/scriptedalchemy</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%2F269812%2Fbb826105-59b6-406e-858f-0f32711037a8.jpeg</url>
      <title>Forem: Zack Jackson</title>
      <link>https://forem.com/scriptedalchemy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/scriptedalchemy"/>
    <language>en</language>
    <item>
      <title>The Future of Module Federation</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Fri, 25 Aug 2023 23:17:06 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/the-future-of-module-federation-5h43</link>
      <guid>https://forem.com/scriptedalchemy/the-future-of-module-federation-5h43</guid>
      <description>&lt;h1&gt;
  
  
  The Future of Module Federation
&lt;/h1&gt;

&lt;p&gt;Over the past 4 years, I have encountered my fair share of limitations in Module Federation. It did the job it was built to do, import code from other bundles. But over time, as use cases, scale, and userbase got larger — there were design oversights that would have been really helpful to consider.&lt;/p&gt;

&lt;p&gt;I never expected federation to become as popular as it has, in hindsight there are adjustments that could be made to make it more powerful and helpful. This is something the Infra team saw as well, and they ended up forking the plugin, implementing browser devtools, and addressing many gotchas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hC8baDGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AFChP8sJhJFmtAIRBLkKcrQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hC8baDGp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2AFChP8sJhJFmtAIRBLkKcrQ.png" alt="" width="532" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the next quarter, we are going to try and separate our internal couplings present in the fork, and instead — implement some aspects directly into Module Federation.&lt;/p&gt;

&lt;p&gt;To do so, federation needs to change, in a non breaking manner.&lt;br&gt;
&lt;a href="https://github.com/module-federation/universe/discussions/1170"&gt;&lt;strong&gt;Module Federation Redesign · module-federation/universe · Discussion #1170&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hooks
&lt;/h3&gt;

&lt;p&gt;We deliberately did not add hooks into the plugin as end users would not need or should not tinker around with internal mechanics. I agree with that, but i dont think we considered that we should offer some “framework api”&lt;/p&gt;

&lt;p&gt;If federation needs to be modified at all we must either change webpack or fork the whole plugin, ouch. And fork we did in order to integrate it with better management systems and tools.&lt;/p&gt;

&lt;p&gt;In version 1.5, we want to introduce hooks so that enhancing federation doesnt require forking the pluign entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Framework APIs
&lt;/h3&gt;

&lt;p&gt;Similar to hooks, in general we need more mid level apis either at build time or runtime. The standard {get,init} api can feel a little too limiting when you're dealing with complex applications. More plugability at runtime and compile time would give framework authors more to work with.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript Support and Remote Types
&lt;/h3&gt;

&lt;p&gt;There is an increasing emphasis on incorporating robust type systems to enhance code safety and maintainability. Recognizing this need, the next iteration of module federation is set to introduce **built-in **TypeScript support for remote types.&lt;/p&gt;

&lt;p&gt;This feature aims to seamlessly integrate remote type definitions, allowing developers to leverage the strong typing capabilities of TypeScript across federated modules.&lt;/p&gt;

&lt;p&gt;By doing so, it enhances interoperability, reduces the risk of type-related errors, and fosters a more coherent development experience.&lt;/p&gt;

&lt;p&gt;This sets the stage for further innovation in creating more reliable and efficient distributed systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialization Phases
&lt;/h3&gt;

&lt;p&gt;A major one is the concept of middleware and startup code.&lt;/p&gt;

&lt;p&gt;Hosts should be able to apply express-like middleware on the remotes they consume. This would help alot with AB tests, dynamic environment switching, authorization and permissions, error handling and so on.&lt;/p&gt;

&lt;p&gt;But, middleware on the consumer end is not always enough or appropriate. Sometimes I may need or want to ship some “startup” code as the author of a remote. Some piece of runtime code that can be executed during the initialization phase of a remote. Like getting environment variables, or ensuring data needed is ready or exists, or inject providers into the application.&lt;/p&gt;

&lt;p&gt;Remotes need a way to be able to prepare their consuming environment, if they need to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lifecycle
&lt;/h3&gt;

&lt;p&gt;Similar and adjacent to middleware, we we could benefit from a basic lifecycle. Something like a plugin system thats at runtime, that can provide us with more callbacks to react to whats going on.&lt;/p&gt;

&lt;p&gt;The middleware implementation provides outlines various hooks that provide opportunities to intervene in the federated module process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;beforeInit &amp;amp; init: Preparing the initial environment and managing configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;beforeLoadRemote &amp;amp; loadRemoteMatch: Control over the loading of remote federated modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;loadRemote: Dynamic control over the loading process of individual federated modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;errorLoadRemote: Managing errors that occur during the remote loading process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;beforeLoadShare &amp;amp; loadShare: Control over shared modules and their behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;beforePreloadRemote: Optimization and control over preload operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Middleware:
&lt;/h2&gt;

&lt;p&gt;How should one interact with the middleware flow in an integrated manner?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new ModuleFederationPlugin({
    middleware: './src/federation-middleware.js'
})

//federation-middleware.js

module.exports = {
 beforeInit,
 beforeLoadingRemote,
 loadRemoteMatch,
 loadRemote,
 errorLoadRemote,
 beforeLoadShare,
 beforePreloadRemote
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At Runtime:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hooks = new PluginSystem({
    beforeInit: new SyncWaterfallHook&amp;lt;{
      userOptions: UserOptions;
      options: Options;
      origin: VmokHost;
    }&amp;gt;('beforeInit'),
    init: new SyncHook&amp;lt;
    [
      {
        options: Options;
        origin: VmokHost;
      },
    ],
    void
    &amp;gt;(),
    beforeLoadRemote: new AsyncWaterfallHook&amp;lt;{
      id: string;
      options: Options;
      origin: VmokHost;
    }&amp;gt;('beforeLoadRemote'),
    loadRemoteMatch: new AsyncWaterfallHook&amp;lt;{
      id: string;
      pkgNameOrAlias: string;
      expose: string;
      remote: RemoteInfo;
      options: Options;
      origin: VmokHost;
    }&amp;gt;('loadRemoteMatch'),
    loadRemote: new AsyncHook&amp;lt;
    [
      {
        id: string;
        expose: string;
        pkgNameOrAlias: string;
        remote: RemoteInfo;
        options: ModuleOptions;
        origin: VmokHost;
        exposeModule: any;
        moduleInstance: Module;
      },
    ],
    void
    &amp;gt;('loadRemote'),
    errorLoadRemote: new AsyncHook&amp;lt;
    [
      {
        id: string;
        error: unknown;
      },
    ],
    void
    &amp;gt;('errorLoadRemote'),
    beforeLoadShare: new AsyncWaterfallHook&amp;lt;{
      pkgName: string;
      shareInfo?: Shared;
      shared: Options['shared'];
      origin: VmokHost;
    }&amp;gt;('beforeLoadShare'),
    loadShare: new AsyncHook&amp;lt;[VmokHost, string, ShareInfos]&amp;gt;(),
    beforePreloadRemote: new AsyncHook&amp;lt;{
      preloadOps: Array&amp;lt;PreloadRemoteArgs&amp;gt;;
      options: Options;
      origin: VmokHost;
    }&amp;gt;(),
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Startup
&lt;/h2&gt;

&lt;p&gt;The startup code in Module Federation represents an architectural evolution where remotes have their own lifecycle. This allows nuanced control over the bootstrapping of federated modules, working in tandem with middleware to enable an intricately negotiated 4-way handshake.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new ModuleFederationPlugin({
    startup: './src/federation-startup.js'
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Examples and Applications
&lt;/h3&gt;

&lt;p&gt;The startup phase incorporates various elements that can be tailored to specific needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Environment Configuration: Set up runtime environments for different federated modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;State Management: Manage global states and inject middleware in state stores.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-Time Communication: Manage real-time channels like WebSockets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Critical Resource Preloading: Preload resources for a smoother user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Error Handling: Handle errors with auto-recovery mechanisms.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Integrity: Implement integrity checks on loaded modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access Control: Implement runtime access control.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Theming and Localization: Apply themes or localization settings dynamically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cache Management: Manage cache across federated modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integration with Legacy Systems: Integrate with older systems by adapting interfaces.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Custom UI Components Loading: Load or unload UI components dynamically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Health Monitoring and Reporting: Embed health checks for critical dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compliance and Security Enforcement: Ensure compliance with legal or business rules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Experimentation and A/B Testing: Support dynamic A/B testing without altering the core codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Plug-and-Play Extensibility: Enable third-party developers to extend functionalities.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  4-Way Handshake
&lt;/h3&gt;

&lt;p&gt;During the 4-way handshake process, middleware and startup code work collaboratively:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remote Initialization (Startup): Execution of prescribed startup tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Middleware Execution: Enables the host to perform actions and adapt behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Dependency Linking: Completes the connection and linking in the dependency graph.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Application Execution: Begins executing the application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Startup Hooks/Lifecycle
&lt;/h3&gt;

&lt;p&gt;Startup hooks focus on the initialization and preparation actions taken by the providers/remotes. They may be the mirror image of the middleware hooks, focusing on provision rather than consumption.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startupHooks = new PluginSystem({
    beforeStartup: new SyncWaterfallHook&amp;lt;{
      moduleOptions: ModuleOptions;
      environment: Environment;
      provider: VmokProvider;
    }&amp;gt;('beforeStartup'),
    onStartup: new SyncHook&amp;lt;
    [
      {
        provider: VmokProvider;
        environment: Environment;
      },
    ],
    void
    &amp;gt;('onStartup'),
    beforeInitializeRemote: new AsyncWaterfallHook&amp;lt;{
      id: string;
      initializationOptions: InitializationOptions;
      provider: VmokProvider;
    }&amp;gt;('beforeInitializeRemote'),
    initializeRemote: new AsyncHook&amp;lt;
    [
      {
        id: string;
        initializationOptions: InitializationOptions;
        provider: VmokProvider;
        remoteInstance: Remote;
      },
    ],
    void
    &amp;gt;('initializeRemote'),
    errorInitializeRemote: new AsyncHook&amp;lt;
    [
      {
        id: string;
        error: unknown;
      },
    ],
    void
    &amp;gt;('errorInitializeRemote'),
    beforePrepareEnvironment: new AsyncWaterfallHook&amp;lt;{
      environment: Environment;
      provider: VmokProvider;
    }&amp;gt;('beforePrepareEnvironment'),
    prepareEnvironment: new AsyncHook&amp;lt;
    [
      {
        environment: Environment;
        provider: VmokProvider;
      },
    ],
    void
    &amp;gt;('prepareEnvironment'),
    beforeFinalizeStartup: new AsyncWaterfallHook&amp;lt;{
      finalizationOptions: FinalizationOptions;
      provider: VmokProvider;
    }&amp;gt;('beforeFinalizeStartup'),
    finalizeStartup: new AsyncHook&amp;lt;
    [
      {
        finalizationOptions: FinalizationOptions;
        provider: VmokProvider;
      },
    ],
    void
    &amp;gt;('finalizeStartup'),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Explanation of Startup Hooks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;beforeStartup&lt;/strong&gt;: Allows initial configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;onStartup&lt;/strong&gt;: Core initialization logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;beforeInitializeRemote&lt;/strong&gt;: Preprocessing before initializing a remote module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;initializeRemote&lt;/strong&gt;: Initialization of a remote module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;errorInitializeRemote&lt;/strong&gt;: Handling errors during initialization.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;beforePrepareEnvironment&lt;/strong&gt;: Actions before environment configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;prepareEnvironment&lt;/strong&gt;: Actual environment setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;beforeFinalizeStartup&lt;/strong&gt;: Preprocessing before finalizing the startup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;finalizeStartup&lt;/strong&gt;: Final actions, including clean-up or validation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Middleware &amp;amp; Startup as a whole
&lt;/h2&gt;

&lt;p&gt;The integration of middleware and startup code in Module Federation’s architecture marks a significant advancement in handling federated modules. They offer a symmetrical design where middleware focuses on the consumption and host perspective, while startup code targets the provisioning and provider’s view.&lt;/p&gt;
&lt;h3&gt;
  
  
  Middleware
&lt;/h3&gt;

&lt;p&gt;With various hooks for controlling and customizing different stages of federated module loading and execution, middleware enables a tailored experience for consumers. It provides a granular level of control over aspects such as remote loading, error management, shared module behavior, and preload operations. Middleware allows an intricate alignment with the complex demands of modern distributed systems, offering flexibility, robustness, and efficient handling of federated modules.&lt;/p&gt;
&lt;h3&gt;
  
  
  Startup
&lt;/h3&gt;

&lt;p&gt;Startup code, on the other hand, introduces a nuanced lifecycle for remotes, focusing on initialization and preparation actions. It emphasizes the provider’s perspective, allowing actions like environment configuration, error handling, integration with legacy systems, cache management, and more. The startup hooks provide a rich lifecycle model that complements the consumption-oriented middleware hooks.&lt;/p&gt;
&lt;h3&gt;
  
  
  Combined Effect
&lt;/h3&gt;

&lt;p&gt;Together, middleware and startup form a cohesive and comprehensive protocol that caters to both sides of federated module operations. The well-designed hooks and lifecycle phases provide a powerful toolkit for developers to have fine-grained control over the process, from initialization to execution. The 4-way handshake model illustrates how these two components work in unison to ensure a smooth and effective operation.&lt;/p&gt;

&lt;p&gt;In essence, the combined power of middleware and startup in Module Federation fosters a more adaptive, resilient, and scalable architecture. It reflects a thoughtful design that anticipates the multifaceted needs of modern development environments, providing the tools and methodologies to create intricate, distributed systems with ease and precision. Whether it’s the flexible customization offered by middleware or the robust initialization provided by startup, this duo forms the backbone of an intelligent system that is poised to revolutionize the way federated modules are handled and executed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Runtime API / SDK
&lt;/h3&gt;

&lt;p&gt;Middleware, lifecycles, its all related, so is the need for an SDK and better runtime API.&lt;/p&gt;

&lt;p&gt;Runtime API should expose the middleware primitives in some way, hookable lifecycles that can be used in react for example.&lt;/p&gt;

&lt;p&gt;The SDK on the other hand, aims to take what we are building into the Webpack runtime and turn it inside out.&lt;/p&gt;

&lt;p&gt;Federation v1.5 would be more painful to try and support in other build tools, federation already is tricky or “same idea not compatible”. To support other tools, i dont know if their APIs would be worth the effort — its just difficult, federation uses many of Webpacks apis to pull it off so well.&lt;/p&gt;

&lt;p&gt;So, instead of maintaining a replica of what Webpack can already do… what if we shipped an empty “webpack runtime”, wrapped its &lt;strong&gt;webpack_require&lt;/strong&gt; exports in a library, and ship it to NPM?&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {createContainer} from '@module-federation/sdk';
const federationConfig = {
  name: 'app2',
  exposes: {
    "./Button": () =&amp;gt; {
      return import('./App').then(f =&amp;gt; () =&amp;gt; f)
    }
  },
  shared: {
    react: {
      version: '18.2.0',
      import: () =&amp;gt; import('react').then(f =&amp;gt; () =&amp;gt; f),
      weakRef: require.resolveWeak('react'),
    },
  'react-dom': {
   version: '18.2.0',
   import: () =&amp;gt; import('react-dom').then(f =&amp;gt; () =&amp;gt; f),
   weakRef: require.resolveWeak('react-dom'),
  }
  }
}

export default createContainer(federationConfig) // =&amp;gt; {get,init}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Plugin Hooks
&lt;/h3&gt;
&lt;h3&gt;
  
  
  Compile Time Hooks for Module Federation:
&lt;/h3&gt;

&lt;p&gt;This aspect is not fully developed, but the following should offer a window into the direction&lt;/p&gt;
&lt;h3&gt;
  
  
  Initialization Hooks
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;beforeCompileInit: Called before initializing the compilation process.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeCompileInit: new SyncHook&amp;lt;[InitializationOptions]&amp;gt;('beforeCompileInit'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  “Filesystem” Hooks
&lt;/h3&gt;

&lt;p&gt;customizeFilesystem: Customizing the filesystem for loading chunks or altering the definition of a filesystem during compilation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customizeFilesystem: new AsyncHook&amp;lt;[FilesystemOptions]&amp;gt;('customizeFilesystem'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Template Generation Hooks
&lt;/h3&gt;

&lt;p&gt;beforeTemplateGeneration: Preprocessing before generating templates for federated modules.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeTemplateGeneration: new AsyncWaterfallHook&amp;lt;[TemplateOptions]&amp;gt;('beforeTemplateGeneration'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;generateTemplate: Generating templates for federated modules during compile time.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;generateTemplate: new AsyncHook&amp;lt;[GenerateTemplateOptions]&amp;gt;('generateTemplate'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  API Manipulation Hooks
&lt;/h3&gt;

&lt;p&gt;beforeAPIAlteration: Called before altering or extending the API interfaces.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;beforeAPIAlteration: new SyncHook&amp;lt;[APIOptions]&amp;gt;('beforeAPIAlteration'),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;alterAPI: Altering or adding more exports onto the main interface.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alterAPI: new AsyncHook&amp;lt;[AlterAPIOptions]&amp;gt;('alterAPI'),&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Using (Web|Rs)pack Runtime as a Library? A Possibility&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Much of the federation’s value lies in Webpack’s runtime. The idea is to use a “Webpack runtime” to inject dynamic imports into a container-producing factory.&lt;/p&gt;

&lt;p&gt;This concept resembles single-spa, where an entry point could be exported from any build as a remote entry or host. The runtime would boot the application, with no need to use Webpack to build it.&lt;/p&gt;

&lt;p&gt;Instead of replicating what Webpack does, the idea is to use its pre-built runtime, modify it slightly, and employ Webpack’s actual runtime as a framework. The parent build tool would handle script loading, so the SDK’s responsibilities would be minimal.&lt;/p&gt;

&lt;p&gt;Creating a clean SDK with only a Webpack plugin might not be possible, and though it’s not an easy task, it’s preferable to recreating federation with a smaller build API.&lt;/p&gt;

&lt;p&gt;As someone who’s worked extensively with Webpack, I’m grateful for having Rspack. It allows flexibility with plugins and has proven more valuable in the long run despite a learning curve.&lt;/p&gt;

&lt;p&gt;Difficult architectural or business problems became more manageable or even trivial. With rspack, compatibility is maintained with Webpack, but there’s room for enhancement, and its speed opens new possibilities.&lt;/p&gt;

&lt;p&gt;It’s a balance between speed and capability. If rspack can build an 18,000 file codebase in 4 seconds, not 60, it’s fast enough that new powerful capabilities could be introduced without noticeable delays. Doing some of these tasks in Javascript might not be feasible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping it up
&lt;/h3&gt;

&lt;p&gt;The evolution of module federation is marked by the development of more refined and specialized APIs. These improvements enable developers to address framework-level challenges, facilitating more nuanced control over the handling of and formation of a distributed system and its module tree.&lt;/p&gt;

&lt;p&gt;The introduction of middleware, startup hooks, and compile-time plugin hooks represents a significant step forward. These capabilities allow for a greater range of customization, enriching the architectures scope and utility.&lt;/p&gt;

&lt;p&gt;The full potential of these advancements can only be realized within a unified meta-framework that encapsulates the diverse needs of modern development. This is the role that &lt;a href="https://modernjs.dev/"&gt;ModernJS&lt;/a&gt; aims to fulfill in future iterations. As a platform, it integrates these new features into a coherent whole, providing a practical and efficient approach to building and managing distributed systems.&lt;/p&gt;

&lt;p&gt;By giving module federation a “home” within &lt;a href="https://modernjs.dev/"&gt;ModernJ&lt;/a&gt;S, these new capabilities can be leveraged to solve real-world challenges, without losing sight of the underlying technical complexities. This alignment between innovation and practicality forms the foundation for further growth and refinement in the field of micro-frontends and code distribution.&lt;br&gt;
&lt;a href="https://modernjs.dev/"&gt;&lt;strong&gt;Modern.js&lt;/strong&gt;&lt;br&gt;
*A Progressive React Framework for modern web development.*modernjs.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>modulefederation</category>
      <category>microfrontend</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Rspack 0.3 Release Announcement</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Fri, 25 Aug 2023 22:49:05 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/rspack-03-release-announcement-3i7e</link>
      <guid>https://forem.com/scriptedalchemy/rspack-03-release-announcement-3i7e</guid>
      <description>&lt;p&gt;Since the launch of &lt;a href="https://rspack.dev"&gt;Rspack&lt;/a&gt; 0.2, we've been meticulously gathering community feedback and iterating on our offering. We're thrilled to unveil Rspack 0.3—a significant upgrade that amplifies flexibility, compatibility, and performance. This new release brings a series of breaking changes, major feature rollouts, and finer-grained controls, all aligned to provide you with a more robust, adaptable, and efficient build tool. Read on for a comprehensive look at what Rspack 0.3 has in store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breaking Changes
&lt;/h2&gt;

&lt;p&gt;In version 0.3, Rspack aligns the default CSS handling behavior with webpack when set &lt;code&gt;experiments.css = true&lt;/code&gt;. This involves removing many built-in CSS transformation logic, which introduces some breaking changes. If your application previously relied on these transformation logic, please pay attention to the migration steps below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Removal of @rspack/postcss-loader and builtins.postcss
&lt;/h3&gt;

&lt;p&gt;Before Rspack fully supported &lt;code&gt;postcss-loader&lt;/code&gt;, Rspack implemented &lt;code&gt;@rspack/postcss-loader&lt;/code&gt; and built-in &lt;code&gt;builtins.postcss&lt;/code&gt; to fulfill the functionality. Currently, Rspack fully supports &lt;code&gt;postcss-loader&lt;/code&gt;, so we have decided to deprecate &lt;code&gt;@rspack/postcss-loader&lt;/code&gt; and &lt;code&gt;builtins.postcss&lt;/code&gt;. Users of &lt;code&gt;@rspack/postcss-loader&lt;/code&gt; can seamlessly migrate to &lt;code&gt;postcss-loader&lt;/code&gt;, while users that previously used Rspack’s &lt;code&gt;builtins.postcss&lt;/code&gt; for the &lt;code&gt;px2rem&lt;/code&gt; conversion functionality can migrate to &lt;code&gt;postcss-loader&lt;/code&gt; and &lt;code&gt;postcss-plugin-px2rem&lt;/code&gt;. Here is the migration process:&lt;/p&gt;

&lt;p&gt;• Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;builtins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pxtorem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;css$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;postcssOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-plugin-px2rem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="na"&gt;rootValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                  &lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;],&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Removal of Built-in CSS Autoprefixer Functionality
&lt;/h3&gt;

&lt;p&gt;To align better with webpack’s CSS handling, Rspack removes the built-in autoprefixer functionality in 0.3. You can use &lt;code&gt;postcss-loader&lt;/code&gt; to achieve &lt;code&gt;autoprefixer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;css$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;postcssOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;autoprefixer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can refer to the &lt;a href="https://github.com/web-infra-dev/rspack/blob/main/examples/postcss-loader/rspack.config.js"&gt;examples/postcss-loader&lt;/a&gt; for a complete example.&lt;/p&gt;

&lt;h3&gt;
  
  
  Access to Internal Modules Restricted
&lt;/h3&gt;

&lt;p&gt;Due to the current instability of the internal module API in Rspack, directly accessing the internal modules can easily lead to breaking changes. Therefore, Rspack restricts the ability to directly access internal modules and only supports accessing Rspack’s API from the root module.&lt;/p&gt;

&lt;p&gt;• Before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Stats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rspack/core/dist/stats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// not supported since 0.3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;• After:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Stats&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@rspack/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Major Feature Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Web Workers Support
&lt;/h3&gt;

&lt;p&gt;Rspack natively supports Web Workers, which means you can use Web Workers out of the box without using worker-loader. Here is how to use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./worker.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-worker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information about web workers support, see &lt;a href="https://dev.to/guide/web-workers"&gt;web workers&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;builtin:swc-loader&lt;/code&gt; Support
&lt;/h3&gt;

&lt;p&gt;Although Rspack provides many SWC compilation configuration options, these configurations are global and cannot fulfill the requirement of using different swc transformation logic for different modules. Therefore, Rspack supports &lt;code&gt;builtin:swc-loader&lt;/code&gt; to provide more fine-grained SWC transformation configuration. Compared to the JavaScript version of &lt;code&gt;swc-loader&lt;/code&gt;, &lt;code&gt;builtin:swc-loader&lt;/code&gt; has better performance. You can use &lt;code&gt;builtin:swc-loader&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;jsx$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;builtin:swc-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Enable source map&lt;/span&gt;
            &lt;span class="na"&gt;sourceMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;jsc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;syntax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ecmascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;jsx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="na"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;react&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;pragma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;React.createElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;pragmaFrag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;React.Fragment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;throwIfNamespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="na"&gt;useBuiltins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
              &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascript/auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can refer to &lt;a href="https://github.com/web-infra-dev/rspack/tree/main/examples/builtin-swc-loader"&gt;examples/builtin-swc-loader&lt;/a&gt; for more examples. Currently, &lt;code&gt;builtin:swc-loader&lt;/code&gt; still has limitations, such as not supporting wasm plugins, etc. Rspack will continue to iterate and support more features of &lt;code&gt;builtin:swc-loader&lt;/code&gt; in future versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved Profile Support
&lt;/h3&gt;

&lt;p&gt;Performance optimization is a common requirement in business support. To reduce the cost of performance optimization for businesses, we have improved the experience of Rspack Profile. You can generate profile-related files for performance optimization by using the RSPACK_PROFILE environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ RSPACK_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ALL rspack build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more detailed information about Profile, see &lt;a href="https://dev.to/guide/profile"&gt;Performance Profiling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Alignment with More APIs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;splitChunks.chunks&lt;/code&gt; supports regex.&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;splitChunk.\{cacheGroup\}.type&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;splitChunk.\{cacheGroup\}.idHint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;ensureChunkConditionsPlugin&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rule.use&lt;/code&gt; supports functions.&lt;/li&gt;
&lt;li&gt;Supports &lt;code&gt;configuration.profile&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  More Hook and Plugin Support
&lt;/h3&gt;

&lt;p&gt;Compared to version 0.2, we have implemented more plugin APIs and made compatibility improvements for more plugins in version 0.3. At the same time, we have refined the plugin API support progress of webpack, making the support progress of plugin APIs transparent. You can track the implementation progress of plugin APIs here: &lt;a href="https://github.com/orgs/web-infra-dev/projects/9"&gt;plugin-api-progress&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Alignment with Webpack Architecture
&lt;/h3&gt;

&lt;p&gt;In version 0.3, we have further optimized the alignment with the webpack architecture, migrating from the original AST-based codegen architecture to the string transformation-based architecture. This alignment work further ensures that Rspack can align with more Hook APIs of webpack during the codegen stage to be compatible with more community plugins.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rspack Ecosystem
&lt;/h3&gt;

&lt;p&gt;Starting from version 0.2, Rspack provides support for vue-loader. However, creating a complete Vue.js CLI solution based on vue-loader can be a complex task. To simplify the development of Vue.js applications using Rspack, we offer the &lt;a href="https://modernjs.dev/builder/en"&gt;Modern.js Builder&lt;/a&gt;, which provides an out-of-the-box Vue.js engineering solution called &lt;a href="https://modernjs.dev/builder/en/guide/framework/vue3.html"&gt;Modern.js Vue.js Support&lt;/a&gt;. This solution helps developers easily develop Vue.js applications using Rspack.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Announcing Rspack 0.2</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Fri, 25 Aug 2023 22:42:56 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/announcing-rspack-02-53ai</link>
      <guid>https://forem.com/scriptedalchemy/announcing-rspack-02-53ai</guid>
      <description>&lt;p&gt;Approximately a quarter-year post the unveiling of Rspack 0.1, we've been met with robust community engagement and constructive critique. With the advent of Rspack 0.2, we've augmented our offering with key advancements, including but not limited to, &lt;code&gt;realContentHash&lt;/code&gt; for enhanced cache reliability, &lt;code&gt;DataURI&lt;/code&gt; for inline asset handling, and native support for the ESM file format. Our technical strides also include strengthened synergies with webpack's API, culminating in full compatibility tests with vue-loader for both Vue3 (version 17) and Vue2 (version 15). We extend an open invitation for you to explore these newly-incorporated features in Rspack 0.2 and are keen to assimilate your expert feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main feature updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Loader
&lt;/h3&gt;

&lt;p&gt;Version 0.2 has completed compatibility with most of the loader APIs, including: inline match resource, pitching loader, and inline loader. More APIs have further improved compatibility with webpack loaders, details of which can be found in our webpack compatibility updates &lt;a href="https://www.rspack.dev/api/loader-api.html"&gt;Loader API&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugin Hooks
&lt;/h3&gt;

&lt;p&gt;New hooks for plugins have been added.&lt;/p&gt;

&lt;p&gt;Compiler hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#beforecompile"&gt;beforeCompile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#aftercompile"&gt;afterCompile&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Compilation hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#optimizemodules"&gt;optimizeModules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#optimizechunkmodules"&gt;optimizeChunkModule&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#finishmodules"&gt;finishModules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#chunkasset"&gt;chunkAsset&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;NormalModuleFactory hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#beforeresolve"&gt;beforeResolve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#afterresolve"&gt;afterResolve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#resolveforscheme"&gt;ResolveForScheme&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ContextModuleFactory hooks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.rspack.dev/api/plugin-api.html#beforeresolve"&gt;beforeResolve&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  realContentHash
&lt;/h3&gt;

&lt;p&gt;We have implemented optimization.realContentHash, which calculates the Hash based on the final product's file content. This makes the generated Hash more stable and is better utilized for caching. In version 0.2, this feature will be enabled by default for production environment builds.&lt;/p&gt;

&lt;h3&gt;
  
  
  ESM/System format
&lt;/h3&gt;

&lt;p&gt;In the new version, System/ESM products can be generated, and the configuration for outputting ESM products is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//rspack.config.js
module.exports = {
  // …
  experiments: {
    outputModule: true,
  },
  output: {
    chunkFormat: 'module',
    chunkLoading: 'import',
    library: {
      type: 'module',
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New &lt;code&gt;SplitChunksPlugin&lt;/code&gt; implementation
&lt;/h3&gt;

&lt;p&gt;We have restructured the existing implementation of &lt;code&gt;SplitChunksPlugin&lt;/code&gt; in Rspack, making the behavior of &lt;code&gt;SplitChunksPlugin&lt;/code&gt; more predictable and reducing the cost of troubleshooting related issues.&lt;/p&gt;

&lt;p&gt;After the restructuring, we are confident to implement more features on SplitChunksPlugin. We are pleased to announce that in version 0.2, SplitChunksPlugin supports the following configuration options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;splitChunks.maxSize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;splitChunks.maxAsyncSize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;splitChunks.maxInitialSize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;splitChunks.maxAsyncRequests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;splitChunks.maxInitialRequests&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In version 0.2, we will use the new &lt;code&gt;SplitChunksPlugin&lt;/code&gt; by default. If you encounter problems, please provide feedback promptly, and we will fix them as soon as possible. You can switch back to the deprecated implementation by using the &lt;code&gt;experiments.newSplitChunks: false&lt;/code&gt; option, but we strongly recommend using the new version. In version 0.3, we will remove the deprecated implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  DataURI support
&lt;/h3&gt;

&lt;p&gt;We have implemented support for DataURI. Now you can write the following code to implement virtual modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import x from 'data:text/javascript,export default 42';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, we have supported &lt;code&gt;mimetype&lt;/code&gt; and &lt;code&gt;scheme&lt;/code&gt; as two types of module rule conditions. For example, you can make resources with &lt;code&gt;scheme&lt;/code&gt; as &lt;code&gt;'data'&lt;/code&gt; no longer treated as inline processing, but as separate resource files through the following method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//rspack.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;asset/resource&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Breaking Changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Alignment of Filename Generation Logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In version 0.1.12, we further aligned the file name generation logic with webpack, and refactored the implementation of file name generation. However, the [ext] in &lt;code&gt;output.filename&lt;/code&gt;, &lt;code&gt;output.chunkFilename&lt;/code&gt;, &lt;code&gt;output.cssFilename&lt;/code&gt;, and &lt;code&gt;output.cssChunkFilename&lt;/code&gt; will no longer be replaced. This behavior is now consistent with webpack but is a breaking change for versions of Rspack prior to 0.1.12. If you used [ext] in the above 4 filename configurations, you need to change it to the corresponding &lt;code&gt;.js&lt;/code&gt; or &lt;code&gt;.css&lt;/code&gt;, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  module.exports = {
    output: {
  -    filename: "[name][ext]",
  +    filename: "[name].js",

  -    chunkFilename: "async/[name][ext]",
  +    chunkFilename: "async/[name].js",

  -    cssFilename: "[name][ext]",
  +    cssFilename: "[name].css",

  -    cssChunkFilename: "async/[name][ext]",
  +    cssChunkFilename: "async/[name].css",
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Details: &lt;a href="https://github.com/web-infra-dev/rspack/issues/3270"&gt;https://github.com/web-infra-dev/rspack/issues/3270&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enabled realContentHash by default in production&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details: &lt;a href="https://github.com/web-infra-dev/rspack/pull/3338"&gt;https://github.com/web-infra-dev/rspack/pull/3338&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modified the Extensions of Resolve&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details: &lt;a href="https://github.com/web-infra-dev/rspack/pull/3242"&gt;https://github.com/web-infra-dev/rspack/pull/3242&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modified the Export Method of @rspack/dev-middleware and @rspack/html-plugin, and Removed &lt;code&gt;getRspackMemoryAssets&lt;/code&gt; Exported by @rspack/dev-middleware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details: &lt;a href="https://github.com/web-infra-dev/rspack/pull/3358"&gt;https://github.com/web-infra-dev/rspack/pull/3358&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Webpack Compatibility Updates
&lt;/h2&gt;

&lt;p&gt;As we support more webpack APIs, we are also compatible with more community plugins and loaders. We have adapted some plugins and loaders that have a high demand in the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  fork-ts-checker-webpack-plugin
&lt;/h3&gt;

&lt;p&gt;Type checking in TypeScript for Rspack is highly demanded. Rspack has fully adapted &lt;a href="https://github.com/TypeStrong/fork-ts-checker-webpack-plugin"&gt;fork-ts-checker-webpack-plugin&lt;/a&gt;. You can use this plugin to perform TypeScript type checking during compilation. However, as TypeScript's type checking is usually very time-consuming, this makes the time required for type checking on larger projects may far exceed the build time of Rspack itself. In dev mode, this plugin will not block the build, but in build mode, this plugin will block the build. Please choose whether to enable this plugin based on your actual needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  license-webpack-plugin
&lt;/h3&gt;

&lt;p&gt;A widely reported community demand is support for extracting licenses from code. Now, Rspack can achieve the requirement of extracting licenses from the code through &lt;a href="https://github.com/xz64/license-webpack-plugin"&gt;license-webpack-plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  style-loader &amp;amp; css-loader
&lt;/h3&gt;

&lt;p&gt;Although Rspack supports and enables the &lt;code&gt;experiments.css&lt;/code&gt; feature of webpack by default, there are still many communities that strongly depend on &lt;a href="https://github.com/webpack-contrib/style-loader"&gt;style-loader&lt;/a&gt; &amp;amp; &lt;a href="https://github.com/webpack-contrib/css-loader"&gt;css-loader&lt;/a&gt;. We have completed support for style-loader and css-loader in 0.2.0, which also allows us to better adapt to frameworks such as Svelte and Vue.&lt;/p&gt;

&lt;h3&gt;
  
  
  node-loader
&lt;/h3&gt;

&lt;p&gt;When using Rspack to package Node applications like Nestjs, a common requirement is to package libraries containing addons. These libraries' native dependencies cannot be directly packaged into js, so they need special treatment. Rspack has adapted &lt;a href="https://github.com/webpack-contrib/node-loader"&gt;node-loader&lt;/a&gt;, so you can now use Rspack to build node applications.&lt;/p&gt;

&lt;p&gt;Rspack has additional adaptation of webpack's plugins. We have tracked the adapted plugins and loaders in &lt;a href="https://github.com/web-infra-dev/rspack/tree/main/examples/loader-compat"&gt;loader-compat&lt;/a&gt; and &lt;a href="https://github.com/web-infra-dev/rspack/tree/main/examples/plugin-compat"&gt;plugin-compat&lt;/a&gt;. If you find that a community plugin or loader you are using is also compatible, welcome to submit it to us so we can list it in our compatibility matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framework Ecosystem Updates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Modern.js Framework
&lt;/h3&gt;

&lt;p&gt;Thanks to the close collaboration and parallel iteration of the &lt;a href="https://modernjs.dev/en/"&gt;Modern.js framework&lt;/a&gt; and Rspack, &lt;strong&gt;Modern.js Rspack mode has covered 85% of the framework's capabilities&lt;/strong&gt;, supporting SSR, BFF, micro front-end scenarios, and aligning with TypeScript type checking, code compatibility detection and other features.&lt;/p&gt;

&lt;p&gt;At ByteDance, more than 80 projects are using the Modern.js Rspack mode. Some of the projects have been deployed into production and have seen a 10x improvement in build performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modern.js Doc
&lt;/h3&gt;

&lt;p&gt;In addition to the Modern.js framework, the document site solution under the Modern.js system - &lt;a href="https://modernjs.dev/doc-tools/"&gt;Modern.js Doc&lt;/a&gt; - has also switched the bundler from webpack to Rspack, and rewritten the MDX compilation process based on Rust.&lt;/p&gt;

&lt;p&gt;Compared to previous versions using webpack, the current version's build speed can be reduced to seconds. Using the Modern.js official website documentation as an example, the project's startup and build time has been reduced from 30 seconds to less than 2 seconds. In the future, we plan to rename Modern.js Doc to &lt;strong&gt;Rspress&lt;/strong&gt; as the official documentation site solution for Rspack and maintain it through a separate repository.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Welcome to visit the &lt;a href="https://github.com/web-infra-dev/modern.js"&gt;Modern.js code repository&lt;/a&gt; and experience the above content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Vue
&lt;/h3&gt;

&lt;p&gt;Rspack 0.2 has achieved compatibility with vue-loader! For Vue3 projects, you can use Rspack's native CSS and TS processors to improve the compilation speed of Vue projects. All you need to do is upgrade vue-loader to version 17.2.2 or above and set &lt;code&gt;experimentalInlineMatchResource: true&lt;/code&gt;. For more information on Vue3/Vue2 support, please refer to &lt;a href="https://dev.to/guide/vue"&gt;guide-vue&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Svelte
&lt;/h3&gt;

&lt;p&gt;Thanks to Rspack's excellent support for the Loader API and the excellent design of &lt;a href="https://github.com/sveltejs/svelte-loader"&gt;svelte-loader&lt;/a&gt;, Rspack has fully adapted &lt;a href="https://github.com/sveltejs/svelte-loader"&gt;svelte-loader&lt;/a&gt;. Therefore, you can directly use &lt;a href="https://github.com/sveltejs/svelte-loader"&gt;svelte-loader&lt;/a&gt; in Rspack for svelte application development. You can refer to &lt;a href="https://github.com/web-infra-dev/rspack/tree/main/examples/svelte"&gt;example-svelte&lt;/a&gt; to complete the svelte-loader related configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storybook
&lt;/h3&gt;

&lt;p&gt;With the help of the Storybook team, Rspack has completed support for the Storybook React version. You can follow the &lt;a href="https://www.rspack.dev/guide/migrate-storybook.html"&gt;migrate Storybook&lt;/a&gt; method to migrate from the webpack version to the Rspack version. In actual projects, tests have shown that the Rspack version is 5-10 times faster than the Webpack version when the docgen feature is not turned on. When docgen is turned on, since Rspack still relies on babel to handle docgen, the performance is affected, but there is still a 2-3 times improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular
&lt;/h3&gt;

&lt;p&gt;With the help of the &lt;a href="https://valor-software.com/"&gt;Valor&lt;/a&gt; team, Rspack has completed preliminary support for Angular. You can use Rspack to build Angular applications, but the support for dev and HMR has not yet been fully adapted. We will continue to follow up on Angular support in version 0.2.x.&lt;/p&gt;

&lt;h3&gt;
  
  
  NestJS
&lt;/h3&gt;

&lt;p&gt;With the help of &lt;a href="https://rosa.be/"&gt;Rosa&lt;/a&gt;, &lt;a href="https://nx.dev/"&gt;Nx&lt;/a&gt;, and &lt;a href="https://valor-software.com/"&gt;Valor&lt;/a&gt;, Rspack has completed the compilation support for &lt;a href="https://nestjs.com/"&gt;NestJS&lt;/a&gt;. You can use Rspack to package NestJS applications, and in actual projects, tests have shown that Rspack has a 5-10 times build performance improvement compared to the webpack version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark
&lt;/h2&gt;

&lt;p&gt;Added a benchmark comparison with esbuild. Please refer to the following link for more details: &lt;a href="https://github.com/web-infra-dev/performance-compare"&gt;https://github.com/web-infra-dev/performance-compare&lt;/a&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Dev guide
&lt;/h2&gt;

&lt;p&gt;The Rspack team cherishes the valuable contributions made by the open source community and wants to actively fosters collaboration. We are committed to maintaining an open approach, striving to engage and involve the community at every step.&lt;/p&gt;

&lt;p&gt;This is why we are currently crafting a comprehensive development guide that equips contributors with all the essential materials required to facilitate the development of Rspack.&lt;/p&gt;

&lt;p&gt;The current version of the guide contains all the necessary materials for building, testing, debugging, and profiling Rspack. Additionally, it includes contribution procedures, such as creating a minimal reproducible example.&lt;br&gt;
In the future, the guide will offer an insightful overview of Rspack's architecture, enabling contributors to gain a profound understanding of the project's intricate inner workings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test infrastructures
&lt;/h2&gt;

&lt;p&gt;In order to ship with confidence, we are currently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building and testing a list of examples in the Rspack repository (currently 38 examples)&lt;/li&gt;
&lt;li&gt;Porting all webpack tests from the webpack repository&lt;/li&gt;
&lt;li&gt;Running all tests on Node 14, 16 and 18&lt;/li&gt;
&lt;li&gt;Maintaining a separate ecosystem-ci repository for integration tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Nightly Release
&lt;/h2&gt;

&lt;p&gt;In order to expedite iteration, Rspack is released daily with the "@nightly" tag to npm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Acknowledgements
&lt;/h2&gt;

&lt;p&gt;With the release of Rspack 0.2, we wholeheartedly thank all the contributors who have put effort into this version.&lt;/p&gt;

&lt;p&gt;Special thanks to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/TheLarkInn"&gt;@TheLarkInn&lt;/a&gt; and &lt;a href="https://github.com/alexander-akait"&gt;@alexander-akait&lt;/a&gt;, for answering and resolving many of Rspack team's questions about Webpack.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/zackarychapple"&gt;@zackarychapple&lt;/a&gt;, &lt;a href="https://github.com/valorkin"&gt;@valorkin&lt;/a&gt;, &lt;a href="https://github.com/edusperoni"&gt;@edusperoni&lt;/a&gt;, and &lt;a href="https://github.com/Coly010"&gt;@Coly101&lt;/a&gt; for assisting the Rspack team with basic support for Angular and &lt;a href="https://github.com/zackarychapple"&gt;@zackarychapple&lt;/a&gt; for reviewing this release blog.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/suxin2017"&gt;@suxin2017&lt;/a&gt;, for supporting System.js format and optional-dependency functionality in Rspack, as well as contributing a lot in terms of Windows compatibility.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/faga295"&gt;@faga295&lt;/a&gt;, for supporting the decompression code comment feature and rspack preview feature in Rspack.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/lippzhang"&gt;@lippzhang&lt;/a&gt;, for making numerous contributions in aligning Rspack's behavior with Webpack.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/HerringtonDarkholme"&gt;@HerringtonDarkholme&lt;/a&gt;, for allowing Rspack to use rspack.config.ts as a configuration file.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dhruvkelawala"&gt;@dhruvkelawala&lt;/a&gt;, for implementing the builtins.provide feature in Rspack.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/magic-akari"&gt;@magic-akari&lt;/a&gt;, for supporting the &lt;code&gt;new URL("./foo", import.meta.url)&lt;/code&gt; syntax in Rspack.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/tuchg"&gt;@tuchg&lt;/a&gt;, for supporting the packing of .wasm files in Rspack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also want to thank all the users of Rspack, for showing trust in such a young open-source project. Your valuable feedback plays a key role in our project improvements and optimizations. Your support and trust is our motivation to move forward.&lt;/p&gt;

&lt;p&gt;Finally, let us collectively celebrate the release of Rspack 0.2 and look forward to future developments and more opportunities for collaboration. Thanks again to all friends who support and pay attention to Rspack!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webpack</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Bundler Design: A Comprehensive Exploration of Modern Bundling Technologies and Techniques</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Fri, 25 Aug 2023 22:23:18 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/bundler-design-a-comprehensive-exploration-of-modern-bundling-technologies-and-techniques-be6</link>
      <guid>https://forem.com/scriptedalchemy/bundler-design-a-comprehensive-exploration-of-modern-bundling-technologies-and-techniques-be6</guid>
      <description>&lt;p&gt;Lynx, our company’s (ByteDance) self-developed cross-platform framework (similar to React Native), has a compilation tool that diverges significantly from traditional web compilation tool chains. Unlike conventional tools, it doesn’t support dynamic styles or scripts, essentially eliminating bundleless and code splitting. The module system relies on JSON instead of JS, and there’s no browsing server environment.&lt;/p&gt;

&lt;p&gt;Given the need for real-time compilation on the web (build system), dynamic compilation (WebIDE), server-side compilation and delivery, and multi-version switching, we were compelled to create a universal bundler. This bundler had to be flexible, customizable, and operable both locally and in the browser. During its development, we faced several challenges but ultimately succeeded in creating a new universal bundler based on esbuild, resolving most of the issues we encountered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Update: Since the writing of this article, we have released &lt;a href="https://rspack.dev"&gt;rspack&lt;/a&gt;. The information however is valuable, while not necessarily up to date. I have pulled translated and republished it in english, because I believe that its a great in depth read&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="https://scriptedalchemy.medium.com/rust-port-of-webpack-rspack-the-new-kid-on-the-block-c3a3de569bfb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wUaRNRdG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://miro.medium.com/v2/resize:fill:88:88/1%2Aa0iOJNhhhm4IS6V2atHtNQ.jpeg" alt="Zack Jackson"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://scriptedalchemy.medium.com/rust-port-of-webpack-rspack-the-new-kid-on-the-block-c3a3de569bfb" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Rust Port of Webpack: Rspack | Medium&lt;/h2&gt;
      &lt;h3&gt;Zack Jackson ・ &lt;time&gt;Aug 24, 2023&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YjpYcCMa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/medium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        scriptedalchemy.Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;*Note: The original article is in Chinese, authored by &lt;a class="mentioned-user" href="https://dev.to/hardfist"&gt;@hardfist&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Bundler?
&lt;/h2&gt;

&lt;p&gt;A bundler’s task is to package a series of codes organized by modules into one or more files. Common bundlers include webpack, rollup, esbuild, etc. While most of these refer to the JS-based module system, they don’t exclude other organizational forms (e.g., wasm, usingComponents of JSON for applets, import of CSS and HTML). The generated files might also vary, such as multiple JS files created by code splitting or different JS, CSS, HTML files.&lt;/p&gt;

&lt;p&gt;Most bundlers share similar core working principles, but they may emphasize specific functions. Here’s a brief overview:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Webpack&lt;/strong&gt;: Known for supporting web development, especially with built-in HMR support. It has a robust plugin system and excellent compatibility with various module systems (amd, cjs, umd, esm, etc.). However, this compatibility can be a double-edged sword, leading to webpack-oriented programming. Its rich ecosystem is a plus, but it’s criticized for not being clean enough, lacking support for esm format generation, and being unsuitable for library development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollup&lt;/strong&gt;: Focused on library development, it’s based on the ESM module system and offers strong support for tree shaking. The product is clean and supports multiple output formats, making it suitable for library development. However, it has some drawbacks, such as needing to rely on plugins for cjs support, requiring more hacks, lacking HMR support, and depending on various plugins for application development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Esbuild&lt;/strong&gt;: Praised for its performance, esbuild offers built-in support for CSS, images, React, TypeScript, etc., and boasts an incredibly fast compilation speed (100 times faster than webpack and rollup). Its main disadvantage is a relatively simple plugin system and an ecosystem that’s not as mature as webpack and rollup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rspack&lt;/strong&gt;: Webpacks API rewritten in rust, but this was only after the writing of this post. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How bundlers work
&lt;/h2&gt;

&lt;p&gt;The implementation of bundler is very similar to the implementation of most compilers, and it also adopts a three-stage design. We can compare it&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;llvm&lt;/strong&gt;: Compile each language into LLVM IR through the front end of the compiler, then perform various optimizations based on LLVM IR, and then generate different cpu instruction set codes based on the optimized LLVM IR according to different processor architectures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;bundler&lt;/strong&gt;: Compile each module into a module graph first, then perform optimizations such as tree shaking &amp;amp; code spliting &amp;amp; minify based on the module graph, and finally generate js code in different formats from the optimized module graph according to the specified format.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comparison of LLVM and Bundler
&lt;/h3&gt;

&lt;p&gt;The similarities between traditional LLVM and bundlers allow many compilation optimization strategies to be applied in bundlers. Esbuild exemplifies this approach taken to the extreme. To understand how a bundler works, we’ll use rollup as an example, given its streamlined functions and structure. The bundle process of rollup is divided into two steps: rollup and generate, corresponding to the bundler front-end and back-end respectively.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Example: Rollup Process
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Generating the Module Graph
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//src/main.js
import lib from './lib';
console.log('lib:', lib);
//src/lib.js
const answer = 42;
export default answer;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generating the Module Graph
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const rollup = require('rollup');
const util = require('util');
async function main() {
  const bundle = await rollup.rollup({
    input: ['./src/index.js'],
  });
  console.log(util.inspect(bundle.cache.modules, { colors: true, depth: null }));
}
main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
    code: 'const answer = 42;\nexport default answer;\n',
    ast: xxx,
    dependencies: [],
    id: 'Users/admin/github/neo/examples/rollup-demo/src/lib.js'
    ...
  },
  {
    ast: xxx,
    code: 'import lib from './lib';\n\nconsole.log('lib:', lib);\n',
    dependencies: [ '/Users/admin/github/neo/examples/rollup-demo/src/lib.js' ]
    id: '/Users/admin/github/neo/examples/rollup-demo/src/index.js',
    ...
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output represents the parsed AST structure of each module included in the generated product, as well as the dependencies between modules. After building the module graph, rollup can continue to build products based on the module graph according to the user’s configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the Content
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const result = await bundle.generate({
  format: 'cjs',
});
console.log('result:', result);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generated Content
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports: [],
facadeModuleId: '/Users/admin/github/neo/examples/rollup-demo/src/index.js',
isDynamicEntry: false,
isEntry: true,
type: 'chunk',
code: "'use strict';\n\nconst answer = 42;\n\nconsole.log('lib:', answer);\n",
dynamicImports: [],
fileName: 'index.js',
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plugin System:
&lt;/h3&gt;

&lt;p&gt;Most bundlers offer a plug-in system to allow users to customize the bundler’s logic. For example, rollup’s plug-in system is divided into input and output plug-ins. The input plug-in corresponds to generating the Module Graph, while the output plug-in corresponds to generating the product according to the Module Graph. Here, we’ll focus on the input plug-in, the core of the bundler plug-in system, using esbuild as an example.&lt;/p&gt;

&lt;h4&gt;
  
  
  Core Hooks of Input Plug-in Systems
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;onResolve&lt;/strong&gt;: Determines the actual module address based on a module ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;onLoad&lt;/strong&gt;: Loads module content according to the module address.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esbuild and rollup differ from webpack in that esbuild only provides load hooks, and you can perform transform work within these hooks. Rollup additionally provides transform hooks, while webpack delegates transform work to the loader.&lt;/p&gt;

&lt;h4&gt;
  
  
  Esbuild Plug-in System
&lt;/h4&gt;

&lt;p&gt;The esbuild plug-in system’s most distinctive feature is support for virtual modules. Here are some examples to demonstrate the role of the plugin:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Loader&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A common requirement in webpack is to use various loaders to process non-JS resources. Here’s how to use the esbuild plugin to implement a simple less-loader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const less = (): Plugin =&amp;gt; {
  return {
    name: 'less',
    setup(build) {
      build.onLoad({ filter: /.less$/ }, async (args) =&amp;gt; {
        const content = await fs.promises.readFile(args.path);
        const result = await render(content.toString());
        return {
          contents: result.css,
          loader: 'css',
        };
      });
    },
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example 2: Sourcemap, Cache, and Error Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A more mature plug-in must consider sourcemap mapping after transformation, custom cache to reduce repeated overhead, and error handling. Here’s an example using svelte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let sveltePlugin = {
  name: 'svelte',
  setup(build) {
    let svelte = require('svelte/compiler')
    let path = require('path')
    let fs = require('fs')
    let cache = new LRUCache(); // 使用一个LRUcache来避免watch过程中内存一直上涨
    build.onLoad({ filter: /.svelte$/ }, async (args) =&amp;gt; {
      let value = cache.get(args.path); // 使用path作为key
      let input = await fs.promises.readFile(args.path, 'utf8');
      if(value &amp;amp;&amp;amp; value.input === input){
         return value // 缓存命中，跳过后续transform逻辑，节省性能
      }
      // This converts a message in Svelte's format to esbuild's format
      let convertMessage = ({ message, start, end }) =&amp;gt; {
        let location
        if (start &amp;amp;&amp;amp; end) {
          let lineText = source.split(/\r\n|\r|\n/g)[start.line - 1]
          let lineEnd = start.line === end.line ? end.column : lineText.length
          location = {
            file: filename,
            line: start.line,
            column: start.column,
            length: lineEnd - start.column,
            lineText,
          }
        }
        return { text: message, location }
      }

      // Load the file from the file system
      let source = await fs.promises.readFile(args.path, 'utf8')
      let filename = path.relative(process.cwd(), args.path)

      // Convert Svelte syntax to JavaScript
      try {
        let { js, warnings } = svelte.compile(source, { filename })
        let contents = js.code + `//# sourceMappingURL=` + js.map.toUrl() // 返回sourcemap，esbuild会自动将整个链路的sourcemap进行merge
        return { contents, warnings: warnings.map(convertMessage) } // 将warning和errors上报给esbuild，经esbuild再上报给业务方
      } catch (e) {
        return { errors: [convertMessage(e)] }
      }
    })
  }
}

require('esbuild').build({
  entryPoints: ['app.js'],
  bundle: true,
  outfile: 'out.js',
  plugins: [sveltePlugin],
}).catch(() =&amp;gt; process.exit(1))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Virtual Module
&lt;/h2&gt;

&lt;p&gt;The esbuild plugin system’s support for virtual modules represents a significant advancement over rollup. Generally, a bundler needs to process two types of modules: those whose paths correspond to real disk file paths, and those whose paths don’t correspond to real ones. The latter, known as virtual modules, generate content based on the path form. Virtual modules have a wide range of applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Glob Import
&lt;/h3&gt;

&lt;p&gt;A common scenario is when developing a REPL like rollupjs.org/repl/, where code samples are loaded into memfs and then built based on memfs in the browser. If there are many files involved, importing them one by one can be cumbersome. Support for glob import can simplify this process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File Structure&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;
examples
 index.html
 index.tsx
 index.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code&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 examples from ‘glob:./examples/**/*’;
import {vol} from ‘memfs’;
vol.fromJson(examples,’/’); // Mount the local examples directory to memfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This functionality can be achieved by tools like vite or babel-plugin-macro. Here’s how esbuild can implement it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyze Custom Path in onResolve&lt;/strong&gt;: Pass the metadata to onLoad through pluginData and path, and customize a namespace to prevent normal file load logic from loading the returned path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Get Metadata in onLoad&lt;/strong&gt;: Customize the logic of loading and generating data according to the metadata, and hand over the generated content to esbuild’s built-in loader for processing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Code Implementation&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;
const globReg = /^glob:/;
export const pluginGlob = (): Plugin =&amp;gt; {
  return {
    name: 'glob',
    setup(build) {
      build.onResolve({ filter: globReg }, (args) =&amp;gt; {
        return {
          path: path.resolve(args.resolveDir, args.path.replace(globReg, '')),
          namespace: 'glob',
          pluginData: {
            resolveDir: args.resolveDir,
          },
        };
      });
      build.onLoad({ filter: /.*/, namespace: 'glob' }, async (args) =&amp;gt; {
        const matchPath: string[] = await new Promise((resolve, reject) =&amp;gt; {
          glob(
            args.path,
            {
              cwd: args.pluginData.resolveDir,
            },
            (err, data) =&amp;gt; {
              if (err) {
                reject(err);
              } else {
                resolve(data);
              }
            }
          );
        });
        const result: Record&amp;lt;string, string&amp;gt; = {};
        await Promise.all(
          matchPath.map(async (x) =&amp;gt; {
            const contents = await fs.promises.readFile(x);
            result[path.basename(x)] = contents.toString();
          })
        );
        return {
          contents: JSON.stringify(result),
          loader: 'json',
        };
      });
    },
  };
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The filtering based on filter and namespace in esbuild is for performance considerations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The virtual module can not only obtain content from the disk but also calculate content directly in memory, and even import the module as a function call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Virtual Module
&lt;/h2&gt;

&lt;p&gt;The virtual module concept in esbuild is not only powerful but also highly flexible, allowing for various innovative applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Environment Variables as Virtual Module
&lt;/h3&gt;

&lt;p&gt;You can create a virtual module that represents the environment variables of the system. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let envPlugin = {
  name: 'env',
  setup(build) {
    // Intercept import paths called "env" so esbuild doesn't attempt
    // to map them to a file system location. Tag them with the "env-ns"
    // namespace to reserve them for this plugin.
    build.onResolve({ filter: /^env$/ }, args =&amp;gt; ({
      path: args.path,
      namespace: 'env-ns',
    }))

    // Load paths tagged with the "env-ns" namespace and behave as if
    // they point to a JSON file containing the environment variables.
    build.onLoad({ filter: /.*/, namespace: 'env-ns' }, () =&amp;gt; ({
      contents: JSON.stringify(process.env),
      loader: 'json',
    }))
  },
}

// 
import { NODE_ENV } from 'env' 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Function Virtual Module
&lt;/h3&gt;

&lt;p&gt;You can use the module name as a function, complete compile-time calculations, and even support recursive function calls. This example demonstrates a Fibonacci sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; build.onResolve({ filter: /^fib((\d+))/ }, args =&amp;gt; {
            return { path: args.path, namespace: 'fib' }
   })
  build.onLoad({ filter: /^fib((\d+))/, namespace: 'fib' }, args =&amp;gt; {
        let match = /^fib((\d+))/.exec(args.path), n = +match[1]
        let contents = n &amp;lt; 2 ? `export default ${n}` : `
              import n1 from 'fib(${n - 1}) ${args.path}'
              import n2 from 'fib(${n - 2}) ${args.path}'
              export default n1 + n2`
         return { contents }
  })



import fib5 from 'fib(5)' 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Stream Import
&lt;/h3&gt;

&lt;p&gt;You can run development without downloading node_modules, similar to the streaming import scene of Deno and Snowpack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Plugin } from 'esbuild';
import { fetchPkg } from './http';
export const UnpkgNamepsace = 'unpkg';
export const UnpkgHost = 'https://unpkg.com/';
export const pluginUnpkg = (): Plugin =&amp;gt; {
  const cache: Record&amp;lt;string, { url: string; content: string }&amp;gt; = {};
  return {
    name: 'unpkg',
    setup(build) {
      build.onLoad({ namespace: UnpkgNamepsace, filter: /.*/ }, async (args) =&amp;gt; {
        const pathUrl = new URL(args.path, args.pluginData.parentUrl).toString();
        let value = cache[pathUrl];
        if (!value) {
          value = await fetchPkg(pathUrl);
        }
        cache[pathUrl] = value;
        return {
          contents: value.content,
          pluginData: {
            parentUrl: value.url,
          },
        };
      });
      build.onResolve({ namespace: UnpkgNamepsace, filter: /.*/ }, async (args) =&amp;gt; {
        return {
          namespace: UnpkgNamepsace,
          path: args.path,
          pluginData: args.pluginData,
        };
      });
    },
  };
};

// in file
import react from 'react';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scenarios and Flexibility
&lt;/h2&gt;

&lt;p&gt;The virtual module allows for different scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local Development: Completely use local file loading.&lt;/li&gt;
&lt;li&gt;Local Development without Node Modules: Suitable for super-large monorepo projects where installing all node_modules is too slow.&lt;/li&gt;
&lt;li&gt;Web-Side Real-Time Compilation: For performance and network issues, where third-party libraries are fixed, and business code may change.&lt;/li&gt;
&lt;li&gt;Dynamic Compilation on the Web Side: Intranet WebIDE scenarios, where both third-party libraries and business code are not fixed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Converting CommonJS (CJS) to ECMAScript Modules (ESM)
&lt;/h3&gt;

&lt;p&gt;On the browser, has been a complex task. While rollup offers a solution, it comes with inherent problems and additional complexities. Esbuild provides an alternative approach, utilizing a module wrapper similar to Node for CJS compatibility, and introducing a minimal runtime to support CJS. This method ensures better compatibility with CJS, simplifies the process by eliminating the need for additional plugins, and represents a promising direction for those seeking to perform this conversion on the browser without unnecessary complications.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Virtual Module Support in Rollup
&lt;/h3&gt;

&lt;p&gt;The support of rollup’s virtual module is quite hacky, and a ‘\0’ is put in front of the dependency path, which is intrusive to the path, and is not very friendly to some ffi scenarios (c++ string regards ‘\0’ as a terminal symbol). When dealing with more complex virtual module scenarios, the path ‘\0’ is very easy to deal with problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  File System
&lt;/h3&gt;

&lt;p&gt;The local bundler accesses the local file system, but there is no local file system in the browser, so how to access files can generally be realized by implementing the bundler as independent of the specific &lt;code&gt;fs&lt;/code&gt;, and all file access is configurable &lt;code&gt;fs&lt;/code&gt; to access. Rollup’s REPL(&lt;a href="https://rollupjs.org/repl/"&gt;https://rollupjs.org/repl/&lt;/a&gt;) does that. Therefore, we only need to replace the loading logic of the module from &lt;code&gt;fs&lt;/code&gt; with the &lt;code&gt;memfs&lt;/code&gt; on the browser. The onLoad hooks can be used to replace the reading logic of the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node Module Resolution
&lt;/h3&gt;

&lt;p&gt;When we switch file access to &lt;code&gt;memfs&lt;/code&gt;, an ensuing problem is how to obtain the actual path format corresponding to the id of require and import. The algorithm for mapping an id to a real file address in node is module resolution. This algorithm’s implementation is more complex and needs to consider the following situations. For detailed algorithms, see &lt;a href="https://tech.bytedance.net/articles/69/"&gt;https://tech.bytedance.net/articles/69/&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;file|index|directory three situations&lt;/li&gt;
&lt;li&gt;js, json, addon multi-file suffix&lt;/li&gt;
&lt;li&gt;The difference between esm and cjs loader&lt;/li&gt;
&lt;li&gt;main field processing&lt;/li&gt;
&lt;li&gt;Conditional exports processing&lt;/li&gt;
&lt;li&gt;exports subpath&lt;/li&gt;
&lt;li&gt;NODE_PATH processing&lt;/li&gt;
&lt;li&gt;recursive lookup&lt;/li&gt;
&lt;li&gt;Symlink processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the complexity of node module resolution itself, we may also need to consider the main module filed fallback, alias support, ts and other suffix support and other functions that webpack supports but are more popular in the community, yarn|pnpm|npm and other package management tools are compatible and other issues. It is costly to implement this set of algorithms from scratch, and the module resolution algorithm of node has been updated. The enhanced-resolve module of webpack basically realizes the above functions, and supports custom &lt;code&gt;fs&lt;/code&gt;, which can be easily transplanted to &lt;code&gt;memfs&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main Field
&lt;/h3&gt;

&lt;p&gt;The main field is also a relatively complicated problem, mainly because there is no unified specification, and the community library does not fully comply with the specification, which mainly involves the distribution of packages, except that the main field is officially supported by nodejs, module, browser, browser Various bundlers and third-party community libraries have not reached a consensus on fields such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to configure the entry of cjs and esm, esnext and es5, node and browser, dev and prod&lt;/li&gt;
&lt;li&gt;The code in module| main should be es5 or esnext (determines whether the code in node_module needs to use transformer)&lt;/li&gt;
&lt;li&gt;Should the code in the module point to the implementation of the browser or the implementation of the node (determines the node bundler and the priority of main and module in the case of browser bundler)&lt;/li&gt;
&lt;li&gt;How to distribute and process the difference code between node and browser, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Upkg
&lt;/h3&gt;

&lt;p&gt;Next, we need to process the module of &lt;code&gt;node_modules&lt;/code&gt;. There are two ways at this time. One is to mount the full amount of node_modules into &lt;code&gt;memfs&lt;/code&gt;, and then use enhanced-resolve to load the corresponding modules in &lt;code&gt;memfs&lt;/code&gt;. The other way is to use For unpkg, convert the id of node_modules to unpkg’s request. These two methods have their applicable scenarios. The first one is suitable for a relatively fixed number of third-party modules (if it is not fixed, &lt;code&gt;memfs&lt;/code&gt; must not be able to carry infinite node_modules modules), and the access speed of &lt;code&gt;memfs&lt;/code&gt; is much faster than network request access, so it is very Suitable for the realization of building systems. The second type is suitable for the number of third-party modules is not fixed, and there is no obvious real-time requirement for compilation speed. This type is more suitable for webide scenarios like codesandbox, and businesses can independently choose the npm modules they want.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shims and Polyfills
&lt;/h3&gt;

&lt;p&gt;Another problem encountered by web bundler is that most of the community modules are developed around node, which will rely heavily on the native API of node, but the browser does not support these APIs, so these modules are directly run on the browser. There will be problems. At this time, there are two situations...&lt;/p&gt;

&lt;h4&gt;
  
  
  Simulating Node Utility APIs
&lt;/h4&gt;

&lt;p&gt;One is that these modules actually rely on some node utility APIs such as utils, path, etc. These modules do not actually depend on node runtime. At this time, we can actually simulate these APIs on the browser. Browserify is actually designed to solve this kind of scenario, providing a large number of node API polyfills on the browser, such as path-browserify, stream-browserify, etc. These polyfills allow developers to utilize Node-like functionality within the browser environment, bridging the gap between server-side and client-side code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Separating Browser and Node Logic
&lt;/h4&gt;

&lt;p&gt;The other situation is to process the logic of the browser and node separately. Although the code of node does not need to be executed on the browser, it is not expected that the implementation of node will increase the size of the browser bundle package and cause errors. At this time, we need node-related modules to be externally processed. This means that the code specific to the Node environment is isolated from the browser bundle, ensuring that the browser does not have to load unnecessary code that it cannot execute.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Little Trick
&lt;/h3&gt;

&lt;p&gt;A little trick to handle this situation, especially when configuring external may be troublesome or impossible to modify the bundler configuration, is to wrap &lt;code&gt;require&lt;/code&gt; in &lt;code&gt;eval&lt;/code&gt;, and most bundlers will skip the packaging of the require module. Such as &lt;code&gt;eval(‘require’)(‘os’)&lt;/code&gt;. This trick allows developers to bypass certain bundling constraints, providing more flexibility in handling platform-specific dependencies.&lt;/p&gt;

&lt;p&gt;In conclusion, shims and polyfills play a crucial role in bridging the differences between the Node and browser environments. By simulating Node APIs or separating logic based on the platform, developers can create more portable and efficient code that runs smoothly across different environments. Whether it’s through the use of existing libraries like Browserify or clever coding tricks, these techniques are essential tools in the modern web development toolkit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Assembly
&lt;/h2&gt;

&lt;p&gt;Web Assembly (Wasm) is a binary instruction format that allows code written in languages like C++ to be executed in a web browser. This technology has opened up new possibilities for web development, enabling performance-critical applications to run at near-native speed. However, integrating Web Assembly into a web project can present challenges, particularly when it comes to managing file size.&lt;/p&gt;

&lt;h3&gt;
  
  
  C++ Modules and Web Assembly
&lt;/h3&gt;

&lt;p&gt;In many businesses, including the one described here, C++ modules are essential. In a local environment, C++ can be compiled into a static library and called through Foreign Function Interface (FFI). However, in the browser, it needs to be compiled into Web Assembly to run. This compilation process can result in large file sizes. For example, the Web Assembly module of esbuild is about 8MB, and a custom-compiled static library may also be around 3MB. These large file sizes can have a significant impact on the overall package size, affecting load times and user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Splitting Solution
&lt;/h3&gt;

&lt;p&gt;A potential solution to this problem is to apply code splitting techniques to the Web Assembly modules. By dividing the Web Assembly code into “hot” and “cold” segments, developers can optimize the loading process:&lt;/p&gt;

&lt;p&gt;— &lt;strong&gt;Hot Code&lt;/strong&gt;: This segment includes the code that is most likely to be used during the initial access. By loading only this portion of the Web Assembly module at first, the initial load time can be reduced, enhancing the user experience.&lt;br&gt;
— &lt;strong&gt;Cold Code&lt;/strong&gt;: This segment includes the code that is less likely to be used or only needed in specific scenarios. By deferring the loading of this portion, the overall package size for the initial load can be minimized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applications of esbuild
&lt;/h3&gt;

&lt;p&gt;esbuild is a versatile tool that offers three core functionalities, each of which can be used independently or in combination with the others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minifier&lt;/strong&gt;: Reduces the file size of code by removing unnecessary characters and spaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transformer&lt;/strong&gt;: Converts code from one form to another, such as from TypeScript to JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bundler&lt;/strong&gt;: Combines multiple files and dependencies into a single file for easier distribution.&lt;/li&gt;
&lt;li&gt;Below are some specific applications where esbuild can be utilized:&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Enhanced Registration and Minification Tools
&lt;/h4&gt;

&lt;p&gt;By leveraging esbuild’s transformation function, developers can use esbuild-register to replace the registration of unit test frameworks like ts-node. This substitution significantly boosts the speed of the process. An example of this can be found at github.com/aelbore/esb. Additionally, since ts-node now supports custom registers, it's possible to directly replace the register with esbuild-register. When it comes to minification, esbuild's performance surpasses that of terser by more than 100 times, making it a highly efficient choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Node Bundler: A Case for Bundling in the Node Community
&lt;/h2&gt;

&lt;p&gt;Unlike the front-end community, the node community rarely employs bundling solutions. This discrepancy arises partly because node services may utilize operations like file system (fs) and addons that are not bundle-friendly. Additionally, most bundling tools are designed with the front-end in mind, leading to the need for extra configuration when applied to the node domain.&lt;/p&gt;

&lt;p&gt;However, bundling node applications or services offers significant advantages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reduction in Node Modules Volume: Bundling can decrease the size of node_modules, accelerating installation. By installing only the bundled code instead of numerous dependencies, the installation volume is greatly reduced, speeding up the process. Tools like pnpm and yarn exemplify this approach (source).&lt;/li&gt;
&lt;li&gt;Enhanced Cold Start Speed: Bundling can improve the cold start speed of applications by reducing the JS code size through tree shaking. Since parsing overhead is a significant factor in the cold start speed of large applications, this reduction is especially beneficial for applications sensitive to cold start times. Additionally, avoiding file IO further enhances the speed, making bundling suitable for scenarios like serverless that are sensitive to cold start.&lt;/li&gt;
&lt;li&gt;Avoidance of Upstream Semver Disruption: Semver (Semantic Versioning) is a community specification with strict code requirements. Bundling the code can prevent upstream dependencies from causing application bugs, a crucial consideration for high-security applications like compilers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Given these benefits, the author strongly advocates for bundling node applications, and esbuild offers ready support for node bundles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges and Limitations of esbuild
&lt;/h2&gt;

&lt;p&gt;While esbuild offers many advantages, it’s essential to recognize some of its challenges and limitations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Debugging Difficulties:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Language Barrier: esbuild’s core code is written in Golang, and users interact with compiled binary code and JavaScript glue code.&lt;/li&gt;
&lt;li&gt;Debugging Constraints: Breakpoint debugging the binary code is nearly impossible using tools like lldb or gdb.&lt;/li&gt;
&lt;li&gt;High Debugging Requirements: Debugging esbuild’s code requires pulling down the code, recompiling, and debugging, a process that is both demanding and complex.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limited Target Support:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ES6 Targeting: esbuild’s transformer currently only targets ES6.&lt;/li&gt;
&lt;li&gt;ES5 Considerations: Many developers, especially in certain regions, still need to consider ES5 scenarios. As a result, esbuild cannot be used as the final product on its own and often requires collaboration with tools like Babel, TSC, or SWC to transition from ES6 to ES5.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Performance and Size Issues with Golang WebAssembly (Wasm):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance Degradation: The performance of Wasm compiled by Golang is suboptimal, with a 3–5 times degradation compared to native performance.&lt;/li&gt;
&lt;li&gt;Package Size: The Wasm package compiled by Go is relatively large (8M+), making it unsuitable for scenarios sensitive to package size.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Smaller Plugin API:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited Hooks: Compared to the extensive plugin API support in Webpack and Rollup, esbuild only supports two plugin hooks: onLoad and onResolve.&lt;/li&gt;
&lt;li&gt;Functionality Gaps: While these hooks enable a wide range of tasks, they are still relatively limited. For instance, post-processing of chunks after code splitting is not supported.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Rust Port of Webpack? Rspack, the New Kid on the Block</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Fri, 25 Aug 2023 22:00:50 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/rust-port-of-webpack-rspack-the-new-kid-on-the-block-3pgh</link>
      <guid>https://forem.com/scriptedalchemy/rust-port-of-webpack-rspack-the-new-kid-on-the-block-3pgh</guid>
      <description>&lt;p&gt;Created by the ByteDance Web Infra team, Rspack is a Rust-based bundler. It’s known for fast performance, interoperability with the Webpack ecosystem, strong customization abilities, and defaults — letting users hit the ground running without needing to configure much. It’s been made to solve tough challenges in business settings, improving the experience of many developers.&lt;/p&gt;

&lt;p&gt;We’ve officially open-sourced Rspack to encourage innovation and teamwork. Developers, tech fans, and anyone interested in web development are welcome to join us. Whether you want to explore, create, or just be part of something big, Rspack is ready for you.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1655538017669648385-153" src="https://platform.twitter.com/embed/Tweet.html?id=1655538017669648385"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1655538017669648385-153');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1655538017669648385&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This &lt;a href="https://zhuanlan.zhihu.com/p/612776782"&gt;article&lt;/a&gt; was translated, written by &lt;a class="mentioned-user" href="https://dev.to/hardfist"&gt;@hardfist&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Rspack: An In-Depth Look
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Develop Rspack?
&lt;/h3&gt;

&lt;p&gt;ByteDance works with lots of big front-end applications, about 6,500, that take a long time to build, sometimes up to half an hour. They tried many ways to make the process faster, but nothing from the existing community tools worked well enough. After looking deeper into the problem, they found that no tools were quite right for what they needed, so they decided to create &lt;a href="https://rspack.dev"&gt;Rspack&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1646081461622128641-832" src="https://platform.twitter.com/embed/Tweet.html?id=1646081461622128641"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1646081461622128641-832');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1646081461622128641&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Good Dev Start Performance: Engineers often run the npm run dev command multiple times a day. With large-scale projects, each run might require a 10 minute wait, causing significant inconvenience. Therefore, optimizing the dev start time became a crucial necessity.&lt;/li&gt;
&lt;li&gt;Good Build Performance: The npm run build command is frequently executed in the CI/CD environment, determining the efficiency of application production delivery. In some instances, build times could reach 20 to 30 minutes, emphasizing the need for a more time-efficient solution.&lt;/li&gt;
&lt;li&gt;Enough Flexible Configuration: ByteDance’s varied user project configurations haven’t been fully unified, leading to issues when migrating the Webpack configuration to other build tools. The need for a solution with the flexibility of Webpack was apparent.&lt;/li&gt;
&lt;li&gt;Production Environment Optimization Capability: Prior to Rspack, community solutions encountered negative impacts on the production environment optimization. Ensuring product optimization in the production environment was a non-negotiable feature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After examining four main areas in need of improvement and looking into existing solutions, it became clear that nothing quite met the specific needs of large-scale front-end applications. The decision was made to create Rspack, though not without challenges.&lt;/p&gt;

&lt;p&gt;Rspack isn’t just an answer to existing problems; it’s a custom-built tool, carefully designed to fit unique build requirements of large projects and modern needs. It represents a thoughtful effort to enhance performance, flexibility, and optimization, with the hope of making a meaningful difference in the web development landscape.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ambitious Path to Rspack:
&lt;/h3&gt;

&lt;p&gt;A thorough investigation into existing community solutions showed that there were no tools that fulfilled all the specific needs identified. This led to the decision to develop Rspack in-house. By shaping the tool to meet these challenges, the team embarked on an innovative path, crafting a customized solution that holds the potential to become a force to be reckoned with.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1694617380452962615-609" src="https://platform.twitter.com/embed/Tweet.html?id=1694617380452962615"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1694617380452962615-609');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1694617380452962615&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Collaboration and Inspirations
&lt;/h3&gt;

&lt;p&gt;Rspack’s development is a result of collective inspiration, guidance, and support from various projects and individuals in the community:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Webpack Team and Community: For creating an excellent packaging tool and a rich ecosystem.&lt;/li&gt;
&lt;li&gt;@sokra: For significant work on the webpack project.&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/scriptedalchemy"&gt;@scriptedalchemy&lt;/a&gt;: For creating the module federation and helping connect Rspack with the community.&lt;/li&gt;
&lt;li&gt;SWC project (created by @kdy1): For support in Rspack’s dependency analysis, code transpilation, and compression.&lt;/li&gt;
&lt;li&gt;esbuild project (created by @evanw): Inspiring Rspack’s concurrency architecture.&lt;/li&gt;
&lt;li&gt;NAPI-RS project (created by &lt;a class="mentioned-user" href="https://dev.to/brooooooklyn"&gt;@brooooooklyn&lt;/a&gt;): For support in Rspack’s node-binding implementation.&lt;/li&gt;
&lt;li&gt;Parcel project (created by @devongovett): An early explorer of Rust Bundler, inspiring Rspack’s incremental build architecture.&lt;/li&gt;
&lt;li&gt;Vite project (created by @尤雨溪): Its compatibility design with the Rollup community inspired the compatibility design of Rspack and Webpack communities.&lt;/li&gt;
&lt;li&gt;Rolldown project (created by the Rolldown team): Explores using Rust to build a high-performance Bundler + compatible Rollup API, inspired the design direction of Rspack.&lt;/li&gt;
&lt;li&gt;html-webpack-plugin project (created by &lt;a class="mentioned-user" href="https://dev.to/jantimon"&gt;@jantimon&lt;/a&gt;): Rspack forks this to avoid using webpack API not yet supported in Rspack.&lt;/li&gt;
&lt;li&gt;Turbopack project: Inspired the AST-based path rewriting logic in Rspack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rspack’s unique appeal extends to its interoperability with the existing Webpack ecosystem, including loaders, API, and config. While boasting a seamless integration, Rspack offers an added advantage: it comes with “wheels on.” This means that developers can get started without the verbosity or complexity typically associated with powerful tools. The design philosophy of Rspack is to provide power as and when you need it, making it accessible for beginners yet robust for experts.&lt;/p&gt;

&lt;p&gt;What sets Rspack apart is its commitment to compatibility without compromising on functionality. The team behind Rspack is constantly expanding the API surface by adding more of Webpack’s plugin hooks, ensuring a broad alignment with the existing ecosystem. This thoughtful inclusion provides a dual benefit: it allows for easy transition for those familiar with Webpack and opens up avenues for exploiting more advanced features.&lt;/p&gt;

&lt;p&gt;The development environment at ByteDance, characterized by a vast portfolio of software and a high-speed iterative process, demands an agile and powerful tool like Rspack. With the capability to compile large codebases rapidly, integration with Webpack’s ecosystem, and a design that enables both ease of entry and advanced utilization, Rspack proves itself as a valuable asset.&lt;/p&gt;

&lt;p&gt;To try out Rspack, view the repository: &lt;a href="https://github.com/web-infra-dev/rspack"&gt;GitHub&lt;/a&gt; — Rspack and check the official website: &lt;a href="https://rspack.dev/"&gt;Rspack Official Website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0OH9vsgg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6214x2hqvkf8vytmyb70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0OH9vsgg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6214x2hqvkf8vytmyb70.png" alt="Image description" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://javascript.plainenglish.io/rust-port-of-webpack-rspack-the-new-kid-on-the-block-c3a3de569bfb?source=rss-9ef1379caffc------2"&gt;Continue reading on JavaScript in Plain English »&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Next.js 11, Module Federation, and SSR — A whole new world</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Sat, 04 Sep 2021 22:10:41 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/next-js-11-module-federation-and-ssr-a-whole-new-world-4e0p</link>
      <guid>https://forem.com/scriptedalchemy/next-js-11-module-federation-and-ssr-a-whole-new-world-4e0p</guid>
      <description>&lt;p&gt;Server-side rendering with Next 11 and Module federation is ready for prime time! Bonus: we got "hot" (live) reloading working on federated applications!&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  Its been a long and painful road to module federation inside a next.js application — but we have finally been able to remove most of that pain.
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the first time I can confidently say that we have been able to achieve full-scale Module Federation in Next.js — not just client-side but server-side as well!&lt;/p&gt;

&lt;p&gt;Months ago, we demonstrated the concept of code-streaming, the idea was to make Node work like a browser and download remote chunks, executing them under its process. This was seamless and easy but posed some security concerns and in the case of next.js, where we are unable to "hot reload" production, those required chunks would get "stuck" and your host applications need to be restarted in order to re-fetch new remote chunks what were updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7YpNXy5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aigm7orS9Yr33inZajjLbKw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7YpNXy5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aigm7orS9Yr33inZajjLbKw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Say hello to multi-server rendering!
&lt;/h2&gt;

&lt;p&gt;The Module Federation Group has conjured up a more acceptable solution to solve Federated SSR. Our solution doesn’t just work with Next.js applications — but this article is going to focus on utilizing our new system within the context one Next.js&lt;/p&gt;

&lt;p&gt;Jacob outlines more details around the underlaying architecture&lt;br&gt;
&lt;a href="https://www.ebey.me/blog/webpack-federation-ssr"&gt;&lt;strong&gt;Webpack Federation SSR | ebey.me&lt;/strong&gt;&lt;br&gt;
*Webpack Module Federation has been a game changer in the micro-frontend space allowing multiple SPA's to operate as one…*www.ebey.me&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Huge credit and shout out to &lt;a href=""&gt;Jacob Ebey.&lt;/a&gt; A critical part and mastermind behind this architecture&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Multi-server rendering is exactly what it sounds like, the remotes accept props from the host application and perform the render at their origin, sending back the pre-rendered HTML. The whole process is blazing fast and if you put it behind a CDN, its even faster. Since rendering a single component only takes around 10ms–20ms, and our parser only adds 5–7ms of overhead on larger payloads.&lt;/p&gt;

&lt;p&gt;Once we get the markup from the remote origin, our parser converts the HTML back into React, if you are passing host-originated children inside a remote component, those children are re-connected to the host render tree and render context. So they are still able to participate in any app-specific context that takes place during the render cycle.&lt;/p&gt;

&lt;p&gt;What’s important to note is that we are able to asynchronously render any remote components at their origins simultaneously, so an RTT waterfall does not begin to develop, the response time is as fast as the slowest response — just like a Promise.all&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  getOrCreateFederatedComponentCtx,
  federatedComponentsContext,
  federatedComponent,
} from "nextjs-shared";

import remotes from "../remotes";

const Header = federatedComponent("home", "./header");

function MyApp({ Component, pageProps, federatedComponentsCtx, shellData }) {
  return (
    &amp;lt;federatedComponentsContext.Provider
      value={getOrCreateFederatedComponentCtx(
        { remotes },
        federatedComponentsCtx
      )}
    &amp;gt;
      &amp;lt;Header items={shellData.header.menu} /&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/federatedComponentsContext.Provider&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Hydration and avoiding flicker
&lt;/h3&gt;

&lt;p&gt;User experience needs to be seamless, so we cannot have any flicker happen during hydration. In order to achieve this, we utilize a mechanism similar to react-lazy-hydration, where we only hydrate parts of the react tree from HTML into interactive React at startup. This preserves the existing markup and suppresses any hydration problems that may happen. Once Webpack kicks in and the federated code is executed, the SSR’d remote module is then hydrated into a federated react component.&lt;/p&gt;

&lt;p&gt;I use react-lazy-hydration quite extensively to improve performance, offloading expensive components so they are only hydrated when TTI is reached or that are about to be scrolled into view with intersection observer. So applying a similar tactic to federated SSR is perfectly acceptable to me, and very effective.&lt;/p&gt;
&lt;h3&gt;
  
  
  Module Federation and Chunk Flushing are back!
&lt;/h3&gt;

&lt;p&gt;One big request from the community has been that packages like react-loadable or loadable-components are unable to "flush" out and render federated Javascript tags and style sheets that were used. Causing additional RTT as the remote container kicks in, and has to go download these additional JS chunks right away.&lt;/p&gt;

&lt;p&gt;Our new solution solves this problem, server-side rendered federated modules also flush out their JS and CSS chunks under our latest architecture design. Order to the world has been restored!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z-milfbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcdKeu-y-2y54mgy-sMdWUQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z-milfbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AcdKeu-y-2y54mgy-sMdWUQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While other third parties do not support federated chunk flushing, when using our &lt;code&gt;fetchFederatedComponent&lt;/code&gt; function, the flush will happen as expected and we handle flushing of federated chunks independently. If you use code splitting, keep using loadable-components for your internal chunks but you would be able to use our federated functions for getting those critical assets rendered to the DOM during SSR.&lt;/p&gt;

&lt;p&gt;We place the CSS and js chunks into next.js context so next is aware of these additional scripts the whole time — ensuring there's no flicker during rehydration, no additional RTT to slow down your load times.&lt;/p&gt;
&lt;h3&gt;
  
  
  Making Module Federation and Next.js play nice
&lt;/h3&gt;

&lt;p&gt;Next.js does not support Module Federation out of the box, you will need to depend on a &lt;a href="https://app.privjs.com/buy/packageDetail?pkg=@module-federation/nextjs-mf"&gt;plugin&lt;/a&gt; from the Module Federation Group which provides support. As far as I am aware, there are no near-future plans to see Next.js support Module Federation out of the box and when it does arrive — there are slim chances that SSR support will be available. At the time of writing, I believe that the MF Group is the only organization that possesses the technology to offer a "no limits" capability on Next's platform.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://app.privjs.com/buy/packageDetail?pkg=@module-federation/nextjs-mf"&gt;nextjs-mf&lt;/a&gt; plugin enables Module Federation on the &lt;strong&gt;client-side&lt;/strong&gt;, regardless of SSR you will need this in order for Federation to work at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Case for Module Federation on Next.js applications
&lt;/h2&gt;

&lt;p&gt;Next.js is not modular, it's very monolithic and mostly focuses on faster monolithic builds. But this pattern isn’t sustainable, Next Zones attempts to get closer to a more modular setup, but you are still locked in at page verticals and cannot escape a full page reload when switching zones.&lt;/p&gt;

&lt;p&gt;Federation enables us to make Next.js highly modular. You can develop a MegaNav that can be deployed independently of the rest of your application, or split teams up in a more granular and autonomous manner. Teams can own components and are not chained to a page, and those components can be easily distributed across other pages without needing to re-deploy an entire Next.js instance or multiple instances. You don't have to depend on npm package bumps as a way to distribute shared code and you don’t have to depend on third-party vendors for patterns like ESI in order to get some modularity.&lt;/p&gt;

&lt;p&gt;With server-side rendering solved, there are no drawbacks to leveraging module federation to tame and scale Next.js far more effectively.&lt;/p&gt;
&lt;h3&gt;
  
  
  No Page Reloads!!
&lt;/h3&gt;

&lt;p&gt;Next Zones had the right idea but it's time to wave goodbye to page reloads when jumping between apps and instead welcome Federated Page Routing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4-CTp8dq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AVuCj3vRa0tez7fxYV74rNg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4-CTp8dq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AVuCj3vRa0tez7fxYV74rNg.jpeg" alt="And the 97 lighthouse score speaks for itself"&gt;&lt;/a&gt;&lt;em&gt;And the 97 lighthouse score speaks for itself&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The core concept here is that you stay on the host application and instead federate the page into that application, not reload, and SSR another page from another application. SSR costs money, avoiding a page refresh and instead, leveraging client-side routing to simply pull the page from another application is faster, cheaper, and a better user experience.&lt;/p&gt;



&lt;p&gt;To make this possible, we take advantage of the mechanics of Module Federation and next.js a CatchAll route.&lt;/p&gt;

&lt;p&gt;We have a primitive example of omnidirectional, distributed routing available on Github.&lt;br&gt;
&lt;a href="https://github.com/module-federation/module-federation-examples/tree/master/nextjs"&gt;&lt;strong&gt;module-federation-examples/nextjs at master · module-federation/module-federation-examples&lt;/strong&gt;&lt;br&gt;
*Module Federation in Next.js depends on @module-federation/nextjs-mf It will not work unless you have access to this…*github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each application exposes a route map via module federation and the CatchAll page federates all the remote route-maps together, then uses some simple pattern recognition to see if the current path matches any existing mapped routed from a specific remote, if it does we call that remote and get the federated page — if we are unable to resolve the route, or if a JS error occurs for any reason, the CatchAll route simply performs a window.location.reload() which would bounce the user back through your application infrastructure and either land them on another SSR route that wasn’t mapped, an external URL, or a 404 page.&lt;/p&gt;

&lt;p&gt;This mechanism and how we designed the federation plugin for Next.js ensures that even if federated pages have an error, the Next.js route will not, guaranteeing that navigating between pages will always work, and in the worst-case falling back to a page reload.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// [...slug].js
import { createFederatedCatchAll } from "nextjs-shared"; export default createFederatedCatchAll(["checkout", "home"]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and the magic behind createFederatedCatchAll&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function createFederatedCatchAll(remotes) {&lt;br&gt;
  const FederatedCatchAll = (initialProps) =&amp;gt; {&lt;br&gt;
    const [lazyProps, setProps] = React.useState({});
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { FederatedPage, render404, renderError, needsReload, ...props } = {
  ...lazyProps,
  ...initialProps,
};

React.useEffect(async () =&amp;amp;gt; {
  if (needsReload) {
    const federatedProps = await FederatedCatchAll.getInitialProps(props);
    setProps(federatedProps);
  }
}, []);

if (render404) {
  // *TODO: Render 404 page
  *return React.createElement("h1", {}, "404 Not Found");
}
if (renderError) {
  // *TODO: Render error page
  *return React.createElement("h1", {}, "Oops, something went wrong.");
}

if (FederatedPage) {
  return React.createElement(FederatedPage, props);
}

return null;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;FederatedCatchAll.getInitialProps = async (ctx) =&amp;gt; {&lt;br&gt;
    const { err, req, res, AppTree, ...props } = ctx;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (err) {
  // *TODO: Run getInitialProps for error page
  *return { renderError: true, ...props };
}

if (!***process***.browser) {
  return { needsReload: true, ...props };
}

try {
  const matchedPage = await matchFederatedPage(remotes, ctx.asPath);

  const remote = matchedPage?.value?.remote;
  const mod = matchedPage?.value?.module;

  if (!remote || !mod) {
    // *TODO: Run getInitialProps for 404 page
    *return { render404: true, ...props };
  }

  ***console***.log("loading exposed module", mod, "from remote", remote);
  try {
    if (!***window***[remote].__initialized) {
      ***window***[remote].__initialized = true;
      await ***window***[remote].init(__webpack_share_scopes__.default);
    }
  } catch (initErr) {
    ***console***.log("initErr", initErr);
  }

  const FederatedPage = await ***window***[remote]
    .get(mod)
    .then((factory) =&amp;amp;gt; factory().default);
  ***console***.log("FederatedPage", FederatedPage);
  if (!FederatedPage) {
    // *TODO: Run getInitialProps for 404 page
    *return { render404: true, ...props };
  }

  const modifiedContext = {
    ...ctx,
    query: matchedPage.params,
  };
  const federatedPageProps =
    (await FederatedPage.getInitialProps?.(modifiedContext)) || {};
  return { ...federatedPageProps, FederatedPage };
} catch (err) {
  ***console***.log("err", err);
  // *TODO: Run getInitialProps for error page
  *return { renderError: true, ...props };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;};&lt;/p&gt;

&lt;p&gt;return FederatedCatchAll;&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Interested in Federated SSR? Contact us!&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Our fetch implementation of SSR is not open source and took immense time and effort to develop, for any companies interested in leveraging our technology, we are happy to hold a workshop or consult, the Module Federation Group does accept clients. We are the creators of Module Federation&lt;/p&gt;

&lt;p&gt;You can get in contact:&lt;/p&gt;

&lt;p&gt;&lt;a href="//mailto:Zackary.l.jackson@gmail.com"&gt;Zackary.l.jackson@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or over Twitter&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/ScriptedAlchemy"&gt;ScriptedAlchemy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/ebey_jacob"&gt;ebey_jacob&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or book a workshop directly&lt;br&gt;
&lt;a href="https://calendly.com/scripted-alchemy/next-js-federated-ssr-workshop"&gt;&lt;strong&gt;Next.js Federated SSR Workshop - Zack Jackson&lt;/strong&gt;&lt;br&gt;
*Workshop plus private access to source code that contains a reference architecture for Federated SSR on Next.js - 8…*calendly.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>modulefederation</category>
      <category>webpack</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Micro Frontend Architecture: Replacing a monolith from the inside out</title>
      <dc:creator>Zack Jackson</dc:creator>
      <pubDate>Tue, 12 Nov 2019 02:42:12 +0000</pubDate>
      <link>https://forem.com/scriptedalchemy/micro-frontend-architecture-replacing-a-monolith-from-the-inside-out-3ali</link>
      <guid>https://forem.com/scriptedalchemy/micro-frontend-architecture-replacing-a-monolith-from-the-inside-out-3ali</guid>
      <description>&lt;h2&gt;
  
  
  How to modernize a legacy application with micro-frontend technology
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/@ScriptedAlchemy?source=post_page-----61f60d2e14c1----------------------"&gt;Zack Jackson&lt;/a&gt; &lt;br&gt;
&lt;em&gt;This article is part of a series on micro-frontend applications and techniques for managing them.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Let us assume there’s a Monolithic codebase. The monolith uses one of the backend templating engines or systems, jQuery, and has no real considerations for frontend — or worse, comes from a time before SPAs existed. Maybe it has some asset pipeline like Ruby on Rails does. In that case, you might have backend variables inside javascript files — like &lt;em&gt;.js.erb&lt;/em&gt; files, or AEM Fragments. &lt;strong&gt;A coupled, spaghetti codebase that feels next to impossible to modernize.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  You want to stop writing frontend code inside this monolith and move to more JavaScript oriented ecosystem, but how?
&lt;/h2&gt;

&lt;p&gt;Most companies cannot afford (will not accept) the engineering downtime of a “tools down” rewrite. Features need to progress under active development. Those features are undoubtedly getting harder to release at the same speed.&lt;/p&gt;
&lt;h2&gt;
  
  
  The monolith needs should be broken down into smaller pieces in a progressive, transitional way. It cannot interrupt business
&lt;/h2&gt;

&lt;p&gt;However, decoupling a monolith can be tricky, primarily when new API’s to support a JavaScript application need to undergo planning or development to support the frontend migration.&lt;/p&gt;

&lt;p&gt;Iterative frontend development, micro frontend (MFE) implementation, and team autonomy are blocked while waiting for the necessary APIs to undergo development or finish and go into a release cycle. &lt;strong&gt;FALSE, you can decouple the frontend in parallel to backend&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M5sbwKq5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/3072/1%2AP7xZ-hErIvKArY3DDY18mQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--M5sbwKq5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/3072/1%2AP7xZ-hErIvKArY3DDY18mQ.jpeg" width="1536" height="642"&gt;&lt;/a&gt;&lt;br&gt;
Zack Jackson — ScriptedAlchemy&lt;br&gt;
Here is one solution to decouple a frontend and port it to a standalone MFE complete with SSR. This method allows a team to do so without waiting for backend API’s to be abstracted and decoupled into microservices or even consumable API’s within the monolith. &lt;strong&gt;Replace the monolith from the inside out&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  The Blockers
&lt;/h1&gt;

&lt;p&gt;Micro frontends typically have these two necessary dependencies.&lt;br&gt;
1) Authentication &lt;br&gt;
2) Data to feed the application, both in the browser and during server-side rendering (SSR)&lt;br&gt;
In my experience, user authentication seems always to be the hardest part to separate from a monolithic backend. Regardless of if the legacy system is Rails, Java, .Net, etc.&lt;br&gt;
There are other challenging aspects to micro frontend architecture, which will be elaborated on in a future series. So stay tuned!&lt;/p&gt;
&lt;h1&gt;
  
  
  Use the Monolith as a Layout Engine
&lt;/h1&gt;

&lt;p&gt;There are a couple of different architectural specifications for MFE platform design. This article will focus on an adapted specification which is popular amongst backend microservices — &lt;strong&gt;LOSA (Lots Of Small Applications)&lt;/strong&gt;architectureis a good option for “inside-out” migrations.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DxAEI4dJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2Ax4AIizwcAeaVyC_eTrIU0A.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DxAEI4dJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2Ax4AIizwcAeaVyC_eTrIU0A.jpeg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d5CPfB55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4404/1%2Ax4AIizwcAeaVyC_eTrIU0A.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--d5CPfB55--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4404/1%2Ax4AIizwcAeaVyC_eTrIU0A.jpeg" width="2202" height="533"&gt;&lt;/a&gt;&lt;br&gt;
LOSA Request/Response flow via the monolith. Image credit to Robert Arkwright&lt;br&gt;
&lt;strong&gt;LOSA&lt;/strong&gt; applications (micro frontends in general) are standalone Node.js services capable of server-side rendering a part or fragment of a webpage that the service as mentioned earlier is responsible for servicing. A page can be made up of multiple &lt;strong&gt;LOSA&lt;/strong&gt; services. These apps/or micro-frontends are built and deployed to a container which is independent. Operating in a standalone manner&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---O6tlmqP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4404/1%2AtzE-p6IHtG5oqMybdIz_iQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s---O6tlmqP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4404/1%2AtzE-p6IHtG5oqMybdIz_iQ.jpeg" width="2202" height="533"&gt;&lt;/a&gt;&lt;br&gt;
The same web page, composed three different ways, demonstrating an incremental migration path. Starting as a monolith rendered page, transitioning to LOSA micro frontends and finally ending up as a micro frontend verticle, completely replacing the monolith. Image Credit Robert Arkwright&lt;br&gt;
The monolith remains responsible for handling an HTTP request object, sending the final response to the client. Micro frontends can stay behind a firewall within the cluster — only available directly to the legacy system until such a time when an API gateway &amp;amp; user authentication can be decoupled (or at least turned into an API endpoint). You don’t need many changes to prepare these frontends for their post-monolith life.&lt;/p&gt;
&lt;h1&gt;
  
  
  The Render Flow
&lt;/h1&gt;

&lt;p&gt;Below is modeled example of what a request/response could when up resembling.&lt;br&gt;
First, a request is made:&lt;br&gt;
GET/POST '&lt;a href="https://MFEwebsite.com/parts/header?format=json"&gt;https://MFEwebsite.com/parts/header?format=json&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KdFegTY2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2APBPgZnLihWpoYYVNyiSKAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KdFegTY2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2APBPgZnLihWpoYYVNyiSKAA.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BMgH_Rof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4776/1%2APBPgZnLihWpoYYVNyiSKAA.png" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--BMgH_Rof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4776/1%2APBPgZnLihWpoYYVNyiSKAA.png" width="2388" height="1668"&gt;&lt;/a&gt;&lt;br&gt;
Rendering a page can require a variety of data, any “missing” information that cannot yet be queried from a decoupled endpoint can be &lt;strong&gt;sent&lt;/strong&gt; &lt;em&gt;to_the_MFE (_micro frontend) &lt;strong&gt;as props&lt;/strong&gt;_during&lt;/em&gt; the request. Heres what the MFE does when a request is made, the request is passed through a piece of middleware which is responsible for rendering the react application, a query is made to any necessary APIs that are decoupled and its response is sent back to it as props. These props will make up window.INITIAL_STATE&lt;/p&gt;
&lt;h1&gt;
  
  
  The code
&lt;/h1&gt;

&lt;p&gt;If you are in need of some inspiration on how to implement some of these template functions or filters, then Hypernova is worth looking at. I haven’t used Hypernova, always opting to build my own. I have implemented similar mechanisms into Rails, Node, and PHP backends. Due to the proprietary nature of various backend platforms, I’ll be using Hypernova’s examples to convey a rudimentary concept.&lt;br&gt;
Here is what an MFE rendering endpoint would look like in express:&lt;br&gt;
&lt;strong&gt;The request from another system, in this case — the monolith&lt;/strong&gt;&lt;br&gt;
GET/POST '&lt;a href="https://MFEwebsite.com/parts/header?format=json"&gt;https://MFEwebsite.com/parts/header?format=json&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
   html: '&amp;lt;div&amp;gt; ... &amp;lt;/div&amp;gt;',
   css: '/static/header.3042u3298423.css',
   js: '/static/header.idhf93hf23iu.js',
   initial_state: {items:[...]}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The middleware that handles the response:&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;export function exampleRenderAPIware(req, res) {
  const renderedMarkup = renderHTMLpage(
    req,
    this.index,
    intial_state,
  );
  asyncRender.then(() =&amp;gt; {
    const responseObject = {
      html: renderedMarkup,
      initial_state,
      js: jsResource,
      css: cssResource,
    };
    res.status(200).end(JSON.stringify(responseObject));
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controllers making these initial POST requests should handle the responses, placing JS and CSS into the right locations. And finally rendering the react app into the appropriate spot in the legacy template. Here’s an example of what that legacy template looks like now. The assets, usually handled by some other controller in your monolith, will be responsible for injecting those scripts and styles into what’s left on the legacy header and bottom of the body tag. Remember, the monolith still serves as the layout engine. We are replacing parts, and adding new features in a React SSR way. Eventually, these LOSA apps could be stitched back together under one MFE or with Webpack black magic I’m developing. Known as  &lt;a href="https://github.com/ScriptedAlchemy/webpack-external-import"&gt;webpack-external-import&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What about migrating from template data to a new API?
&lt;/h2&gt;

&lt;p&gt;When a new API is decoupled and brought online, what can be expected in migration?&lt;br&gt;
When the monolith is providing the data to an MFE, express.js accesses this information off the HTTP request body. Now express would need to asynchronously fetch from the API. Data formats might have changed, but React still receives props. Underwhelmingly straightforward.&lt;/p&gt;

&lt;h1&gt;
  
  
  Performance
&lt;/h1&gt;

&lt;p&gt;Compared to older monoliths, the new LOSA (lots of small applications) architecture wasn't performant enough, taking 400–600ms for a part of the page to render. We used Async Worker structures, meaning that instead of one SSR’d app, we could ask multiple services to SSR different parts of the application. This made it very hard to bring production offline because a “production failure” meant maybe losing a sidebar or footer for 10 mins till it was fixed. Separation of concerns at its finest.&lt;br&gt;
Here’s what I mean by LOSA async workers. There were many node services, each responsible for rendering a component/components&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OmjNDp-I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2AO8QFoZCYUclxH-iDYEc49A%402x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OmjNDp-I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/%26%26%26SFLOCALFILEPATH%26%26%261%2AO8QFoZCYUclxH-iDYEc49A%402x.jpeg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ytcthmxd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4776/1%2AO8QFoZCYUclxH-iDYEc49A%402x.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ytcthmxd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4776/1%2AO8QFoZCYUclxH-iDYEc49A%402x.jpeg" width="2388" height="1668"&gt;&lt;/a&gt;&lt;br&gt;
Controllers (the grey gear) powering a legacy backend view can divert the view data to a post request instead of to a backend templating engine. Recycling data means there isn’t much effort required on the backend to support these mechanics. Avoiding major modifications will free up most of backend engineering to focus on decoupling data providers, while the frontend can progress independently. Since the view data was posted to an external react service, the response to that POST, which contains markup — is then passed to the backend templating engine, along with stylesheet, initial state, and CSS URLs. The templating engine now just renders the response from the POST request, thus decoupling your view or part of it from the legacy monolith.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Render Time
&lt;/h2&gt;

&lt;p&gt;React was slow!! SSR just isn’t fast — so our new react solution LOSA architecture wasn’t performant enough to be viable. Our solution, &lt;strong&gt;Fragment caching inside react&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oceFT3-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4216/1%2AjILQjF2AroeXDVR_neY_fQ%402x.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--oceFT3-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4216/1%2AjILQjF2AroeXDVR_neY_fQ%402x.jpeg" width="2108" height="1040"&gt;&lt;/a&gt;&lt;br&gt;
    *   Yellow: No React fragment caching — end-to-end(+-400ms)&lt;br&gt;
    *   Dark purple: With React fragment caching — End-to-end (+-150ms)&lt;br&gt;
    *   Orange: The fully optimized architecture (+-20ms)&lt;br&gt;
    *   Green(at bottom of data points): native fragment cache from the backend&lt;br&gt;
I will need to write another article to detail the whole process around creating a fully optimized react server (Sorry  &lt;a href="https://medium.com/u/742f2d568062?source=post_page-----61f60d2e14c1----------------------"&gt;Anton Korzunov&lt;/a&gt; ). The Graphana data shows that we at least doubled our render performance, the round robin-times were still really slow. While internally, react was able to render very quickly — the end-to-end times were not as performant as we hoped. At least 150ms. As you can see, and as I’ll elaborate on in the next article — I can compete with fragment backend fragment caching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render time vs round-robin time
&lt;/h2&gt;

&lt;p&gt;Render times are part of the challenge but even after implementing fragment caching inside React. I was disappointed to see that while our internal render times within Node.js were blazing fast (around 20ms). The whole end to end trip &lt;strong&gt;still&lt;/strong&gt; took 140–200ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the bottlenecks
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1   JSON size, specifically initial application state. Send the bare minimum state needed to render the page. Stop dumping so much stringified state into the initial render. Send enough state so React is able to re-hydrate and maybe some extra state for making above the fold components interactive immediately.&lt;br&gt;
2   The number of DOM nodes to render — stop wrapping your code in useless divs, just to put a class on it. Take advantage of the semantic nature of HTML and the cascading effects of CSS. You end up writing way less markup, thus causing way less React.createComponent functions to be generated.&lt;br&gt;
3   Garbage collection — more details will follow in a followup article series&lt;br&gt;
4   Only as fast as the data providers. — Make use of Redis caches in the middle tier. If you throw the “cache invalidation is hard” argument at me then look at event sourcing. Even better, tackle the problem with CQRS and async workers on the writes and reads.&lt;br&gt;
5   HTTP overhead between monolith and MFE — gRPC, CQRS, UDP, Protobuf. This communication between the monolith and your MFE should be happening internally over kubernetes networks. POST is slow, but works. When you hit the problem, handle it accordingly.&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  How I outperformed a backend rendering&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Templatization, fragment caching, and gRPC/CQRS, removing bloat from the initial state JSON. React is slow(er) on the server. It's easy to forget, no abstraction is faster, only less slow.&lt;/p&gt;

&lt;h1&gt;
  
  
  What about scale?
&lt;/h1&gt;

&lt;p&gt;Any good solution needs to be cost-effective at scale. Operating costs grow to astronomical amounts. Money talks, bad performance costs. I build cheap solutions at scale. Heres ways where perf can cost you:&lt;br&gt;
1) paying for expensive third-party services to shoulder the load&lt;br&gt;
2) paying for more / bigger containers&lt;br&gt;
3) missed revenue due to bad performance&lt;br&gt;
4) The monolith usually causes release cycles or deployment traffic jam’s as two branches cannot going into master at the same time.&lt;br&gt;
5) Developers can move faster in lower-risk environments, business is able to deliver new ideas to market and roll back problematic areas — a team that can move fast and efficiently is a cost-effective enabler to business.&lt;/p&gt;

&lt;h1&gt;
  
  
  The result
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Traffic&lt;/strong&gt;: 10 million (renders) / day&lt;br&gt;
&lt;strong&gt;Resource Allocations:&lt;/strong&gt;&lt;br&gt;
    *   Instances: 5&lt;br&gt;
    *   RAM: 100mi (100 megs of ram)&lt;br&gt;
    *   CPU: 100 (single-core)&lt;br&gt;
    *   Max CPU usage threshold: 65%&lt;br&gt;
    *   Response time: 20–25ms&lt;br&gt;
    *   DOM Complexity: High&lt;br&gt;
    *   95% reduction in response time.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O043BLgG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4136/1%2AfS9hsG5Ehv6wngJXE2sdRw.jpeg" class="article-body-image-wrapper"&gt;&lt;img class="de t u iq ak" src="https://res.cloudinary.com/practicaldev/image/fetch/s--O043BLgG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4136/1%2AfS9hsG5Ehv6wngJXE2sdRw.jpeg" width="2068" height="1035"&gt;&lt;/a&gt;&lt;br&gt;
    *   Green: Backend render times&lt;br&gt;
    *   Blue: React With Fragment Caching and state optimization.&lt;/p&gt;

&lt;h2&gt;
  
  
  My single-threaded javascript application was faster than a multi-threaded backend system with a fully-fledged fragment cache.
&lt;/h2&gt;

&lt;p&gt;Follow me on  &lt;a href="https://twitter.com/ScriptedAlchemy"&gt;twitter&lt;/a&gt;  :)&lt;br&gt;
DM me if you are in need more information or a consultation.&lt;br&gt;
In the next series — I shall elaborate on the performance aspect that was briefly mentioned towards the end of this article.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>react</category>
      <category>webpack</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
