ยท 7 min

Metflix

Metflix is a website inspired by Netflix built with Astro, TypeScript, and Tailwind CSS. It explores how to implement custom reactivity, load content dynamically with IntersectionObserver, and handle dynamic events with MutationObserver.

Metflix

A few months ago, I decided to build Metflix, a project inspired by the Netflix streaming platform, with the goal of learning advanced frontend development concepts without using reactive frameworks like React or Vue. The result was a modern, fast, and smooth user experience site, even without using a full framework.

Why this project?

I wanted to see how far I could go without relying on external libraries. Instead of using tools like Zustand, Pinia or Redux, I wanted to implement my own reactive state system signal. I also wanted to reinforce my skills with IntersectionObserver to load content efficiently. Finally, I wanted to explore how to handle dynamic events when new elements are inserted into the DOM to re-load the addEventListener efficiently for each new inserted card, which I did with MutationObserver.

The result was a modern, fast, and smooth user experience site, even without using a full framework.

Technologies used

๐Ÿ“ฆ Project architecture

Metflix has a simple but very modular architecture:

  • A main page with multiple movie carousels.
  • A detail page for each selected movie.
  • Each carousel loads data through an API The Movie Database.
  • As the user reaches the end of the carousel, more results are automatically loaded.
  • Clicking on a movie updates the visual Hero with details and the movie trailer.

๐Ÿ”„ Customized reactive system with signal.

One of the interesting parts of the project was to implement a status system similar to signals in Preact or SolidJS.

/src/utils/signal.ts
type SignalSubscriber<T> = (value: T) => void;
 
function signal<T>(initialValue: T) {
  let value = initialValue;
  const subscribers = new Set<SignalSubscriber<T>>();
 
  const notify = () => {
    subscribers.forEach((sub) => sub(value));
  };
 
  const signal = {
    get value() {
      return value;
    },
    set value(newValue: T) {
      if (newValue !== value) {
        value = newValue;
        notify();
      }
    },
    subscribe(cb: SignalSubscriber<T>) {
      subscribers.add(cb);
      return () => {
        subscribers.delete(cb);
      };
    },
  };
 
  return signal;
}

This system allows you to automatically update the interface every time the state changes, without the need to use reactive frameworks.

๐Ÿ” Infinite loading with IntersectionObserver

To simulate an infinite scroll, IntersectionObserver was used to observe an invisible element at the end of each carousel with the purpose of loading new movies just before the user reaches the end, providing a smooth experience.

IntersectionObserver

๐Ÿง  DOM observation with MutationObserver

One of the problems of the project was detecting when new movie cards were inserted inside each carousel, so that the click event could be assigned to them. This is where MutationObserver is introduced:

With this technique:

  • I check new insertions of a DOM element to apply listeners cleanly and surgically.
  • I apply listeners cleanly
  • I avoid duplicates by using removeEventListener before adding a new one.

๐Ÿ’ก Lessons learned

  1. You don't always need a framework - It is possible to create small reactive systems from scratch without relying on reactive libraries, but it has its own maintenance cost and complexity to consider when scaling.
  2. IntersectionObserver is key to improving performance and user experience.
  3. MutationObserver is a powerful tool, although little used, it is usually ideal for dynamic scenarios as in this project.
  4. The creation of an image caching system helped me to identify that not loading images dynamically with JavaScript will again have a redundant HTTP request despite having been previously loaded, so saving the information of the previously loaded images helps to avoid redundant HTTP requests and optimizes the user experience with slow connections and saving megabytes of internet data.

๐Ÿ“ Conclusion

Metflix is a movie site, but it is also a practical example of learning how to build modern, reactive applications without relying on full frameworks.

If you want to start understanding how concepts like signals, IntersectionObserver or MutationObserver work, this project can help you as an excellent starting point.