This monorepo contains the web projects for Filecoin Foundation and Filecoin Foundation for the Decentralized Web. It is managed using Turborepo.
This codebase includes multiple workspaces for applications and internal packages. Applications are deployed projects while packages centralize shared code used across applications.
You can find the applications in the apps
directory, which include:
- ff-site: The Filecoin Foundation website, live at fil.org
- ffdweb-site: The Filecoin Foundation for the Decentralized Web website, live at ffdweb.org
- uxit: The public dashboard of the Filecoin Foundation User Experience Improvement Team, live at uxit.fil.org
You can find the packages in the packages
directory. These packages include components, hooks, types, utility functions and configuration shared across the applications.
Note
They are just-in-time packages, meaning they are built by the application that uses them. They do not produce a compiled JavaScript output and are not published anywhere.
To get started, clone the repository:
git clone https://github.com/FilecoinFoundationWeb/filecoin-foundation.git
cd filecoin-foundation
Then, install the dependencies:
npm install
At this point you should be able to run the development server for any of the applications.
Note
We use npx turbo <commands>
instead of relying on npm scripts or globally installed Turbo. This ensures the correct version defined in the project is used and avoids script indirection.
Running npx turbo dev
from the root of the monorepo will call the dev
script for all applications and packages in the monorepo, as defined in each package.json
. In our case, this will start the development server for all applications in our monorepo, packages do not have a dev
script.
In 99% of cases, you only want to start the development server for one application at a time. To do so, you should run npx turbo dev
with a filter flag.
For instance, to start the development server of the ffdweb-site
application, run:
npx turbo dev --filter=ffdweb-site
You can also use the shorthand syntax:
npx turbo ffdweb-site#dev
Important
When using npm commands, such as npm install
, the --workspace
flag refers to the path of the application or package workspace, relative to the root of the monorepo. When using turbo commands, such as turbo dev
, the --filter
flag refers to the name of the application or package, as defined in each workspace package.json
.
The npm install <dependency>
command will install dependencies for all applications and packages in the monorepo. Generally, you want to add a dependency inside a specific application or package. To do so, run:
npm install <dependency> --workspace=<application/package>
Important
The install commands should be run from the root of the monorepo. Do not install dependencies inside the application or package directory, otherwise Turborepo will not be aware of it and will not resolve the dependencies properly.
For example, to add jest
to the ff-site
application, run:
npm install jest --workspace 'apps/ff-site'
Or the shorthand syntax:
npm i jest -w 'apps/ff-site'
This will update both the apps/ff-site/package.json
and the root package-lock.json
file.
We also use syncpack to check and fix version mismatch across the monorepo with the following commands:
npm run check:versions
npm run fix:versions
npm run check:versions
is already set as a pre-push hook with husky, so it runs automatically before every push. npm run fix:versions
should be run manually when necessary, usually after adding/updating a dependency or reviewing Dependabot PRs.
Packages in the monorepo can be viewed as private npm dependencies. To add a package, create a directory in the packages
directory and add a package.json
file. The name of the package should start with @filecoin-foundation/
.
Then, create a src
directory in the package directory and add your source files. The local package.json
should export some or all of the source files:
"exports": {
"./Button": "./src/Button.tsx",
}
packages/ui/package.json
Finally, to use the newly-created package in an application, add it as a dependency manually in the application's package.json
file and run npm install
from the root of the monorepo.
For instance, to use the @filecoin-foundation/ui
package in the ff-site
application, add the following line to the dependencies
section of the apps/ff-site/package.json
file:
"dependencies": {
"@filecoin-foundation/ui": "0.0.0",
}
apps/ff-site/package.json
Tip
As noted above, internal packages use just-in-time compilation. They don’t include a build step — the consuming application compiles them directly.
For more information, read the Anatomy of a package section of the Turborepo docs.
Similar to the development command, running npx turbo build
from the root of the monorepo will call the build
script for all applications and packages in the monorepo, as defined in each package.json
. In our case, this will build all applications in our monorepo, packages do not have a build
script.
To build a specific application, the ffdweb-site
one for example, you can use the filter flag:
npx turbo build --filter=ffdweb-site
or the shorthand syntax:
npx turbo ffdweb-site#build
Once the build is complete, you might want to start the production server by running npx turbo start --filter=ffdweb-site
or npx turbo ffdweb-site#start
.
We use Turborepo’s remote caching feature to speed up local development. This lets everyone share and access the same build cache on Vercel and speed up development.
To opt in, run npx turbo login
to authenticate with Vercel and npx turbo link
to link your local repo to the Vercel cache. You will need to be added to our Vercel organization to be able to do so.
Once the project is successfully linked, you should see Remote caching enabled
in the logs the next time you run npx turbo dev
or npx turbo build
locally.
To maintain the quality and consistency of our codebase, we have established a set of development guidelines. Contributors are encouraged to follow these practices when making contributions to the project. These guidelines apply to all apps
in the monorepo.
Reusable React components should be stored in the general _components
directory. Page-specific components should live closer to the page they are used on.
Use named exports for React components to maintain consistency and support efficient tree shaking. This practice facilitates easier and more predictable imports across the project.
When defining props for components, explicitly name the props type rather than using a generic Props
type. For example,
type BadgeProps = {
featured: boolean
children?: string
}
-
Centralized Paths: Utilize the
PATHS
object for defining and accessing paths throughout the application. See_constants/paths.ts
-
Site Metadata and URLs: Reference site metadata and URLs using centralized constants to ensure consistency and ease of maintenance. See
_constants/siteMetadata.ts
When adding a new page to the project, please ensure the following:
-
Update PATHS Configuration: Ensure the
PATHS
object includes configurations for new content types, specifying paths, labels, and content directory paths. See_constants/paths.ts
-
Metadata and SEO: Each new page should have associated metadata and SEO tags defined. Use the
createMetadata
function to set up a page's metadata correctly. Example:export const metadata = createMetadata(seo, PATHS.ABOUT.path)
-
Structured Data: Include structured data for the new page to enhance search engine visibility and accessibility. Use the
generateWebPageStructuredData
function to create structured data for the page, which provides the base structured data. Example:const aboutPageBaseData = generateWebPageStructuredData({ title: seo.title, description: seo.description, path: PATHS.ABOUT.path, })
This can be further customized based on the page's content and structure. Example:
const aboutPageStructuredData: WithContext<WebPage> = { ...aboutPageBaseData, about: { '@type': 'Organization', name: ORGANIZATION_NAME, contactPoint: [ { '@type': 'ContactPoint', contactType: FILECOIN_FOUNDATION_URLS.email.label, email: FILECOIN_FOUNDATION_URLS.email.href, }, { '@type': 'ContactPoint', contactType: FILECOIN_FOUNDATION_URLS.grants.email.label, email: FILECOIN_FOUNDATION_URLS.grants.email.href, }, ], }, sameAs: Object.values(FILECOIN_FOUNDATION_URLS.social).map( (link) => link.href ), }
-
Testing: Ensure that tests are added to verify the presence of metadata and structured data on the new page. These tests are crucial for maintaining the integrity of the site's SEO and ensuring that all pages meet our standards for content visibility.
-
Updating the Sitemap: When adding new dynamic content (such as blog posts, ecosystem projects, or events) that isn't automatically included in the sitemap through static routing, it's essential to manually update the sitemap with the new page's details. This step is crucial for SEO, helping ensure that search engines can easily discover and index these new pages.
Following these guidelines helps ensure that our website remains consistent, accessible, and search engine friendly.