islandsbanki.is

A starter kit from Ueno. Based on react-universally

Usage no npm install needed!

<script type="module">
  import islandsbankiIs from 'https://cdn.skypack.dev/islandsbanki.is';
</script>

README

Getting started

This project depends on components from @islandsbanki/ui-kit. You will need to clone that project and symlink it into this project to update the components. Here are instructions for doing so:

  • Make sure you can access the ui-kit NPM package (NPM authentication)
  • Run yarn link in these folders
    • ./node_modules/react
    • ./node_modules/react-dom
    • ./node_modules/react-router
    • ./node_modules/react-router-dom
  • In the root of ui-kit run yarn link-to-isb-web to connect the above modules to ui-kit.
  • In the root of ui-kit run yarn link
  • Build the ui-kit files and watch for changes by running yarn dev
  • In the root of this project run yarn link @islandsbanki/ui-kit

You can edit ui-kit files and have the changes reflected in this project.

Updating ui-kit

When a pull request on ui-kit is accepted a new version should be published to NPM. Strict semVer should be followed to not break other projects that might depend on ui-kit.

NPM Authentication

NOTE: You will need to access the islandsbanki organisation on NPM to continue. Ask your project lead to add you to the organisation on NPM if you arent a member yet.

# This is one way to do so
echo NPM_TOKEN="REPLACE_WITH_TOKEN" >> ~/.bash_profile

API Gateway Authentication

This application communicates with the รslandsbanki API Gateway (APIGW). This requires that you keep a copy of a certain certificate on your local machine.

  1. Obtain the certificate files and store them on your local machine (how?)
  2. Set the following environment variables:
API_GW_URL=https://api-test.islandsbanki.is
API_GW_CERT=/Users/haraldurka/certs/ApiGwIAZTest.pem # Replace with correct path and filename
API_GW_KEY=/Users/haraldurka/certs/ApiGwIAZTest.key # Replace with correct path and filename

Publishing new release

Follow these steps for a correct release

ui-kit:

  1. Checkout the master branch and pull latest changes
  2. If there are changes, update version: npm version major/minor/patch
    (if there are no changes, go directly to web below)
  3. Publish new version of package to NPM: npm publish
  4. Push changes (no commit needed)

web:

  1. Checkout the master branch and pull latest changes
  2. Make a branch from master with the semver naming convention:
    release/major.minor.patch (e.g.release/4.13.2)
  3. Checkout the develop branch and pull latest changes
  4. Merge develop into the release branch
    IF UI KIT WAS NOT UPDATED, SKIP STEP 5 AND 6
  5. Update UI-kit dependency: yarn upgrade @islandsbanki/ui-kit
  6. Commit changes with the message upgrade ui-kit
  7. Push changes
  8. Update web version (ui-kit step #2)
  9. Create pull request from release to master and have it reviewed.

๐Ÿ”ฅ Hotfix ๐Ÿ”ฅ

  1. Create a new branch from master (make sure to pull the latest changes first, and follow the naming convention hotfix/[name_of_branch])
  2. Commit, push your changes and create a PR
  3. Have your PR reviewed, accepted and merged into masterย ย ย ย ย ย ย โš ๏ธ Make sure you don't merge it into develop โš ๏ธ
  4. Follow steps 10 and 11 in the list above.
  5. Make sure you apply your changes to the develop branch as well ย ย ย โš ๏ธ otherwise your changes will be overwritten on next release โš ๏ธ

Development

> yarn
> yarn dev
...
Server listening on http://localhost:3000

Hot reloading with state and decorators

By default we're using react-jobs for async stuff with server-side rendering. If we mix that with mobx and decorators suddenly hot reloading with state will stop working. This is due to a bug in react-hot-loader when higher-order components are composed. So instead of doing:

@inject('store')
@withJob({ work: ({ store }) => store.fetch() })
export default class Thing extends PureComponent {}

and not have stateful hot reloading, instead do

class Thing extends PureComponent {}

const thingWithJob = withJob({ work: ({ store }) => store.fetch() })(Thing);
export default inject('store')(thingWithJob);

If your stateful component withJob doesn't contain another component in its sub-tree, you can get away with having a @withJob decorator.

Dev tools

Dev tools (vertical and horizontal grids, mobx devtools) are hidden by default. To show them use ctrl + k. Horizontal grid can be toggled via ctrl + l.

Password protecting

By setting a PASSWORD_PROTECT env variable, the server will ask the client to authenticate with basic auth. If the string contains a : it will be split and set the username as the first part and the password as the second part, e.g. Aladdin:OpenSesame. If no : is in the string (or it starts with a :), the username will be empty and the password the given string.

Single route development

If youโ€™re working on a single route and donโ€™t want to build the entire app you can do so by using the --route argument, for example:

> yarn dev --route=about

about being the folder name of the targeted route (inside shared/routes). This can be very useful when the app gets bigger and rebuilds and HMR start to get slower.

Notes

  • When adding configuration values and environment specific values, use the project config
  • In development vendor DLLs are created (see devVendorDLL in config/values.js) to speed up builds, for large projects you can add your own deps there

Production build

yarn build
yarn start

Code splitting

Code splitting is enabled by default. We use react-universal-component and other related modules to do both JS and CSS chunks. To code split, all you have to do is wrap a component with react-universal-component. An example of this can be found in shared/routes/grid/index.js. To disable code splitting you just need to change the file to:

export default from './Grid';

Static site build

You can generate a static site by configuring the appropriate staticSiteGeneration values in config/values.js. Then run yarn build:static and the static pages will be generated in build/static.

To see the generated site, use yarn start:static or copy the build/static directory to the web server of your choice. Note that any error pages (e.g. 404.html) will not work without some server intelligence to send requests to the correct file.

More information on the internals of the static site build are in the directory's README.

Updating from upstream

Make sure you have the upstream remote:

> git remote -v # should show..
...
upstream git@github.com:ueno-llc/starter-kit-universally.git (fetch)
...
# if not, run...
git remote add upstream https://github.com/ueno-llc/starter-kit-universally.git
git remote set-url --push upstream no_push # disable push to upstream

Then, update:

git fetch upstream
git merge upstream/master

# These are the usual conflicts
git rm -r -f shared/components/DemoApp
git checkout --ours package.json

Remote development

There are two ways of doing remote development:

  1. Providing IP address via HOST to run on local network
  2. Using ngrok to expose localhost to the internet
> HOST=192.168.1.1 yarn dev # run from IP address
> HOST=$(ipconfig getifaddr en0) yarn dev # one-liner on mac
...
Server listening on http://192.168.1.1:3000
# run ngrok via script
> yarn dev-remote
...
Server listening on https://xyz.ngrok.io

Environment variables

.env_example should contain all environment variables, required or not. All environment variables should default to development values.

Paths, must be absolute URLs because of axios and the server not knowing its hostname

  • BASE_URL - Used for compiling canonical urls and local api url (for internal requests)

publicPath is set by the following environment variables:

  1. In development the publicPath is set by these variables:
  2. REMOTE_URL - Only set when running yarn dev-remote
  • HOST and CLIENT_DEV_PORT - Generates a url pointing to the dev server
  • Otherwise itโ€™s set to /client/

localApiUrl is set by the following environment rules:

  1. HEROKU_APP_NAME - Injected into an Heroku app url string
  • BASE_URL - /api is appended
  • HOST and PORT - Used to compile a local api url

This allows for the build to work in dev, on Heroku PR apps and Heroku prod. See ./config/values.js for details.

Stricter development

For those so inclined, pre-commit linting hooks can be added by changing lint-stage in package.json to:

"lint-staged": {
  "*.{js,jsx}": "./node_modules/.bin/eslint",
  "*.{css,scss}": "./node_modules/.bin/stylelint"
}

Testing can be enabled by adding to scripts:

"test": "jest"

Measuring performance

At some point during your projects lifetime, it will suddenly become slow. It might be some silly dependency, missed configuration or the alignment of the stars. After suffering through long build times one time to many, you'll start tweaking and tearing stuff apart. While doing that it's nice to know if you're having any effect, so there are some scripts included to help with that, located in ./internal/performance.

Before starting, set PERFORMANCE=true in the env so the build spits out timings.

Measuring initial build times, runs the dev build, kills it, runs it again N times. When finished it writes the average of all the runs to stdout.

> chmod +x ./internal/performance/build.sh # allow execution
> ./internal/performance/build.sh
Running "yarn dev" 5 times
2627.793
2697.435
4140.478
2911.944
2846.027

2175.239

Measuring hot reload rebuilds, runs the dev task and waits for changes that trigger rebuilds. When the script is interrupted (e.g. by ctrl+c) it writes the average of all runs to stdout.

> chmod +x ./internal/performance/hot.sh # allow execution
> ./internal/performance/hot.sh
Running "yarn dev" watching for hot reloads
Build complete
794.079
518.700
500.460
492.716
^C
576.488

React, Universally

A starter kit for universal react applications.

All Contributors

About

This starter kit contains all the build tooling and configuration you need to kick off your next universal React project, whilst containing a minimal "project" set up allowing you to make your own architecture decisions (Redux/MobX etc).

NOTICE: Please read this important issue about the behaviour of this project when using react-async-component, which is by default bundled with it.

Features

  • ๐Ÿ‘€ react as the view.
  • ๐Ÿ”€ react-router v4 as the router.
  • ๐Ÿš„ express server.
  • ๐ŸŽญ jest as the test framework.
  • ๐Ÿ’„ Combines prettier and Airbnb's ESlint configuration - performing code formatting on commit. Stop worrying about code style consistency.
  • ๐Ÿ–Œ Very basic CSS support - it's up to you to extend it with CSS Modules etc.
  • โœ‚๏ธ Code splitting - easily define code split points in your source using react-async-component.
  • ๐ŸŒ Server Side Rendering.
  • ๐Ÿ˜Ž Progressive Web Application ready, with offline support, via a Service Worker.
  • ๐Ÿ˜ Long term browser caching of assets with automated cache invalidation.
  • ๐Ÿ“ฆ All source is bundled using Webpack v3.
  • ๐Ÿš€ Full ES2017+ support - use the exact same JS syntax across the entire project. No more folder context switching! We also only use syntax that is stage-3 or later in the TC39 process.
  • ๐Ÿ”ง Centralised application configuration with helpers to avoid boilerplate in your code. Also has support for environment specific configuration files.
  • ๐Ÿ”ฅ Extreme live development - hot reloading of ALL changes to client/server source, with auto development server restarts when your application configuration changes. All this with a high level of error tolerance and verbose logging to the console.
  • โ›‘ SEO friendly - react-helmet provides control of the page title/meta/styles/scripts from within your components.
  • ๐Ÿค– Optimised Webpack builds via HappyPack and an auto generated Vendor DLL for smooth development experiences.
  • ๐Ÿƒ Tree-shaking, courtesy of Webpack.
  • ๐Ÿ‘ฎ Security on the express server using helmet and hpp.
  • ๐Ÿœ Asset bundling support. e.g. images/fonts.
  • ๐ŸŽ› Preconfigured to support development and optimised production builds.
  • โค๏ธ Preconfigured to deploy to now with a single command.

Redux/MobX, data persistence, modern styling frameworks and all the other bells and whistles have been explicitly excluded from this starter kit. It's up to you to decide what technologies you would like to add to your own implementation based upon your own needs.

However, we now include a set of "feature branches", each implementing a technology on top of the clean master branch. This provides you with an example on how to integrate said technologies, or use the branches to merge in a configuration that meets your requirements. See the Feature Branches documentation for more.

Getting started

git clone https://github.com/ueno-llc/starter-kit-universally my-project
cd my-project
npm install
npm run dev

Now go make some changes to the Home component to see the tooling in action.

Docs

Who's using it and where?

You can see who is using it and how in the comments here. Feel free to add to that telling us how you are using it, we'd love to hear from you.

Contributors

Thanks goes to these wonderful people (emoji key):


Andrรฉs Calabrese

๐Ÿ’ป

Andrey Luiz

๐Ÿ’ป

Alin Porumb

๐Ÿ’ป

Benjamin Kniffler

๐Ÿ’ป

Birkir Rafn Guรฐjรณnsson

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ‘€

Carson Perrotti

๐Ÿ’ฌ ๐Ÿ’ป ๐Ÿ“– ๐Ÿ‘€

Christian Glombek

๐Ÿ› ๐Ÿ’ป

Christoph Werner

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ‘€

David Edmondson

๐Ÿ’ป

Dion Dirza

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ‘€

Evgeny Boxer

๐Ÿ› ๐Ÿ’ป

Joe Kohlmann

๐Ÿ› ๐Ÿ’ป

Lucian Lature

๐Ÿ› ๐Ÿ’ป ๐Ÿ‘€

Mark Shlick

๐Ÿ’ป

Ryan Lindskog

๐Ÿ’ป

Steven Enten

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ‘€

Sean Matheson

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– ๐Ÿ’ก ๐Ÿ‘€ โš ๏ธ ๐Ÿ”ง

Steven Truesdell

๐Ÿ’ฌ ๐Ÿ› ๐Ÿ’ป ๐Ÿ“– โš ๏ธ

Thomas Leitgeb

๐Ÿ› ๐Ÿ’ป

Tyler Nieman

๐Ÿ’ป

This project follows the all-contributors specification. Contributions of any kind welcome!