Front-End Development Articles / Blogs / Perficient https://blogs.perficient.com/category/services/innovation-product-development/development/front-end-development/ Expert Digital Insights Tue, 19 Nov 2024 15:07:36 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Front-End Development Articles / Blogs / Perficient https://blogs.perficient.com/category/services/innovation-product-development/development/front-end-development/ 32 32 30508587 Introduction to State Handling Excellence in React- A Developer’s Perspective https://blogs.perficient.com/2024/11/14/introduction-to-state-handling-excellence-in-react-a-developers-perspective/ https://blogs.perficient.com/2024/11/14/introduction-to-state-handling-excellence-in-react-a-developers-perspective/#respond Thu, 14 Nov 2024 12:46:46 +0000 https://blogs.perficient.com/?p=371698

Handling an application’s state, or state management, plays an essential role in creating dynamic and responsive user interfaces and effectively executing business logic.

React offers numerous state management methods for storing and updating data, making it a popular web development technology.

Think of it like different ice cream flavors: some people like chocolate (Redux), some like vanilla (Recoil), and some like strawberry (MobX). With React, developers can select the flavor that best suits their needs and projects.

React allows developers the flexibility to select how best to organize their code, whether that means keeping things simple using React Hooks or putting everything in one location with Redux.

It is like having a bunch of ice cream toppings; it makes development flexible and enjoyable! 

 

 

Picture1

 

 

Choosing an appropriate state management library for your React application involves considering various aspects. When making your choice, consider the following crucial factors: 

 

Picture7

 

 

Let’s discuss some of the popular state management libraries and patterns in the React ecosystem:

State Management

 

Let’s dive deeper into these popular state management libraries.

Redux 

For developers, Redux is like a superhero, especially when they are creating large, complex programs. This amazing tool assists with tracking everything that occurs within your app, much like a superhero watching over the whole city. Redux provides a special store to store all your project data.

The best feature is that no component can just modify things in this store at random; instead, they must notify Redux of what needs to be done by sending a message known as an action. Everything becomes easier to understand and more predictable as the outcome. 

One key advantage of Redux is its seamless integration with React, a popular framework in web development. By combining these two technologies, developers can ensure the smooth functioning of their applications and easily address any issues that may arise.

Think of Redux as a reliable guide for managing your app’s state, simplifying the process, and preventing you from getting overwhelmed by its complexity.  

Here are some Key concepts in Redux. These concepts work together to establish a structured and predictable framework that ensures systematic management of data flow and application state. 

Key Concept in Redux

Recoil

Recoil is an experimental state management library developed by Facebook that provides a powerful solution for handling states in React applications, particularly for small-to-medium-sized projects.

It enhances the capabilities of the basic React framework and offers a group of features that can be tough to accomplish with React alone. 

Recoil’s flexibility and adaptability in managing state are key advantages, especially when dealing with components. It allows developers to handle the state in ways that meet a project’s specific needs.

Recoil simplifies managing data in React, making complex state handling effortless. It is like having a handy tool that takes the stress out of managing your application’s data.

For more information about Recoil, you can check out my upcoming blog. 

React Hooks 

The introduction of React Hooks in React version 16.8 in February revolutionized state management in functional components. Before Hooks, the handling state of functional components was limited, and class components were mainly used. 

The useState Hook is the primary component of Hooks, allowing simple state management within functional components.

Furthermore, react offers additional Hooks for particular use cases and advanced functionality, enhancing the overall development experience and increasing state management flexibility. 

Below are a few of the most used React hooks for state management. 

 

most popular

Context API 

A built-in feature of React called the Context API makes it easier to maintain a local state within a component tree and allows the state to be shared globally without having to be explicitly sent down through props.

It is frequently used to update and provide easy access to states for components located further down the component tree and to manage states at higher levels of the component tree. 

Context Object

It was made with createContext and comes with a provider and a consumer for sharing state management. 

Supplier: wraps components to provide context. 

Consumer: Accesses the component’s context value. 

Default Values: Provides a default value for components outside a provider’s scope when the context is created. 

Nested Contexts: Allows the nesting of multiple contexts, each with a separate provider and consumer. 

Dynamic Context Updates: This enables the context value to be updated dynamically based on the component’s logic or state. 

Performance Optimization: Optimizes rendering and avoids needless re-renders using techniques such as React. Memo. 

 

MobX

React developers can use MobX, a useful tool, to manage the dynamic data in their projects. Like a manager operating in the background, it ensures that the user interface (the user interface) updates automatically when data changes.

It is beneficial for clean, scalable state management for your app. 

It simplifies the process of tracking changing data, which is essential in React. MobX lets you specify certain areas of your data (or state) to be tracked and updates the display whenever those parts change.  

MobX is a helpful utility that monitors the data in your app and ensures that everything remains coordinated without requiring you to update the UI (User Interface) manually whenever something changes.

It is a clever approach to dealing with React application state management problems. 

You can refer to the official MobX documentation at https://mobx.js.org/  for further information and advanced usage. 

Zustand 

Zustand is a helpful tool for React, making it easier to manage and control the data in your applications.

It is known for being straightforward and not overly complex, yet despite this, it still has a lot of powerful features for managing how things are stored and updated in React.

It functions similarly to a straightforward and reliable helper in managing the data in your application. It is a lightweight yet powerful alternative to other state management solutions like Redux or MobX. 

Below are a few key points about Zustand worth noting. 

Zustand

 

Jotai 

For React apps, Jotai is a simplified state management solution that offers an option to more well-known tools like Redux and Context API. Its easy-to-use API and lightweight design make it attractive for developers looking for a simple state management solution. 

Jotai is made to work well with small or big applications and is easy to integrate into projects. It has a cool feature called atoms and derived atoms that make handling state simple and improve the overall development experience. 

With a focus on simplicity, Jotai presents a concise API, unveiling just a few exports from its main bundle. 

Atom’ is used to create fundamental states without assigned values, and ‘useAtom’ helps in managing states within React components. ‘createStore’ is the core of state management in Jotai, acting as a pivotal point.

The ‘Provider’ connects components, enabling the sharing of state details and simplifying communication across various project parts. This approach indeed offers a straightforward method for managing state in React applications. 

In summary, React provides a variety of state management libraries to cater to different requirements. Whether you value Redux for its established dependability, MobX for its simplicity, or Recoil for its contemporary approach, every project has an option. The crucial aspect is to select the most suitable option for your project and what your team is comfortable with. By thoroughly evaluating the factors mentioned in the blog, you can confidently opt for the most appropriate state management solution for your React applications. 

 

Here are the official websites where you can find more information about the state management libraries and React features we discussed. 

Redux: https://redux.js.org/ 

Recoil: https://recoiljs.org/ 

React Hooks: https://reactjs.org/docs/hooks-intro.html 

Context API: https://reactjs.org/docs/context.html 

MobX: https://mobx.js.org/README.html 

Zustand: https://github.com/pmndrs/zustand 

Jotai: https://github.com/pmndrs/jotai  

Plus, stay tuned for my upcoming blogs to dive deep into the world of state management! 

]]>
https://blogs.perficient.com/2024/11/14/introduction-to-state-handling-excellence-in-react-a-developers-perspective/feed/ 0 371698
Understanding Debouncing and Throttling in JavaScript – A Comprehensive Guide https://blogs.perficient.com/2024/11/12/understanding-debouncing-and-throttling-in-javascript-a-comprehensive-guide/ https://blogs.perficient.com/2024/11/12/understanding-debouncing-and-throttling-in-javascript-a-comprehensive-guide/#respond Tue, 12 Nov 2024 10:56:02 +0000 https://blogs.perficient.com/?p=371786

Throttling and debouncing are two essential optimization strategies. In this comprehensive guide, we will delve into the concepts of debouncing and throttling, explore their use cases, and understand how to implement them in JavaScript.

Debouncing Explained

What is Debouncing?

Debouncing is a programming technique used to prevent time-consuming operations from running too frequently, which might cause a web application’s performance to lag. It forces a function to wait a certain amount after the last invocation before executing.

When to Use Debouncing?

  1. Input Fields: Debouncing is often applied to input fields to delay the execution of a function until the user has stopped typing. This prevents unnecessary API calls or other resource-intensive operations on every keystroke.
  2. Resize and Scroll Events: When handling events like window resizing or scrolling, debouncing helps avoid performance issues by limiting the frequency of function calls.

Debouncing Implementation

Let’s look at a basic implementation of a debounce function in JavaScript:

const debounce = (func, delay) => {
    let timeoutId;
    return (...args) => {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => func.apply(this, args), delay);
    };
};

Example usage:

const debouncedFunction = debounce(() => {
console.log("Debounced function called");
}, 300);
// Attach debounced function to an event, e.g., button click
document.getElementById("myButton").addEventListener("click", debouncedFunction);

 

Scenario: Search Input in an E-commerce Site

When a user types in a search input box, you want to wait until they stop typing before sending the search query to the server. This prevents sending a request for every keystroke.

Scenario: Autosaving

When a user writes a document or fills out a form, you might want to autosave their input only after they’ve stopped typing for a certain period.

Throttling Explained

What is Throttling?

Throttling is a technique that ensures a function is only executed at a certain rate, limiting the number of times it can be called over time. Unlike debouncing, throttling guarantees the execution of a function at regular intervals.

When to Use Throttling?

  1. Scrolling: Throttling is beneficial when handling scroll events to control the rate at which a function is executed. This prevents overwhelming the browser with continuous function calls during rapid scrolling.
  2. Mousemove Events: Throttling is useful for mousemove events to prevent excessive calculations when tracking the movement of the mouse.

Throttling Implementation

Here’s a basic implementation of a throttle function in JavaScript:

const throttle = (func, limit) => {
    let throttled = false;
    return (...args) => {
        if (!throttled) {
            func.apply(this, args);
            throttled = true;
            setTimeout(() => {
                throttled = false;
            }, limit);
        }
    };
};

Example usage:

const throttledFunction = throttle(() => {
console.log("Throttled function called");
}, 300);
// Attach throttled function to an event, e.g., window scroll
window.addEventListener("scroll", throttledFunction);

 

Scenario: Window Resize Event

When a user resizes the browser window, the resize event can fire many times per second. Throttling can ensure the event handler executes at most once every 100 milliseconds, reducing the number of times the layout or other elements need to be recalculated.

Scenario: Scrolling Event

When a user scrolls a webpage, the scroll event can fire many times. Throttling can ensure the event handler executes at most once every 200 milliseconds, which is useful for tasks like lazy loading images or infinite scrolling.

 

Debouncing vs. Throttling

Debouncing and Throttling Differences

Execution Guarantee:

  • Debouncing: Ensures that a function won’t be run until a predetermined amount of time has elapsed since its last call.
  • Throttling: Guarantees a maximum number of executions in a given time frame.

Frequency of Execution:

  • Debouncing: Delays a function’s execution until a predetermined amount of time has passed since the last call.
  • Throttling: Ensures a function is not executed more often than once in a specified amount of time.

Use Cases:

  • Debouncing: Ideal for scenarios where you want to wait for a pause in user input, such as typing or resizing.
  • Throttling: Suitable for scenarios where you want to limit the frequency of function calls, such as scroll events.

Choosing Between Debouncing and Throttling

    • Debouncing is suitable when:
      • You want to wait for a pause in user input before taking an action.
      • You want to delay the execution of a function until after a certain time has passed since the last invocation.
    • Throttling is suitable when:
      • You want to ensure a function is not called more frequently than a specified rate.
      • You want to limit the number of times a function can be executed within a given time frame.

Conclusion

Debouncing and throttling in JavaScript are essential tools in a web developer’s kit for optimizing the performance of functions. By understanding these concepts and knowing when to apply them, you can significantly improve the user experience of your web applications. Whether you need to delay API calls during user input or control the rate of function execution during scroll events, debouncing and throttling provide elegant solutions to common challenges in web development.

]]>
https://blogs.perficient.com/2024/11/12/understanding-debouncing-and-throttling-in-javascript-a-comprehensive-guide/feed/ 0 371786
Best Practices for Structuring Redux Applications https://blogs.perficient.com/2024/11/12/best-practices-for-structuring-redux-applications/ https://blogs.perficient.com/2024/11/12/best-practices-for-structuring-redux-applications/#respond Tue, 12 Nov 2024 10:32:25 +0000 https://blogs.perficient.com/?p=371796

Redux has become a staple in state management for React applications, providing a predictable state container that makes it easier to manage your application’s state. However, as applications grow in size and complexity, adopting best practices for structuring your Redux code becomes crucial. In this guide, we’ll explore these best practices and demonstrate how to implement them with code examples.

1. Organize Your Code Around Features

One key principle in Redux application structure is organizing code around features. Each feature should have its own set of actions, reducers, and components, which facilitates codebase maintenance and comprehension.

folder Structure

 

2. Normalize Your State Shape

Consider normalizing your state shape, especially when dealing with relational data. This entails structuring your state to reduce the number of nested structures, which will increase its efficiency and manageability.

//Normalized state shape
{
  entities: {
    users: {
      "1": { id: 1, name: 'Johnny Doe' },
      "2": { id: 2, name: 'Jennifer Doe' }
    },
    posts: {
      "101": { id: 101, userId: 1, title: 'Post 1' },
      "102": { id: 102, userId: 2, title: 'Post 2' }
    }
  },
  result: [101, 102]
}

3. Middleware for Side Effects

Use middleware to manage asynchronous activities and side effects, such as redux-thunk or redux-saga. This keeps your reducers pure and moves complex logic outside of them.

// Using redux-thunk
const fetchUser = (userId) => {
return async (dispatch) => {
dispatch(fetchUserRequest());
try {
const response = await api.fetchUser(userId);
dispatch(fetchUserSuccess(response.data));
} catch (error) {
dispatch(fetchUserFailure(error.message));
}
};
};

4. Selectors for Efficient State Access

Functions known as selectors contain the logic needed to retrieve Redux state slices. Use selectors to efficiently access and compute derived state.

// Selectors
export const selectAllUsers = (state) => Object.values(state.entities.users);
export const getUserById = (state, userId) => state.entities.users[userId];

5. Testing Your Redux Code

Write tests for your actions, reducers, and selectors. Tools like Jest and Enzyme can be invaluable for testing Redux code.

// Example Jest Test
test('should handle FETCH_USER_SUCCESS', () => {
const prevState = { ...initialState };
const action = { type: FETCH_USER_SUCCESS, payload: mockData };
const newState = userReducer(prevState, action);
expect(newState).toEqual({
...initialState,
data: mockData,
error: null,
loading: false,
});
});

 

Conclusion

Adhering to these best practices can ensure a more maintainable and scalable Redux architecture for your React applications. Remember, keeping your code organized, predictable, and efficient is key.

 

]]>
https://blogs.perficient.com/2024/11/12/best-practices-for-structuring-redux-applications/feed/ 0 371796
Exploring Next.js Conf by Vercel: New Features in Version 15 and Their Significance https://blogs.perficient.com/2024/10/29/next-js-conf-whats-new-in-version-15-and-what-does-it-mean-for-us/ https://blogs.perficient.com/2024/10/29/next-js-conf-whats-new-in-version-15-and-what-does-it-mean-for-us/#respond Tue, 29 Oct 2024 22:31:42 +0000 https://blogs.perficient.com/?p=371211

Img 20241024 180252 1 I’ve been working with Next.Js for a quite a while and have been watching its development with interest all this time. Last week I was happy attended Next.js Conf in San Francisco. Perficient was proud to sponsor the event, allowing us to showcase our Sitecore Practice alongside my colleague David Lewis from the Optimizely Practice.

Vercel released new version 15 of Next.js framework. That was truly innovative day and I’d like to share my takeaways from the event about this new version.

Vercel seriously worked on mistakes

In the past, the Next.js team made some questionable decisions, such as rushing releases and maintaining rigid opinions despite community feedback. This included changes like rewriting the fetch API, implementing hard caching, and introducing numerous bugs, among other issues, while once again overlooking community requests. It took nearly a year for the team to recognize that these approaches were ineffective and to begin addressing the underlying problems. With the release of version 15, there is finally a sense that the framework is truly meeting the needs of its community, much as it has successfully done in previous iterations.

React 19

We are currently facing an unusual situation. Over six months have passed since the release candidate of React.js was introduced, yet the stable version has not been published. This delay directly impacts Next.js, as the two frameworks are closely intertwined. As a result, Next.js is currently utilizing the release candidate version of React.js, but this is only partially accurate. In reality, Next.js employs two different React.js configurations:

  • React.js 19 Canary for the App Router
  • React.js 18 for the Pages Router

Interestingly, there was an initial plan to integrate the React.js 19 version for the Pages Router as well. However, these changes were later rolled back. Full support for React.js version 19 is expected once the stable release is officially launched.

Form component

This next.js innovation is in fact already familiar form from react-dom, but with some improvements. You benefit from Next.Js implementation primarily in cases when a successful form submission involves a transition to another page. In that case, the loading.tsx and layout.tsx abstractions for the following page will get preloaded.

import Form from 'next/form'
 
export default function Page() {
  return (
    <Form action="/search">
      {/* On submission, the input value will be appended to 
          the URL, e.g. /search?query=abc */}
      <input name="query" />
      <button type="submit">Submit</button>
    </Form>
  )
}

Img 20241024 115119

Developer Experience (DX)

When discussing Next.js, the developer experience (DX) is impossible to overlook. Beyond the typical “Faster, Higher, Stronger” claims, Next.js has introduced several meaningful improvements that significantly enhance DX:

  1. Long-awaited support for ESlint v9. Next.js never supported ESlint v9. This is despite the fact that both eslint (v8) and some of its own dependencies were already marked as deprecated. Because of that developers were essentially forced to keep deprecated packages.
  2. The error interface in next.js – which is already clear and convenient – was slightly improved:
    1. Added a button to copy the call stack;
    2. Added the ability to open the source of the error in the editor on a specific line.
  3. Added Static Indicator – an element in the corner of the page showing that the page is built in static mode. The pre-built page indicator has been with us for years so it was slightly updated and adapted for App Router.
  4. Also added a directory with debug information – .next/diagnostics. That’s where one can find information about the build process and all errors that occur (sometimes helps to parse problems).

Versioning the documentation

One particularly valuable enhancement is the ability to access different versions of the documentation. But why is this so crucial for the developer experience?

Updating Next.js to accommodate major changes can be a challenging and time-consuming task. As a result, older versions like Next.js 12 and 13 remain widely used, with over 2 million and 4 million monthly downloads respectively. Developers working with these versions need documentation that is specific to their setup, as the latest documentation may include significant changes that are not compatible with their projects. By providing versioned documentation, Next.js ensures that developers have the reliable resources they need to maintain and update their applications

Turbopack

Probably the biggest news:

  • Turbopack is now fully complete for development mode! “100% of existing tests ran with no errors for Turbopack”
  • Now the turbo team is working on the production version, progressively going through the tests and covering them all (currently about 96%)

Turbopack introduces a range of new features that enhance its functionality and performance:

  1. Setting a memory limit for a Turbopack build;
  2. Tree Shaking (in other words that is removal of the unused code):
  3. const nextConfig = {
      experimental: {
        turbo: {
          treeShaking: true,
          memoryLimit: 1024 * 1024 * 512 // bytes (512MB)
        },
      },
    }

    These turbopack change alone reduced memory usage by 25-30% and speeded up heavy page assembly by 30-50%.”

  4. Fixed significant issues with styles. In version 14, there were often situations when the styles were broken in order during navigation, and because of this, style A became higher than style B, then lower. This changed their priority and, accordingly, the elements looked different.
  5. The next long-awaited improvement. Now you can write the configuration in TypeScript, and the file correspondingly would be next.config.ts:
    import type { NextConfig } from 'next';
     
    const nextConfig: NextConfig = {
      /* here goes you config */
    };
     
    export default nextConfig;

    Same strongly-typed syntax as usual, but very nice to have, finally!

  6. Another interesting innovation is retrying a failed page generation before actually failing the build for static pages. If the page fails the assembly for the connectivity issues, it will try it again:
    const nextConfig = {
      experimental: {
        staticGenerationRetryCount: 3,
      },
    }

Framework API changes

Updating Next.js often involves some of the most challenging aspects, and version 15 is no exception with its critical enhancements.

One significant change in version 15 is the transition of several framework APIs to asynchronous operations. This shift particularly affects the core framework-centric abstractions, including:

  • cookies,
  • headers,
  • params and
  • searchParams (also called Dynamic APIs).
import { cookies } from 'next/headers';
 
export async function AdminPanel() {
  const cookieStore = await cookies();
  const token = cookieStore.get('token');
  // ...
}

The changes are big indeed, but the Next.js team suggests one could update to the new APIs automatically by calling their codemod:

npx @next/codemod@canary next-async-request-api .

Caching

In my opinion, that is where the most important changes have happened. And the most important news is that Caching is now disabled by default!

Let’s take a look on what’s changed:

  • Actually, fetch now uses the no-store value by default instead of force-cache;
  • API routes use force-dynamic mode by default (previously it was force-static by default);
  • Caching in the client router has also been disabled. Previously, if a client visited a page within the path, it was cached on the client and remained in this state until the page reload. Now the current page will be loaded each time. This functionality can be altered via next.config.js:
    const nextConfig = {
      experimental: {
        staleTimes: {
          dynamic: 30 // defaults to 0
        },
      },
    }
  • Moreover, even if client caching is enabled, it most likely will be updated at the correct time. Namely, if the enabled page cache on the server expires.
  • Server components are now cached in development mode. Due to this, updates in development are faster.
  • Following the above, one can reset the cache by just reloading a page or can also completely disable the functionality via next.config.js:
    const nextConfig = {
      experimental: {
        serverComponentsHmrCache: false, // defaults to true
      },
    }
  • You can control the “Cache-Control” header which was previously always overwritten with the internal values ​​of next.js. This caused artifacts with caching via CDN;
  •  next/dynamic caches modules for reuse, rather than loading again each time;

Partial Prerendering (PPR)

This could be the main teaser of the release. PPR is a page assembly mode, in which Next.Js prerenders and caches as much of the route as possible,. while some individual elements are built on each request. In this case, the pre-assembled part is immediately sent to the client, and the remaining are loaded dynamically.

Partially Prerendered Product Page showing static nav and product information, and dynamic cart and recommended products

PPR diagram from the official documentation

The feature existed already six months ago in the release candidate as an experimental API. Previously PPR was enabled for the entire project, but since now it one can enable it for each segment (layout or page):

export const experimental_ppr = true

Another change is Partial Fallback Prerendering (PFPR). Due to this improvement, the pre-assembled part is immediately sent to the client, and the rest are loaded dynamically. At this time, a callback component is shown in place of the dynamic elements.

import { Suspense } from "react"
import { StaticComponent, DynamicComponent } from "@/app/ui"
 
export const experimental_ppr = true
 
export default function Page() {
  return {
     <>
         <StaticComponent />
         <Suspense fallback={...}>
             <DynamicComponent />
         </Suspense>
     </>
  };
}

Instrumentation

Instrumentation comes as a stable API. The instrumentation file allows users to affect Next.js server lifecycle. Works universally with all Pages Router and App Router segments.

Currently, instrumentation supports hooks:

  • register – called once when initializing the next.js server. Can be used for integration with monitoring libraries (OpenTelemetry, datalog) or for specific project tasks.
  • onRequestError – a new hook called on all server errors. Can be used for integration with error tracking libraries (Sentry).

Interceptor

Interceptor is route-level middleware. It feels as something like a full-fledged existing middleware, but, unlike the one:

  • Can work in node.js runtime;
  • Works on the server, therefore has access to the environment and a single cache;
  • Can be added multiple times and is nesting inherited (like middleware worked when it was in beta);
  • Works, among other things, for server functions.

In this case, when creating an interceptor file, all pages underneath the tree become dynamic.

  • If we keep Vercel in mind, now middleware will be effective as a primary simple check at the CDN level (so that it could immediately return redirects if the request is not allowed), and interceptors will work on the server, doing full checks and complex operations.
  • For the self-host, apparently, such a division will be less effective since both abstractions work on the server. Perhaps it will be enough just to use only interceptor.

Welcome v0 – Vercel’s new Generative UI

Img 20241024 154822

Last but not least, Next.js introduces Generative UI (v0), a groundbreaking feature that combines the best practices of frontend development with the full potential of generative AI. Currently in Beta, I had the opportunity to experience Generative UI firsthand at the event. I was thrilled to see how powerful and intuitive it is—from the very first prompt, it successfully generated the configuration for Sitecore!

Img 20241024 155506

I am thrilled to conclude that our toolbelt has been enriched with new, practical tools that enable us to deliver exceptional solutions effortlessly, eliminating the need to reinvent the wheel.

Well done, Vercel! Thanks everyone building this wonderful ecosystem:

Img 20241024 101237

]]>
https://blogs.perficient.com/2024/10/29/next-js-conf-whats-new-in-version-15-and-what-does-it-mean-for-us/feed/ 0 371211
Customize Quill.js and Error Handling in Vue.js https://blogs.perficient.com/2024/10/02/customize-quill-js-and-error-handling-in-vue-js/ https://blogs.perficient.com/2024/10/02/customize-quill-js-and-error-handling-in-vue-js/#respond Wed, 02 Oct 2024 12:23:43 +0000 https://blogs.perficient.com/?p=369656

In my previous blog, Rich Text Editor in Vue Application: Using Quill.js, we covered the fundamentals of setting up Quill.js in a Vue.js application to create a rich text editor. This blog will build on that foundation by diving deeper into Quill.js customization in Vue.js to meet specific needs.

By the end of this tutorial, you’ll gain a comprehensive understanding of how to customize Quill.js to meet your specific needs, including creating multiple toolbar configurations, managing different editor modes, and handling advanced text change events.

Recap: Rich Text Editor in Vue Application: Using Quill.js

If you haven’t read Rich Text Editor in Vue Application: Using Quill.js blog, here’s a brief overview of the setup process:

  1. Install Quill.js: Use npm to install Quill.js in your Vue project.
  2. Create a Custom Component: Encapsulate the editor logic in a Quill.vue component.
  3. Build the Editor Template: Define a basic structure for the editor in the template.
  4. Configure Toolbar Options: Set up default options for text formatting.
  5. Initialize the Editor: Use the mounted lifecycle hook to instantiate Quill.js.

You can find the full setup details in my previous blog post. [Rich Text Editor in Vue Application: Using Quill.js]

We will cover few Key Features of the Component

Dynamic Toolbar Options:

The Quill editor supports various toolbar configurations, allowing you to customize the editing experience based on user needs or application requirements. Quill.js customization in Vue.js enables you to tailor the editor’s toolbar to fit the specific needs of your users.

Step 1: Define Toolbar Options

Start by defining your toolbar options as objects. This will allow you to easily manage and customize the toolbar based on user preferences or component props.

The component defines three different sets of toolbar options:

  • Default Toolbar Options: Includes essential formatting tools like bold, italic, underline, lists, and links.

Default Toolbar Options

  • Small Toolbar Options: A simplified version with just the most commonly used formatting options.

Small Toolbar Options

  • Large Toolbar Options: An expanded set that adds more features like font selection and color options.

Large Toolbar Options

Step 2: Add a Prop for Toolbar Option

In your Quill.vue component, add a prop to accept the toolbar option. This allows you to customize the toolbar from the parent component.

Prop For Toolbar Option

Step 3: Create a Method to Get Toolbar Options

Implement a method that returns the appropriate toolbar options based on the value of the toolbarOption prop. This method will be called during the initialization of the Quill editor.

Get Toolbar Options Method

 

Step 4: Initialize Quill with Dynamic Toolbar Options

In the mounted lifecycle hook, call the getToolbarOptions method when initializing the Quill editor. This ensures that the editor uses the correct toolbar configuration.

Initialize Quill With Dynamic Toolbar Options

 

Step 5: Use the Custom Quill Component

In the parent component, you can now specify which toolbar option to use when including the CustomQuillEditor.

Use The Custom Quill Component

Step 6: Customizing the Toolbar

You can further customize the toolbar by adding additional buttons or dropdowns. For example, if you want to add a font dropdown

Customizing The Toolbar

 

Error Handling in Quill.js

Proper error handling ensures a smooth user experience, even when things go wrong. Quill.js customization in Vue.js also involves implementing robust error handling mechanisms to manage various scenarios.

Step 1: Identify Possible Error Scenarios

Consider common error scenarios that might occur while using the Quill editor:

  • Initialization errors when creating the Quill instance.
  • Issues when setting or getting content.
  • Errors during user input (e.g., invalid HTML).

Step 2: Wrap Initialization in a Try-Catch Block

When you initialize the Quill editor, use a try-catch block to catch any errors that occur during setup. This allows you to handle initialization failures gracefully.

Wrap Initialization In A Try Catch Block

Step 3: Handle Text Change Errors

Implement error handling to catch potential issues when getting or setting content.

Handle Text Change Errors

 

Step 4: Validate Content Before Setting

Validate the content before setting it to prevent errors from invalid HTML:

Validate Content Before Setting

Then, use this method before setting the content in the mounted hook:

If Valid Then Set

Step 5: Emit Errors to Parent Component

In case of an error, emit an event to the parent component to notify it of the error. This can be helpful for displaying user-friendly error messages.

Emit Error To Parent Component

Step 6: Implement User Feedback

In your parent component, listen for the error event emitted by the Quill editor. Use this information to display feedback to the user.

Handle Error

Error Message Display

 

Additional Enhancements

  • Dynamic Toolbar Changes: If you want to change the toolbar options dynamically (e.g., based on user actions), consider using a watcher on the toolbarOption prop to reinitialize Quill with the new options.
  • Customization: Feel free to add more complex configurations, such as custom buttons or dropdowns. Refer to the Quill.js documentation for detailed options.

 

Conclusion

By focusing on Quill.js customization in Vue.js, you can create a highly flexible and user-friendly rich text editor in your Vue.js application. Whether you’re catering to different user needs or ensuring a smooth experience, these techniques will help you build a powerful text editor.

For more advanced customization, explore the Quill.js documentation and see how you can further enhance your editor’s functionality.

 

]]>
https://blogs.perficient.com/2024/10/02/customize-quill-js-and-error-handling-in-vue-js/feed/ 0 369656
Rich Text Editor in Vue Application: Using Quill.js https://blogs.perficient.com/2024/10/01/rich-text-editor-in-vue-application-using-quill-js/ https://blogs.perficient.com/2024/10/01/rich-text-editor-in-vue-application-using-quill-js/#respond Tue, 01 Oct 2024 05:18:03 +0000 https://blogs.perficient.com/?p=369624

Rich text editors are essential for many web applications, allowing users to format text, add links, and even insert media directly into their content. Quill.js is a powerful, customizable open-source editor that integrates seamlessly with modern frameworks like Vue.js. This tutorial will walk us through the steps to set up and integrate Quill.js in a Vue.js project to create a dynamic rich text editor.

By the end of this guide, you’ll have a fully functional, tailored-to-your-needs rich text editor in your Vue.js application.

Prerequisites:

Before diving into the code, ensure that you have the following setup and basic knowledge of:

Step 1: Installing Quill.js in Your Vue Application

First, we need to install Quill.js in your Vue project. Open your terminal, navigate to your project directory, and then run this command:

Install Quill

 

This command installs Quill.js and saves it as a dependency in your project.

Step 2: Creating a Custom Quill.js Component for Rich Text Editing

Let’s begin by creating a new Vue component called Quill.vue. This component will encapsulate the logic for initializing and managing the Quill editor instance.

Step 3: Building the Quill Editor Template in Vue.js

Define the basic template structure in Quill.vue

Set Up Quill.js Template

Step 4: Importing Quill.js and CSS

Import the Quill.js library and the necessary CSS for the Snow theme.

Import Dependencies

Step 5: Configuring Toolbar Options for Your Vue Rich Text Editor

Set up the default toolbar options for the editor.

This configuration provides basic text formatting options and controls for lists and links.

Define Default Toolbar Option

 

Step 6: Initializing the Quill.js Editor in Your Vue Component

In the mounted lifecycle hook, initialize the Quill editor on the referenced div element.

Initialize The Quill Editor

 

  • this.$refs.div: Accesses the div where Quill.js will be rendered.
  • new Quilljs(element, { ...DefaultToolbarOptions }): Initializes Quill.js with the defined toolbar options.
  • quill.on('text-change'): Sets up an event listener to capture text changes and update the component’s currentValue, which is emitted to the parent component.

 

Step 7: Capturing Text Changes in Quill.js with Vue.js

The @Watch decorator monitors the value prop, ensuring that any changes made externally are reflected in the editor.

Watch For Value Changes

This makes the component reactive to prop changes from its parent.

Step 8: Integrating the Quill.js Editor into Your Vue.js Application

Finally, use the Quill component in a parent component as shown below:

Use In Parent Component

In this tutorial, we walked through the steps to integrate Quill.js into a Vue.js application, creating a customizable rich text editor. This setup gives you the flexibility to build a feature-rich text editor tailored to your project’s needs.

Whether you’re building a content management system, a blogging platform, or any application that requires text editing, Quill.js with Vue.js provides a robust solution.

]]>
https://blogs.perficient.com/2024/10/01/rich-text-editor-in-vue-application-using-quill-js/feed/ 0 369624
Vue.js Location Autocomplete: Integration Guide https://blogs.perficient.com/2024/09/19/vue-js-location-autocomplete-a-complete-integration-guide/ https://blogs.perficient.com/2024/09/19/vue-js-location-autocomplete-a-complete-integration-guide/#respond Thu, 19 Sep 2024 05:58:35 +0000 https://blogs.perficient.com/?p=369393

In this tutorial, we’ll explore how to achieve Vue.js Location Autocomplete by integrating the Google Maps Places Autocomplete API with a custom Geo Location component. We’ll walk you through each step to set up the Vue.js Location Autocomplete feature, manage user input, and bind it to Vue’s v-model for smooth two-way data binding.

Prerequisites for Vue.js Location Autocomplete

To start with Vue.js Location Autocomplete, ensure you have a basic understanding of Vue.js and TypeScript. Additionally, you need to enable the Maps API on your Google Cloud account.

Steps to Build a Google Maps Autocomplete Component

Step 1: Set Up the Google Places API

First, activate the Places API through the Google Cloud Console and obtain your API key. Subsequently, load the Google Maps script in your application, typically in your index.html file. For more details, refer to the Google Maps Places API documentation.

Install

Load Google Maps Script

Step 2: Set Up the Basic Component

Next, create a Vue component called Geo Location. This component will use Google Maps’ Places Autocomplete service to fetch location data. For more information on Vue.js, visit the Vue.js documentation.

Here’s the component template:

Template

This Vue.js template defines an input field for integrating the Google Maps Places Autocomplete API:

  • <input type="search">: Defines a search box for location input.
  • ref="textbox": Allows direct access to the input element in the script.
  • :placeholder="'search location'": Binds the placeholder to a static string.
  • :value="value": Binds the input value to a reactive value property.
  • @input="input": Calls the input method when the user types in the field.
  • @change="change": Calls the change method when the input value changes.

Step 3: Define the Component in TypeScript

Then, Set up the structure for your Geo Location component using TypeScript, and use vue-property-decorator to manage props and Vue lifecycle hooks.

Basic Component

  • Use the @Component decorator from vue-property-decorator to define the Geo Location component.
  • Use the @Prop() decorator to pass the value prop from the parent component.
  • Consequently, the value prop is bound to the v-model.

Step 4: Access the Input Element

To work with Google Places Autocomplete, reference the input element with a getter:

Get Input Text

  • Retrieve the input element using this.$refs.textbox and the ref attribute from the template.
  • Furthermore, ensure TypeScript recognizes the element as an HTMLInputElement by using it as HTMLInputElement, providing proper type safety.

Step 5: Initialize Google Places Autocomplete

Inside the mounted lifecycle hook, initialize the Google Places Autocomplete object and bind it to your input field. Also, listen for the place_changed event to capture when a place is selected from the dropdown. For additional information, see the Google Maps JavaScript API documentation.

Initialization

  • Create an instance of Google’s Autocomplete for the input field, thereby enabling suggestions for location searches.
  • Moreover, a listener can be added to detect when a user selects a place from the suggestions. As a result, call the placeChanged method to handle the selected place.

Step 6: Handle Input and Change Events

Define methods to handle user input and change events.

Events

  • The input method triggers whenever the user types in the input field.
  • Similarly, the change method fires when a selection is made.

Step 7: Capture Selected Place

The placeChanged method triggers when the user selects a location from the dropdown. Here, extract either the formatted_address or the place’s name and pass it to the parent component.

Set Selected Location

  • Retrieve the selected place from the Autocomplete suggestions using this.autoComplete.getPlace().
  • Consequently, emit the selected place’s formatted_address or name back to the parent component via the input() and change() methods.

Step 8: Use in Parent Component

Finally, use the GeoLocation component in a parent component as shown below:

Call from Parent Component

  • Bind the input value to the selectedLocation data property using the v-model directive.
  • In addition, dynamically apply the ‘has-error’ class if the location search fails using v-bind: class.

By following this approach, you can easily integrate Google Maps Places Autocomplete into your Vue.js applications, thereby enhancing the user experience when entering location data. This guide provides a flexible and reusable way to work with location-based inputs.

 

]]>
https://blogs.perficient.com/2024/09/19/vue-js-location-autocomplete-a-complete-integration-guide/feed/ 0 369393
A Guide to Lazy Loading in Angular https://blogs.perficient.com/2024/09/18/a-guide-to-lazy-loading-in-angular/ https://blogs.perficient.com/2024/09/18/a-guide-to-lazy-loading-in-angular/#respond Wed, 18 Sep 2024 05:51:14 +0000 https://blogs.perficient.com/?p=369150

Lazy loading should be considered for large applications with numerous routes. Sometimes, optimizing performance may risk delivering a better user experience.

Using the technique known as “lazy loading,” the browser loads only the modules or parts that are required for the particular scenario. All the modules will not be loaded except the active route. This technique achieves lower initial bundle sizes and contributes to faster load times.

Generally, when we start the application by default, NgModules are eagerly loaded. It means that as soon as all the NgModules will load, whether that is necessary or not.

Use loadChildren (instead of component) in the AppRoutingModule routes configuration to lazy load Angular modules.

const routes: Routes = [
    {
      path: "items",
      loadChildren: () =>
        import("./items/items.module").then((m) => m.ItemsModule),
    },
  ];

Steps to Implement Lazy Loading in Angular

  1. Create a feature module with a routing file
  2. Create Components
  3. Add Route for Components
  4. Add Navigation Links
  5. Implement Lazy Loading

1. Create a Feature Module with a Routing File

Create a new angular application or in your existing application, here we are going to create a new Admin module. To create the module, we’ll use the Angular cli command. We can create a module with modules in the Angular application using the command that Angular provides. Thus, we’ll use the following command to create the admin module:

ng g module admin --routing

When we successfully execute the above command, we will create files like this:

src/app/admin/admin.module.ts
src/app/admin/admin-routing.module.ts

 

2. Create Components

Let’s create the Components for Modules. The following command will create a component for the admin module. Thus, we will create three components—home, user, and post—in our admin module.

ng g component admin/admin
ng g component admin/user
ng g component admin/post

 

3. Add Route for Components

Here, the route will be added using the created component. After that, we will use our file named admin-routing module and update it.

src/app/admin/admin-routing.module.ts

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { AdminComponent } from "./home/home.component";
import { UserComponent } from "./user/user.component";
import { PostComponent } from "./post/post.component";

const routes: Routes = [
 { path: "", component: AdminComponent },
 { path: "user", component: UserComponent },
 { path: "post", component: PostComponent },
];

@NgModule({
 imports: [RouterModule.forChild(routes)],
 exports: [RouterModule],
})

export class AdminRoutingModule {}

 

4. Add Navigation Links

Now, we will add links to the app component’s HTML file. We will use route-outlet to add all route’s links.

src/app/app.component.html

<div class="container">
 <nav>
  <ul>
   <li>
    <a href="#home" routerLink="/admin">
      Admin
    </a>
   </li>
   <li>
    <a href="#user" routerLink="/admin/user">
      User
    </a>
   </li>
   <li>
     <a href="#post" routerLink="/admin/post">
      Post
     </a>
   </li>
  </ul>
 </nav>
</div>

 

5. Implement Lazy Loading

Now, Import App RoutingModule to the module.ts file. Using the following way:

src/app/app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";

@NgModule({
 declarations: [AppComponent],
 imports: [BrowserModule, AppRoutingModule],
 providers: [],
 bootstrap: [AppComponent],
})

export class AppModule {}

Make necessary changes in app-routing.module.ts.

Here, we will load the module lazily using loadChildren.

app-routing.module.ts

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { HomeComponent } from "./home/home.component";

const routes: Routes = [
 {
  path: "admin",
  loadChildren: () =>
  import("./module/admin.module").then((m) => m.AdminModule),
 },
 {
  path: "other",
  loadChildren: () =>
  import("./module/other.module").then((m) => m.OtherModule),
 },
 {
  path: "",
  component: HomeComponent,
 },
];

@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule],
 providers: [],
})

export class AppRoutingModule {}

Now, our above code is ready to run. To run the code, use the following command:

ng serve

 

]]>
https://blogs.perficient.com/2024/09/18/a-guide-to-lazy-loading-in-angular/feed/ 0 369150
Custom Select Picker with Vue.js: A Comprehensive Tutorial https://blogs.perficient.com/2024/09/18/custom-select-picker-component-with-vue-js/ https://blogs.perficient.com/2024/09/18/custom-select-picker-component-with-vue-js/#respond Wed, 18 Sep 2024 05:06:39 +0000 https://blogs.perficient.com/?p=367915

In this blog post, we’ll develop a Custom Select Picker using Vue.js, TypeScript, and jQuery.

This article will teach you how to use Vue.js to create a custom select-picker component. Select-pickers are adaptable user interface elements that let users select from a list of alternatives in numerous ways. We’ll improve this component by adding more features like “Apply” and “Cancel” buttons to provide users with more control over their choices.

Prerequisites for Creating a Vue.js Custom Select-Picker

Before we dive into the code, it’s important to first ensure you have a basic understanding of the following technologies:

Step 1: Setting Up the Custom Select Picker Component in Vue

We’ll start by defining our Vue component using the template, script, and style; sections.

  • The template section will contain the HTML structure.
  • The script section will contain the business logic.
  • The style section will be used for custom styles.

Code for setting Up the blank component

Step 2: Initializing the component

In the script section, we import the necessary modules and define the component class.

We will use the VueJs decorators below:

  • 1) @Component: This defines a Vue component using a TypeScript class, enabling a cleaner, more structured, and object-oriented approach through class-based syntax.
  • 2) @Prop: In class-based components, this defines props, allowing a parent component to pass custom attributes to a child component.

Code to Initialize the component

Step 3: Handling Events

We manage different events to improve the component’s functionality, including displaying and hiding the dropdown and applying and canceling selections.

code to handle show and hide events of select picker

Step 4: Adding Apply and Cancel buttons

We’ll dynamically create and insert the “Apply” and “Cancel” buttons into the dropdown using jQuery.

jQuery code to create Apply and Cancel Button

Update the mounted method to add these buttons to the UI.

Code to render buttons on UI

Step 5: Adding Apply and Cancel buttons functionality

Now, write code for the Apply and Cancel buttons functionality inserted into the custom select picker component dropdown.

Code for Apply and Cancel Button functionality

Conclusion

By following this tutorial, you will successfully build a custom select-picker component with Vue.js that enhances user control and interaction. Whether you’re working on a complex form or a simple selection tool, this component can be adapted to meet your project’s needs. For further insights into improving your Vue.js components, explore the Vue.js official documentation. Testing the component thoroughly will ensure it performs optimally across different scenarios.

]]>
https://blogs.perficient.com/2024/09/18/custom-select-picker-component-with-vue-js/feed/ 0 367915
GitHub Copilot: Boosting Productivity in Visual Studio Code https://blogs.perficient.com/2024/09/16/boosting-productivity-in-visual-studio-code/ https://blogs.perficient.com/2024/09/16/boosting-productivity-in-visual-studio-code/#respond Mon, 16 Sep 2024 22:20:32 +0000 https://blogs.perficient.com/?p=369233

AI has arrived in the ever-evolving world of software development and staying ahead means embracing tools that can boost productivity and streamline workflows. GitHub Copilot, an AI-powered coding assistant developed by GitHub and OpenAI, has been turning heads since its debut. Integrated seamlessly with Visual Studio Code (VS Code), Copilot is more than just an autocomplete tool—it’s like having a coding partner who’s always ready to help.

In this post, we’ll dive into how you can leverage GitHub Copilot within VS Code to enhance your coding efficiency. Whether you’re new to Copilot or looking to unlock its full potential, we’ve got you covered. And if you didn’t catch the initial introduction when you first enabled Copilot, we’ll show you how to access the Welcome Screen to get you up to speed.


Getting Started: Accessing the GitHub Copilot Welcome Screen

Upon enabling GitHub Copilot, you might expect to see an introductory screen outlining its features. However, if you don’t see this initial introduction, don’t worry—you can still access it. From the Welcome screen in VS Code:

  • Click on the “More…” Button: In the lower right corner of VS Code, you’ll find a “More…” (represented by three dots or an ellipsis) button.

Vscodewelcome

  • Select “GitHub Copilot”: From the dropdown menu that appears, choose “GitHub Copilot”.

Commandpalette

This will bring up the Welcome Screen, providing a snapshot of Copilot’s capabilities. From generating code snippets and entire function implementations to executing specific instructions based on your comments, this screen serves as an excellent primer. It helps you familiarize yourself with the AI assistant that’s poised to become an integral part of your coding workflow.

Welcomescreen


Leveraging the Chat Functionality

One of Copilot’s most powerful features is its Chat functionality. Think of it as an AI colleague who’s always available to answer questions, explain code, or even help troubleshoot issues—all within the context of your current project.

Key Uses of Copilot Chat:

  • Understanding Complex Code: If you’re working with a large or unfamiliar codebase, you can ask Copilot to explain functions, classes, or modules. For example, “Can you explain what the authenticateUser function does in auth.js?”
  • Exploring the Workspace with @workspace: Use the @workspace command to query across your entire project. This is particularly useful for finding where certain functions are defined or how modules interact.  By default chat does not search your full project, so if you’re looking for information about more than just the file you’re in, you’re going to want to use @workspace in your chats.
  • Troubleshooting and Debugging: Encountering an error? Paste the error message into the chat and ask for potential fixes or explanations.
  • Generating Code Snippets: Need a quick example of how to implement a specific feature? Ask Copilot to generate a code snippet, such as “Show me how to parse a JSON file in Python.” or if it’s a huge project you can simply just find out where the files are you’re looking for.

The chat function effectively transforms Copilot into an interactive assistant that’s intimately familiar with your codebase.

Example Interaction:

Chat

Enhancing Workflow with the New Chat Window Feature

To make the most out of Copilot’s chat capabilities, especially during intensive coding sessions, you might prefer to have the chat in a separate window. This allows you to keep your editor uncluttered and maintain focus on your code while still having immediate access to Copilot’s assistance.

How to Open Copilot Chat in a New Window:

  1. Open Copilot Chat Panel: Click on the Copilot icon in the sidebar or use the Command Palette (Ctrl+Shift+P or Cmd+Shift+P) and select “GitHub Copilot: Chat”.
  2. Pop Out the Chat Window: In the chat panel, look for the “…” icon and select “Open Chat in New Window”.
  3. Position the Window: The chat will open in a new window. You can drag it to another monitor or position it alongside your main editor window.  Don’t worry, you won’t lose any of your context or history.

Newwindow

Benefits of Using a Separate Chat Window:

  • Uninterrupted Coding Space: Keep your editor free from distractions while still having Copilot readily available.
  • Improved Multitasking: Interact with Copilot without constantly switching tabs or splitting your screen within VS Code.
  • Customized Workspace Layout: Arrange your tools in a way that best suits your workflow, especially if you’re using multiple monitors.

Customizing Your Experience: Exploring Copilot Settings

Out of the box, Copilot is a powerful tool, but diving into its settings allows you to tailor its behavior to your specific needs and preferences. Customization can make the difference between a helpful assistant and an indispensable part of your development process.

Accessing Copilot Settings:

  • Via Settings Menu: Go to File > Preferences > Settings (Ctrl+, or Cmd+,), then either go down to Extensions or search for “GitHub Copilot.”
  • Directly Through Command Palette: Open the Command Palette and type “Open User Settings”, then search for “GitHub Copilot.”

There are a lot settings in here and I suggest taking some time to walk through them and read through the options.  This area is probably worth a blog post of it’s own, so I’ll put it on the list.

Settings


Conclusion

GitHub Copilot is more than a novelty—it’s a transformative tool that can significantly enhance your development workflow. By taking the time to explore its features and customize its settings, you can tailor Copilot to act as a true extension of your coding self.  I would advise you to experiment with some of the different options.  Don’t hesitate to try out different settings to see what works best for you.  Embrace GitHub Copilot as a partner in your coding journey, and watch how it transforms not just how you write code, but how you think about development.

Additional Resources

]]>
https://blogs.perficient.com/2024/09/16/boosting-productivity-in-visual-studio-code/feed/ 0 369233
A rabbit hole in web development https://blogs.perficient.com/2024/09/11/a-rabbit-hole-in-web-development/ https://blogs.perficient.com/2024/09/11/a-rabbit-hole-in-web-development/#respond Wed, 11 Sep 2024 16:15:35 +0000 https://blogs.perficient.com/?p=369021

A rabbit hole

Recently, I was learning about some new Adobe software, and came across the line of code import Theme from "@swc-react/theme". This quickly dropped me into the web development education rabbit hole…

  • A quick search shows me that "@swc-react/theme" is React Wrappers for Spectrum Web Components.

  • Another search shows that Spectrum Web Components is a particular implementation of Adobe Spectrum that uses Open Web Components‘s project generator.

  • What is Open Web Components? Well, whatever it is, it relies on something called Lit.

  • What is Lit? It’s a JavaScript library that relies on Web Components.

  • At the end of the rabbit hole, we learn that Web Components is a collection of modern HTML and JavaScript features that allow implementation of “components”, which are modular, HTML-parameterizable pieces of a webpage that have their own associated HTML, JavaScript, and CSS. Components are typically implemented by more heavyweight frameworks such as React or Angular.

Of course, few of the clarifying details I’ve added in the above bullet points were clear to me during my initial time in the rabbit hole.

The following is an article that presents the relevant content from the rabbit-hole in a more foundational, “bottom-up” approach.

Web components

Web Components is a suite of different technologies [standard to HTML and JavaScript] allowing you to create reusable custom elements – with their functionality encapsulated away from the rest of your code – and utilize them in your web apps.”

The “suite of different technologies” are the custom elements JavaScript API, the shadow DOM JavaScript API, and the <template> and <slot> HTML elements.

Custom elements (JavaScript API)

The custom elements JavaScript API allows

  • extension of built-in HTML elements, such as <p>, so that an extended HTML element can be used in HTML with code such as <p is="word-counter"> . (The argument to is specifies which extension of <p> is used.) These are called customized built-in elements.

  • creation of new HTML elements that have new tag names such as <custom-element>. These are called autonomous (HTML) elements.

A custom element is implemented as a class which extends either

  • an interface corresponding to an HTML element, in the case of extending an existing HTML element

    or

  • HTMLElement, in the case of creating a new HTML element

The class will need to implement several “lifecycle callback functions”. The class, say Cls, is then passed to window.customElementRegistry.define("my-custom-element", Cls).

Shadow DOM (JavaScript API)

The shadow DOM JavaScript API allows “hidden” DOM trees, called shadow trees, to be attached to elements in the regular DOM tree. Shadow trees are hidden in the sense that they are not selected by tools such as document.querySelectorAll(). They allow for encapsulation because none of the code inside a shadow tree can affect the portion of the overall DOM tree that is its parent.

Shadow trees are effected by using

  • <template shadowrootmode="open"> </template> in HTML

    or

  • const shadow = elem.attatchShadow({mode: "open"}) in JavaScript

<template>

The <template> HTML element is not actually rendered by the browser. Instead, when template is the JavaScript Element representing a <template> HTML element (e.g. const template = document.querySelectorAll("#some-template")), we are expected to manually render* template.content. This manual rendering is done by writing code such as document.body.appendChild(template.content).

But- still- what good is this? At this stage, all we know about <template> is that use of it requires manually rendering HTML. It seems useless!

*template.content is of type DocumentFragment, which is a data structure that represents template.innerHTML. You can read about a situation in which you would want to use DocumentFragment over innerHTML here. It’s not clear to me how using DocumentFragment is vastly superior to innerHTML in this scenario, but there is probably some small performance advantage.

Slotting

<template> does become quite useful when it’s paired with the <slot> element. The <slot> element allows us to define portions of the <template> inner HTML that are variable so that we can later “plug-in” custom HTML into those portions of the <template> inner HTML.

In order achieve this functionality of <slot>, we must actually use <slot> alongside custom element and shadow DOM concepts, as this was how <slot> was designed to be used.

Slotted custom elements

We now describe how <slot> is used with custom elements, the shadow DOM, and templates to implement a “slotted” custom element.

  1. Include code such as

<template id = "some-template">
    ...
    <slot name = "some-slot"> default text </slot>
    ...
</template>

in the HTML.

  1. In the class that defines a custom element, write a constructor that creates a shadow tree by including const shadowRoot = this.attachShadow({mode: "open"}) in the constructor.

  1. In same constructor, right after the creation of the shadow tree, set template.content to be the inner HTML of the shadow tree: shadowRoot.attachChild(template.content.cloneNode(true)).

(To see an example of this, inspect this webpage with your browser’s development tools.)

We see that the three concepts of custom elements, the shadow DOM, and templates are all involved. (1) and (3) are about templates, (2) is about the shadow DOM, and (2) and (3) occur in the custom element’s constructor!

But how does <slot> come into play? Well, suppose that a custom element called “some-element” is configured in the above way. Then then the HTML

<some-element> </some-element>

is interpreted by the browser to be the inner HTML of the template with the inner HTML of the template’s <slot> element replacing the template’s <slot> element. So, the browser will render the HTML

...
default text
...

Alternatively, the HTML

<some-element>
    <div slot = "some-slot"> replacement text </div>
</some-element>

is interpreted by the browser to be the inner HTML of the template with the inner HTML of the newly specified <slot> element replacing the template’s <slot> element. So, the browser will render the HTML

...
replacement text
...

Modern components

The type of custom element above implements the idea of a modern component, which is

  • easily reusable

  • encapsulated (in the sense that one component’s code is separate from other components and does not affect other components state or behavior)

  • allows for parameterization of HTML with <slot>

We’ve seen that writing the above type of custom element requires a lot of boilerplate. We could eliminate the boilerplate by writing a class that implements the modern component functionality. The class’s constructor would take the HTML that is to underlie the modern component as an argument*.

* If <slot> functionality is used, then the HTML that is to underlie the modern component would contain a the same kind of <slot> element that <template> did above.

Lit

Lit is a library that provides a class, LitElement, that implements this notion of modern component. As Lit’s documentation says, the advantage of this approach is that, since modern components rely on standard HTML and JavaScript APIs, they are supported by almost all web browsers (all web browser that support the required HTML and JavaScript APIs, that is), and do not require any frameworks such as Angular or React to run.

Open Web Components

Open Web Components is a website that “gives a set of recommendations and defaults” on how to write modern web components”. The “Getting Started” page recommends that to begin developing a web component, you should make use of their npm package by running npm init @open-wc, which generates an example Lit component.

Spectrum Web Components

Spectrum Web Components is the “frameworkless” or “as close to vanilla JS as possible” implementation of Adobe Spectrum. Spectrum Web Components are Lit components and thus extend LitElement.

React Wrappers for Spectrum Web Components

swc-react is a collection of React wrapper components for the Spectrum Web Components (SWC) library, enabling you to use SWC in your React applications with ease. It relies on the @lit/react package to provide seamless integration between React and the SWC library.”

Why not just use React Spectrum components?

swc-react and React components are two technologies that implement the idea of a component in some way. I would think that if we’re using React, wouldn’t it more natural to just use React components, and not import an extra library that make Lit components useable in React? Well, Adobe documentation says:

We recommend using swc-react over React Spectrum in your add-ons based on React, because it currently offers a more comprehensive set of components which provide built-in benefits as detailed above in the Spectrum Web Components section, and is more actively supported.

So I suppose that answers my question 🙂

]]>
https://blogs.perficient.com/2024/09/11/a-rabbit-hole-in-web-development/feed/ 0 369021
How to Speed Up Magento 2 Website: Part 1 https://blogs.perficient.com/2024/09/05/how-to-speed-up-magento-2-website-part-1/ https://blogs.perficient.com/2024/09/05/how-to-speed-up-magento-2-website-part-1/#respond Thu, 05 Sep 2024 10:48:46 +0000 https://blogs.perficient.com/?p=356278

Part 1: Optimizing Server Performance

Speed is a critical factor for the success of any online store, and optimizing your Magento 2 website’s performance can significantly enhance user experience, conversion rates, and search engine rankings.

Nobody enjoys a website that loads slowly, and it’s well-known that an ecommerce site with prolonged loading times can result in a loss of customers for a business.

For example, Google Studies have indicated that when a desktop website takes longer than 4 seconds to load, 25% of users are likely to exit. This percentage increases significantly for mobile users, with 53% leaving if a website exceeds a 3-second loading time.

This article covers common speed problems and solutions for your Magento 2 website.

Evaluate Website Load Time

Use tools like Google Page Speed Insights, GTmetrix, or Pingdom to regularly monitor your website’s performance. Conduct thorough testing after implementing changes to measure their impact on speed and user experience.

  1. Page Speed Insights (https://pagespeed.web.dev/): A Google-provided tool used to assess the loading speed of your website’s desktop and mobile iterations. Strive for a score of 90 or above. Page Speed Insights provides recommendations for areas that require improvement, facilitating a clear starting point for enhancements.
  2. GT Metrix (https://gtmetrix.com/): A recommended tool by Adobe Commerce: New Relic: This website monitoring tool offers a dashboard to track server queries, report errors, monitor transaction performance, and more. When selecting Magento extensions compatible with New Relic, you can monitor their impact on website speed. It’s a paid tool, but if you use a paid version of Magento, you receive it at no cost.

Tip 1: Keep Magento Up to Date

Regularly update your Magento version when new releases are available to enhance your website’s performance. These updates often include patches and improvements.

You can check the release schedule here to ensure your website is current. To find out your current version, simply glance at the bottom of your Admin Panel. Check here (https://experienceleague.adobe.com/docs/commerce-operations/release/planning/schedule.html) for the release schedule and see if your website is up to date.

If you are unsure which version you are running, there are many ways to check, but the easiest is looking at the bottom of the Admin Panel.

Find Which Version You Are Running

GIF demonstrating how to check which version you are using

 

Tip 2: Optimize Your Magento 2 Mode

Magento 2 offers three modes: default, developer, and production. If you’re migrating from Magento 1, this may be new. Here’s the key:

  • Production mode is the fastest.
  • Developer and default modes are for development and debugging.

To check your current mode, Run php bin/magento deploy:mode:show on the command line. This will display the current operational mode.

You can switch modes by using the same command with your chosen mode.

Tip 3: Speed Up Your Website with Caching

Magento 2 provides various caching mechanisms to enhance performance. Utilize full-page caching to store complete pages in cache, reducing server response time. Additionally, enable browser caching to store static files like images, CSS, and JavaScript in the user’s browser, reducing server load for returning visitors.

Caching can significantly boost your website’s performance. It works by preloading page content, so the server doesn’t have to reload it each time a visitor returns.

In Magento, ensure that caching is enabled. Go to System > Cache Management, select all caches, enable them, and then submit the changes. This simple step can make a big difference in loading speed.

Cache Management

GIF demonstrating how to manage cache from the Admin panel

 

Tip 4: Boost Speed with Varnish Cache

Magento recommends Varnish Cache, an advanced open-source solution. While Magento has its own caching system, Varnish goes a step further. It accelerates web applications by caching dynamic and static content, saving bandwidth, and enhancing server response times.

Configuring Varnish Cache can be complex, so consult online guides or professionals before making setting changes.

Varnish Cache

GIF showing how to configure Varnish Cache as your caching application

 

To sum up, making your Magento 2 website run faster is key to giving users a better experience and increasing sales. Keep your Magento updated, choose the right operational mode, and use caching to speed things up. Tools like Google Page Speed Insights and GTmetrix can help you track your site’s performance, and Varnish Cache can give an extra boost. By doing these things, you’ll create a quicker, more efficient online store that both your customers and your business will love.

]]>
https://blogs.perficient.com/2024/09/05/how-to-speed-up-magento-2-website-part-1/feed/ 0 356278