A.K.A - How to develop/localhost setup :)
Make sure you have node and pnpm installed. Also, read the local workstation setup for being able to access TruckOs's private gitlab registries.
You can install pnpm as follows:
- If on mac with homebrew:
brew install pnpm
- via npm, installing it globally
npm install -g pnpm
Make sure you have system deps required by Playwright
You can install pnpm as follows:
- Run this as a one-time script
npx playwright install-deps
We do lint/etc and have the setup so that style/etc is all automatic. Hence, it is strongly recommended you have plugins installed/enabled that automatically fix style for you so you don't get commit rejects/etc.
- Add vscode extensions:
- ESLint
- Prettier
- MDX
- Color Highlight (optional)
First off, make sure you have all node_modules
installed
pnpm install
Then we have the following:
storybook
: Run Storybook to check componentspnpm run dev
test-storybook
: Start Storybook tests in the background.npx test-storybook --watchAll --coverage
test
: Run all unit tests via jestpnpm run test
test:coverage
: Runs tests with jest and generated test coverage repots. A report is printed tostdout
while other formats (e.g., json, html) are written to acoverage
directorypnpm run test:coverage
test:coverage:ci
: Same astest:coverage
it also passes--ci
flag to Jest, ensures correct snapshot testing behaviour in a CI environment - see docsdev
: launch the app running locally with a dev server and hot module reloadingpnpm run dev
extract-i18n
: Extract phrases for translation. See the section on Internationalisationpnpm run extract-i18n
api-types:gen
: If you change the api files, then run this to regenerate bindings/merge together/etc.pnpm run api-types:gen
tos-cdk:clean:all-local
: If it's your first checkout or properties that are from config have been changed/added, make sure you update them in the environment definitions, and then run this so that the config file for local is regenerated from templates and placed locally in your public dir.pnpm run tos-cdk:clean:all-local
aws:test:get-s3-url
: If you need a valid S3 pre-signed URL for testing, run this command. You'll need a.env
file withYou'll need anpnpm run aws:test:get-s3-url
.env
file that looks as follows (only public information here - get the secret from Fernando or someone else who has it ;).AWS_ACCESS_KEY_ID=AKIA2EJ4VQTM7BGDS6CJ AWS_SECRET_ACCESS_KEY=### ASK FOR THE KEY ##### AWS_S3_BUCKET_NAME=truckos-dev-data-documentsbucket9ec9deb9-1dht08po0ke8p
For the command to extract phrases for translation from the code, look at the development commands section
The command will run the parser to extract any missing phrases from the translation files.
It explicitly looks for the t('xxxxx')
structure in the code. This means that for validation schemas we have a
dummy t
function to wrap the strings so they are picked up. This is because the validation strings are translated
at the point of being displayed on the component rather than via the schema.
Note that the entire translation file is refreshed when this command is run. Existing translations are kept but unused
translations are removed. You can change the i18next-parser.config.js
file to have createOldCatalogs: true
if you
wish to have the old version kept in case of accidental removal (although git commit history should mean this isn't
needed).
- Have a read to the LearnRxJS primer, it's a good one.
- Take a look at React-RxJS - we use it to create react hooks from observables :)
- Observables are postfixed with
$
.- Hence, if you have an observable for a
company
object, it should be namedcompany$
.
- Hence, if you have an observable for a
- Component files and directories are capitalised (e.g. BackButton.tsx)
- Other script files are snake-case (e.g. object-utils.ts)
method 1 | method 2 | difference |
---|---|---|
switchMap |
mergeMap |
They take the same parameters and both return observables, but the switchMap will make sure that if there's any subscriber currently waiting on a result, it will get unsubscribed. That means that subscribers end up only getting the latest result vs. in mergemap where they get all results of all the changes to the observable . |
If you create a subscriber to an observable in a component that can be mounted/unmounted depending on state, you have to make sure that you unsubscribe as well. If you don't, a couple of things happen:
- Even if you unmount the component, the subscriber lives on. That means that if you trigger any actions (like redirecting) based on the subscriber, even if your component is unmounted, the actions will be triggered (imagine being redirected for no apparent from a page you were looking at to a completely different one just because somehow the observable changed).
- When you mount, a new subscriber is created and off we go again. aka: How to create a memory leak ;).
Hence - make sure you do the following:
- Make sure the subscription uses
useRef
(part of react). It allows the value to change but doesn't trigger a re-render (as opposed touseState
which does). - use
useEffect
to unsubscribe on unmounting. You take advantage of the functionality that allows to execute code on mounting and unmounting (read more here)
So putting those two together, the pattern would be something like:
import { useEffect, useRef } from 'react';
import { Subscription } from 'rxjs';
const subscription = useRef<Subscription | undefined>(undefined);
const observable$ = props.obervable; //comes from somewhere.
//...
useEffect(
() => {
//code here runs on mount
subscription.current = observable$.subscribe(onChangesFunction);
return () => {
//Code here runs on unmount
subscription.current?.unsubscribe();
};
},
[
/* it's important that there are no dependencies */
]
);
//...