In this blog post, we will learn how to build and deploy a composable React app to Netlify, using Bit.
In Bit, everything is a component. The app is also just a deployable component. This means we can easily compose it with another component - the Netlify Deployer component - to deploy it to Netlify. Just like playing with Lego blocks.
This is the app we will build:
You can see the deployed app here.
If you're feeling a bit tired today, here's a TL;DR of the steps we will take:
Add this snippet to your my-app.react-app.tsx
file:
import type { ReactAppOptions } from '@teambit/react';
import {
Netlify,
NetlifyOptions,
} from '@teambit/cloud-providers.deployers.netlify';
const netlifyConfig: NetlifyOptions = {
accessToken: process.env.NETLIFY_AUTH_TOKEN as string,
productionSiteName: 'your-site-name',
team: 'your-team-name',
};
const netlify = new Netlify(netlifyConfig);
export const MyApp: ReactAppOptions = {
name: 'my-app',
entry: [require.resolve('./my-app.app-root')],
deploy: netlify.deploy.bind(netlify),
};
export default MyApp;
Don't forget to add your Netlify token to your environment variables.
Great job! You've just deployed your React app to Netlify with Bit. Now every time you tag a new version of your app, Bit will automatically deploy it to Netlify.
If you change any of the app dependencies, Bit will also deploy the updated version of the app.
Let's take a closer look at how this works.
Please make sure that the Bit binary is installed on your machine:
npx @teambit/bvm install
You can quickly get up and running with a composable React app by using a Starter. Run the following command:
This command creates a new workspace from the React-app starter. It includes a React App component in addition to some preconfigured React components.
To standardize your development workflow, you can create your own Starters and Component scaffolder.
Your workspace should look like this after running the command:
As you can see you have three components in your workspace. In this blog post, we will focus on the app
component.
Here are some useful commands to get you started:
The latter command opens the workspace UI in a new browser window. It's useful for writing documentation, tests, etc., for the component.
It's time to deploy the app! To accomplish this, we will use the Netlify Deployer component. It is designed to plug into the deploy task that is part of the tag pipeline and deploy the app to Netlify.
When you run the bit tag
command, a series of tasks are executed.
To see all the tasks that are executed when you run the bit tag
command, run the following command:
Here's the output:
Build Pipeline Tasks:
teambit.harmony/aspect:CoreExporter
teambit.compilation/compiler:BabelCompiler
teambit.compilation/compiler:TSCompiler
teambit.defender/tester:TestComponents
teambit.pkg/pkg:PreparePackages
teambit.harmony/application:build_application
teambit.preview/preview:GenerateEnvTemplate
teambit.preview/preview:GeneratePreview
Tag Pipeline Tasks:
teambit.pkg/pkg:PackComponents
teambit.pkg/pkg:PublishComponents
teambit.harmony/application:deploy_application
Snap Pipeline Tasks:
teambit.pkg/pkg:PackComponents
teambit.harmony/application:deploy_application
We won't dig into the details of each task, but we'll focus on the deploy_application
one. The app will be deployed by this task. It doesn't matter if the app is a React app or a Node app.
In our case, we are deploying a React app to Netlify. Hence, we will use Netlify Deployer. Let's install it in our workspace:
Now we can add it to the deploy task slot. In the my-app.react-app.ts
file add the following:
You will have to add your Netlify access token to the `NETLIFY_AUTH_TOKEN` environment variable. Learn more about it here.
import type { ReactAppOptions } from '@teambit/react';
import {
Netlify,
NetlifyOptions,
} from '@teambit/cloud-providers.deployers.netlify';
const netlifyConfig: NetlifyOptions = {
accessToken: process.env.NETLIFY_AUTH_TOKEN as string,
productionSiteName: 'your-site-name',
stagingSiteName: 'your-site-name-staging',
team: 'your-team-name',
};
const netlify = new Netlify(netlifyConfig);
export const MyApp: ReactAppOptions = {
name: 'my-app',
entry: [require.resolve('./my-app.app-root')],
deploy: netlify.deploy.bind(netlify),
};
export default MyApp;
As you can see in the above code snippet, we are defining two site names. A production one and a staging one. When you lock your component to a release version (e.g. 1.0.0), the production site name will be used, whereas the staging site name will be used for snaps with no release version (hashes).
Now all we have to do is to run the bit tag
command to deploy the app to Netlify:
Since all components in the workspace are new, Bit will tag them all and deploy the app to Netlify. Here is the terminal output:
new components
(first version for components)
> apps/my-app@0.0.1
> pages/home@0.0.1
> themes/theme@0.0.1
If you look closely at the output, you will see that the deploy_application
task was executed. This is the task that deploys the app to Netlify:
✔ env "teambit.harmony/aspect", task "teambit.harmony/application:deploy_application" has completed successfully in 8s
Now that we have deployed the app, let's export them to the remote scope:
Because we built our app based on component-based software engineering (CBSE) principles, each part of the app functions independently and can be exported to a remote scope, imported into a different workspace, and used in another app as a dependency
Let's say we want to modify the home page. we'll make a simple change in the home.tsx
file:
- <Paragraph className={styles.texts}>Understanding Bit's Commands</Paragraph>
+ <Paragraph className={styles.texts}>Understanding Bits' Commands</Paragraph>
It would be expected that only the pages/home
component would be versioned if we tagged again. However, this is not the case. All home page dependents (in this case only the app) will be tagged in the workspace, and the app will be deployed again. The reason is that Bit tracks the dependency graph, and knows which components are impacted.
Here's the output:
changed components
(components that got a version bump)
> pages/home@0.0.2
auto-tagged dependents:
apps/my-app@0.0.2
The app was automatically tagged, which is exactly what we wanted. When we make changes, only the affected components will be tagged and deployed. As a result, we can save a lot of time and resources.
Don't forget to export the second version of the apps/my-app
and pages/home
components to the remote scope:
Here's a sneak peek at a new product released on bit.cloud later this year called Ripple CI - the first component-driven continuous integration tool.
With Ripple, you only build components, not projects. When you update a component, Ripple will run for that component and every dependent component impacted by the change, across your entire system and apps.
As a result, your builds run much faster. They propagate to every impacted product and simulate the change. In addition, they will save tons of time by isolating failures and errors, so you don't have to run everything again. It's still in beta for now :)
In the picture above from Ripple-CI, you can see changes were made to the use-change-request
hook. Consequently, only dependent components are rebuilt and versioned until the app component is deployed (if all tests and builds pass).
We learned how to deploy a React app to Netlify using Bit in this blog post. Additionally, we learned how to keep the app up-to-date by only tagging the affected components.
Everything becomes easier when you build apps in a distributed (component-driven) manner. Components can be built, tested, and deployed independently. After that, you compose them together to build more apps and features, just like you would with Lego blocks.
Changing the deployer component would allow us to change the service provider anytime. The deployment pipeline could also be expanded with more deployers. It's as simple as adding a new component to the pipeline, for example, the Cloudflare Deployer.
There is still a lot to learn about component-based software engineering. Please visit the Documentation for more information. Feel free to join the community Slack channel if you have any questions.
This blog post component has been updated to reflect the latest changes I made to the Netlify deployer component. Before I wrote this blog post, we had only one site name.
I have now implemented the option to have two site names, one for production and one for staging. When you lock your component to a release version (e.g. 1.0.0), the production site name will be used, whereas the staging site name will be used for snaps with no release version (hashes).
As a result, every app with the Netlify deployer component as a dependency (such as The Bit Blog you are currently reading) will have the same, updated, deployment pipeline. An excellent example of how Bit can help you build a component-based software engineering system.