Pyrene is a monorepo made of different subprojects.
The subprojects are:
Pyrene
React UI components.Pyrene-graphs
React UI components.Tuktuktwo
React UI components (svg) used byPyrene-graphs
.Kitchensink
web application which demonstrates the components of thePyrene
andPyrene-graphs
subprojects.
The items 1.
, 2.
, 3
. are separated npm modules.
The item 4.
, is not a library but an application. Thus, this subproject is not meant to be reused.
Pyrene
subproject on npmjs.
Pyrene-graphs
subproject on npmjs.
Tuktuktwo
subproject on npmjs.
Kitchensink
subproject on GitHub Pages.
-
The requirements for using the
Pyrene
,Pyrene-graphs
andTuktuktwo
subprojects are set as apeerDepenencies
in their ownpackage.json
, each. -
nodejs 12.
npm install @osag/pyrene
.- Import
Pyrene
subproject's style at the entry point of your application:
import '@osag/pyrene/dist/pyrene.css';
npm install @osag/pyrene-graphs
.- Import
Pyrene-graphs
subproject's style at the entry point of your application:
import '@osag/pyrene-graphs/dist/pyrene-graphs.css';
npm install @osag/tuktuktwo
.
The npm dependencies at the root of the monorepo are for Storybook only. Indeed, the npm dependencies related to Storybook are shared among the various subprojects.
Otherwise, each subproject handles its dependencies on its own. See this here, why the current architecture might need some improvements.
The Pyrene TypeScript source code is compiled down to JavaScript with Babel. We do not use tsc
(TypeScript compiler).
The process of transpilation is hand over to webpack. In the webpack configuration, you can see that the webpack loader babel-loader
is responsible for that process.
The reason why we compile the TypeScript code through Babel, is that we need to access the parser during the compilation process for converting the typing of props' component done in TypeScript into a PropTypes
object in JavaScript. See here, why we do so.
This is a fair question given that Pyrene compiles TypeScript down to JavaScript with Babel and not with tsc
(TypeScript compiler). Babel does only compile and does not do any any type-checking. You have thereby the answer to your question.
- As mentioned here, TypeScript is compiled by Babel. The problem is that the Babel plugin we are using, does not support TypeScript syntax properly, for example, we cannot do type extension like this:
type MyButtonBase = {
label: string,
onClick: () => void,
}
type MyButtonProps = MyButtonBase & {
lodading: boolean,
}
const MyButton: React.FC<MyButtonProps> = (props) => (
<div>
<button>...</button>
</div>
);
- The proper way of using TypeScript generics in React is the following:
const Card: React.FC<CardProps> = ({
title,
content,
}) => (
<div>...</div>
);
However, in order to have the Babel plugin properly working, we cannot use TypeScript generics the proper way - see the type duplication -:
const Card: React.FC<CardProps> = ({
title,
content,
}: CardProps) => (
<div>...</div>
);
Some components in the Pyrene
subproject are not standalone components (Textfield
, Checkbox
, etc.).
These input components can by used only when the parent is passing a state
and a state setter
as props to them.
For demonstrating those components with Kitchensink
, you have to provide a StateProvider
in the example file for Kitchensink
to re-render the component.
For demonstrating those components with Storybook, you can use the useState
in the story - see this resource - for the component to re-render.
Kitchensink
is a React application.
Kitchensink
's goal is to demonstrate how do the components work and how to use them. On that purpose, Kitchensink
uses Pyrene
and Pyrene-graphs
subprojects as npm dependencies. See on that regard the kitchensink/package.json
.
Firstly, Kichensink extracts all Pyrene comoponents out of the Pyrene bundle.
Secondly, Kitchensink
analyses the PropTypes
object of each Pyrene component. Based on that object, Kitchensink
generates the documentation for each component, means the props
, the type
of these props, if those are required
or not, etc. This PropTypes
object is generated by a Babel plugin, called babel-plugin-typescript-to-proptypes
. Indeed, the bundle that Kichensink takes as an input does not contain any typing any more.
The instance of the component embedded in Kitchensink is controlled by example
file of each component.
The migration to Storybook is still ongoing. The reasons for migrating from Kitchensink
to Storybook were the following:
- In the
Pyrene
,Pyrene-grpahs
andTuktuktwo
subprojects, the components cannot be properly written in TypeScript, see Hacks. - Storybook does a better job.
PropTypes
is originally intended for run time type-checking. See here whyPropTypes
is currently misused.
For running Storybook. At the root of the monorepo:
> npm install
> npm run storybook
Browse http://localhost:6006
CI is managed by GitHub Actions, by the following files:
.github/workflows/lint.yml
.github/workflows/test.yml
Those two actions are automatically triggered upon a commit or a PR merge on all subprojects.
Since Pyrene
, Pyrene-graphs
and Tuktuktwo
subprojects are separated npm modules, releases are done separately per project.
Go into the subproject you'd like to release:
> npm run release
A new release automatically trigers a Kitchensink CD, see here.
CD for Kitchensink
means build and deploy of Kitchensink
.
This is managed by GitHub Actions, by the following file:
.github/workflows/kitchensink.yml
That action is automatically triggered upon a Pyrene release. It is also possible to manually trigger it in GitHub website, under Actions, Workflows, select Kitchensink
. Click on the Run workflow
button. You can as well do it by running the following commands:
> git push github main
> git push github --tags
Please, refer to the guideline for setting up a development environment with Pyrene.
If you create a new component in the Pyrene
, Pyrene-graphs
or Tuktuktwo
subproject, you need to import it in the index file.
If you add a third party library, you need to load the CSS of that library, with the css-loader
in the webpack configuration.
- Replace
Kitchensink
by Storybook (ongoing). - Remove the hacks done for
Kitchensink
to work properly. - PropTypes generation for each component is not pertinent in a production environment. This
PropTypes
are generated for documentation purpose only inKitchensink
. The original purpose ofPropTypes
, which is run time type-checking, is misused, since the type-checking is covered already by TypeScript. - Do the compilation with
tsc
(TypeScript compiler) and not Babel. - Design a better architecture, sharing common npm dependencies across all subprojects with Lerna. Right now, same npm dependencies are all over the place.
- Add snapshot testing for mitigating regression.
- All components could have a
className
props for overriding style. - Pyrene bundle should be split up by component. Indeed, the users of Pyrene will have the entire Pyrene source in their app's bundle even if they are using just a few of the available Pyrene components.
- Do not change a component's internal state from the parent by using React
ref
, example here.
Document created on the 22th December 2021