What are the benefits of adding configs to package.json? - reactjs

I have always placed different "tooling configurations" in their own files in my front-end projects.
For example: babel in babel.config.js, jest in jest.config.js, eslint in an .eslintrc.json, etc.
I have noticed recently however that it is possible to place many of these configurations directly in a projects package.json file instead.
I did some digging around online and asked a few colleagues but no-one can seem to give me a definitive answer as to why one might prefer one approach over the other.
Is it purely a matter of preference?

My suggestion is to avoid stuffing package.json with custom configs mainly for two reasons.
First is regarding developer expectations. Putting yourself in the position of a person that is just getting off with JavaScript and NPM ecosystem, you see something that's not documented, at least not where you expect it to be. This kind of experience could easily drive folks away especially if they come from more strict developer platforms and languages.
Second, keyword collision or more importantly the thought of such being possible. We don't expect NPM to consider not using some keyword in the future just because some shiny new lib is using it too, do we?
On the other hand having dedicated files for babel, browserlist, postcss is such more simple, self-explanatory approach and every single of those projects already recommends using dedicated files for configurations.

Here are the Pros and Cons of package.json configs IMO:
Pro package.json becomes a single source of truth for your apps packages, scripts, and, now, configs. It's a one-stop for everything related to your app.
Pro It declutters your root directory. Having a separate config file floating around for all your different packages gets messy.
Con Keyword collision possibility. If Node comes out with a new keyword that happens to match that of an existing package config, then you have to either not use the keyword or move the config to a separate file.
Con Most package documentation references the separate config file in their examples. It could be confusing for troubleshooting or new team members.
Con Your package.json file could get HUGE. And if many configs are managed, the potential for a merge conflict with another team member increases greatly.
Overall it comes down to personal preference. There are some tools like husky (https://github.com/typicode/husky) that put config in package.json by default. Our team does a combination of both.

I think there is no benefit you will make the package.json file more complicated and there is no reason for that if you make separate files you make declarative and people understand the project better

Related

Is more granular versioning in a monorepo with a container possible?

My team has a monorepo written with React, built with Webpack, and managed with Lerna.
Currently, our monorepo contains a package for each screen in the app, plus a "container" package that is basically a router that lazily serves each screen. The container package has all the screens' packages as dependencies.
The problem we keep running into is that, by Lerna's convention, that container package always contains the latest version of each screen. However, we aren't always ready to take the latest version of each screen to production.
I think we need more granular control over the versions of each screen/dependency.
What would be a better way to handle this? Module Federation? peerDependencies? Are there other alternatives?
I don't know if this is right for your use case as you may need to stick with a monorepo for some reason, but we have a similar situation where our frontend needs to pull in different screens from different custom packages. The way we handle this is by structuring each screen or set of screens as its own npm package in its own directory (this can be as simple as just creating a corresponding package.json), publishing it to its own private Git repository, and then installing it in the container package via npm as you would any other module (you will need to create a Git token or set up SSH access if you use a private repo).
The added benefit of this is that you can use Git release tags to mark commits with versions (we wrote our own utility that manages this process for us automatically using Git hooks to make this easier), and then you can use the same semver ranges that you would with a regular npm package to control which version you install.
For example, one of your dependencies in your container package.json could look something like this: "my-package": "git+ssh://git#github.<company>.com:<org or user>/<repo>#semver:^1.0.0 and on the GitHub side, you would mark your commit with the tag v1.0.0. Now just import your components and render as needed
However, we aren't always ready to take the latest version of each screen to production.
If this is a situation that occurs very often, then maybe a monorepo is not the best way to structure the project code? A monorepo is ideal to accommodate the opposite case, where you want to be sure that everything integrates together before merging.
This is often the fastest way to develop, as you don't end up pushing an indeterminate amount of integration work into the future. If you (or someone else) have to come back to it later you'll lose time context switching. Getting it out of the way is more efficient and a monorepo makes that as easy as it can be.
If you need to support older versions of code for some time because it's depended on by code you can't change (yet), you can sometimes just store multiple versions on your main branch. React is a great example, take a look at all the .new.js and .old.js files:
https://github.com/facebook/react/tree/e099e1dc0eeaef7ef1cb2b6430533b2e962f80a9/packages/react-reconciler/src Current last commit on main
Sure, it creates some "duplication", but if you need to have both versions working and maintained for the foreseeable future, it's much easier if they're both there all the time. Everybody gets to pull it, nobody can miss it because they didn't check out some tag/branch.
You shouldn't overdo this either, of course. Ideally it's a temporary measure you can remove once no code depends on the old version anymore.

Setting up development environment

I'm a recent CS grad working for a start-up. I've been tasked with adding new features to some software they bought. I've downloaded the software from AWS and have begun trying to get started but I'm having trouble with the front-end, which is built with React and bundled by Webpack.
The download left me with an old version of the front-end and minified files of the new version. I was able to use their source maps to unpack them and get the unbundled files but now I can't figure out how to rebuild it.
The old version is set up to have its dependencies installed and minified by npm. I would like to set up something similar with the new version. I've been able to add all its dependencies to the package.json file but I keep running into errors, mostly stemming from versioning conflicts. What should I do in this situation? Am I just going about this the wrong way?
Software might be a vague term to describe what you have in your hands.
It seems from your wording that you have the source code of an older version, but the production build (bundle.js, main.chunk.js, etc) of some newer version, for which you don't have (or potentially own) the source code.
React is very complex itself, it was probably built using Create React App, dealing with the bundled and ejected files is probably worse, and adding the new features without the source code sounds like a nightmare for a CS grad at a startup. This might even potentially be illegal.

Does it make sense to eject a project from create react app and "take back control"

Create react app is an awesome way to setup a new react project. However i can see it forces certain decisions onto you that come baked in, eg using Jest rather than other test runners such as karma/mocha. As I am setting up a new greenfield project with React, am trying to identify is the best practise to stay with it and accept certain constraints or do most teams end up ejecting and in the parlance of brexit "take back control" and what the reasoning is.
create-react-app actually has a lot of sensible defaults and make it an ideal starting point. But they also regularly update things to stay in sync with where the industry is going. So that's great. And it is maintained by some of the same people responsible for React.
The biggest drawback (and strength) is that it doesn't include many other libraries. You have to add those yourself.
But if you do that you occasionally find that you need to add or tweak a small thing in the Babel/Webpack config.
Luckily there is a middle group. Using libraries like react-app-rewired (https://github.com/timarney/react-app-rewired) allows you to make small changes to the Webpack config without ejecting just yet.
Once you do that you will want to be very careful with upgrading react-scripts. Because every time you do it might break your Webpack changes to their script.
But only once that pain is too much would I consider ejecting.

What is the general practice for express and react based application. Keeping the server and client code in same or different projects/folders?

I am from a microsoft background where I always used to keep server and client applications in separate projects.
Now I am writing a client-server application with express as back-end and react js as front-end. Since i am totally a newbie to these two tools, I would like to know..
what is the general practice?:
keeping the express(server) code base and react(client) code base as separate projects? or keeping the server and client code bases together in the same project? I could not think of any pros & cons of either of these approaches.
Your valuable recommendations are welcome!.
PS: please do not mark this question as opinionated.. i believe have a valid reason to ask for recommendations.
I would prefer keeping the server and client as separate projects because that way we can easily manage their dependencies, dev dependencies and unit tests files.
Also if in case we need to move to a different framework for front end at later point we can do that without disturbing the server.
In my opinion, it's probably best to have separate projects here. But you made me think a little about the "why" for something that seems obvious at first glance, but maybe is not.
My expectation is that a project should be mostly organized one-to-one on building a single type of target, whether that be a website, a mobile app, a backend service. Projects are usually an expression of all the dependencies needed to build or otherwise output one functioning, standalone software component. Build and testing tools in the software development ecosystem are organized around this convention, as are industry expectations.
Even if you could make the argument that there are advantages to monolithic projects that generate multiple software components, you are going against people's expectations and that creates the need for more learning and communication. So all things being equal, it's better to go with a more popular choice.
Other common disadvantages of monolithic projects:
greater tendency for design to become tightly coupled and brittle
longer build times (if using one "build everything" script)
takes longer to figure out what the heck all this code in the project is!
It's also quite possible to make macro-projects that work with multiple sub-projects, and in a way have the benefits of both approaches. This is basically just some kind of build script that grabs the output of sub-project builds and does something useful with them in a combination, e.g. deploy to a server environment, run automated tests.
Finally, all devs should be equipped with tools that let them hop between discreet projects easily. If there are pains to doing this, it's best to solve them without resorting to a monolothic project structure.
Some examples of practices that help with developing React/Node-based software that relies on multiple projects:
The IDE easily supports editing multiple projects. And not in some cumbersome "one project loaded at a time" way.
Projects are deployed to a repository that can be easily used by npm or yarn to load in software components as dependencies.
Use "npm link" to work with editable local versions of sub-projects all at once. More generally, don't require a full publish and deploy action to have access to sub-projects you are developing along with your main React-based project.
Use automated build systems like Jenkins to handle macro tasks like building projects together, deploying, or running automated tests.
Use versioning scrupulously in package.json. Let each software component have it's own version# and follow the semver convention which indicates when changes may break compatibility.
If you have a single team (developer) working on front and back end software, then set the dependency versions in package.json to always get the latest versions of sub-projects (packages).
If you have separate teams working on front and backend software, you may want to relax the dependency version to be major version#s only with semver range in package.json. (Basically, you want some protection from breaking changes.)

How to Organize related applications into git repo's?

What is the decision tree to know when to split a suite of related and/or cohesive applications into git repo's and/or branches? Should I keep each app in a repo? Or all app's & dependencies in a single repo? Or something in-between?
answer How should I organize multiple related applications using git? claims that a repository per project is appropriate, but does not give clues as to what a project would be.
And then there's the question of dev, test, integration test, and production checkouts when the git repo's are split. Answer how do you organize your programming work lists some branch/tag options, but ignores the multi-app details.
There's also the DB schema! incremental definition of the schema helps, but again, where would one keep this definition if the DB spans back-end and front-end app's?
Some examples I've been pondering:
a front-end web app and it's back-end CGI/DB: one repo or two?
a set of web back-ends that use features from other back-ends
a set of front-end app's that share CSS and jquery plug-ins
selenium scripts that test front-end features across dependent code - in the front-end app repo or the dependent code repo?
If I want to work on a single app, it's hard (well, tedious and error prone) to check out a directory of a repo, so I have to check out the entire git tree (or at least clone the whole tree), so that implies that git is not really built for keeping all the app's & dependencies in a single tree.
But if I want to keep each of the projects (app's, frameworks, dependencies, doc trees, CSS) in it's own repo, then I run into chasing my tail for dependency resolution, that is, I don't know which version of each app are compatible. I think git tags are a good way to go, if only I could move them to newer versions that maintain compatibility.
When app's split or merge -- as happens often with refactoring models down to baser models -- can i move the git history of just those files to another git? I don't see how to do this, so that leans towards a single repo for it all.
If I develop a new feature across app's, it would be nice for branches to represent features.
I think I want a repo of repo's -- does that exist?
This is about using a component approach: a component being a coherent set of files which have their own history (own set of branches, tags and merges).
It should include only what cannot be generated (although the db schema can sometime be added to the repo, as seen in "What is the right approach to deal with Rails db/schema.rb file in GIT?". You still can generate it though, as shown in "What is the preferred way to manage schema.rb in git?", to avoid needless conflicts)
A component can evolve without another one having to evolve. See "Structuring related components in git".
That is the main criteria which allows you to answer: "X and Y: one or two repos?".
You can split a repo into two later, but be aware that will change their history: other contributor will need to reset their own repo to that new history.
You can group those different components repos in one with submodules, as explained here (that is the "repo of repos", or, if you want to have only one repo, in subtree, as illustrated here.

Resources