How do you manage several ReactJS projects? - reactjs

Background: My company's web-app is in fact several completely separated apps that have minimal effect on one another. That's why it doesn't make any sense to keep them under a single project - so I'm using separate projects. However, since I started migrating and writing new apps in ReactJS (using Webpack for bundling) I find many opportunities for reuse, in order to avoid code duplication and to avoid downloading common resources again after another app already fetched them:
I'm using specific versions of 3rd party npm modules - so no reason to bundle them over and over again - and no reason to upload them to the server more than once (for all the projects).
How do you share package.json fixed versions across projects?
Do you bundle all/groups of npm modules together or each separately? I want to get everything from the server for cases of on-premise deployment.
What measures to you take to make sure you don't forget to re-bundle the node modules in case you decided to update one of them?
Similar question goes for font files (keeping the font on the server and another font for icons)
common style sheets
common JS code - like utils & common
common web.config configurations
common images (currently some of them are inline in different bundles)
and last - common components - how do you share them? Do you use a separate project and publish to npm? symlink?
Or maybe, after all, I should go with a monorepo? And how?

You could create a separate project, my_modules, which is just a manifest of the shared, common packages. You'd have a package.json with all the common modules, and a single index.js which does something like:
import React, { Component, PropTypes } from 'react';
import moment from 'moment';
export { React, Component, PropTypes, moment };
Then, you'd publish this new my_modules project to github, and install that in your other projects.
import { React, Component, PropTypes } from 'my-modules';
Every time you change a package, you'd increment the version, and then update that version in your projects (which is still a bit of a pain, but you could use something like greenkeeper.io to ensure they don't get stale).
Similarly, you can do the same thing for just about everything else you've mentioned, although you don't want to go overboard with this; you should only share standard assets that doesn't change very often, and keep project-specific assets in their own repo.
EDIT: wanted to add, for React components, this is actually a really good practice, because it forces you to write generalized, independent components. You can use something like React Storybook to create these components in isolation. You can publish one master package with all the packages, individual components as packages, or somewhere in between (eg. all Form components in one package). Either way, though, they can still share a repo for convenience.

Related

How to organize two React projects with shared components?

I have two React projects. They share most of the components (with minor differences in certain props). Also, the Redux they both use will also share a similar data model (95% are the same) and differ in some reducer actions (one have and the other one doesn't).
Their front-end pages/containers consist of components that behave similarly. I'd like to make the common components shared between the two projects and I could pass in different props to let them render differently.
Ideally, the two projects should generate two different artifacts, but it seems better to put them in a single repository. I'm not sure how I should organize my projects.
Lerna should work but would it be too complex for my scenario? Actually, in most cases, the component implementations and handling logic behind are similar.
One solution is to maintain 3 different projects: one for each of the existing projects and a separate "library" with the shared components. You can do either 3 separate git repositories or one repo with each project in its own subdirectory. With 3 separate git repos, you can publish the library project so that you can install it with npm. This can be either to the public NPM registry, if you wish to share your library, or to a private registry.

React - Any way to standardize import paths?

I'm building a website with a bunch of individual components, which I stored in a components folder in my folder architecture, and when I'm setting the routes, I constantly need to type out the whole file path. For example
let mathModules = "./components/MathModules/Programs/";
import MultiplesOf2 from mathModules+"Multiplicity101/MultiplesOf2";
For each module and future modules I constantly have to add ./components/MathModules/Programs/ where the only difference is the latter 2 substrings. The above code obviously doesn't work, but is there a way to achieve a similar effect without importing a "Routing" file that lives closer to the target path.

Micro-Frontends, Web Components, and Sharing Libraries

so I'm working on migrating my company's app to a micro-frontend approach. We are following the standard described in https://micro-frontends.org/. While under the hood everything is currently using React, we are wrapping things with Web Components so that we will have the freedom and flexibility to be framework-agnostic in the future. We've got a working architecture up and running and so far it is working beautifully. We even created a fancy compatibility layer on top of the Web Component spec which allows us to pass React-like props to the Web Components, including Objects, Arrays, and even Functions. This allows for much better interaction between them.
The main concern we have right now is duplication of libraries. We're a React shop, so even though we have this framework agnostic approach, everything is using React. While this new approach gives us the ability to individually upgrade pieces of our app to a newer React version (finally), we still don't like the idea of so much duplication of the React library.
To put it in perspective, even Gzipped, React/ReactDOM are over 40kb. That's super tiny individually, but scaled up it starts to take up more and more bandwidth. RAM-wise it's less of an issue, about 130kb for those libraries, and given the RAM capacity of most devices now it's not a huge deal.
But, of course, we want things to be as optimized and streamlined as possible. So I'm hoping someone can suggest a way for the micro-frontend apps (the ones wrapped in a Web Component) can get React and other libraries from the parent app.
You should know that the parent app JavaScript is loaded prior to the micro-frontends. Each micro-frontend is loaded via a <script> tag. Lastly, we are NOT using the Shadow DOM at the moment, a tradeoff we made to benefit how we are migrating our existing code into the new micro-frontend architecture.
The core idea is to tell module bundler on how to package your micro-frontends.
Assuming you are using Webpack to bundle your applications, here are the two things that you need to do.
Step 1:
Declare React as an External dependency like in your Webpack config:
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
Step 2:
Before you load your parent application's JS, ensure that you are loading React and ReactDOM from CDN or other equivalent place:
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
Put these script in your main index.html which is responsible for bootstrapping your entire SPA.
Explanation
When you declare certain package/library as external, Webpack does not include it as part of the bundle. It assumes that the outer environment will make that particular version available as a global variable. In case of React, it uses React and ReactDOM as global variables.
By doing this and including it via CDN, you will be left with exactly one copy of React and ReactDOM. When a user visits the application for the First time, it will be slower but once cached, it should not be a problem
Further, you can extend this idea and also declare them as external for your parent app or parent shell container.
Possible solution is to prepare library using Import Map but as it does not support IE11+ I recommend you using SystemJS?
https://github.com/systemjs/systemjs
especially this one seems to be close to your case:
https://github.com/systemjs/systemjs-examples/tree/master/loading-code/react-hello-world
At html you do:
<script type="systemjs-importmap">
{
"imports": {
"react": "https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js",
"react-dom": "https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"
}
}
</script>
<script src="https://cdn.jsdelivr.net/npm/systemjs/dist/system.min.js"></script>
Then you could import ReactJS, as browser knows where to take it from.
Potentially there is a possibility to build some kind of library that looks into your micro front end's (MFE's) package.json, to get know which library needs to be in use and dynamically create imports object similar to example above.
We need to keep in mind that there is a need to cover versioning check. Mentioned library could potentially store some kind of map which connects dependency with version with place where it's accessible. Imagine that in case mentioned we need to deal with different react version on each MFE :).
Then while loading another MFE library could check if required dependencies has been already included, if some missing, download it, otherwise use what has been already fetched.
Another thing is use webpack 5, with module federation, which I not recommended yet, as it is not stable enough for production, but there is a possibility to start playing with it. Hard part will be covering version check, so most probably need another abstraction layer to deal with it.
https://indepth.dev/webpack-5-module-federation-a-game-changer-in-javascript-architecture/

dynamically require/import different component modules in React Native depending on build config

I'm working on a React Native project where we will need to build two different flavours of the app, which mostly the same but vary in a few small features. I wanted to see if there was a way to do this through babel somehow, by having different files named similarly for each build and triggering differetn builds by setting and environment variable. This would be similar to the way that React Native does for having custom js files for iOS and Android like this:
my-component.android.js
my-component.ios.js
so my different build flavours would look like this:
my-component.flavourA.js
my-component.flavourB.js
or even
my-component.flavourA.android.js
my-component.flavourB.android.js
my-component.flavourA.ios.js
my-component.flavourB.ios.js
I am trying to find a way of using babel to change the require() function (and import statements) such that the correct files are resolved from a simple require call of:
require('./my-component');
depending on which FLAVOUR environment variable is set. Or:
import * from './my-component';
I have looked at trying to use a combination of babel-plugin-module-resolver, babel-plugin-replace-require and babel-preprocessor but I'm not able to work out if this even possible without writing my own babel plugin.
Is there an easier way of achieving this that I am missing?

Efficiently Managing Types in TypeScript

I've been working on a large TS project for work and absolutely love it. When the project started we stored all of our custom-defined interfaces and types in a single types.ts file, which just exported each of them. That way, we could import only the types we needed in each module (in our case, React components). In this sense, we essentially have a global.d.ts file as defined here with the added benefit of it actually being a module because of the export syntax in types.ts.
Of course, the project has scaled and it's really time to move these definitions elsewhere. My question is how to actually build out separate .d.ts files to do this. Should I have separate .d.ts files for each component (or perhaps component group) and then reference them in a single index.d.ts? Should I just stick with what I have? Other suggestions? Really I'm just looking for advice on how other devs manage type definitions in a scalable, maintainable way. We are using TS 2.4.2 with React, Redux, redux-saga, and webpack.

Resources