<?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: Morgan</title>
    <description>The latest articles on DEV Community by Morgan (@morganshaw).</description>
    <link>https://dev.to/morganshaw</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%2F569299%2F5c01571e-9312-478b-a89b-d573df701b3e.jpeg</url>
      <title>DEV Community: Morgan</title>
      <link>https://dev.to/morganshaw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/morganshaw"/>
    <language>en</language>
    <item>
      <title>Migrating from Vue 2 to Vue 3.1</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Mon, 27 Sep 2021 15:57:06 +0000</pubDate>
      <link>https://dev.to/mescius/migrating-from-vue-2-to-vue-3-1-1ng1</link>
      <guid>https://dev.to/mescius/migrating-from-vue-2-to-vue-3-1-1ng1</guid>
      <description>&lt;p&gt;Developers enjoy using the open-source Vue.js, a model-view-viewmodel (MVVM) JavaScript framework, to build user interfaces and single-page applications. Its incremental, adaptable, and monolithic framework has core libraries focused on the view layer and integrates with other libraries for other layers. &lt;/p&gt;

&lt;p&gt;Vue version 2 does have its drawbacks, like limited typescript support, performance bottlenecks, challenging maintainability, and finite scalability. Vue version 3 aims to solve these issues with significant changes in architecture and function to ensure better performance, readability, maintainability, and security. Although Vue 3 is relatively new and still a work-in-progress, almost all projects will eventually need to convert or migrate to Vue 3.&lt;/p&gt;

&lt;p&gt;Let’s explore some changes in the new version of Vue.js and use a hands-on example to demonstrate how to migrate an application from Vue 2 to Vue 3. You’ll need to be familiar with Vue 2 to follow along.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vue 3 Changes
&lt;/h3&gt;

&lt;p&gt;Vue 3 has many changes, including fundamental architectural changes such as a new Global API, a new Composition API, changes to the Template Directives, changes to the Render function API, and many more. We’ll go over these differences briefly, but you can explore Vue’s &lt;a href="https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for the most in-depth information about each development. &lt;/p&gt;

&lt;h4&gt;
  
  
  Global API or Create an Application
&lt;/h4&gt;

&lt;p&gt;The Vue 2 method of creating applications kept the global state accessible so that global configurations like plugins and mixins could permanently mutate the state. This ability could potentially pollute the application.&lt;/p&gt;

&lt;p&gt;The Vue version 2 app creation syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; new Vue({
   store,
   render: h =&amp;gt; h(App)
 }).$mount('#app');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In contrast, Vue version 3 uses the new .createApp method for creating a new application. Since this is the entry-point of all Vue applications, the new root API is a major breaking change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Vue, { createApp } from 'vue';

createApp(App)
  .use(store)
  .mount("#app");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Defining New Components
&lt;/h4&gt;

&lt;p&gt;Vue 3 also changes the way Vue creates components.  &lt;/p&gt;

&lt;p&gt;The Vue 2 way is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vue.component('component-name', 
{   
 // component code here
})  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 replaces Vue.component with the root component as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = Vue.createApp({…})
app.component(‘component-name’){
   ///Component code
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using Data Options
&lt;/h4&gt;

&lt;p&gt;Vue 3 considers data as a function that returns whatever objects you need. Data isn’t an object anymore.&lt;/p&gt;

&lt;p&gt;Vue 2 handles data like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = new Vue({
   // options object
    el: '#app'
    data: 
    {
          object: &amp;lt;some object&amp;gt;
    }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 uses data like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const app = Vue.createApp({ 
  // options object    
data(){ 
       return {
            object: &amp;lt;some object or string etc&amp;gt;
      }
    }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  V-if and V-for Precedence
&lt;/h4&gt;

&lt;p&gt;If we use both the v-if and v-for directives on the same element, the v-for takes precedence in Vue 2. This precedence reverses in Vue 3, so v-if takes precedence.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vue Router Changes
&lt;/h4&gt;

&lt;p&gt;The new version of Vue Router also introduces a few breaking changes of its own. The main change is the new createRouter function. Modes like history also have create functions. &lt;/p&gt;

&lt;p&gt;The new way to use Router in Vue 3 is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createRouter, createWebHistory } from 'vue-router'
createRouter({
  history: createWebHistory(),
  hash: createWebHashHistory(),
  abstract: createMemoryHistory()
  routes: [],
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use Router, we employ the app.use(router) option before mounting the application, where the app is the root component.&lt;/p&gt;

&lt;h4&gt;
  
  
  Vuex Changes
&lt;/h4&gt;

&lt;p&gt;The new Vuex version, which is compatible with Vue 3, also has application-breaking changes similar to Vue Router. We first need to import createStore from Vuex, then use the createStore function to create a store for our application.&lt;/p&gt;

&lt;p&gt;To use Vuex in Vue 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default new Vuex.Store({
  …
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, to use Vuex createStore in Vue 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createStore } from 'vuex'
export const store = createStore({
  state () {
    return {
      count: 1
    }
  }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 also introduces the useStore. Vuex 4 uses the useStore function to get the store from a setup hook in a Vue application. According to Vue 3’s documentation, we operate useStore as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These new methods change the way we declare and use these components in a Vue application. For a list of all the other changes in Vue 3, refer to its &lt;a href="https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes" rel="noopener noreferrer"&gt;documentation.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Migration Build
&lt;/h3&gt;

&lt;p&gt;Because of Vue 3’s many changes, when developers try to run their Vue 2 application after upgrading their Vue version from 2 to 3, it fails compilation with multiple errors. Considering the size of production applications, correcting all the compiler and runtime errors can be daunting.&lt;/p&gt;

&lt;p&gt;To ease app migration from Vue 2 to Vue3, the Vue team introduced a &lt;a href="https://v3.vuejs.org/guide/migration/migration-build.html" rel="noopener noreferrer"&gt;migration build.&lt;/a&gt; According to its documentation, it helps developers configure Vue 2 behavior in Vue 3.&lt;/p&gt;

&lt;p&gt;This build runs in Vue 2 mode by default, so most public APIs (with a few exceptions) behave precisely like Vue 2. When features change or are deprecated, the migration build produces runtime warnings. Developers can also enable or disable each component’s compatibility.&lt;/p&gt;

&lt;p&gt;The migration build helps shift your application from version 2 to version 3 without rewriting the entire application. It works by running the Vue 2 application as-is, including breaking changes, in Vue 3. At the same time, it throws warnings to show what code you need to change. This build provides a smoother, easier way to make your Vue 2 app changes for Vue 3 compliance. The migration build doesn’t handle the Vue 2 specific libraries and depreciated APIs.&lt;/p&gt;

&lt;p&gt;The migration build is not an ideal, long-term solution, but you can use it as an intermediary to upgrading. That said, you can use it for production applications, if essential, according to its documentation: "If you do get your app running on the migration build, you can ship it to production before the migration is complete. Although there is a small performance/size overhead, it should not noticeably affect production UX."&lt;/p&gt;

&lt;h3&gt;
  
  
  Run a Vue 2 Application with a Migration Build
&lt;/h3&gt;

&lt;p&gt;To understand how to migrate an application, we'll explore an example. We built a Vue 2 album manager similar to Brad Traversy's To-do Manager application. Album Manager can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add an album&lt;/li&gt;
&lt;li&gt;Delete an album&lt;/li&gt;
&lt;li&gt;Mark an album as “heard”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application looks like this in Vue 2:&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage1.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage1.png" alt="image1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our app doesn’t use any third-party libraries. However, if your application does rely on these libraries, it’s best to wait for their Vue 3-compatible versions before migrating the application.&lt;/p&gt;

&lt;p&gt;According to the Vue documentation, dependencies relying on internal Vue 2 APIs or undocumented behavior commonly use private properties on VNodes. Although you can use the migration build for server-side rendering (SSR), migrating a custom setup is more involved: Vue 3 doesn’t have a bundle renderer. Vue’s creators recommend using Vue 3 SSR with Vite.&lt;/p&gt;

&lt;p&gt;If you use Nuxt.js, Vuetify, Quasar, or ElementUI, the Vue team recommends waiting for the next version. Although most significant libraries plan to release Vue 3 compatible versions soon, your application may use minor libraries that break.&lt;/p&gt;

&lt;p&gt;It may be challenging to migrate large and complex libraries even when using the migration build. However, Vue’s creators say they plan to backport Composition API and other Vue 3 features to the 2.7 release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Ready for the Migration Build
&lt;/h3&gt;

&lt;p&gt;To start the migration build, we first install the current Vue version globally on our system. To check for the Vue version, we trigger the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vue – version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command should return the current version of Vue.&lt;/p&gt;

&lt;p&gt;Next, to install the migration build, we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -global vue@^3.1.0 @vue/compat@^3.1.0
npm install -global --save-dev @vue/compiler-sfc@^3.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have installed the compatibility build, we can uninstall the template compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm uninstall vue-template-compiler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we run the Vue upgrade to check if any dependent libraries need upgrading.&lt;/p&gt;

&lt;p&gt;Now that we have installed all our dependencies and Vue migration build, we can enable the build. To do this, we edit or create a vue.config.js file with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module.exports = {
  chainWebpack: config =&amp;gt; {
    config.resolve.alias.set('vue', '@vue/compat')

    config.module
      .rule('vue')
      .use('vue-loader')
      .tap(options =&amp;gt; {
        return {
          ...options,
          compilerOptions: {
            compatConfig: {
              MODE: 2
            }
          }
        }
      })
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we have added the code and saved our file, we can run the application in compatibility mode by running the&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;npm run serve&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 command.&lt;/p&gt;

&lt;p&gt;If we’ve resolved all the dependencies correctly, the application runs as-is. But, when we open the console window, we may see multiple warnings.&lt;/p&gt;

&lt;p&gt;For example, the application runs when we run Album Manager in migration build mode, but we see the following error:&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage2.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage2.png" alt="image2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The running application looks like this:&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage3.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage3.png" alt="image3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The console errors may be warnings, but they’re breaking changes. The migration build lowers their intensity to warnings but simultaneously points out all the changes we need to make for our application to be Vue 3 compatible.&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage4.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage4.png" alt="image4"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Making Changes
&lt;/h3&gt;

&lt;p&gt;Now that we know the required changes, we can start making our application Vue 3 compatible.&lt;/p&gt;

&lt;p&gt;First, we need to upgrade Vuex to the next version. To do so, we run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -global vuex@next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we upgrade the Vue version using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @vue/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s always a good idea to&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;run npm install&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 as well.&lt;/p&gt;

&lt;p&gt;After we take care of all the upgrades, we next need to change our code. Let’s explore the code changes we need to make Album Manager run as a Vue 3 application.&lt;/p&gt;
&lt;h4&gt;
  
  
  Changing the Create API
&lt;/h4&gt;

&lt;p&gt;As we discussed earlier, Vue 3 has a new way of creating the app. To incorporate this change, we change the main.js file. We keep the Vue 2 code commented in the file for comparison. So, we change the main.js to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Vue, { createApp } from 'vue';
import App from './App.vue';
import store from './store/index';

Vue.config.productionTip = false;

//Vue 3 code
createApp(App)
  .use(store)
  .mount("#app");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Changing the Store
&lt;/h4&gt;

&lt;p&gt;Let’s simplify the store folder and write all our code in index.js. To keep our application consistent, we create action-types.js, which contains our function names.&lt;/p&gt;

&lt;p&gt;In the Vue 2 version, we create the store using the Veux.store function to enable the modules. In Vue 3, this code changes to the createStore function.&lt;/p&gt;

&lt;p&gt;The Vue 2 version is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vue.use(Vuex)
 export default new Vuex.Store({
   state: { … },
  mutations: { … },
  actions: ( … },
 modules: {  … }
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to create actions and mutations for all the activities that we perform in the application, like fetching, updating, adding, and deleting albums. To fetch data, we use &lt;a href="https://jsonplaceholder.typicode.com/albums" rel="noopener noreferrer"&gt;Typicode endpoints&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We set up the store similar to the Vue 2 syntax. The only difference is that we set it all inside the createStore function.&lt;/p&gt;

&lt;p&gt;For example, to set up the first action (that is, fetch albums), we create the following index.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default Vuex.createStore({
  state: {
    albums: [],
  },
  mutations: {
    [ACTION_TYPES.fetchAlbums]: (state, albums) =&amp;gt; (state.albums = albums),
},
 actions: {
    onFetchAlbums: async ({ commit }) =&amp;gt; {
      const response = await Axios.get(
        "https://jsonplaceholder.typicode.com/albums"
      );
      const data = response.data;
      for (var k in data) {
        data[k].completed = false;
        console.log(data[k]);
      }
      //console.log(response.data);
      commit(ACTION_TYPES.fetchAlbums, data);
    },
 },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We set up all the other actions similarly.&lt;/p&gt;

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

&lt;p&gt;In the Vue files, we use the computed, onMounted, and setup functions. We write this code as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useStore } from "vuex";
import { computed, onMounted } from "vue";
export default {
  name: "Fetch Albums",
  setup() {
    const store = useStore();
    const albums = computed(() =&amp;gt; store.state.albums);

  onMounted(() =&amp;gt; {
      store.dispatch("onFetchAlbums");
  });
….
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s look at these changes in a little more detail.&lt;/p&gt;

&lt;h4&gt;
  
  
  Computed
&lt;/h4&gt;

&lt;p&gt;The computed function replaces the computed property in Vue 2. We pass a getter to the computed function and get an immutable object in return.&lt;/p&gt;

&lt;h4&gt;
  
  
  onMounted
&lt;/h4&gt;

&lt;p&gt;The onMounted hook replaces the mounted property from Vue 2, which takes in a callback function.&lt;/p&gt;

&lt;p&gt;For example, in Albums.vue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;onMounted(() =&amp;gt; {
      store.dispatch("onFetchAlbums");
  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Function
&lt;/h3&gt;

&lt;p&gt;Vue3 uses the composition API to handle components. The setup function is the starting point of all components.&lt;/p&gt;

&lt;p&gt;The setup function takes properties and context. We directly return the data we want to expose in the application in the setup function.&lt;/p&gt;

&lt;h4&gt;
  
  
  ref
&lt;/h4&gt;

&lt;p&gt;The AddAlbums.vue file uses the ref function to initialize a &lt;a href="https://v3.vuejs.org/guide/composition-api-introduction.html#reactive-variables-with-ref" rel="noopener noreferrer"&gt;reactive variable.&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ref } from "vue";

 setup() {
    const store = useStore();
    const title = ref("");
    const addAlbum = e =&amp;gt; {
      e.preventDefault();
      store.dispatch("onAddAlbum", {
        title: title.value
      });
      title.value = "";
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These cover the main changes we need to make our application Vue 3 compatible. When we now run our application in Vue 3, it looks like this:&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage5.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fspread%2F20210921-migrating-from-vue-2-to-vue-3-1%2FImage5.png" alt="image5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Vue 3 has significant architectural changes, like the composition API and functions, new Vuex version, new Vue router, reactive variables, and many more. With these changes comes the possibility that your Vue 2 applications can break. Regardless of the size of an application, it’s daunting to migrate them. The Vue team introduced the migration build to mitigate this issue. The migration build runs the Vue 2 application in compatibility mode while warning about breaking changes and changes required to make your application Vue 3 compatible.&lt;/p&gt;

&lt;p&gt;Although the migration build is beneficial, it can’t cover all the possible problems. This tool also isn’t a long-term solution: It’s simply a springboard to start your migration. Migrating your application from Vue 2 to Vue 3 is still a significant task requiring thorough planning. But, it’s a must-do as developers gradually upgrade to the new version of Vue and take advantage of its improved features.&lt;/p&gt;

&lt;p&gt;Whether you work with Vue 2 or switch over to Vue 3, you can save development time by including GrapeCity’s Vue-compatible components in your application. &lt;a href="https://www.grapecity.com/spreadjs" rel="noopener noreferrer"&gt;SpreadJS&lt;/a&gt; and &lt;a href="https://www.grapecity.com/wijmo" rel="noopener noreferrer"&gt;Wijmo&lt;/a&gt; quickly add spreadsheet components like charts and pivot tables, maps, and more than 100 user interface components to your application.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Import and Analyze Dynamics365 Sales Data into Your .NET Application</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Tue, 14 Sep 2021 13:55:01 +0000</pubDate>
      <link>https://dev.to/mescius/how-to-import-and-analyze-dynamics365-sales-data-into-your-net-application-4m3l</link>
      <guid>https://dev.to/mescius/how-to-import-and-analyze-dynamics365-sales-data-into-your-net-application-4m3l</guid>
      <description>&lt;p&gt;Dynamics 365 Sales is a customer relationship management application that lets organizations manage sales processes and more. The application itself provides many features for reporting and data analysis; however, sometimes, there may be a need to create external applications for various purposes, including reporting and analysis. For this, Dynamics 365 provides services that external applications can access to get data. In this blog, we will see how we can use &lt;a href="https://www.grapecity.com/componentone/net-data-service-components"&gt;ComponentOne DataServices&lt;/a&gt; libraries like &lt;a href="https://www.grapecity.com/componentone/net-data-connector-component"&gt;DataConnectors&lt;/a&gt; and &lt;a href="https://www.grapecity.com/data-engine"&gt;DateEngine&lt;/a&gt; to fetch data and perform in-memory analysis.&lt;/p&gt;

&lt;p&gt;Take a further look at DataConnectors &lt;a href="https://www.grapecity.com/componentone/demos/dataconnectors/dataconnectorexplorer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Business Use Case
&lt;/h3&gt;

&lt;p&gt;For this demonstration, we want to analyze Dynamics 365 Sales Opportunities data in a .NET application to find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opportunities at each stage of sales&lt;/li&gt;
&lt;li&gt;Open opportunities for each product&lt;/li&gt;
&lt;li&gt;Opportunities value in each sales representative's bucket&lt;/li&gt;
&lt;li&gt;Opportunities in each fiscal quarter&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;To assimilate the above information, we would need the following fields from the &lt;a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/opportunity?view=dynamics-ce-odata-9"&gt;Opportunities entity&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;owner&lt;/li&gt;
&lt;li&gt;createdon&lt;/li&gt;
&lt;li&gt;stagename&lt;/li&gt;
&lt;li&gt;quantity&lt;/li&gt;
&lt;li&gt;extendedamount&lt;/li&gt;
&lt;li&gt;productname&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above data is often mapped across separate entities. For example, the Opportunities table may have a GUID for ownerid instead of the name of salesrep, the actual name of the sales rep may exist in another systemsuser table. Therefore, to get data, users may need to fetch data from different tables, which can get complicated. ComponentOne DataConnectors is a timesaver in this case, as the data connector lets users use SQL in ADO.NET or LINQ and EntityFramework Core to fetch and query data. This blog will use its &lt;a href="https://www.grapecity.com/componentone/docs/services/online-dataconnector/startdynamic365.html"&gt;Dynamics 365 Sales&lt;/a&gt; ADO.NET classes, and SQL JOIN queries to get the desired data from multiple tables.&lt;/p&gt;

&lt;p&gt;Once the data is available, we will use C1DataEngine and C1PivotEngine to create &lt;a href="https://www.grapecity.com/componentone/docs/services/online-dataengine/pivot-transform.html"&gt;in memory pivots&lt;/a&gt; to get desired results. To start, we create a WinForms application and add following NuGet packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C1.AdoNet.D365&lt;/li&gt;
&lt;li&gt;C1.DataEngine&lt;/li&gt;
&lt;li&gt;C1.PivotEngine&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Fetch Data from Dynamics 365 Sales
&lt;/h4&gt;

&lt;p&gt;Add a class named PivotService and declare public property for C1DataEngine &lt;a href="https://www.grapecity.com/componentone/docs/services/online-dataengine/dataenginefundamentals.html"&gt;WorkSpace.&lt;/a&gt; Add GetData() method to fetch data from Dynamics 365 Sales.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PivotService
    {
      private Workspace ws;
      public Workspace Workspace =&amp;gt; ws;
      private dynamic opportunity;
      private readonly string QueryName = "BaseQuery";
      public C1PivotEngine engine;

    private string GetD365SConnection()
      {
        var config = Properties.Settings.Default;
        string extendProperties = "{\"resource\":\"" + config.Resource + "\"}";
        string conectionStr = $@"Url={config.UrlDynamics};Use Etag=true;OAuth Client Id={config.ClientID};OAuth Client Secret={config.ClientSecret};OAuth Token Endpoint={config.TokenEndpoint};OAuth Extend Properties={extendProperties}";

        return conectionStr;
      }



      public void GetData()
      {
        C1.AdoNet.D365S.C1D365SConnection con = new C1.AdoNet.D365S.C1D365SConnection(GetD365SConnection());
        con.Open();

        string sql = "select op.opportunityid, op.name, op._ownerid_value,op.createdon, op._parentaccountid_value,op.estimatedclosedate, op._parentcontactid_value, osp._activestageid_value, gc_renewaldate, gc_paymenttermscode, gc_opportunitytype, p.productnumber, p.name as productname, p.gc_salesedition, ps.stagename, opp.priceperunit, opp.quantity, opp.extendedamount, su.fullname as salesrep from opportunities op inner join opportunityproducts opp on opp._opportunityid_value = op.opportunityid inner join opportunitysalesprocesses osp on osp._opportunityid_value = op.opportunityid inner join products p on p.productid = opp._productid_value inner join accounts a on a.accountid = op._parentaccountid_value and a.name like 'account%' inner join processstages ps on ps.processstageid = osp._activestageid_value inner join systemusers su on su.systemuserid = op._ownerid_value LIMIT 105";

        var cmd = new C1.AdoNet.D365S.C1D365SCommand(con, sql);
        var connector = new DbConnector(this.ws, con, cmd);
        connector.GetData("Opportunities");

      }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we created an instance of C1D365SConnection &amp;amp; C1D365SCommand, assigned the SQL query &amp;amp; connection to the command object. Finally, the &lt;a href="https://www.grapecity.com/componentone/docs/services/online-dataengine/dataenginefundamentals.html"&gt;DbConnector&lt;/a&gt; object is used, which executes the command to import the data to DataEngine workspace. The result is named Opportunities. &lt;/p&gt;

&lt;h4&gt;
  
  
  DataEngine Configuration
&lt;/h4&gt;

&lt;p&gt;We next define a base query to fetch required columns from the imported data. This query will be available in memory for us to apply further transformations over the data. We create this query in the Init() method of the PivotService class. We also declare an instance of C1PivotEngine  allowing us to create pivot transformation over the base query by connecting its instance to the DataEngine workspace.&lt;/p&gt;

&lt;p&gt;DataEngine Configuration Expand source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public PivotService()
        {
            Init();
        }

private void Init()
        {
            this.ws = new Workspace();
            this.ws.Init("workspace");

           //Import data if Opportunities table is null or data is stale in workspace
            if (Properties.Settings.Default.threshhold.Date &amp;lt; DateTime.Now.Date )
            {
                if (this.ws.GetTableData("Opportunities") == null)
                {
                    this.GetData();
                    Properties.Settings.Default["threshhold"] = DateTime.Now.Date;
                    Properties.Settings.Default.Save();
              }            
            }

            this.opportunity = this.ws.table("Opportunities");

            if (this.opportunity!=null)
            {
                var queryName = this.QueryName;

// create base query and execute it
                var settings = new
                {
                    opportunity.stagename,
                    opportunity.salesrep,
                    opportunity.createdon,
                    opportunity.productname,
                    opportunity.extendedamount,
                    Sales = Op.Sum(opportunity.extendedamount),
                    Quantity = Op.Count(opportunity.quantity),
                    QuantityTotal = Op.Sum(opportunity.quantity)
                };

                dynamic query = this.ws.query(queryName, settings);
                query.Query.Execute();

              //initialize pivotengine and connect workspace &amp;amp; base query
                this.engine = new C1PivotEngine();
                this.engine.Workspace = this.ws;
                this.engine.ConnectDataEngine(queryName);
          }            
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we will create several pivot transformations and avoid repetitive code, we will create a method to pass pivot fields from different transformations queries and return pivoted data based on the fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private C1PivotEngine CreateFlexPivotEngine(string queryName, string[] colFields, string[] rowFields, string[] valFields)
      {
        var fp = this.engine; 
        fp.BeginUpdate();
        this.engine.ColumnFields.Clear();
        this.engine.RowFields.Clear();
        this.engine.ValueFields.Clear();
        fp.ColumnFields.Add(colFields);
        fp.RowFields.Add(rowFields);
        fp.ValueFields.Add(valFields);
        fp.EndUpdate();
        return fp;
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pivot Transformations
&lt;/h4&gt;

&lt;p&gt;Now we are ready to create pivots over the data we fetched from Dynamics365 server and create methods for each transformation. In the method, we will pass row, column, value fields to the above 'CreateFlexPivotEngine" function to create a pivot using these fields and return the pivotengine object. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opportunities at Each Stage of Sales&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, we want to know the value of opportunities at each stage of Sale. We do this by pivoting over the stagename and sales fields of the base query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public IBindingList OpportunityByStage()
      {
        var fp = this.CreateFlexPivotEngine(this.QueryName, new string[] { "" }, new string[] { "stagename" }, new string[] { "Sales" });
        return fp.PivotDefaultView;
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PXHR1Xtf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image1_StageValue.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PXHR1Xtf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image1_StageValue.PNG" alt="image1" width="243" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open Opportunities for Each Product&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The product-wise open opportunities could be known by creating a pivot using productname and sales column on the base query. Also, to get only open opportunities, we filter stagename to exclude 'close' salesstage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public IBindingList ProductOppportunity()
      {
        var fp = this.CreateFlexPivotEngine(this.QueryName, new string[] { "stagename" }, new string[] { "productname" }, new string[] { "Sales" });
        var fld = fp.ColumnFields[0].Filter;
        fld.Condition1.Operator = ConditionOperator.NotEquals;
        fld.Condition1.Parameter = "close";
        return fp.PivotDefaultView;
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p3MLdGQY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image2_ProductOps.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p3MLdGQY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image2_ProductOps.PNG" alt="image2" width="656" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opportunities Value in Each Sales Representative's Bucket&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To know the value of opportunities with each salesrep, pivot over the slaresrep, stagename and sales fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public IBindingList OpportunityByRep()
      {
        var fp = this.CreateFlexPivotEngine(this.QueryName, new string[] { "salesrep" }, new string[] { "stagename" }, new string[] { "Sales" });
        return fp.PivotDefaultView;
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following result listing sales against each sales rep at every stage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XsfQSN7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image3_SalesrepOps.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XsfQSN7k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image3_SalesrepOps.PNG" alt="image3" width="484" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Opportunities in Each Fiscal Quarter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;C1PivotEngine allows us to group data over a range to present meaningful information. It creates range groups over string, numbers, and dates. In this case, we apply range grouping over the createdon field to get quarterly opportunity data. We pass the createdon field twice to rowfields so that one can show date and other could be used to get the fiscal quarter. This gives us sales estimates at each stage in each quarter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public IBindingList OpportunityByFiscalQuarter()
      {
        var fp = this.CreateFlexPivotEngine(this.QueryName, new string[] { "stagename" }, new string[] { "createdon", "createdon" }, new string[] { "Sales" });
        var year = fp.RowFields[0];
        year.Range.RangeType = RangeType.FiscalYear;
        year.Range.FiscalYearFirstMonth = 4;

        var month = fp.RowFields[1];
        month.Range.RangeType = RangeType.FiscalQuarter;

        return fp.PivotDefaultView;
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tLa00I-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://global-cdn.grapecity.com/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image4_QuarterlyOpsValue.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tLa00I-V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://global-cdn.grapecity.com/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Image4_QuarterlyOpsValue.PNG" alt="image4" width="770" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You may view the complete code of this application by downloading it &lt;a href="https://gccontent.blob.core.windows.net/gccontent/blogs/componentone/20210907-how-to-import-data-from-dynamics365-sales-to-net/Dynamics365Analytics.zip"&gt;here&lt;/a&gt; . You will need to update connection settings as per your Dynamics 365 server in order to run the sample.&lt;/p&gt;

&lt;p&gt;We have seen how easy it is to fetch data from Dynamics 365 Sales using DataConnector libraries. It is as if we are using known ADO.NET classes without the learning curve. We also saw how we could perform pivot transformation over this data using C1DataEngine library. The C1DataEngine library can query and aggregate millions of records in memory within a fraction of a second, and coupled with pivot transforms, it makes a powerful data analysis library. &lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Best Practices for React Developers in 2021</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Mon, 13 Sep 2021 20:39:45 +0000</pubDate>
      <link>https://dev.to/mescius/best-practices-for-react-developers-in-2021-42a</link>
      <guid>https://dev.to/mescius/best-practices-for-react-developers-in-2021-42a</guid>
      <description>&lt;p&gt;It may be hard to believe, but this year React turned eight years old. In the technology landscape, especially on client-side web development, this is quite remarkable. How can a simple library for building UIs be that old and still be this relevant?&lt;/p&gt;

&lt;p&gt;The reason is, React not only revolutionized the building of UIs, but it also made functional paradigms for building UIs popular. And even then, React did not stop there. They continued to push innovative concepts forward without breaking the existing codes. As a result, React is stabler, leaner, and faster than ever. &lt;/p&gt;

&lt;p&gt;But, the downside of React's ever-evolving nature is that best practices change over time. To harvest some of the newest performance benefits, one needs to carefully study the new additions. And figuring that out is not always easy, sometimes it's not straightforward at all.&lt;/p&gt;

&lt;p&gt;In this article, we will take a look at the best practices that apply to React in 2021. &lt;/p&gt;

&lt;h4&gt;
  
  
  Conventions
&lt;/h4&gt;

&lt;p&gt;To structure your work with React, it makes sense to follow a few conventions. Some conventions are even required for the tooling to work smoothly. For example, if you name your components using camelCase, then the following would not work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myComponent = () =&amp;gt; &amp;lt;div&amp;gt;Hello World!&amp;lt;/div&amp;gt;;

ReactDOM.render(&amp;lt;myComponent /&amp;gt;, document.querySelector('#app'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the standard JSX transformer from Babel (or TypeScript) uses the naming convention to decide whether to pass a string or an identifier to React.&lt;/p&gt;

&lt;p&gt;As a result, the transpiled code would look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myComponent = () =&amp;gt; React.createElement("div", null, "Hello World!");

ReactDOM.render(React.createElement("myComponent", null), document.querySelector('#app'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not what we want. Instead, we can use PascalCase. In this case, the JSX transformer will detect the usage of a custom component and the required reference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = () =&amp;gt; &amp;lt;div&amp;gt;Hello World!&amp;lt;/div&amp;gt;;

ReactDOM.render(&amp;lt;MyComponent /&amp;gt;, document.querySelector('#app'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, everything is fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReactDOM.render(React.createElement(MyComponent, null), document.querySelector('#app'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While other conventions are less strict, they should be still followed. For instance, it makes sense to use quoted string attributes instead of JSX expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// avoid
&amp;lt;input type={'text'} /&amp;gt;

// better
&amp;lt;input type="text" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Likewise, it makes sense to keep the attribute quote style consistent. Most guides will propagate using single-quoted strings in JS expressions, and double-quoted strings for these React props. In the end, it doesn’t matter as long as its usage within the codebase is consistent. &lt;/p&gt;

&lt;p&gt;Speaking of conventions and props, these should also follow the standard JS naming convention of using camelCase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// avoid
const MyComponent = ({ is_valid, Value }) =&amp;gt; {
  // ...
  return null;
};

// better
const MyComponent = ({ isValid, value }) =&amp;gt; {
  // ...
  return null;
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, be sure not to misuse the names of the built-in HTML component props (for example, style or className). If using these props, forward them to the respective in-built component. Also, keep them at the original type (for example, for style a CSS style object and for className a string).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// avoid
const MyComponent = ({ style, cssStyle }) =&amp;gt; {
  if (style === 'dark') {
    // ...
  }

  // ...
  return &amp;lt;div style={cssStyle}&amp;gt;...&amp;lt;/div&amp;gt;;
};

// better
const MyComponent = ({ kind, style }) =&amp;gt; {
  if (kind === 'dark') {
    // ...
  }

  // ...
  return &amp;lt;div style={style}&amp;gt;...&amp;lt;/div&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the intention of the props much clearer and establishes a consistency level that is critical for efficient usage of larger component collections.&lt;/p&gt;

&lt;h4&gt;
  
  
  Component Separation
&lt;/h4&gt;

&lt;p&gt;One of React's biggest advantages is its ability to easily test and reason about components. However, this is only possible if a component is small and dedicated enough to support that. &lt;/p&gt;

&lt;p&gt;Back when React first started gaining popularity, they introduced the concept of a controller and a view component to efficiently structure larger components. Even though today we have dedicated state containers and hooks, it still makes sense to structure and categorize components in some way.&lt;/p&gt;

&lt;p&gt;Let's consider the simple example of loading some data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = () =&amp;gt; {
  const [data, setData] = React.useState();

  React.useEffect(() =&amp;gt; {
    let active = true;

    fetch('...')
      .then(res =&amp;gt; res.json())
      .then(data =&amp;gt; active &amp;amp;&amp;amp; setData(data))
      .catch(err =&amp;gt; active &amp;amp;&amp;amp; setData(err));


    return () =&amp;gt; {
      active = false;
    };
  }, []);

  return (
    data === undefined ?
      &amp;lt;div&amp;gt;Loading ...&amp;lt;/div&amp;gt; :
      data instanceof Error ?
        &amp;lt;div&amp;gt;Error!&amp;lt;/div&amp;gt; :
        &amp;lt;div&amp;gt;Loaded! Do something with data...&amp;lt;/div&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, a componentless action would be better suited here. But the point is that the written component has to both gather the data and display it.&lt;/p&gt;

&lt;p&gt;A cleaner model would imply a separation that could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = ({ error, loading, data }) =&amp;gt; {
  return (
    loading ?
      &amp;lt;div&amp;gt;Loading ...&amp;lt;/div&amp;gt; :
      error ?
        &amp;lt;div&amp;gt;Error!&amp;lt;/div&amp;gt; :
        &amp;lt;div&amp;gt;Loaded! Do something with data...&amp;lt;/div&amp;gt;
  );
};

const MyLoader = () =&amp;gt; {
  const [data, setData] = React.useState();

  React.useEffect(() =&amp;gt; {
    let active = true;

    fetch('...')
      .then(res =&amp;gt; res.json())
      .then(data =&amp;gt; active &amp;amp;&amp;amp; setData(data))
      .catch(err =&amp;gt; active &amp;amp;&amp;amp; setData(err));

    return () =&amp;gt; {
      active = false;
    };
  }, []);

  const isError = data instanceof Error;

  return (
    &amp;lt;MyComponent
      error={isError ? data : undefined}
      loading={data === undefined}
      data={!isError ? data : undefined} /&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To further improve it, the most ideal separation is extraction into a custom hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function useRemoteData() {
  const [data, setData] = React.useState();

  React.useEffect(() =&amp;gt; {
    let active = true;

    fetch('...')
      .then(res =&amp;gt; res.json())
      .then(data =&amp;gt; active &amp;amp;&amp;amp; setData(data))
      .catch(err =&amp;gt; active &amp;amp;&amp;amp; setData(err));

    return () =&amp;gt; {
      active = false;
    };
  }, []);

  const isError = data instanceof Error;

  return [data === undefined, !isError ? data : undefined, isError ? data : undefined];
}

const MyComponent = () =&amp;gt; {
  const [loading, data, error] = useRemoteData();

  return (
    loading ?
      &amp;lt;div&amp;gt;Loading ...&amp;lt;/div&amp;gt; :
      error ?
        &amp;lt;div&amp;gt;Error!&amp;lt;/div&amp;gt; :
        &amp;lt;div&amp;gt;Loaded! Do something with data...&amp;lt;/div&amp;gt;
  );
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Hooks
&lt;/h4&gt;

&lt;p&gt;React hooks are among the most debated technology features in the frontend space. When they were first introduced, they were considered elegant and innovative. On the flip side, there have been a growing number of critics over the years.&lt;/p&gt;

&lt;p&gt;Pros and cons aside, in general, using hooks can be a best practice depending on the scenario.&lt;/p&gt;

&lt;p&gt;Keep in mind that some hooks are there to help you with performance optimizations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;useMemo helps avoid doing expensive calculations on every re-render.&lt;/li&gt;
&lt;li&gt;useCallback produces stable handlers, similarly to useMemo, but more conveniently geared towards callbacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, let’s look at the following code without useMemo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = ({ items, region }) =&amp;gt; {
  const taxedItems = items.map(item =&amp;gt; ({
      ...item,
      tax: getTax(item, region),
  }));

  return (
      &amp;lt;&amp;gt;
        {taxedItems.map(item =&amp;gt; &amp;lt;li key={item.id}&amp;gt;
          Tax: {item.tax}
        &amp;lt;/li&amp;gt;)}
      &amp;lt;/&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Considering there might be a lot of items in that array, and that the getTax operation is quite expensive (no pun intended), you’d have quite a bad re-rendering time, assuming minimal items and region change.&lt;/p&gt;

&lt;p&gt;Therefore, the code would benefit a lot from useMemo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = ({ items, region }) =&amp;gt; {
  const taxedItems = React.useMemo(() =&amp;gt; items.map(item =&amp;gt; ({
      ...item,
      tax: getTax(item, region),
  })), [items, region]);

  return (
      &amp;lt;&amp;gt;
        {taxedItems.map(item =&amp;gt; &amp;lt;li key={item.id}&amp;gt;
          Tax: {item.tax}
        &amp;lt;/li&amp;gt;)}
      &amp;lt;/&amp;gt;
  );
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of useMemo is that it's almost invisible. As you can see, all we need to do is to wrap the computation in a function. That's it. No other changes required.&lt;/p&gt;

&lt;p&gt;A more subtle issue is the lack of useCallback. Let's have a look at some very generic code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = () =&amp;gt; {
  const save = () =&amp;gt; {
    // some computation
  };
  return &amp;lt;OtherComponent onSave={save} /&amp;gt;;
}; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we don't know anything about OtherComponent, but there are certain possible changes originating here, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s a pure component and will prevent re-rendering, as long as all props remain untouched.&lt;/li&gt;
&lt;li&gt;It uses the callback on either some memoization or effect hooks.&lt;/li&gt;
&lt;li&gt;It passes the callback to some component that uses one of these properties.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either way, passing values as props that essentially have not changed should also result in values that have not changed. The fact that we have a function declared inside our rendering function will be problematic.&lt;/p&gt;

&lt;p&gt;An easy way out is to write the same thing using useCallback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const MyComponent = () =&amp;gt; {
  const save = React.useCallback(() =&amp;gt; {
    // some computation
  }, []);
  return &amp;lt;OtherComponent onSave={save} /&amp;gt;;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the recomputed callback is taken only if one of the dependencies given in the array changed. Otherwise, the previous callback (for instance, a stable reference) is returned.&lt;/p&gt;

&lt;p&gt;Like before, there are almost no code changes required for this optimization. As a result, you should always wrap callbacks using useCallback.&lt;/p&gt;

&lt;h4&gt;
  
  
  Components
&lt;/h4&gt;

&lt;p&gt;Speaking of pure components, while class components had the PureComponent abstraction, a functional pure component can be introduced to React explicitly using memo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// no memoed component
const MyComponent = ({ isValid }) =&amp;gt; (
  &amp;lt;div style=\{{ color: isValid ? 'green' : 'red' }}&amp;gt;
    status
  &amp;lt;/div&amp;gt;
);

// memoed component
const MyComponent = React.memo(({ isValid }) =&amp;gt; (
  &amp;lt;div style=\{{ color: isValid ? 'green' : 'red' }}&amp;gt;
    status
  &amp;lt;/div&amp;gt;
));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://reactjs.org/docs/react-api.html"&gt;React documentation&lt;/a&gt; is quite detailed about memo. It says: “If your component renders the same result given the same props, you can wrap it in a call to React.memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.”&lt;/p&gt;

&lt;p&gt;Keep in mind that — like any other comparison done by React — the props are only shallowly compared. Therefore, this optimization is only applied if we are careful what to pass in. For instance, if we use useMemo and other techniques for complex props such as arrays, objects, and functions.&lt;/p&gt;

&lt;p&gt;You may have noticed that we exclusively used functional components. As a matter of fact, since the introduction of hooks, you can practically work without class components.&lt;/p&gt;

&lt;p&gt;There are only two possible reasons to still use class components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You want to have access to the more sophisticated life cycle events. For example, shouldComponentUpdate.&lt;/li&gt;
&lt;li&gt;You want to introduce error boundaries.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;However, even in these cases, you might just need to write one React class component to fulfill your needs. Look at this boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class Boundary extends React.Component {
  state = {
    error: undefined,
  };

  componentDidCatch(error) {
    this.setState({
      error,
    });
  }

  render() {
    const { error } = this.state;
    const { children, ShowError } = this.props;

    if (error) {
      return &amp;lt;ShowError error={error} /&amp;gt;;
    }

    return children;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only will the component catch any errors which may appear in its children, but it will also display a fallback component passed in as ShowError receiving a single prop: the error.&lt;/p&gt;

&lt;h4&gt;
  
  
  Operators
&lt;/h4&gt;

&lt;p&gt;Some operators can be used to simplify the tree construction in React. For instance, the ternary operator allows us to write code that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  {currentUser ? &amp;lt;strong&amp;gt;{currentUser}&amp;lt;/strong&amp;gt; : &amp;lt;span&amp;gt;Not logged in&amp;lt;/span&amp;gt;}
&amp;lt;/div&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boolean operators such as &amp;amp;&amp;amp; and || may also be useful, but there are a few traps to watch out for. As an example, look at this code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  {numUsers &amp;amp;&amp;amp; &amp;lt;i&amp;gt;There are {numUsers} users logged in.&amp;lt;/i&amp;gt;}
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming that numUsers is always a number between 0 and the total number of users, we'd end up with the expected output if numUsers is positive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;i&amp;gt;There are 5 users logged in.&amp;lt;/i&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, for the edge case of zero users, we'd get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  0
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which may not be what we wanted, so a boolean conversion or more explicit comparison could help here. In general, the following is more readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  {numUsers &amp;gt; 0 &amp;amp;&amp;amp; &amp;lt;i&amp;gt;There are {numUsers} users logged in.&amp;lt;/i&amp;gt;}
&amp;lt;/div&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in the zero users edge case scenario we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the ternary operator as an exclusive boolean operator avoids the issue completely. But what about a state where we don't want to render anything? We could either use false or an empty fragment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  {numUsers ? &amp;lt;i&amp;gt;There are {numUsers} users logged in.&amp;lt;/i&amp;gt; : &amp;lt;&amp;gt;&amp;lt;/&amp;gt;}
&amp;lt;/div&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty fragment has the advantage of giving us the ability to just add content later. However, for users less familiar with React, it could look a bit strange.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;In this article, we went over some of the best practices that make your React codebase easier to work with. By switching over from class components to functional components, you can dive more into hooks. This will provide the ability to automatically introduce a great separation of concerns, where the behavioral aspects are all done in functions and rendering is defined within components.&lt;/p&gt;

&lt;p&gt;By following a set of useful conventions, together with some techniques such as the use of the right operators, hooks, and separation of concerns, you should end up with a clean codebase that can be maintained and extended quite easily.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Angular Best Practices for 2021</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Mon, 23 Aug 2021 14:12:41 +0000</pubDate>
      <link>https://dev.to/mescius/angular-best-practices-for-2021-e7</link>
      <guid>https://dev.to/mescius/angular-best-practices-for-2021-e7</guid>
      <description>&lt;p&gt;Built with TypeScript by Google developers, Angular is an open-source JavaScript framework designed for building front-end applications. &lt;/p&gt;

&lt;p&gt;Angular 2+ is a successor to Angular.js, rewritten from scratch using TypeScript instead of JavaScript, which helped avoid many issues related to JavaScript and ensures following best practices and integrations with IDEs thanks to static typing and the class-based oriented object features of TypeScript. &lt;/p&gt;

&lt;p&gt;Angular is not just a framework but an entire platform packed with features that make front-end web and mobile development more manageable. Also, thanks to projects by the community, you can build native apps for mobile (Ionic and NativeScript) and desktop (Electron) devices. &lt;/p&gt;

&lt;p&gt;Angular is like other modern JavaScript libraries, such as React and Vue.js, and uses many shared concepts. While React is more popular among web developers worldwide, Angular is suitable for enterprise apps.&lt;/p&gt;

&lt;p&gt;This article covers some of the best practices that developers should follow when building Angular applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Angular CLI
&lt;/h3&gt;

&lt;p&gt;The first thing that you should consider when developing your web application is development tooling. These days, we have modern tools that make front-end web development more straightforward. For Angular, we have many tools, most importantly, the official Angular CLI and &lt;a href="https://nx.dev/"&gt;Nx&lt;/a&gt;, a smart and extensible build framework. &lt;/p&gt;

&lt;p&gt;Even though you can &lt;a href="https://medium.com/angular-in-depth/setting-up-angular-from-scratch-1f518c65d8ab"&gt;create an Angular project without using the official CLI&lt;/a&gt;, this is only useful for learning purposes. For real-world development, you should use &lt;a href="https://angular.io/cli"&gt;Angular CLI&lt;/a&gt;. It’s a command-line interface created by the official team behind Angular, on top of Node.js. It makes it extremely easy to initialize a fully working Angular application from the start, without the hassle of configuring build tools like Webpack. It assists during development by providing the commands for scaffolding constructs such as modules and components, testing (unit, integration, and e2e testing), building the final production bundles, and even helping you with deploying the final app.&lt;/p&gt;

&lt;p&gt;Make sure to use Angular CLI to generate your project since it comes with the best practices recommended by the team, or even use Nx if you are building full-stack applications. &lt;/p&gt;

&lt;p&gt;Before installing Angular CLI, you must have a recent version of Node.js and npm installed. If you do not, you can use one of the following methods: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download the installer for your operating system from the &lt;a href="https://nodejs.org/en/"&gt;official website&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Use the official package manager for your target system&lt;/li&gt;
&lt;li&gt;Use a Node version management tool such as &lt;a href="https://github.com/nvm-sh/nvm"&gt;NVM&lt;/a&gt;, enabling you to manage &lt;a href="https://www.shabang.dev/multiple-versions-node-nvm/"&gt;multiple versions of Node&lt;/a&gt; on your system. It’s also helpful to install packages globally on your machine without using sudo on Linux or MAC and with no extra configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, install Angular CLI using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g @angular/cli 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command installs the CLI globally on your system. &lt;/p&gt;

&lt;p&gt;You can run the ng command to get all the available commands at your disposal and then run ng followed by a particular command and the --help option to display the help file for that command. &lt;/p&gt;

&lt;p&gt;You can check the installed version using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng version 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run the following command to generate a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng new angular-practices-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Angular asks you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Would you like to add Angular routing? Type “y”&lt;/li&gt;
&lt;li&gt;Which stylesheet format would you like to use? Use the arrow keys to pick SCSS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use a Scalable and Maintainable Project Structure
&lt;/h3&gt;

&lt;p&gt;If you have done web development before, you know that finding a convenient project structure or architecture is not always easy on the first try. Still, it gets easier as you get more experience building both small and large apps.&lt;/p&gt;

&lt;p&gt;For a small application, the default structure generated by Angular CLI is okay. Still, once your project grows, you’ll find it difficult to maintain and scale your app correctly. &lt;/p&gt;

&lt;p&gt;Here is an excellent article on how to &lt;a href="https://medium.com/@motcowley/angular-folder-structure-d1809be95542"&gt;structure the folders of your application&lt;/a&gt;, where you start from a barebones Angular project and move to a more organized solid folder structure with separate component and page folders. A page is simply a routed component. &lt;/p&gt;

&lt;p&gt;Also, a good practice to follow is architecting your app with a core module, shared module, and feature module for each feature of your application (plus the root application module, which bootstraps the app). You then move the imports in the app module to the core module and leave the app module only for application bootstrapping. &lt;/p&gt;

&lt;p&gt;You must place all the singleton services, which should only have one instance for the entire application in the core module. For example, the authentication service should only have one instance for each application so that it can be part of the core module. &lt;/p&gt;

&lt;p&gt;In the shared module, you should place common artifacts (components, directives, pipes, and so on) used in multiple modules so that you can import the shared module to use them. The shared module is also a good place for &lt;a href="https://webtips101.com/angular-dumb-smart-components/"&gt;dumb components&lt;/a&gt; and pipes that don’t inject services but can only receive data through props. &lt;/p&gt;

&lt;p&gt;Suppose you’re using a UI components library like &lt;a href="https://material.angular.io/"&gt;Angular Material&lt;/a&gt;. In this case, this is an excellent place to import and re-export the components that you intend to use throughout the app, so you don’t need to repeat imports in each module. &lt;/p&gt;

&lt;p&gt;To continue our previously generated project, run the following commands to create core and shared modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module core
ng generate module shared
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let’s assume we need two features for product and cart. &lt;/p&gt;

&lt;p&gt;Generate two feature modules for them with the same command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate module product
ng generate module cart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the src/app/shared.module.ts file and update it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ],
  exports: [
    CommonModule,
    FormsModule
  ]
})
export class SharedModule { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we added the FormsModule to the exports array, so the array exports it to the other modules that import the shared module, but we didn’t add it to the imports array. This way, we can give other modules access to FormsModule without importing it directly in the shared &lt;strong&gt;NgModule.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Next, we re-export CommonModule and FormsModule to use common directives like NgIf and NgFor from CommonModule and bind component properties with ngModel from modules that import this SharedModule. &lt;/p&gt;

&lt;p&gt;Next, open the src/app/app.module.ts file and import the core and shared modules as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    CoreModule,
    SharedModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, remove CommonModule from ProductModule and CartModule and import SharedModule since it already exports CommonModule.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Up to Date
&lt;/h3&gt;

&lt;p&gt;Angular follows semantic versioning with a new major version released every six months. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://semver.org/"&gt;Semantic versioning&lt;/a&gt; is a convention used for versioning software. It has a major.minor.patch format. Angular increments each part when they release major, minor, or patch changes. &lt;/p&gt;

&lt;p&gt;You can follow the news about the latest version of Angular from the &lt;a href="https://github.com/angular/angular/blob/master/CHANGELOG.md"&gt;CHANGELOG&lt;/a&gt; and make sure you keep your Angular version up to date, ensuring you always get the latest features, bug fixes, and performance enhancements like Ivy. &lt;/p&gt;

&lt;p&gt;It would help if you also used &lt;a href="https://update.angular.io/"&gt;this official tool&lt;/a&gt; when updating your project from one version to the next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strict Mode
&lt;/h3&gt;

&lt;p&gt;We mentioned in the introduction that Angular 2+ adopted TypeScript from the early phases, ensuring the platform — including the framework and the tooling — follows best practices such as dependency injection, which makes testing more manageable, and performance budgets. &lt;/p&gt;

&lt;p&gt;The Angular team has moved to &lt;a href="https://blog.angular.io/with-best-practices-from-the-start-d64881a16de8"&gt;apply the strict mode&lt;/a&gt; progressively with an option in Angular 10 to enable strict mode by default for all projects starting with Angular 12. This is a best practice now enabled by default, but if you must disable it for learning purposes, you use the --no-strict option when creating a new project. &lt;/p&gt;

&lt;p&gt;For existing projects, you enable strict mode in tsconfig.json as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, thanks to the Ivy compiler and the language service, you’ll benefit from the TypeScript’s type system in your templates by simply setting strictTemplates to true. This is the default, starting with Angular 12. Check out the &lt;a href="https://angular.io/guide/template-typecheck"&gt;official docs&lt;/a&gt; for more details. &lt;/p&gt;

&lt;p&gt;Make sure to follow the Angular team’s &lt;a href="https://angular.io/guide/security"&gt;recommended security practices&lt;/a&gt; and avoid using &lt;a href="https://angular.io/api/core/ElementRef"&gt;ElementRef&lt;/a&gt; and innerHTML unless you’re sure you know what you are doing!&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Lazy Loading
&lt;/h3&gt;

&lt;p&gt;When using Angular, you should build the so-called SPAs, which refer to single-page applications. This is a modern type of app that’s different from the traditional web apps we created before. &lt;/p&gt;

&lt;p&gt;Angular loads SPA bundles at once from the server and uses JavaScript or client-side routing to enable users to navigate between different views. &lt;/p&gt;

&lt;p&gt;This is the modern approach for building apps today, and this how we build apps with modern frameworks such as Angular, React, and Vue.js. &lt;/p&gt;

&lt;p&gt;Angular provides a powerful router with a plethora of features to use for client-side routing. So, building an SPA is easy once you grasp the necessary concepts. However, this impacts performance since we must download the full app bundles from the server. So, when your app size grows, the downloading time of your application increases! &lt;/p&gt;

&lt;p&gt;Here comes the role of lazy-loading, which revolves around the idea of deferring the loading of specific modules when the users of your application access them. This benefits you by reducing the actual downloading size of the application bundles. Lazy-loading also improves the boot time by not loading unused modules when the application first starts, but only when users trigger navigation. &lt;/p&gt;

&lt;p&gt;As a best practice, you must lazy-load the &lt;a href="https://angular.io/guide/feature-modules"&gt;feature modules&lt;/a&gt; in your application whenever that’s possible. You need one feature module to load eagerly during the app start-up to display the initial content. You should lazy-load all other feature modules to boost performance and decrease the initial bundle size.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://webtips101.com/angular-12-loadchildren-dynamic-import/"&gt;lazy-load a module&lt;/a&gt; using the loadChildren property of the Angular router with the &lt;a href="https://javascript.info/modules-dynamic-imports"&gt;dynamic import syntax&lt;/a&gt;. But thanks to Ivy, you can also lazy-load a component. Let’s see an example! &lt;/p&gt;

&lt;p&gt;First, make sure you have a project with Angular routing set up. With Angular CLI, you take care of this by setting the --routing flag for the ng new command when generating a project or answering “y” when prompted if you “Would like to add Angular routing?” &lt;/p&gt;

&lt;p&gt;Open the src/app/app-routing.module.ts file and lazy-load the product and cart modules as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductModule } from './product/product.module';
import { CartModule } from './cart/cart.module';


const routes: Routes = [
  { path: 'product', loadChildren: () =&amp;gt; import('./product/product.module').then(m =&amp;gt; m.ProductModule) },
  { path: 'cart', loadChildren: () =&amp;gt; import('./cart/cart.module').then(m =&amp;gt; m.CartModule) }
];


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

&lt;/div&gt;



&lt;p&gt;We use the &lt;strong&gt;loadChildren&lt;/strong&gt; property of the route configuration combined with the import statement to lazy-load a module. &lt;/p&gt;

&lt;p&gt;Now, any components you add to these modules will be lazy-loaded! However, with Ivy, we can lazy-load an Angular component without requiring a module. &lt;/p&gt;

&lt;p&gt;First, generate a component using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component header --module=core  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core module imports this.&lt;/p&gt;

&lt;p&gt;Open the src/app/app.component.html file and update as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button (click)="lazyLoadHeader()"&amp;gt;Load header&amp;lt;/button&amp;gt;
&amp;lt;ng-container #header&amp;gt;&amp;lt;/ng-container&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the src/app/app.component.ts file and update it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'angular-practices-demo';
  @ViewChild('header', { read: ViewContainerRef }) headerContainer: ViewContainerRef | null = null;
  constructor(private factoryResolver: ComponentFactoryResolver) { }


  async lazyLoadHeader() {
    const { HeaderComponent } = await import('./header/header.component');
    const factory = this.factoryResolver.resolveComponentFactory(HeaderComponent);
    this.headerContainer?.createComponent(factory);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you click the button, you should see "header works!" which means the component lazy-loaded on-demand and rendered!&lt;/p&gt;

&lt;h3&gt;
  
  
  Unsubscribe from RxJS Observables
&lt;/h3&gt;

&lt;p&gt;When subscribing your components to RxJS Observables, you should always unsubscribe. Otherwise, this causes unwanted memory leaks as the observable stream is open, even after destroying the component using it.&lt;/p&gt;

&lt;p&gt;You can do this in multiple ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unsubscribe the component in the &lt;strong&gt;ngOnDestory&lt;/strong&gt; event after destroying the component&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;async pipe&lt;/strong&gt; to subscribe to Observables and automatically unsubscribe in templates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use ngFor with trackBy
&lt;/h3&gt;

&lt;p&gt;You use the &lt;strong&gt;ngFor&lt;/strong&gt; directive to iterate arrays in Angular templates. When you change an array, the complete DOM tree re-renders, which is not performance-wise. To solve this, you must use ngFor with trackBy, which uniquely identifies each DOM element and enables Angular to re-render only the modified element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component({
  selector: 'my-app',
  template: `
   &amp;lt;li *ngFor="let product of products; trackBy:productById"&amp;gt;{{product.name}}&amp;lt;/li&amp;gt;
  `
})
export class App {
  products:[]; 
   {id:0, name: “product 1”},
   {id:1, name: “product 2”}
  ];


  productById(index, product){
     return product.id; 
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;The Angular team has adopted best practices from the beginning by using TypeScript for Angular development, ensuring types safety, better error handling, and integrations with IDEs. Angular 12 has enabled the strict mode by default, ensuring you follow strict rules that help you build error-free and solid apps. In this article, we have seen some of the best practices that you can follow to build scalable and easily maintainable apps.&lt;/p&gt;

&lt;p&gt;Explore framework-agnostic UI components that have deep support for Angular — including &lt;a href="https://www.grapecity.com/wijmo/angular-ui-components/flexgrid-angular-data-grid"&gt;Angular datagrids&lt;/a&gt;, charts, gauges, and input controls.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What Developers Need to Know About Progressive Web Apps</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Fri, 09 Jul 2021 15:12:32 +0000</pubDate>
      <link>https://dev.to/mescius/what-developers-need-to-know-about-progressive-web-apps-o29</link>
      <guid>https://dev.to/mescius/what-developers-need-to-know-about-progressive-web-apps-o29</guid>
      <description>&lt;p&gt;In 2011, every aspect of our lives seemed to be moving to the web. Smartphone and tablet use was rising, and the recent completion of the HTML5 specification, together with nice additions such as the web manifest, seemed to pave a path to a bright future. As the hip social network Facebook bet strongly on HTML5 for their mobile application, everything was shipshape.&lt;/p&gt;

&lt;p&gt;Then there were some unfortunate setbacks. First, the up-and-coming native app framework PhoneGap did not go anywhere. Facebook then announced they were rewriting their mobile app. HTML5 was not ready yet, they said.&lt;/p&gt;

&lt;p&gt;Finally, as Google announced AMP — a subset of HTML5 with some custom elements — no one wanted to bet on HTML as an app platform. Failed experiments such as webOS and Mozilla’s Firefox OS set the transition back even further.&lt;/p&gt;

&lt;p&gt;Nevertheless, ten years later, we can give this transition another trial. This time, Google is on our side. With browser APIs added in the last decade and Chrome now the default browser on Android, developers have brought together a set of web technologies under the term “progressive web app” (PWA). A PWA can be considered a true web app.&lt;/p&gt;

&lt;p&gt;Today, PWAs are supported by most browsers, but certainly best by Chromium-based browsers such as Microsoft Edge, Brave, Opera, and Google Chrome. One of the browsers with poor support is unfortunately Apple’s Safari. Nevertheless, most features work on Safari. The biggest pain points are PWA installation and push notifications.&lt;/p&gt;

&lt;p&gt;Let’s explore what a PWA is, how to build one, and some challenges you may face. Then, we’ll look at some PWAs in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a PWA, Anyway?
&lt;/h3&gt;

&lt;p&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Progressive_web_application" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;, a PWA has the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Progressive:&lt;/strong&gt; They work for every user, regardless of browser choice, because they’re built with progressive enhancement as a core tenet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive:&lt;/strong&gt; They fit any form factor: desktop, mobile, tablet, and forms yet to emerge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connectivity independent:&lt;/strong&gt; Service workers enable offline work, or on low-quality networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;App-like:&lt;/strong&gt; They feel like an app to the user with app-style interactions and navigation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fresh:&lt;/strong&gt; They are always up to date, thanks to the service worker update process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safe:&lt;/strong&gt; They are served via HTTPS to prevent snooping and ensure content hasn’t been tampered with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discoverable:&lt;/strong&gt; They are identifiable as “applications” thanks to W3C manifests and the service worker registration scope, enabling search engines to find them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-engageable:&lt;/strong&gt; They make re-engagement easy through features like push notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Installable:&lt;/strong&gt; They allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linkable:&lt;/strong&gt; They are easily shared via a URL and don’t require complex installation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a couple of takeaways here. There is no specification or official guideline on what a PWA is or needs to have. The characteristics mentioned are all eventually part of a PWA. However, developers may disregard or implement them differently depending on the circumstances.&lt;/p&gt;

&lt;p&gt;The most important aspect of a PWA is that it is installable. This makes the PWA truly a web app, that is, an application on a mobile phone. Ideally, this also means that the application works — at least to some extent — offline. An offline mode is a core attribute of a good PWA.&lt;/p&gt;

&lt;p&gt;One of the most challenging aspects of an offline mode is proper cache invalidation. Since resources and HTTP requests are now cached on the client, you need to define a proper strategy, such as a network-first strategy. Ideally, the strategy depends on the kind of resource. For instance, the app can retrieve the homepage via a network-first loading strategy, but all its related resources have a hashed file name. This makes all other resources good candidates for a cache-first loading strategy.&lt;/p&gt;

&lt;p&gt;Finally, take the progressive point seriously. We should still respect everything we learned when HTML5 was introduced, such as using unobtrusive JavaScript, using media queries for responsive design, and providing accessibility via fallback elements and Accessible Rich Internet Application (ARIA) attributes.&lt;/p&gt;

&lt;p&gt;Let’s now put this knowledge into practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Build a PWA
&lt;/h3&gt;

&lt;p&gt;While an unobtrusive and responsive website represents a great basis, it is — at least by the previous section’s definition — not a PWA. Instead, the primary goal is to control the way resources and requests are performed, but how is this accomplished? While the standard &lt;strong&gt;XMLHttpRequest&lt;/strong&gt; or &lt;strong&gt;fetch&lt;/strong&gt; APIs may be abstracted away, there is no direct way to override how to resolve general resource fetching, such as script sources or stylesheet links.&lt;/p&gt;

&lt;p&gt;The answer to this riddle is the service worker. By calling the &lt;strong&gt;register&lt;/strong&gt; method on the &lt;strong&gt;navigator&lt;/strong&gt; interface’s &lt;strong&gt;serviceWorker&lt;/strong&gt; API, you can bring in another script, which runs outside the website’s ordinary browsing context. The browser then uses this script to determine various aspects — most importantly, to intercept HTTP calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// check for support
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('my-service-worker.js');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the registration to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The worker must be served over HTTPS.&lt;/li&gt;
&lt;li&gt;The path must be right.&lt;/li&gt;
&lt;li&gt;The source must be at the same origin as the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The service worker doesn’t handle all requests, only requests matching the worker’s scope. The scope is mainly determined by the service worker’s location, even though it might be restricted further via some registration options.&lt;/p&gt;

&lt;p&gt;Before going into the service worker, it makes sense to look at another aspect you should usually cover when creating a PWA: the web manifest.&lt;/p&gt;

&lt;p&gt;With HTML5, the cache manifest was born. This file — linked from the document’s root element, that is, the &lt;strong&gt;html&lt;/strong&gt; tag — has a custom syntax to define what to cache and what to replace, and with what, while offline. While service workers mostly fulfill this role, the concept of a descriptive metafile is still appealing. PWAs use the web manifest to achieve exactly that.&lt;/p&gt;

&lt;p&gt;The application links to the web manifest via a &lt;strong&gt;link&lt;/strong&gt; tag, just like stylesheets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;link href="manifest.json" rel="manifest"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be valid, the file itself must have four values set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The longer, full application name (&lt;strong&gt;name&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;The abbreviated, short application name (&lt;strong&gt;short_name&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;The actual root or starting page, in case the manifest is re-used or used in a single-page application (SPA) (&lt;strong&gt;start_url&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;How the application should display when installed (&lt;strong&gt;display&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The allowed values for display are &lt;strong&gt;standalone&lt;/strong&gt; or &lt;strong&gt;fullscreen&lt;/strong&gt;. The interpretation of that value is fully left to the browser. Other properties, such as &lt;strong&gt;theme_color&lt;/strong&gt; or &lt;strong&gt;background_color&lt;/strong&gt;, are also up to the implementation in the browser or on the operating system (OS) side. Mostly, they help display the dashboard icon, and the splash screen when the app opens, more appropriately.&lt;/p&gt;

&lt;p&gt;Most implementations require the manifest to define a 144x144 pixel icon — otherwise, the manifest is still regarded as valid, but insufficient for making the web app installable.&lt;/p&gt;

&lt;p&gt;A full manifest could look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "Example App",
  "short_name": "ExApp",
  "display": "standalone",
  "start_url": "/",
  "icons": [
   {
     "src": "/images/icon-144.png",
      "sizes": "144x144",
     "type": "image/png"
   }
  ]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plenty of tools and resources help generate a valid and useful manifest file, such as &lt;a href="https://app-manifest.firebaseapp.com/" rel="noopener noreferrer"&gt;Web App Manifest Generator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For service workers, there are two options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use an existing library or framework to give us everything we need in a service worker.&lt;/li&gt;
&lt;li&gt;Implement the appropriate caching and fallback commands ourselves.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second option seems viable at first. After all, handling HTTP requests in a service worker is as simple as writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener('fetch', e =&amp;gt; {
  // Empty for now
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generally, these events are important. For example, if you want to cache additional files upon PWA installation, you can use the &lt;strong&gt;install&lt;/strong&gt; event. In code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener('install', async e =&amp;gt; {
  const cache = await caches.open('files');
  cache.addAll([
    './script.js',
    './style.css',
    './assets/image.png',
  ]);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of the cache API is that you only need to supply these relative paths and the browser does the rest. The browser fetches the URLs and puts them into the cache as you’d expect.&lt;/p&gt;

&lt;p&gt;Handling the &lt;strong&gt;fetch&lt;/strong&gt; event can quickly become tedious. At first, this may not look too bad, but handling the network reliably (and using the right caching strategy) is challenging.&lt;/p&gt;

&lt;p&gt;A network-first strategy is quite often a good starting point. Instead of using the cache for performance enhancement, you only use the cache as a fallback, that is, when going offline. A quick implementation could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener('fetch', async e =&amp;gt; {
  const req = e.request;
  const cache = await caches.open('data');

  try {
    const res = await fetch(req);
    cache.put(req, res.clone());
    await e.respondWith(res);
  } catch {
    const res = await cache.match(req);

    if (res) {
      await e.respondWith(res);
    } else {
      e.respondWith(getFallback(req));
    }
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code sample, the &lt;strong&gt;getFallback&lt;/strong&gt; function implements a cache lookup for some initially defined fallback data. Otherwise, just return “undefined.”&lt;/p&gt;

&lt;p&gt;This quick example shows that an implementation can rapidly get out of hand. A better alternative is to use existing tools and libraries such as &lt;a href="https://developers.google.com/web/tools/workbox" rel="noopener noreferrer"&gt;Workbox&lt;/a&gt;. With its integrations into the webpack bundler, for example, it conveniently generates a service worker that self-updates, has proper cache invalidation rules, and can be configured using a pre-selected caching strategy.&lt;/p&gt;

&lt;p&gt;Let’s see what other challenges you may face, even when you use specialized tools to create your PWA.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges You Might (Not) Expect
&lt;/h3&gt;

&lt;p&gt;PWAs have some challenges we need to tackle, most prominently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache invalidation&lt;/li&gt;
&lt;li&gt;Lack of APIs&lt;/li&gt;
&lt;li&gt;Discoverability&lt;/li&gt;
&lt;li&gt;Platform-native user interface (UI)&lt;/li&gt;
&lt;li&gt;Synchronization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s look at these challenges one-by-one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cache Invalidation
&lt;/h4&gt;

&lt;p&gt;There are three main problems in IT: cache invalidation, naming, and off-by-one errors. The cache invalidation issue seems somewhat trivial with service workers initially, but may become a real issue quite fast when space is limited. Therefore, you cannot just cache every request. If you do, you may cache requests that — by definition — give only preliminary and temporary results.&lt;/p&gt;

&lt;p&gt;One outcome of caching too many requests may be exceptions in the form of a “quota exceeded” error. These errors are quite nasty. They may not even originate from the same application, as different quotas may encounter errors on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The respective request, data, or cache &lt;/li&gt;
&lt;li&gt;The application&lt;/li&gt;
&lt;li&gt;The user’s profile&lt;/li&gt;
&lt;li&gt;The overall browser&lt;/li&gt;
&lt;li&gt;The overall machine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, Google Chrome may allow at most &lt;a href="https://developers.google.com/web/tools/workbox/guides/storage-quota" rel="noopener noreferrer"&gt;100MB&lt;/a&gt; for applications running in Incognito mode. In any case, the specific limits and behavior are up to the serving browser. It makes sense to be rather conservative here.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lack of APIs
&lt;/h4&gt;

&lt;p&gt;One of the great things about native mobile development is that all necessary APIs are already available. Want geofencing in the background? Done. Want to use the fingerprint sensor? Done. Want to secure private data in a special vault? Done. Although the web now has a greatly improved arsenal of APIs, including a payment API, Bluetooth API, and more, these may not be sufficient for your use case.&lt;/p&gt;

&lt;p&gt;Furthermore, although an API exists, it may not be available yet on the target platform. Take, for instance, the payment API. On mobile platforms, the support looks decent at over 90 percent (see image below). However, since the payment API is broken into multiple areas, some parts may have less support. It makes sense to check and test before going into production.&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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage1_API.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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage1_API.png" alt="API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is, of course, always the option of packaging the PWA in a native app bundle. That way, native APIs may be usable and native app distribution can restrict the target platform.&lt;/p&gt;

&lt;h4&gt;
  
  
  Discoverability
&lt;/h4&gt;

&lt;p&gt;If we regard PWAs as a web-native replacement of native apps, then we miss a central app store. Surely, this is one advantage of PWAs, too. No central gatekeeper means more flexibility, but it also means users have a challenging time finding your PWA.&lt;/p&gt;

&lt;p&gt;Luckily, there are multiple ways out of this. For one, you can submit your PWA to an existing PWA catalogue. An alternative is to package the PWA in a native app — as before — and still go through the respective central app stores. Finally, since a PWA is still just a website, you can use your website to advertise it properly. The discoverability may not be great, but it certainly is no worse than for a standard website.&lt;/p&gt;

&lt;h4&gt;
  
  
  Platform-Native UI
&lt;/h4&gt;

&lt;p&gt;Thinking of a PWA as a replacement for a native app also impacts the overall UI and user experience (UX) design. The app should respect the native look and behavior of the underlying platform as much as possible, but how should that work? After all, there are multiple platforms, and presumably you are not even running in an app mode but rather in the standard browser shell.&lt;/p&gt;

&lt;p&gt;At least a CSS media query exists for finding out in what mode the app is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media all and (display-mode: standalone) {
  body {
    /* … */
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the underlying platform, the &lt;strong&gt;navigator.platform&lt;/strong&gt; may be useful. Still, you must implement plenty of functions to mimic the platform behavior as closely as possible. Even then, users can recognize that the app is not native.&lt;/p&gt;

&lt;h4&gt;
  
  
  Synchronization
&lt;/h4&gt;

&lt;p&gt;Going back to cache invalidation, it makes sense to ask the question: How should the app synchronize data when going back online?&lt;/p&gt;

&lt;p&gt;Let’s say a user went offline and submitted a form. Your logic could put that submission in a queue and push it to the server when the user is back online. While this is possible using the &lt;strong&gt;online / offline&lt;/strong&gt; browser event, combined with &lt;strong&gt;navigator.onLine&lt;/strong&gt;, the difficulties may be in the details. Common challenges include dependencies on other requests, handling submission failures, and mitigating replay issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  PWAs in Action
&lt;/h3&gt;

&lt;p&gt;There are plenty of reasons why PWAs are attractive to developers, as well as to companies. One is definitely the ability to circumvent the walled gardens of app store vendors such as Apple and Google.&lt;/p&gt;

&lt;p&gt;Right now, there are a handful really well-done PWA “stores” online. In contrast to the classic app stores, these are catalogues rather than system stores. One example in that category is &lt;a href="https://appsco.pe/" rel="noopener noreferrer"&gt;Appscope&lt;/a&gt;. Its minimalistic and to-the-point design emphasizes what most PWAs try to achieve.&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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage2_Appscope.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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage2_Appscope.png" alt="Appscope"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The website highlights quite a few great PWAs, not only from some large tech companies but also from independent developers and hobbyists. Anyone can submit an entry, and moderators review each entry before it goes live.&lt;/p&gt;

&lt;p&gt;Although there are many examples of impressive PWAs, the best PWAs are not always obvious. Take, for instance, Microsoft Office 365 web apps such as Word and Excel. They work — though sometimes only in a reduced mode such as read-only — in all dimensions and across multiple devices. They notify you of updates, even when closed, and are always updated with the latest assets.&lt;/p&gt;

&lt;p&gt;Many popular apps are now also represented on the web via a PWA, such as the successful start-ups &lt;a href="https://tinder.com/" rel="noopener noreferrer"&gt;Tinder&lt;/a&gt;, &lt;a href="https://www.uber.com/" rel="noopener noreferrer"&gt;Uber&lt;/a&gt;, and &lt;a href="https://www.pinterest.com/" rel="noopener noreferrer"&gt;Pinterest&lt;/a&gt;. Another PWA example is the next version of the open-source electronic medical record-taking system &lt;a href="https://openmrs-spa.org/openmrs/spa/" rel="noopener noreferrer"&gt;OpenMRS&lt;/a&gt;. While previous versions used a server-side rendered UI, their next version will ship with a new single-page application packaged as a PWA. This way, previously impossible activities, such as being offline when recording patient observations or taking notes, are now feasible.&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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage3_PWA.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%2Fglobal-cdn.grapecity.com%2Fblogs%2Fspread%2F20210623-what-developers-need-to-know-about-progressive-web-apps%2FImage3_PWA.png" alt="PWA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Overall, the transition into a PWA is quite straightforward and makes sense especially for tool-like web apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;p&gt;PWAs are here to stay. They fill a growing gap and provide the flexibility and API-richness missing from the first native app replacement attempt ten years ago. Surely, it doesn’t make sense to convert every website to a PWA, but some web applications are an ideal target to become a PWA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grapecity.com/" rel="noopener noreferrer"&gt;GrapeCity’s&lt;/a&gt; enterprise-grade JavaScript products, such as &lt;a href="https://www.grapecity.com/wijmo" rel="noopener noreferrer"&gt;Wijmo&lt;/a&gt; UI components and &lt;a href="https://www.grapecity.com/spreadjs" rel="noopener noreferrer"&gt;SpreadJS&lt;/a&gt; spreadsheet tool, require no modification as you transition your website into a PWA. We are excited to support you on your journey into progressive web applications and can’t wait to see what you build with our products.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>Top Tips for Vue 3 Development</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Fri, 09 Jul 2021 15:05:07 +0000</pubDate>
      <link>https://dev.to/mescius/top-tips-for-vue-3-development-3kig</link>
      <guid>https://dev.to/mescius/top-tips-for-vue-3-development-3kig</guid>
      <description>&lt;p&gt;First released in 2013, Vue is a progressive framework for building web user interfaces. It’s an adoptable, not monolithic, framework that integrates with other frameworks such as React and Angular. While Vue is focused only on the view layer, it can power single-page applications (SPAs) with ease. This fully open-source project is maintained on its &lt;a href="https://github.com/vuejs/vue"&gt;GitHub page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;September 2020’s full release of Vue 3 had significant improvements for developers. Vue 3 is fully backward compatible with Vue 2. It has improved performance, better readability, and several new features.&lt;/p&gt;

&lt;p&gt;Today, we’ll examine a few of those features and see how to use them to enhance your development workflow. We’ll also reflect on some workarounds needed to use these features in previous versions of Vue. We’ll cover TypeScript support, Teleport, and fragments.&lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript Support
&lt;/h3&gt;

&lt;p&gt;One of the most exciting aspects of Vue 3 is that it’s written in, and has full support for, TypeScript (TS). The great thing about native TS support is that we don’t have to use any additional tooling. Also, it helps prevent many potential runtime errors as our applications grow.&lt;/p&gt;

&lt;p&gt;Previously, Vue 2 only had official type declarations for TS. Developers had to install TS using npm and use additional plugins to avoid errors. This often required complicated and roundabout methods of using TS within a Vue 2 app. The Vue 3 API is identical for both TS and JavaScript, meaning that in Vue 3, we get the same level of native support for both platforms.&lt;/p&gt;

&lt;p&gt;Let’s take a quick look at how to define a Vue component using TS in Vue 3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    import { defineComponent } from 'vue'
    const Component = defineComponent({
        // type inference enabled
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example here imports defineComponent so that TS can properly infer types within the Vue component. If we want to use &lt;a href="https://v3.vuejs.org/guide/single-file-component.html#single-file-components"&gt;single file components&lt;/a&gt;, we must include the following tags around our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script lang="ts"&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue 3 provides simple and easy access to TS in all Vue projects. Full TS support in Vue 3 provides greater flexibility for developers. It’s much more accessible than in previous versions of Vue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teleport
&lt;/h3&gt;

&lt;p&gt;Teleport is one exciting Vue 3 feature. In Vue 2, this was called portals and required plug-ins and additional tooling.&lt;/p&gt;

&lt;p&gt;Vue encourages developers to create user interface (UI) systems that contain both the UI and related behavior inside components. These components can then nest within one another in a tree-like format. While this is a great way to construct a UI, in many cases, we want part of a component to exist elsewhere in the document object model (DOM) from a technical standpoint. Teleporting in Vue 3 enables us to have pieces of templates, such as modals, live within a separate component without a bunch of messy CSS or compositional changes. This code, found within the &lt;a href="https://v3.vuejs.org/guide/teleport.html#teleport"&gt;Vue documentation&lt;/a&gt;, enables us to illustrate this change.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the following HTML structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;body&amp;gt;
        &amp;lt;div style="position: relative;"&amp;gt;
            &amp;lt;h3&amp;gt;Tooltips with Vue 3 Teleport&amp;lt;/h3&amp;gt;
            &amp;lt;div&amp;gt;
                &amp;lt;modal-button&amp;gt;&amp;lt;/modal-button&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This HTML creates a basic page with a common modal button. At the moment, the modal inherits the parent div tag’s CSS attributes. In Vue 2, for the modal to inherit the body tag attributes, we needed to use portal plugins or create some messy and error-prone CSS. In Vue 3, however, we use the new teleport feature to send the modal button to the body. We do this without ever removing it from its original place in the DOM.&lt;/p&gt;

&lt;p&gt;The following code achieves this goal quite a bit more simply than did Vue 2’s tooling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    app.component('modal-button', {
        template: `
            &amp;lt;button @click="modalOpen = true"&amp;gt;
                Open full screen modal! (With teleport!)
            &amp;lt;/button&amp;gt;


        &amp;lt;teleport to="body"&amp;gt;
            &amp;lt;div v-if="modalOpen" class="modal"&amp;gt;
                &amp;lt;div&amp;gt;
                    I'm a teleported modal! 
                    (My parent is "body")
                &amp;lt;button @click="modalOpen = false"&amp;gt;
                    Close
                &amp;lt;/button&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/teleport&amp;gt;
        `,
        data() {
            return {
                modalOpen: false
            }
        }
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s as simple as using  to apply the body tag’s CSS attributes to the created modal. In this example, we created a space for the button on the page, but the modal itself functions as a full-screen modal.&lt;/p&gt;

&lt;p&gt;Teleporting is a welcome addition to Vue 3. It’s a great tool for reducing clutter and increasing project readability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fragments
&lt;/h3&gt;

&lt;p&gt;Vue 3 also includes support for fragments or multi-root node components. In Vue 2, each component could only have one root node. There was also no plug-in support for creating multi-root nodes.&lt;/p&gt;

&lt;p&gt;Note that fragments require developers to define non-prop attributes when needed. Non-prop attributes are an attribute or event listener passed on to a component but requiring further definition when used.&lt;/p&gt;

&lt;p&gt;In Vue 2, we often had to create our components within a single div tag. This practice created confusion around which template they may belong to and how. In Vue 3, fragments look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;template&amp;gt;
        &amp;lt;header&amp;gt;...&amp;lt;/header&amp;gt;
        &amp;lt;main v-bind="$attrs"&amp;gt;...&amp;lt;/main&amp;gt;
        &amp;lt;footer&amp;gt;...&amp;lt;/footer&amp;gt;
    &amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see in this example that we only need to create a template, and from there we easily create multiple nodes without a div tag. The main tag includes an example of the non-prop attribute binding that is sometimes required when using fragments in Vue 3.&lt;/p&gt;

&lt;p&gt;Fragments are great for reducing DOM confusion and creating cleaner code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Vue 3 provides more flexibility and better performance than previous framework versions. While the new version brings many new features, the three we explored today are some of the most beneficial for developers to enhance development workflows.&lt;/p&gt;

&lt;p&gt;Vue 3 is also backward compatible with Vue 2 code, meaning no one has to completely rewrite their systems to take advantage of the new features. Vue is completely open-source and maintained purely on GitHub. Consider &lt;a href="https://github.com/vuejs/vue"&gt;joining the project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are seeking ways to use Vue 3 and its features covered today, but don't know where to start, look at some of GrapeCity’s offerings. These components plug seamlessly into your Vue applications to add powerful enhancements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.grapecity.com/spreadjs/vue-spreadsheet-components"&gt;SpreadJS&lt;/a&gt;, for example, is a JavaScript spreadsheet solution that works wonderfully in Vue. Developers easily create custom, feature-rich spreadsheets, dashboards, reports, and much more using only Vue and SpreadJS.&lt;/p&gt;

&lt;p&gt;Or, you can try &lt;a href="https://www.grapecity.com/wijmo/vue-ui-components"&gt;Wijmo&lt;/a&gt;, a UI component collection also available in React and Angular. Wijmo, much like SpreadJS, has a ton of useful features, such as the ability to create flexible charts and data grids all within Vue. Wijmo is super lightweight and won't leave a huge footprint on your project. It enables developers more freedom when using Vue 3.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>React Futures - Server Components</title>
      <dc:creator>Morgan</dc:creator>
      <pubDate>Thu, 10 Jun 2021 17:35:44 +0000</pubDate>
      <link>https://dev.to/mescius/react-futures-server-components-ojl</link>
      <guid>https://dev.to/mescius/react-futures-server-components-ojl</guid>
      <description>&lt;p&gt;In a recent talk, the React team announced a new feature called &lt;a href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html" rel="noopener noreferrer"&gt;React Server Components&lt;/a&gt; (RSC). What is that exactly, and how can we take advantage of it to write better apps? &lt;/p&gt;

&lt;p&gt;If you are familiar with React, you know that it is a client-side library that provides developers with a set of abstractions on top of JavaScript that quickly and efficiently write the user interface to a web application. A client-side library means rendering the view in the DOM is done on the client’s browser using JavaScript. The server, in this case, is only responsible for delivering the bundles of your application containing HTML, CSS, and JavaScript and doesn’t perform any rendering.&lt;/p&gt;

&lt;p&gt;The server sends a response back in HTML containing an empty body and script tags that reference JavaScript bundles in the head. That means JavaScript files must first be downloaded to the user’s browser before the rest of the page starts loading. This has two significant drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decreased performance as the initial load time increases&lt;/li&gt;
&lt;li&gt;Lousy SEO, as many web crawlers can’t parse and read content from JavaScript files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After loading the initial JavaScript file, the content can be loaded asynchronously. The critical content is loaded first and then the non-critical content later, but this still introduces performance problems. To solve these performance issues, developers resort to reducing the bundle size of their React applications using minification, code splitting, dead code elimination, and so on. However, often this is not enough.&lt;/p&gt;

&lt;p&gt;In this article, we’ll give you a deep dive into React Server Components, an experimental feature that can help you overcome these performance obstacles.&lt;/p&gt;

&lt;h4&gt;
  
  
  React Server Components
&lt;/h4&gt;

&lt;p&gt;According to &lt;a href="https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/" rel="noopener noreferrer"&gt;research by Google&lt;/a&gt;, 53 percent of mobile website visitors will leave if a webpage doesn’t load within three seconds. You can see why that’s a problem for apps built using React or other modern front-end frameworks such as Angular or Vue.&lt;/p&gt;

&lt;p&gt;However, an efficient solution exists. We can render React components in HTML on the server thanks to &lt;a href="https://efficientcoder.net/react-server-side-rendering/" rel="noopener noreferrer"&gt;server-side rendering&lt;/a&gt; (SSR). The concept of server-side rendering is not new. It has emerged with the modern client-side JavaScript-heavy libraries and frameworks that do the bulk of their rendering on the client.&lt;/p&gt;

&lt;p&gt;SSR rendering works by rendering a part of the application on the server and sending it as HTML. The browser starts immediately painting the UI without waiting for JavaScript algorithms to render the views to the DOM before showing users some initial content. This results in improved user experience by increasing &lt;a href="https://en.wikipedia.org/wiki/Perceived_performance" rel="noopener noreferrer"&gt;user-perceived performance.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React is component-based. You must write your UI as a set of components with parent-child relationships. These components can be either functions such as &lt;a href="https://www.shabang.dev/react-hooks/" rel="noopener noreferrer"&gt;React hooks&lt;/a&gt; or classes that extend the built-in Component class.&lt;/p&gt;

&lt;p&gt;React Server Components are the usual React components, but the server renders them instead of the client. This technique enables developers to fetch already-rendered components from the server. Since we already have SSR techniques used by developers, with many great and easy-to-use tools — like Nest.js, Gatsby or even Express.js — what’s unique about React Server Components?&lt;/p&gt;

&lt;p&gt;Note: Next.js is a popular framework that makes it easy to create server-side rendered React apps without the hassle of configuring that by yourself.&lt;/p&gt;

&lt;p&gt;At first sight, RSC seems like regular server-side rendering, but it opens the doors to writing apps with extra benefits such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero effect on the final bundle size&lt;/li&gt;
&lt;li&gt;Direct access to the backend resources&lt;/li&gt;
&lt;li&gt;Use of React IO libraries such as react-fs (filesystem), react-pg (Postgres), react-fetch (Fetch API)&lt;/li&gt;
&lt;li&gt;Granular control over the components that the client must download &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zero effect on the final bundle size means that RSC allows your React application to use third-party utility libraries without affecting the client’s bundle size. How is that possible?&lt;/p&gt;

&lt;p&gt;Let’s use this example of a &lt;a href="https://github.com/reactjs/server-components-demo/blob/main/src/TextWithMarkdown.js" rel="noopener noreferrer"&gt;server component:&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import marked from 'marked';
import sanitizeHtml from 'sanitize-html';
// [...]

export default function TextWithMarkdown({text}) {
  return (
    &amp;lt;div
      className="text-with-markdown"
      dangerouslySetInnerHTML={{
        __html: sanitizeHtml(marked(text), {
          allowedTags,
          allowedAttributes,
        }),
      }}
    /&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This component imports two external libraries, marked and sanitize-html. If you use this as a client component, the final bundle also contains these two libraries. They are required by the sanitizeHtml(marked(text), {}) call to sanitize and convert the passed text to Markdown. Thanks to RSC, the server executes the code. The server returns only the final converted text. The libraries are not needed at runtime and are not included!&lt;/p&gt;

&lt;p&gt;Now, what about accessing the server resources directly and React IO libraries? Server resources can range from files to fully-fledged databases, which are essential for building full-stack data-driven apps.&lt;/p&gt;

&lt;p&gt;RSC is in the research phase, but this suggests that we can use React to build full-stack apps that work in the same way traditional apps work. You can use server components to interact with the databases and the file system on the server and return the results to the client. That means you can choose to avoid using REST or &lt;a href="https://www.techiediaries.com/graphql-tutorial/" rel="noopener noreferrer"&gt;GraphQL APIs&lt;/a&gt; to exchange data between the client and server!&lt;/p&gt;

&lt;p&gt;When building business apps, we typically must use a database. With React Server Components, we can access this database from the part of our React app running on the server and return results to the client alongside the rendered component itself instead of only the JSON data we'd send to a fully client-side React application.&lt;/p&gt;

&lt;p&gt;Thanks to RSC, we can build web applications in old app architecture while still having modern UIs. For beginners who don’t want to learn REST or GraphQL but still want to build full apps not just with one language (JavaScript) but also with one library, React makes it more straightforward than the old days when you had to use PHP with HTML and JavaScript to build a full-stack app.&lt;/p&gt;

&lt;p&gt;The React team collaborates with other teams to implement this feature into meta-frameworks like Next.js and Gatbsy using a webpack plugin. However, this doesn’t mean that you can’t use the feature without these tools if you like.&lt;/p&gt;

&lt;p&gt;In SSR, we render the components to HTML and send the results to the client. React Server Components are rendered to a JSON format and streamed to the client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  {
    "id": "./src/App.client.js",
    "chunks": ["main"],
    "name": ""
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  React Server Components Demonstration
&lt;/h4&gt;

&lt;p&gt;Now that we have explored what React Server Components are and their benefits let’s create a step-by-step demonstration. Please note that this is still an experimental technology, so the APIs presented here may change in the future.&lt;/p&gt;

&lt;p&gt;Since RSC is still an experimental feature, we’ll manually create our project instead of using the create-react-app. We’ll use this &lt;a href="https://github.com/techiediaries/rsc-project-template" rel="noopener noreferrer"&gt;project’s template&lt;/a&gt; forked from the official demo.&lt;/p&gt;

&lt;p&gt;Head over to a new command-line interface and start by running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/techiediaries/rsc-project-template rsc-demo
cd rsc-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you’ll have a package.json file and a webpack.config.js file in your folder.&lt;/p&gt;

&lt;p&gt;You will notice that we included several dependencies with an experimental version in the package.json file. We included the principal dependencies, which are react, react-dom, and the react-server-dom-webpack. We used experimental versions that provide support for React Server Components.&lt;/p&gt;

&lt;p&gt;In our demonstration, we use Webpack to build apps and Babel to transpile React code to plain JavaScript. We run our server with Express.js and use &lt;a href="https://www.npmjs.com/package/concurrently" rel="noopener noreferrer"&gt;concurrently&lt;/a&gt; to run multiple commands concurrently. The tool &lt;a href="https://www.npmjs.com/package/nodemon" rel="noopener noreferrer"&gt;nodemon&lt;/a&gt; helps develop node.js-based applications by automatically restarting the node application when file changes in the directory are detected.&lt;/p&gt;

&lt;p&gt;As a development dependency, we included &lt;a href="https://www.npmjs.com/package/cross-env" rel="noopener noreferrer"&gt;cross-env&lt;/a&gt;, which makes it easy to have a single command for setting and using environment variables properly for the target platform.&lt;/p&gt;

&lt;p&gt;Finally, we have some npm scripts to start the development server and build the production bundles using the concurrently, cross-env and nodemon packages and Webpack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "scripts": {
    "start": "concurrently \"npm run server:dev\" \"npm run bundler:dev\"",
    "start:prod": "concurrently \"npm run server:prod\" \"npm run bundler:prod\"",
    "server:dev": "cross-env NODE_ENV=development nodemon -- --conditions=react-server server",
    "server:prod": "cross-env NODE_ENV=production nodemon -- --conditions=react-server server",
    "bundler:dev": "cross-env NODE_ENV=development nodemon -- scripts/build.js",
    "bundler:prod": "cross-env NODE_ENV=production nodemon -- scripts/build.js"
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run the following command to install these dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create a public/index.html file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;!DOCTYPE html&amp;gt;
  &amp;lt;html lang="en"&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;title&amp;gt;React Server Components Demo&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
      &amp;lt;div id="root"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We added a &amp;lt;\div&amp;gt; with the root ID to mark where we can render our React components tree. &lt;/p&gt;

&lt;p&gt;Next, create a src/index.client.js file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import { unstable_createRoot } from 'react-dom';
  import App from './App.client';

  const root = unstable_createRoot(document.getElementById('root'));
  root.render(&amp;lt;App /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, import the unstable_createRoot method for enabling concurrent mode for the whole &amp;lt; App /&amp;gt; tree. Concurrent Mode APIs such as createRoot only exist in the experimental versions of React.&lt;/p&gt;

&lt;p&gt;Next, call the render method of the root object returned from the unstable_createRoot method to render the App components and its children in the DOM element with the root ID retrieved using the getElementById method.&lt;/p&gt;

&lt;p&gt;The App component is imported from an App.client.js file which we create later.&lt;/p&gt;

&lt;p&gt;Next, create a src/Cache.client.js file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import {unstable_getCacheForType} from 'react';
  import {createFromFetch} from 'react-server-dom-webpack';

  function createResponseCache() {
    return new Map();
  }

  export function useServerResponse(props) {
    const key = JSON.stringify(props);
    const cache = unstable_getCacheForType(createResponseCache);
    let response = cache.get(key);
    if (response) {
      return response;
    }
    response = createFromFetch(
      fetch('/react?props=' + encodeURIComponent(key))
    );
    cache.set(key, response);
    return response;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, import the unstable_getCacheForType and the createFromFetch methods. Next, create a response cache using the &lt;a href="https://efficientcoder.net/javascript-map/" rel="noopener noreferrer"&gt;JavaScript Map&lt;/a&gt; data structure. You use this to store collections of keyed data items. Fetch the server component using the &lt;a href="https://developers.google.com/web/updates/2015/03/introduction-to-fetch" rel="noopener noreferrer"&gt;Fetch API&lt;/a&gt; and pass the results to the createFromFetch method to create a convenient response object. Pass the response object to the cache using the Map.set method.&lt;/p&gt;

&lt;p&gt;Next, create a src/App.server.js file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import marked from 'marked';
  export default function App(props) {

    return (
      &amp;lt;div&amp;gt;
        &amp;lt;h3&amp;gt;
          Markdown content rendered on the server
        &amp;lt;/h3&amp;gt;
        &amp;lt;div

          dangerouslySetInnerHTML={{
            __html: marked(props.mdText)
          }}&amp;gt;

        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here create a React component that accepts an mdText prop and convert its Markdown content to HTML using the marked library, then set the results as the inner HTML of a &amp;lt;\div&amp;gt;.&lt;/p&gt;

&lt;p&gt;Since this component’s file ends with the server.js name, this component is a React Server Component rendered on the server.&lt;/p&gt;

&lt;p&gt;Next, create a src/App.client.js file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  import {useState, useRef, Suspense} from 'react';
  import {useServerResponse} from './Cache.client';

  const title = 'React Server Components Demo';

  const RenderedContent = (props) =&amp;gt; {
      const response = useServerResponse(props)
      return response.readRoot()
  }

  export default function App() {

    const [content, setContent] = useState('');
    const contentRef = useRef();

    const handleSubmit = (e) =&amp;gt; {
      e.preventDefault();
      setContent(contentRef.current.value);
    };

    return (
      &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;}&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;h2&amp;gt;{title}&amp;lt;/h2&amp;gt;
        &amp;lt;form onSubmit={ handleSubmit }&amp;gt;
        &amp;lt;textarea ref = { contentRef }
         name="content"
        &amp;gt;
        &amp;lt;/textarea&amp;gt;
        &amp;lt;br /&amp;gt;
        &amp;lt;input
         type="submit" value="Convert.."
        /&amp;gt;
      &amp;lt;/form&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;RenderedContent mdText={content}&amp;gt;&amp;lt;/RenderedContent&amp;gt;

      &amp;lt;/Suspense&amp;gt;
    );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create two components, RenderedContent to accept a prop for Markdown text and call the useServerResponse to fetch the response from the app server component that returns the rendered markdown text.&lt;/p&gt;

&lt;p&gt;Create a new reference by calling React.useRef hook and associate it with the form’s textarea element where we submit the markdown text to send to the server component as a prop.&lt;/p&gt;

&lt;p&gt;We used the &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html" rel="noopener noreferrer"&gt;Suspense component&lt;/a&gt; to asynchronously load the component and specify a loading UI that displays the loading text while the user is waiting. This allows us to build a smoother and more responsive UI.&lt;/p&gt;

&lt;p&gt;Finally, create a server/index.server.js file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  'use strict';

  const register = require('react-server-dom-webpack/node-register');
  register();
  const babelRegister = require('@babel/register');

  babelRegister({
    ignore: [/[\\\/](build|server|node_modules)[\\\/]/],
    presets: [['react-app', {runtime: 'automatic'}]],
    plugins: ['@babel/transform-modules-commonjs'],
  });

  const express = require('express');
  const compress = require('compression');
  const {readFileSync} = require('fs');

  const {pipeToNodeWritable} = require('react-server-dom-webpack/writer');
  const path = require('path');

  const React = require('react');
  const ReactApp = require('../src/App.server').default;

  const PORT = 4000;
  const app = express();

  app.use(compress());
  app.use(express.json());

  app.use(express.static('build'));
  app.use(express.static('public'));

  app.listen(PORT, () =&amp;gt; {
    console.log(`RSC Demo listening at http://localhost:${PORT}`);
  });


  app.get(
    '/',
    async (req, res) =&amp;gt; {
      const html = readFileSync(
        path.resolve(__dirname, '../build/index.html'),
        'utf8'
      );
      res.send(html);
    }
  );

  app.get('/react', function(req, res) {

    const props = JSON.parse(req.query.props);
    res.set('X-Props', JSON.stringify(props));
    const manifest = readFileSync(
      path.resolve(__dirname, '../build/react-client-manifest.json'),
      'utf8'
    );
    const moduleMap = JSON.parse(manifest);
    return pipeToNodeWritable(React.createElement(ReactApp, props), res, moduleMap);

  });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we set up a simple &lt;a href="https://expressjs.com/en/starter/hello-world.html" rel="noopener noreferrer"&gt;Express.js server&lt;/a&gt;, and we expose a /react endpoint that our client code calls to put the rendered component on the server. In the endpoint handler, we read the passed props from the request object, and we call the pipeToNodeWritable method to render the server component and stream it to the response object. This method accepts two arguments, the React component with its props and a module map generated by Webpack using the react-server-dom-webpack/plugin plugin.&lt;/p&gt;

&lt;p&gt;Now, run the following command in the root of your project’s folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app will be listening on &lt;a href="http://localhost:4000/" rel="noopener noreferrer"&gt;http://localhost:4000/&lt;/a&gt;. This is a screen capture of what you see:&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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fwijmo%2F20210610-react-futures-server-components%2FReactFuture.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%2Fglobal-cdn.grapecity.com%2F%2Fblogs%2Fwijmo%2F20210610-react-futures-server-components%2FReactFuture.png" alt="ReactFuture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that we have three types of extensions for the component files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.server.js, which indicates a Server Components&lt;/li&gt;
&lt;li&gt;.client.js, which indicates React Client Components&lt;/li&gt;
&lt;li&gt;The regular .js extension is for shared components, which run on the server or the client, depending on who’s importing them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article introduced you to React Server Components, a new experimental feature that allows you to render components on the server. This feature provides extra benefits compared to standard server-side rendering techniques, such as zero effect on the final bundle size, direct access to server resources, use of React IO libraries, and granular control over clients’ components.&lt;/p&gt;

&lt;p&gt;Access the full code for our &lt;a href="https://github.com/techiediaries/react-server-components-demo" rel="noopener noreferrer"&gt;sample project&lt;/a&gt;, or experiment with RSC yourself. For powerful React tools and components, check out &lt;a href="https://www.grapecity.com/javascript-solutions" rel="noopener noreferrer"&gt;GrapeCity's JavaScript solutions.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
