-
-
Notifications
You must be signed in to change notification settings - Fork 184
Frontend Development
Leszek Pietrzak edited this page Sep 14, 2021
·
16 revisions
We use multiple different libraries that forces the code to be consistent. Please make sure your code editor has all possible plugins installed!
- we use spaces 🙊
- JSDoc currently we comment everything, but will be dropping it when we move to TypeScript
- editorconfig (our config) - best set it to autofix on file save
- prettier (our config) - as for now please use it only on files you've edited in a great way, or on new files
- eslint (our config)
- stylelint (our config)
- coffeelint (our config)
- we prefer
() => {}
overfunction () {}
for unnamed callback functions (for brevity). - for S(CSS) we follow BEM methodology (use our built in
bem
/makeBem
utility), also:- try avoiding nested class names
- try avoiding the
&
shortcut
We follow Cleanup First™ methodology. It boils down to making a cleanup-only PR before starting any work. A step-by-step guide would be:
- Think about which files your changes will touch.
- Make a PR that includes only cleanup1 changes in those files.
- Make a new branch for the actual changes from the cleanup branch.
- If you end up needing to cleanup more files as you work, make a new cleanup PR.
- If you end up cleaning more files than needed, it's ok.
That way we get less merge conflicts, and less complex PRs to review.
1 by "cleanup" we mean stylistic changes, applying prettier, moving things around, renaming, etc.
Some rules we follow:
- only one React component per file
- generally we prefer smaller files
- when creating new React component:
- you should create all it's files next to it, e.g.:
jsapp/js/components/submissions/table.es6 jsapp/js/components/submissions/table.tests.es6 jsapp/js/components/submissions/table.scss
- import styles file in the component
.es6
file
- you should create all it's files next to it, e.g.:
- group
.es6
files by feature, e.g.library/
,submissions/
- generic/common React components go to
jsapp/js/components/common
directory - don't use relative paths in imports
Some notes first:
- we generate an icons font from
svg
files using webfonts-generator package - the source of the icons is the Sketch file from our Google Drive:
/Kobo Product Design/Design Current/04. Design/Comps Sketch/Icons.sketch
- all the icons need to have the same artboard size (
webfonts-generator
requirement) - after kpi#3305 is done, this will be much simpler 😇
Steps to take when adding new icon:
- Open
Icons.sketch
- Create new artboard
Icons/<icon-name>
, make sure it is exportable (easiest way is to clone an existing one) - Draw the icon or drag&drop existing SVG file, make sure the paths are combined and the color is black (
#000000
) - Export all icons
- Copy new icon from
Icons/<icon-name>.svg
tojsapp/svg-icons
in KPI repository - Run the new
svg
file through ImageOptim.app or some alternative non-destructive SVG compressor - Run
npm run generate-icons
- Use your new icon:
<i className='k-icon k-icon-<icon-name>'/>
We are incrementally migrating our codebase to TypeScript. Here's a bunch of useful (and still very much evolving!) notes:
- When you rename
es6
file, if it's a component, rename it totsx
, else go withts
. - When you encounter an untyped file (e.g. your new
.ts
/.tsx
file has an import that is not TypeScript) there are two approaches:- Preferred: Switch the untyped file to TypeScript (i.e. change the file extension and write types for everything inside).
- Faster: Leave untyped file as is, but create
<file name>.d.ts
file next to it with types definitions.
- Let's define types for all the endpoints responses in
dataInterface.d.ts
for now. Ultimately we would probably move them to their respective files with actions definitions, but this plan is not yet fully developed. - When writing types for a Reflux store, you need to create a class that extends
Reflux.Store
, seeassetStore.ts
as a good example file. - TypeScript has two different kinds of modules: ambient and normal. This is best described with example - imagine I have some
.d.ts
file with type definition - thanks to TypeScript, we can use theAsset
interface in all the places without importing it (this is the ambient module):And now we introduce aninterface Asset { type: string }
enum AssetType
with all possible asset types inconstants.ts
file. We want to use it atAsset
interface fortype
property. We could do this:But if a typescript definition file has any import it stops being "ambient" module and becomes a "normal" one, meaning that we no longer can useimport {AssetType} from 'js/constants' interface Asset { type: AssetType }
Asset
without importing it. This is definitely not nice. But there is a nice override (a dynamic import) that allows importing some type from other file without compromising the ambient status:interface Asset { type: import('js/constants').AssetType }