<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Uncle Pushui</title>
    <description>The latest articles on DEV Community by Uncle Pushui (@uncle-pushui).</description>
    <link>https://dev.to/uncle-pushui</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%2F1868785%2F4af20aa0-38f0-4c64-97c1-4c18ab16e060.png</url>
      <title>DEV Community: Uncle Pushui</title>
      <link>https://dev.to/uncle-pushui</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/uncle-pushui"/>
    <language>en</language>
    <item>
      <title>Vite: How to resolve bundle fragmentation?</title>
      <dc:creator>Uncle Pushui</dc:creator>
      <pubDate>Mon, 14 Oct 2024 11:12:00 +0000</pubDate>
      <link>https://dev.to/uncle-pushui/vite-how-to-resolve-bundle-fragmentation-3jm7</link>
      <guid>https://dev.to/uncle-pushui/vite-how-to-resolve-bundle-fragmentation-3jm7</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;When we use Vite for bundle code files, we often encounter this problem: With the development of the business, there are more and more pages, more and more third-party dependencies, and the chunks are getting bigger and bigger. If the pages are imported dynamically, then all the files shared by several pages will be independently bundled to the same chunk, which will create a large number of tiny js chunk files, such as: 1K, 2K, 3K, which significantly increases the resource request of the browser.&lt;/p&gt;

&lt;p&gt;Although you can customize the chunks-merging strategy through the &lt;code&gt;rollupOptions.output.manualChunks&lt;/code&gt;, the dependencies between the files are intricate. If the chunks-merging configuration is unreasonable, it will cause the initial chunks to be too large, or the circular reference will occur. Therefore, the mental burden is heavy. Is there an automated chunks-merging mechanism to completely solve the problem of bundle fragmentation?&lt;/p&gt;

&lt;h2&gt;
  
  
  Two potential issues of chunks-merging
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, there are two potential issues to use the &lt;code&gt;rollupOptions.output.manualChunks&lt;/code&gt; custom chunks-merging strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cause the initial chunks to large
&lt;/h3&gt;

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

&lt;p&gt;As shown in the figure, file A originally only depends on file C, but according to the chunks-merging configuration in the figure, Chunk1 and Chunk2 must be downloaded before using file A. In a complex project, due to the complexity of the dependencies between the files, this dependency will spread quickly with the merger of a large number of small files, resulting in the large size of the initial bundles.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Cause circular reference error
&lt;/h3&gt;

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

&lt;p&gt;As shown in the figure, due to the mutual dependence between the files, Chunk1 and Chunk2 will cause circular dependence error. Then in complex projects, the scenes of mutual dependence between code files are more common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: modular system
&lt;/h2&gt;

&lt;p&gt;Because the chunks-merging configuration will lead to the above two potential issues, it is often difficult to follow, and it is difficult to have a simple and easy-to-use configuration rules that can be followed. Because the chunks-merging configuration is closely related to the current state of the project. Once the code of the project has changed, the chunks-merging configuration also needs to be changed accordingly.&lt;/p&gt;

&lt;p&gt;To solve this problem, I introduced a modular system in the project. That is, the code of the project is split according to business characteristics to form a combination of several modules. Each module can include pages, components, configurations, languages, tools and other resources. Then a module is a natural bundle boundary, and automatically bundled into an independent asynchronous chunk when building, bidding farewell to the hassle of Vite configuration and effectively avoiding the fragmentation of bundles. Especially in large business systems, this advantage is particularly evident. Of course, the use of a modular system is also conducive to code decoupling and facilitating division of labor collaboration.&lt;/p&gt;

&lt;p&gt;Since a module is a bundle boundary, we can control the content and quantity of the chunks by controlling the content and quantity of the modules. And we divide the modules based on business characteristics to make the chunks-merging configuration have obvious business significance. Compared with the customization of the &lt;code&gt;rollupOptions.output.manualChunks&lt;/code&gt;, it is obviously low mental burden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;As the project continues to evolve iteratively, the business modules created will also expand. In addition, for some business scenarios, multiple modules are often required to be implemented together. To solve the above problems, We can introduces the concept of suite. In short, a suite is a combination of a group of business modules. In this way, a project is composed of several suites and several modules. Below is the directory structure of a project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project
├── src
│  ├── module
│  ├── module-vendor
│  ├── suite
│  │  ├── a-demo
│  │  └── a-home
│  │    ├── modules
│  │    │  ├── home-base
│  │    │  ├── home-icon
│  │    │  ├── home-index
│  │    │  └── home-layout
│  └── suite-vendor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;src/module&lt;/td&gt;
&lt;td&gt;Standalone module (not part of a suite)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/module-vendor&lt;/td&gt;
&lt;td&gt;Standalone module (from third-party)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/suite&lt;/td&gt;
&lt;td&gt;Suite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;src/suite-vendor&lt;/td&gt;
&lt;td&gt;Suite (from third-party)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a-demo&lt;/td&gt;
&lt;td&gt;demo suite: Put the test code into a suite, so that it is convenient to disable at any time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a-home&lt;/td&gt;
&lt;td&gt;business suite: including 4 business modules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Chunks-merging effect
&lt;/h2&gt;

&lt;p&gt;Let's take a look at the actual bundle effect:&lt;/p&gt;

&lt;p&gt;Taking the module &lt;strong&gt;home-base&lt;/strong&gt; as an example, the left shows the code of the module, and the right shows the chunk size is 12k, and 3K with gzip. To achieve this chunks-merging effect, no configuration is required.&lt;/p&gt;

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

&lt;p&gt;For another example, we can also concentrate the layout components into the module &lt;strong&gt;home-layout&lt;/strong&gt; for management. The module is bundled into an independent chunk, which size is 29K and 6K with gzip.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Source code inside
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Dynamic import modules
&lt;/h3&gt;

&lt;p&gt;Since the module directory structure of the project is regular, we can extract all the module list before the project startup, and then generate a js file to centrally implement the dynamic import of modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modules&lt;/span&gt; &lt;span class="o"&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;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home-base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home-base&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)};&lt;/span&gt;
&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home-layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home-layout&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;modulesMeta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;modules&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since all modules are dynamically imported through the import method, it will automatically split into independent chunks when performing Vite building.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Chunks-merging Configuration
&lt;/h3&gt;

&lt;p&gt;We also need to customize the chunks-merging configuration through &lt;code&gt;rollupOptions.output.manualChunks&lt;/code&gt; to ensure that the code inside the module is uniformly bundled together to avoid fragmented files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;__ModuleLibs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="sr"&gt;/src&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;module&lt;/span&gt;&lt;span class="se"&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;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/src&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;module-vendor&lt;/span&gt;&lt;span class="se"&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;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/src&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;suite&lt;/span&gt;&lt;span class="se"&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;modules&lt;/span&gt;&lt;span class="se"&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;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/src&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;suite-vendor&lt;/span&gt;&lt;span class="se"&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;modules&lt;/span&gt;&lt;span class="se"&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;/&lt;/span&gt;&lt;span class="p"&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;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;rollupOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;manualChunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;customManualChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;customManualChunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;moduleLib&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;__ModuleLibs&lt;/span&gt;&lt;span class="p"&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;matched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleLib&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matched&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Each file path is matched with a regular expression. If the matching is successful, use the corresponding module name as chunk name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions to two potential issues
&lt;/h2&gt;

&lt;p&gt;If the modules are interdependent, there may be two potential issues mentioned above, as shown in the figure:&lt;/p&gt;

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

&lt;p&gt;In order to prevent the occurrence of the two potential issues, we can implement a dynamic loading and resource positioning mechanism. In short, when we access the resources of &lt;strong&gt;Module 2&lt;/strong&gt; in &lt;strong&gt;Module 1&lt;/strong&gt;, we must first dynamically load module 2, then find the resources of module 2 and return them to the caller.&lt;/p&gt;

&lt;p&gt;For example, there is a Vue component &lt;code&gt;Card&lt;/code&gt; in module 2, and a page component &lt;code&gt;FirstPage&lt;/code&gt; in module 1. We need to use the &lt;code&gt;Card&lt;/code&gt; component in the page component &lt;code&gt;FirstPage&lt;/code&gt;. Then, we need to do it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// dynamically load module&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&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;moduleRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;modulesMeta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;moduleRepo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// create dynamic component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createDynamicComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;defineAsyncComponent&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// dynamically load module&lt;/span&gt;
      &lt;span class="nf"&gt;loadModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;moduleResource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// return the component of module&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;moduleResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ZCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createDynamicComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Module2&lt;/span&gt;&lt;span class="dl"&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;Card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderFirstPage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ZCard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;
  
  
  Advanced import mechanism
&lt;/h2&gt;

&lt;p&gt;Although using &lt;code&gt;createDynamicComponent&lt;/code&gt; can achieve the desired purpose, the code is not concise enough and cannot fully utilize the automatic import mechanism provided by Typescript. We still hope to use the component in the usual way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ZCard&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;Module2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderFirstPage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ZCard&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Such code is in the form of static import, which will cause &lt;strong&gt;Module 1&lt;/strong&gt; and &lt;strong&gt;Module 2&lt;/strong&gt; to be strongly dependent on each other. So, is there a way to have the best of both worlds? Yes. We can develop a Babel plug-in to parse the AST syntax tree and automatically change the &lt;code&gt;ZCard&lt;/code&gt; import to a dynamic import form. In this way, our code is not only concise and intuitive, but also can implement dynamic import, avoiding the occurrence of two potential issues when bundling. In order to avoid distracting the topic, how to develop the Babel plug-in will not be expanded here. If you are interested, you can directly refer to the source code: &lt;a href="https://github.com/cabloy/zova/blob/a6088acf4f520a65fa206b6864329b1712ae0921/zova-dev/packages-utils/babel-plugin-zova-component/src/index.ts" rel="noopener noreferrer"&gt;babel-plugin-zova-component&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article analyzes the causes of Vite bundle fragmentation and proposes a modular system to simplify the chunks-merging configuration. At the same time, it adopts a dynamic loading mechanism to perfectly avoid the occurrence of two potential issues during bundling.&lt;/p&gt;

&lt;p&gt;Of course, there are still many details to consider in order to realize a complete modular system. If you want to experience the out-of-the-box effect, you can visit my open source framework: &lt;a href="https://github.com/cabloy/zova" rel="noopener noreferrer"&gt;https://github.com/cabloy/zova&lt;/a&gt;. You can contact me on twitter: &lt;a href="https://twitter.com/zhennann2024" rel="noopener noreferrer"&gt;https://twitter.com/zhennann2024&lt;/a&gt;&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>vite</category>
      <category>vue3</category>
    </item>
    <item>
      <title>How to achieve unified management of four types of global state data in Vue3?</title>
      <dc:creator>Uncle Pushui</dc:creator>
      <pubDate>Fri, 11 Oct 2024 02:22:00 +0000</pubDate>
      <link>https://dev.to/uncle-pushui/how-to-achieve-unified-management-of-four-types-of-global-state-data-in-vue3-4344</link>
      <guid>https://dev.to/uncle-pushui/how-to-achieve-unified-management-of-four-types-of-global-state-data-in-vue3-4344</guid>
      <description>&lt;h2&gt;
  
  
  Four types of global state data
&lt;/h2&gt;

&lt;p&gt;In actual development, you will encounter four types of global state data: &lt;code&gt;asynchronous data (usually from the server)&lt;/code&gt; and &lt;code&gt;synchronous data&lt;/code&gt;, while &lt;code&gt;synchronous data&lt;/code&gt; is divided into three types: &lt;code&gt;localstorage&lt;/code&gt;, &lt;code&gt;cookie&lt;/code&gt;, and &lt;code&gt;memory&lt;/code&gt;. In the traditional Vue3, different mechanisms are used to handle these state data, while only a unified &lt;code&gt;Model&lt;/code&gt; mechanism is needed in Zova&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Global State Data&lt;/th&gt;
&lt;th&gt;Traditional Vue3&lt;/th&gt;
&lt;th&gt;Zova&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;asynchronous data&lt;/td&gt;
&lt;td&gt;Pinia&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;localstorage&lt;/td&gt;
&lt;td&gt;Pinia + Localstorage&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cookie&lt;/td&gt;
&lt;td&gt;Pinia + Cookie&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;memory&lt;/td&gt;
&lt;td&gt;Pinia&lt;/td&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By using the &lt;code&gt;Model&lt;/code&gt; mechanism to uniformly manage these global state data, some common system capabilities can be provided, including &lt;code&gt;Memory Optimization&lt;/code&gt;, &lt;code&gt;Persistence&lt;/code&gt; and &lt;code&gt;SSR Support&lt;/code&gt;, etc., thereby standardizing data usage, simplifying code structure, and improving code maintainability&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 1. Support for async data and sync data
&lt;/h2&gt;

&lt;p&gt;The base of Zova Model is &lt;a href="https://tanstack.com/query/latest/docs/framework/vue/overview" rel="noopener noreferrer"&gt;TanStack Query&lt;/a&gt;. &lt;code&gt;TanStack Query&lt;/code&gt; provides powerful data acquisition, caching and update capabilities. If you have not used similar data management mechanisms like TanStack Query, it is strongly recommended that you learn about it, and you will definitely be impressed by the thought&lt;/p&gt;

&lt;p&gt;The core of TanStack Query is to manage &lt;code&gt;asynchronous data (usually from the server)&lt;/code&gt;. Zova provides some extension capabilities based on TanStack Query, so as to support the management of &lt;code&gt;synchronous data&lt;/code&gt;. In other words, all the features and capabilities described below apply to both &lt;code&gt;asynchronous data&lt;/code&gt; and &lt;code&gt;synchronous data&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 2. Automatic caching
&lt;/h2&gt;

&lt;p&gt;Locally cache the acquired asynchronous data to avoid repeated acquisition. For synchronous data, read and write operations will be automatically performed on localstorage or cookie&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 3. Automatic update
&lt;/h2&gt;

&lt;p&gt;Provide data expiration strategy and automatically update at the right time&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 4. Reduce duplicate requests
&lt;/h2&gt;

&lt;p&gt;When accessing data in multiple places in the program at the same time, the server API will only be called once. If it is synchronous data, only one operation will be called for localstorage or cookie&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 5. Memory optimization
&lt;/h2&gt;

&lt;p&gt;Although the data managed by Zova Model is in a global state, it does not always occupy memory, but provides a mechanism for memory release and recycling. Specifically, it is to create cache data according to business needs when creating a Vue component instance, release the reference to the cache data when the Vue component instance is unmounted, and if no reference and expiration time reached, the garbage collection mechanism (GC) will be triggered to complete the release of memory, thereby saving memory usage. This has significant benefits for large projects and scenarios where users need to interact with the interface for a long time&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 6. Persistence
&lt;/h2&gt;

&lt;p&gt;Local cache can be persisted and can be automatically restored when the page is refreshed to avoid server requests. If it is asynchronous data, it will be automatically persisted to &lt;code&gt;IndexDB&lt;/code&gt; to meet the storage needs of large amounts of data. If it is synchronous data, it will be automatically persisted to &lt;code&gt;localstorage&lt;/code&gt; or &lt;code&gt;cookie&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Memory optimization&lt;/code&gt; and &lt;code&gt;persistence&lt;/code&gt; work together, and the effect is more obvious for large projects. For example, the data obtained from the server will generate a local cache and automatically persist. When no longer used and expires, the local cache will be automatically destroyed to release memory. When the data is accessed again, the local cache data will be automatically restored from persistence instead of requesting the data from the server again&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 7. SSR support
&lt;/h2&gt;

&lt;p&gt;Different types of state data will also have different implementation mechanisms in SSR mode. Zova Model smoothes out the differences in these state data and uses a unified mechanism to hydrate them, making the implementation of SSR more natural and intuitive, significantly reducing the mental burden&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature 8. Automatic namespace isolation
&lt;/h2&gt;

&lt;p&gt;Zova manages data through Model Bean. The Bean itself has a unique identifier and can be used as a namespace for data, thereby automatically ensuring the uniqueness of the state data naming inside the Bean and avoiding data conflicts&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See: &lt;a href="https://zova.js.org/guide/essentials/ioc/bean-identifier.html" rel="noopener noreferrer"&gt;Bean Identifier&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to create a model bean
&lt;/h2&gt;

&lt;p&gt;Zova provides a VSCode extension that allows you to easily create a model bean through the context menu&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Context Menu - [Module Path]: &lt;code&gt;Zova Create/Bean: Model&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Enter the name of model bean according to the prompt, such as &lt;code&gt;todo&lt;/code&gt;. The VSCode extension will automatically create the code skeleton of &lt;code&gt;model bean&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For example, create a Model Bean &lt;code&gt;todo&lt;/code&gt; in the &lt;code&gt;demo-todo&lt;/code&gt; module&lt;/p&gt;

&lt;p&gt;&lt;code&gt;demo-todo/src/bean/model.todo.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Model&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;zova&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;BeanModelBase&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;zova-module-a-model&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="nd"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelTodo&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BeanModelBase&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;@Model&lt;/code&gt; decorator&lt;/li&gt;
&lt;li&gt;Inherited from base class &lt;code&gt;BeanModelBase&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Async Data
&lt;/h2&gt;

&lt;p&gt;The core of TanStack Query is to manage server-side data. For simplicity, only the definition and use of the &lt;code&gt;select&lt;/code&gt; method are shown here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For complete code examples, please see: &lt;a href="https://github.com/cabloy/zova/blob/main/zova-dev/src/suite/a-demo/modules/demo-todo/src/bean/model.todo.ts" rel="noopener noreferrer"&gt;demo-todo&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to define
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$useQueryExisting&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;queryKey&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;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;queryFn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&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;ul&gt;
&lt;li&gt;Invoke &lt;code&gt;$useQueryExisting&lt;/code&gt; to create a Query object

&lt;ul&gt;
&lt;li&gt;Why not use the &lt;code&gt;$useQuery&lt;/code&gt; method? Because asynchronous data is generally loaded asynchronously when needed. Therefore, we need to ensure that the same Query object is always returned when the &lt;code&gt;select&lt;/code&gt; method is invoked multiple times, so the &lt;code&gt;$useQueryExisting&lt;/code&gt; method must be used&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Pass in &lt;code&gt;queryKey&lt;/code&gt; to ensure the uniqueness of the local cache&lt;/li&gt;

&lt;li&gt;Pass in &lt;code&gt;queryFn&lt;/code&gt; and call this function at the appropriate time to obtain server data

&lt;ul&gt;
&lt;li&gt;service.todo.select: see &lt;a href="https://zova.js.org/guide/essentials/scope/service.html" rel="noopener noreferrer"&gt;Api service&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;demo-todo/src/page/todo/controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ModelTodo&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;../../bean/model.todo.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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerPageTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;ul&gt;
&lt;li&gt;Inject Model Bean instance: &lt;code&gt;$$modelTodo&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;demo-todo/src/page/todo/render.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RenderTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&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;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;          &lt;span class="p"&gt;})}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;ul&gt;
&lt;li&gt;Invoke &lt;code&gt;select&lt;/code&gt; method to obtain the Query object

&lt;ul&gt;
&lt;li&gt;The render method will be executed multiple times, and repeated calls to the &lt;code&gt;select&lt;/code&gt; method return the same Query object&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Directly use the state and data of the Query object

&lt;ul&gt;
&lt;li&gt;See: &lt;a href="https://tanstack.com/query/latest/docs/framework/vue/guides/queries" rel="noopener noreferrer"&gt;TanStack Query: Queries&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to support SSR
&lt;/h3&gt;

&lt;p&gt;In SSR mode, we need to use asynchronous data like this: load the state data on the server, and then render it into an HTML string through the render method. The state data and HTML string will be sent to the client at the same time, and the client will still use the same state data when hydrating so as to maintain state consistency&lt;/p&gt;

&lt;p&gt;To implement the above logic, only one step is required in Zova Model:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;demo-todo/src/page/todo/controller.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ModelTodo&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;../../bean/model.todo.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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerPageTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&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;queryTodos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;queryTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;suspense&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queryTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;queryTodos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&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;ul&gt;
&lt;li&gt;Just invoke &lt;code&gt;suspense&lt;/code&gt; in the &lt;code&gt;__init__&lt;/code&gt; method to wait for asynchronous data loading to complete&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sync Data: localstorage
&lt;/h2&gt;

&lt;p&gt;Since the server does not support &lt;code&gt;window.localStorage&lt;/code&gt;, the localstorage state data does not participate in the SSR hydration process&lt;/p&gt;

&lt;p&gt;The following demonstrates storing user information in localstorage, and the state will be retained when the page is refreshed&lt;/p&gt;

&lt;h3&gt;
  
  
  How to define
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelUser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BeanModelBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ServiceUserEntity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$useQueryLocal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;queryKey&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;user&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Unlike &lt;code&gt;async data&lt;/code&gt; definition, &lt;code&gt;sync data&lt;/code&gt; is defined directly in the initialization method &lt;code&gt;__init__&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Invoke &lt;code&gt;$useQueryLocal&lt;/code&gt; to create a Query object&lt;/li&gt;
&lt;li&gt;Pass in &lt;code&gt;queryKey&lt;/code&gt; to ensure the uniqueness of the local cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use
&lt;/h3&gt;

&lt;p&gt;Read and set data directly like regular variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sync Data: cookie
&lt;/h2&gt;

&lt;p&gt;Cookies in &lt;code&gt;Request Header&lt;/code&gt; are automatically used on the server side, and &lt;code&gt;document.cookie&lt;/code&gt; is automatically used on the client side, thus automatically ensuring the consistency of cookie state data during SSR hydration&lt;/p&gt;

&lt;p&gt;The following demonstrates storing the user Token in a cookie, and the state will be retained when the page is refreshed. Thus, in SSR mode, both the client and the server can use the same &lt;code&gt;jwt token&lt;/code&gt; to access the backend API services&lt;/p&gt;

&lt;h3&gt;
  
  
  How to define
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelUser&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BeanModelBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;token&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$useQueryCookie&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;queryKey&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;token&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Unlike &lt;code&gt;async data&lt;/code&gt; definition, &lt;code&gt;sync data&lt;/code&gt; is defined directly in the initialization method &lt;code&gt;__init__&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Invoke &lt;code&gt;$useQueryCookie&lt;/code&gt; to create a Query object&lt;/li&gt;
&lt;li&gt;Pass in &lt;code&gt;queryKey&lt;/code&gt; to ensure the uniqueness of the local cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use
&lt;/h3&gt;

&lt;p&gt;Read and set data directly like regular variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sync Data: memory
&lt;/h2&gt;

&lt;p&gt;In SSR mode, the global state data defined by the server will be synchronized to the client and automatically complete the hydration&lt;/p&gt;

&lt;p&gt;The following demonstrates the memory-based global state data&lt;/p&gt;

&lt;h3&gt;
  
  
  How to define
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;zova-ui-quasar/src/suite-vendor/a-quasar/modules/quasar-adapter/src/bean/model.theme.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelTheme&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BeanModelBase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;cBrand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cBrand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;$useQueryMem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;queryKey&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;cBrand&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Unlike &lt;code&gt;async data&lt;/code&gt; definition, &lt;code&gt;sync data&lt;/code&gt; is defined directly in the initialization method &lt;code&gt;__init__&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Invoke &lt;code&gt;$useQueryMem&lt;/code&gt; to create a Query object&lt;/li&gt;
&lt;li&gt;Pass in &lt;code&gt;queryKey&lt;/code&gt; to ensure the uniqueness of the local cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to use
&lt;/h3&gt;

&lt;p&gt;Read and set data directly like regular variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cBrand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cBrand&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cBrand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Zova is a vue3 framework with ioc container. It combines the advantages of Vue/React/Angular in code style, while avoiding their shortcomings to make our development experience more elegant and reduce the mental burden. Zova has built-in a lot of interesting features, and the Model mechanism is just one of them.&lt;/p&gt;

&lt;p&gt;Zova has been open sourced, welcome to follow and participate: &lt;a href="https://github.com/cabloy/zova" rel="noopener noreferrer"&gt;https://github.com/cabloy/zova&lt;/a&gt;. You can contact me on twitter: &lt;a href="https://twitter.com/zhennann2024" rel="noopener noreferrer"&gt;https://twitter.com/zhennann2024&lt;/a&gt; &lt;/p&gt;

</description>
      <category>vue3</category>
      <category>pinia</category>
      <category>tanstackquery</category>
      <category>ssr</category>
    </item>
    <item>
      <title>How to provide types for route query parameters in Vue3</title>
      <dc:creator>Uncle Pushui</dc:creator>
      <pubDate>Tue, 06 Aug 2024 10:07:40 +0000</pubDate>
      <link>https://dev.to/uncle-pushui/how-to-provide-types-for-route-query-parameters-in-vue3-4cih</link>
      <guid>https://dev.to/uncle-pushui/how-to-provide-types-for-route-query-parameters-in-vue3-4cih</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Recently, a Vue3 framework that supports IOC containers was released: &lt;a href="https://github.com/cabloy/zova" rel="noopener noreferrer"&gt;Zova&lt;/a&gt;. Unlike previous OOP or Class solutions, Zova still uses Setup syntax at the ui interaction side and only introduces IOC containers at the business side. &lt;code&gt;IOC containers are like a key that opens the door to business engineering for us, allowing us to explore more engineering designs and capabilities.&lt;/code&gt; A netizen made a very good suggestion: Can you provide some business scenarios to explain what Class can do but Composable can't do, so that it will be more convincing.&lt;/p&gt;

&lt;p&gt;First of all, it should be noted that there are actually no business requirements that can be done by this and not by that. Different programming paradigms bring different code styles and different programming experiences, pointing to the evaluation of development efficiency and code maintainability from different paths. Therefore, it ultimately depends on the user's own habits and actual business requirements.&lt;/p&gt;

&lt;p&gt;So, here, we will take this topic &lt;code&gt;How to provide types for route query parameters in Vue3&lt;/code&gt; as an example to see what the code styles of Composable and IOC containers are different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business requirements
&lt;/h2&gt;

&lt;p&gt;Here is a page component &lt;code&gt;User&lt;/code&gt;, which can pass three parameters through &lt;code&gt;Query&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Param&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;id&lt;/td&gt;
&lt;td&gt;number&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;name&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;''&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;married&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Composable: native
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Open page
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/test/demo/user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&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;kevin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;married&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="nf"&gt;toString&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;From the perspective of Typescript types, this code has the following two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;path: no type constraints and autocompletion&lt;/code&gt;. This will have the following three hidden dangers:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Can't remember&lt;/code&gt;: If the path is long or the words are complex, you can't remember the path and need to find it from the source file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Written wrong&lt;/code&gt;: If you accidentally write it wrong, there is no prompt, and the error will only be exposed when it is actually run&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Changed&lt;/code&gt;: If the path is changed during subsequent code maintenance, there will be no prompt in the code here, and the error will only be exposed when it is actually run&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;query: only limited type constraints, inconsistent with business types&lt;/code&gt;

&lt;ol&gt;
&lt;li&gt;For example, &lt;code&gt;Boolean&lt;/code&gt; type is not supported and must be forced to &lt;code&gt;String&lt;/code&gt; type&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Obtain parameters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRoute&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;??&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;married&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;married&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since no type tool is provided, each parameter needs to be processed separately&lt;/p&gt;

&lt;h2&gt;
  
  
  Composable：useRouteQuery
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Open page
&lt;/h3&gt;

&lt;p&gt;(Same as above)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Obtain parameters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;useRouteQuery&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;@vueuse/router&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="nb"&gt;Number&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&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;married&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRouteQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;married&lt;/span&gt;&lt;span class="dl"&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;false&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;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IOC container
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Define types
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;import { zz } from 'zova';
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="p"&gt;export const QuerySchema = zz.object({
&lt;/span&gt;&lt;span class="gi"&gt;+  id: zz.number().default(0),
+  name: zz.string().default(''),
+  married: zz.boolean().default(false),
&lt;/span&gt;});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zz&lt;/code&gt; is an enhanced version based on &lt;code&gt;zod&lt;/code&gt;, which is specially processed for route parameters and supports &lt;code&gt;array&lt;/code&gt; and &lt;code&gt;json&lt;/code&gt;. For details, see: &lt;a href="https://zova.js.org/guide/techniques/router/zod.html" rel="noopener noreferrer"&gt;Zova: zod&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You can specify the default value when defining the types&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  2. Open page
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolvePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/test/demo/user&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&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;kevin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;married&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The parameters of &lt;code&gt;resolvePath&lt;/code&gt; have type constraints and autocompletion, and are consistent with the business types&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  3. Obtain parameters
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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;married&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;married&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get parameter values ​​directly through &lt;code&gt;this.$query&lt;/code&gt;, with precise types and no need to handle default values&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;From the above example comparison, we can see that the IOC container can separate the &lt;code&gt;definition&lt;/code&gt; from the &lt;code&gt;usage&lt;/code&gt;, and the scaffolding can be created by tools on the definition side to further simplify the writing of the definition. Since the normative codes such as TS types and default values ​​are completed on the definition side, the code on the usage side is more concise and intuitive. I don't know what your code style is, and if there is a better way to implement it, you are welcome to communicate in the comment area.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vueuse.org/router/useRouteQuery/" rel="noopener noreferrer"&gt;VueUse: useRouteQuery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zova.js.org/guide/techniques/router/route-query.html" rel="noopener noreferrer"&gt;Zova: Route Query&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Come on, provide an ioc container for Vue3 that is comparable to Angular</title>
      <dc:creator>Uncle Pushui</dc:creator>
      <pubDate>Thu, 01 Aug 2024 12:11:17 +0000</pubDate>
      <link>https://dev.to/uncle-pushui/come-on-provide-an-ioc-container-for-vue3-that-is-comparable-to-angular-5ok</link>
      <guid>https://dev.to/uncle-pushui/come-on-provide-an-ioc-container-for-vue3-that-is-comparable-to-angular-5ok</guid>
      <description>&lt;h2&gt;
  
  
  Why provide an ioc container for Vue3
&lt;/h2&gt;

&lt;p&gt;Vue3 is fully capable of developing large-scale business systems due to its excellent responsive system and convenient functional features. However, we must not only be able to do it, but also do it better. The key to large-scale business systems is decoupling, thereby slowing down the growth of messy code. The ioc container is currently the best decoupling tool. Angular introduced the ioc container from the beginning, so it has always been in a leading position in business engineering, and has been waving to other front-end frameworks: "I'm waiting for you in front, and I hope to see you again in three years." So, I will try to take two steps forward, provide the ioc container in Vue3, and introduce other engineering capabilities based on it to get a new framework: &lt;a href="https://github.com/cabloy/zova" rel="noopener noreferrer"&gt;Zova&lt;/a&gt;. Is it easy to use? I look forward to your trial and feedback&lt;/p&gt;

&lt;h2&gt;
  
  
  IOC Containers
&lt;/h2&gt;

&lt;p&gt;There are two types of ioc containers in Zova:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;global ioc container&lt;/code&gt;(referred to as app container): During system initialization, a unique global bean container will be automatically created. Bean instances created in this container are all singleton mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;component instance ioc container&lt;/code&gt;(referred to as ctx container): When creating Vue component instances, the system will create a bean container for each of them. Bean instances created in this container can share data and logic within the scope of the component instance&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bean Class
&lt;/h2&gt;

&lt;p&gt;Zova adopts a modular system, and Bean Classes are provided by different modules. When using the Bean Class inside the same module, you can directly locate it based on &lt;code&gt;Class type&lt;/code&gt;. When using cross-module, you can locate it based on &lt;code&gt;Bean identifier&lt;/code&gt; instead of &lt;code&gt;Class type/file path&lt;/code&gt;, which is conducive to achieving loose coupling between modules&lt;/p&gt;

&lt;p&gt;Therefore, Zova provides two types of Bean Classes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Anonymous bean&lt;/code&gt;: The class decorated with &lt;code&gt;@Local&lt;/code&gt; is an &lt;code&gt;anonymous bean&lt;/code&gt;. This type of bean is only used within the module, there is no naming conflict, and it is easy to define and use&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Named bean&lt;/code&gt;: Except for &lt;code&gt;@Local&lt;/code&gt;, the classes decorated by the other decorator functions are &lt;code&gt;named beans&lt;/code&gt;. Zova provides a unified naming convention for such beans, which can avoid naming conflicts and facilitate cross-module usage&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Injection mechanism
&lt;/h2&gt;

&lt;p&gt;Zova provides the following injection mechanisms:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Bean Class
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;Bean Class&lt;/code&gt; to lookup and inject bean instance in the ioc container, and automatically create one if not exist. This mechanism is generally used for &lt;code&gt;same module injection&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;ModelTodo&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;../../bean/model.todo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;
  
  
  2. Bean identifier
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;Bean identifier&lt;/code&gt; to lookup and inject bean instance in the ioc container, and automatically create one if not exist. This mechanism is generally used for &lt;code&gt;cross-module injection&lt;/code&gt; and &lt;code&gt;hierarchical injection&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;zova-module-a-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerLayout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a-tabs.model.tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;ul&gt;
&lt;li&gt;Lookup and inject bean instance through &lt;code&gt;a-tabs.model.tabs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Therefore, only the type of ModelTabs needs to be imported to maintain the loose coupling relationship between modules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Registration name
&lt;/h3&gt;

&lt;p&gt;Lookup and inject bean instance in the ioc container through the &lt;code&gt;registration name&lt;/code&gt;, and return a null value if not exist. This mechanism is generally used for &lt;code&gt;same module injection&lt;/code&gt; and &lt;code&gt;hierarchical injection&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;../../bean/model.todo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&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;$$modelTodo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;ul&gt;
&lt;li&gt;Lookup and inject the bean instance by the registration name &lt;code&gt;$$modelTodo&lt;/code&gt;. Generally speaking, you should ensure that the bean instance has been injected in the ioc container in advance, otherwise a null value will be returned&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Variable name
&lt;/h3&gt;

&lt;p&gt;Lookup and inject the bean instance in the ioc container by the &lt;code&gt;variable name&lt;/code&gt;, and return a null value if not exist. This mechanism is generally used for &lt;code&gt;same module injection&lt;/code&gt; and &lt;code&gt;hierarchical injection&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;../../bean/model.todo.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerTodo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTodo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTodo&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;ul&gt;
&lt;li&gt;Lookup and inject the bean instance by the variable name &lt;code&gt;$$modelTodo&lt;/code&gt;. Generally speaking, you should ensure that the Bean instance has been injected in the ioc container in advance, otherwise a null value will be returned&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Injection scope
&lt;/h2&gt;

&lt;p&gt;The default injection scope of &lt;code&gt;anonymous bean&lt;/code&gt; is &lt;code&gt;ctx&lt;/code&gt;, and the default injection scope of &lt;code&gt;named bean&lt;/code&gt; can be specified when defining it. Different scenes have different default injection scopes. In addition, when injecting, you can also override the default injection scope through the &lt;code&gt;injectionScope&lt;/code&gt; option in @Use&lt;/p&gt;

&lt;p&gt;Zova provides the following injection scopes: &lt;code&gt;app/ctx/new/host/skipSelf&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. app
&lt;/h3&gt;

&lt;p&gt;If the injection scope is &lt;code&gt;app&lt;/code&gt;, then inject the bean instance in the global ioc container to achieve the singleton effect&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: test-module1&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StoreCounter&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: test-module2&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StoreCounter&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;zova-module-test-module1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Test&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test-module1.store.counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;$$storeCounter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StoreCounter&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;ul&gt;
&lt;li&gt;The injection scope of &lt;code&gt;Store&lt;/code&gt; is &lt;code&gt;app&lt;/code&gt; by default, so the bean instance will be lookuped and injected in the global ioc container through the bean identifier &lt;code&gt;test-module1.store.counter&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. ctx
&lt;/h3&gt;

&lt;p&gt;If the injection scope is &lt;code&gt;ctx&lt;/code&gt;, then inject the bean instance into the ioc container of the current component instance&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: a-tabs&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelTabs&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: test-module2&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;zova-module-a-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerLayout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a-tabs.model.tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;ul&gt;
&lt;li&gt;The injection scope of &lt;code&gt;Model&lt;/code&gt; is &lt;code&gt;ctx&lt;/code&gt; by default, so the bean instance will be lookuped and injected in the ioc container of the current component instance through the bean identifier &lt;code&gt;a-tabs.model.tabs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. new
&lt;/h3&gt;

&lt;p&gt;If the injection scope is &lt;code&gt;new&lt;/code&gt;, then directly create a new bean instance&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: a-tabs&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelTabs&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in module: test-module2&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;zova-module-a-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ControllerLayout&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;beanFullName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a-tabs.model.tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;injectionScope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;ul&gt;
&lt;li&gt;Since the &lt;code&gt;injectionScope&lt;/code&gt; option is specified as &lt;code&gt;new&lt;/code&gt;, a new bean instance will be directly created through the bean identifier &lt;code&gt;a-tabs.model.tabs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hierarchical injection
&lt;/h2&gt;

&lt;p&gt;Injection scope supports not only &lt;code&gt;app/ctx/new&lt;/code&gt;, but also &lt;code&gt;host/skipSelf&lt;/code&gt; which is called &lt;code&gt;hierarchical injection&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. host
&lt;/h3&gt;

&lt;p&gt;If the injection scope is &lt;code&gt;host&lt;/code&gt;, the bean instance will be lookuped in the ioc container of the current component instance and all parent containers in turn. If it does not exist, a null value is returned&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in parent component&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;zova-module-a-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Parent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a-tabs.model.tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in child component&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;zova-module-a-tabs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;injectionScope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;host&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;$$modelTabs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ModelTabs&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;ul&gt;
&lt;li&gt;Since the parent component has already injected the &lt;code&gt;ModelTabs&lt;/code&gt; bean instance, the child component can directly lookup and inject it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Hierarchical injection&lt;/code&gt; also supports all injection mechanisms: &lt;code&gt;Bean Class/Bean identifier/Registration name/Variable name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. skipSelf
&lt;/h3&gt;

&lt;p&gt;If the injection scope is &lt;code&gt;skipSelf&lt;/code&gt;, then lookup the bean instance in all parent containers in turn. If it does not exist, a null value is returned&lt;/p&gt;

&lt;p&gt;Github: &lt;a href="https://github.com/cabloy/zova" rel="noopener noreferrer"&gt;https://github.com/cabloy/zova&lt;/a&gt;&lt;br&gt;
Demo: &lt;a href="https://zova.js.org/zova-demo/" rel="noopener noreferrer"&gt;https://zova.js.org/zova-demo/&lt;/a&gt;&lt;br&gt;
Docs: &lt;a href="https://zova.js.org/guide/essentials/ioc/introduction.html" rel="noopener noreferrer"&gt;https://zova.js.org/guide/essentials/ioc/introduction.html&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
