Search code examples
typescriptrollupjspreact

Why Preact should be in prod dependency in Grid.js?


I've been reviewing some discussions, such as this one, which suggest that React should typically be placed as a prod dependency. However, I'm uncertain if the same consideration applies to Preact.

According to the official Grid.js website, they specifically mention that preact is the only external dependency they use, highlighting the importance of this choice.

In my understanding, if I want to maintain the context relationship of Preact in my package, and if I intend to export various hooks like useEffect, useCallback, useState, and useRef through index.ts, should I still consider Preact as an external dependency? Or is it viable for me to classify Preact solely as a dev dependency, especially given that I utilize Rollup for bundling both UMD and ESM formats, and Preact is included in the generated JS files?

I'm looking for clarity on whether I can, or should, categorize Preact in a certain way for an efficient and reliable setup. Any insights or advice would be greatly appreciated!


Solution

  • To start off with, I'm a Preact maintainer who's worked a lot on build tooling, including the tool that gridjs uses to build (microbundle).

    Dependency management is fairly complex and there's no one right way to do it. Different situations call for different configs and so you have to pick which situations you want to support and work from there.

    Some comments on your links, however:

    • That React post is pretty flawed, as no one specifies whether the project is a lib or an app
      • When working with apps, dependencies vs devDependencies is near entirely irrelevant. The only benefit is if you restrict devDependencies to just optional tools, such as potentially a linter, formatter, etc. so that you can skip installing them on your CI. This, however, is pretty rare as most people have lint steps as part of their CI process, meaning those deps are needed still.
      • Libs, however, are going to vary based on target use, which no one has specified
    • While gridjs lists Preact as a dependency, I'm not sure it should?
      • Only briefly looked through, but it looks to be inlining Preact everywhere; listing it as a dependency is therefore unnecessary.

    If you want to make a package, there's a couple items to think of:

    • Is this meant only for other Preact projects?
      • If so, what you want is to specify Preact as a peerDependency. This allows Preact projects to bring their own copy of Preact that your lib will then use too. Consumers therefore own & can change the Preact version as they need.
    • Is this meant to stand entirely on its own?
      • If so, you could want to inline Preact, which is what gridjs does via the --no external option to Microbundle
      • Keep in mind, however, this locks the Preact version! If there's a bug in Preact that gets fixed, you have to release a new version of your project to get that fix to your users.
    • Is this even allowed to be used in other Preact projects?
      • Hooks, in both React and Preact, are a bit finicky by design. They don't play well with having multiple copies of the lib (React or Preact) active at once. Inlining Preact into your library therefore can break users if they want to use your lib in their Preact apps as your lib adds a copy in addition to the copy they already have for their app.
    • What environments do you want this to work in?
      • CDNs like unpkg.com or esm.sh act differently to NPM. Which behavior you want depends on where you're publishing your library to.
      • For example, NPM installs peer dependencies by default, if you don't have it already available. esm.sh, on the other hand, doesn't know if you have a copy available or not and therefore always sends one. This impact usage quite a bit.

    But, importantly, you can choose some (seemingly) conflicting options. Package exports allow you to define submodules that can be, for example, very different builds of your library. Maybe my-lib/widget is an all-in-one bundle meant for people wanting to embed your lib onto their site, where my-lib is a normal library, meant more for usage via NPM.


    Hopefully this is useful as generic advice. StackOverflow might not be the best place for a lengthy back-and-forth on your specifics & providing examples, so feel free to ping me in the Preact slack if you wanted, else, I can try to respond here as best as I can via comments.