1.14.4 • Published 4 years ago

stadtenergie v1.14.4

Weekly downloads
1
License
ISC
Repository
github
Last release
4 years ago

Staging Build Conventional Commits style: styled-components npm latest version npm next version

StadtEnergie

description

Requirements

  • Node.js ^8.15.1
  • npm ^5.0.0

Install

​ First, clone the project: ​

$ git clone --depth=1 git@github.com:mobilabsolutions/stadtenergie.git <THE_NAME>
$ cd THE_NAME

​ Then install dependencies and check to see if it works. ​

$ npm install  # Install project dependencies
$ npm run dev    # Compile and launch
npm run ...Description
devRuns next which starts Next.js in development mode.
buildRuns next build which builds the application for production usage.
startRuns next start which starts a Next.js production server.
update-dependenciesUpdate the dependencies of the project.
storybookRun storybook for the ui component.
storybook:buildBuild storybook for the ui component.
storybook:deploydeploy ui components.

Stack

  • react
  • nextjs
  • redux
  • typescript
  • styled components
  • redux-sagas

Concepts

Components

Components are the smallest building blocks of the application. The components, modules and the pages could render this components. ​All the third party components are wrapped in our components folder, so if we want to customize or even change is much more easy.

Services

Mimic's the services provided by the BE. The rule it's to split by pathname. So for e.g if the BE has an ${apiConfig.ENDPOINT}/my-service, a myService.ts should be create on the services folder, with all the calls needed for the project. ​ The calls should be stateless functions that return a promise (args) => Promise<Result|Error>

Pages

​ A page is a React Component exported file in the pages directory. Each page is associated with a route based on its file name.​ So if we have a pages/homepage we can access this route on the browser .../homepage.

Modules

A module represents related code of a specific concept. You should aim to reduce the coupling of related Modules by making the dependency between two Modules unidirectional. Every module has an index.ts file which serves as the entry point for other modules, this way, a module can choose which parts it exposes in its public API(components, actions, types and constants).

A module structure

├── ModuleA
│   ├── index.ts                # Entry point of the module (container)
│   ├── components              # Modules that exclusevely used on the module
│   ├────── ModuleA.tsx         # Component for the ModuleA
│   ├── store                   # Module store
│   │   ├── index.ts            # Entry point for the store
│   │   ├── actions.ts          # Module action
│   │   ├── reducer.ts          # Module reducer
│   │   ├── contants.ts         # Module actions
│   │   ├── selectors.ts        # Module selectors
│   │   ├── sagas               # Module sagas

​A module could be global(the app needs it to work properly, such as User, App, etc) or a feature one.

The global module register the reducers and sagas on the root store like usual.

The feature module could contain it's own store and it's injected to the root store only when needed. The store should be used only inside the respective module. Because we use a strategy of lazy registering reducer/saga we need to include useInjectReducer, useInjectSaga if needed. This way the first load of the app will be much more faster because don't need to initialize unnecessary reducers or sagas. ​ The useInjectSaga should be used for side effects on the module, communication with global store (like user, app, or ui(modal, etc)). The communication between 2 global modules should be done on the root sagas store/sagas

const MODULE_KEY = 'moduleA';

const ContainerInfo = () => {
  //inject reducer dynamically
  useInjectReducer({ key: MODULE_KEY, reducer });
  //inject saga dynamically
  useInjectSaga({ key: MODULE_KEY, saga });

  const moduleAData = useSelector(({ moduleA }) => moduleA);
  ...
};

Communication between modules

To communicate between 2 modules should be made by the sagas(aggregations). Group 1 (1)

Folder Structure

.
├── config                     # Project and build configurations
│   ├── webpack                # The webpack configuration for each env
│   ├── testing                # Testing configuration
├── src                        # Application source code
│   ├── index.ts               # Application bootstrap and rendering
│   ├── components             # Global Reusable Stateless components
│   ├── modules                # Global Reusable modules
│   │   ├── ModuleA            # ModuleA feature
│   │   ├──── store            # Include (action.ts, reducer.ts, saga.ts)
│   │   ├──── components       # Components that are used on the module
│   │   └──── index.ts         # The entry point of the module
│   ├── configs                # Global configuration peer environment
│   ├── core                   # Core
│   ├── layouts                # Components that dictate major page structure
│   │   └── Main               # Main layout
│   │   └── Authenticated      # Authenticated layout
│   │   └── index.ts           # Main file for layout
│   ├── pages                  # Main route definitions and async split points
│   │   ├── index.ts           # Bootstrap main application routes with store
│   │   ├── route1             # Route 
│   │   │   └── index.ts       # The route component
│   │   ├── route2             # Route
│   │   │   └── index.ts       # The route component
│   ├── store                  # Redux-specific pieces
│   │   ├── configureStore.ts  # Create and instrument redux store
│   │   └── reducers.ts        # Reducer registry
│   │   └── sagas.ts           # Sagas registry
│   └── assets                 # Assets folder
│   │   ├── styles             # Styles folder
│   │   │   ├── style.css      # Style entry point
│   │   │   ├── global.css     # Global styles
│   │   ├── fonts              # Fonts folder
│   │   ├── images             # Images folder
└── tests                      # Unit tests

Styles

​ ​...

Styleguide

​ Run npm run styleguide to start style a guide dev server. ​ Run npm run styleguide:build to build a static version. ​​

Every component should have a README.md in which the component should be described by a few simple examples and a short description.

​For a more detailed explaination you can check the styleguidist docs over here

i18n

The app is prepared to work with i18n, to do we just need to create a file on public/static/locales where the name of the file will be the namespace. For example: pages.landing.json the namespace will be pages.homes try always use the the folder structure for the translations file. pages.AAA, components.BBB, modules.CCC.

The translation files are json.

pages.home.json
{
  "h1": "A simple example"
}

to use on the code we just need to:

...
import { useTranslation, includeDefaultNamespaces } from 'utils/i18n';

const Page: NextComponentType = () => {
  const { t: translation, i18n } = useTranslation();
  return (
    <React.Fragment>
      {translation('pages.home:title')}
      <button
        onClick={() =>
          i18n.changeLanguage(i18n.language === 'en' ? 'de' : 'en')
        }
      >
        {translation('change-locale')}
      </button>
      {i18n.language}
    </React.Fragment>
  );
};

Page.getInitialProps = async () => ({
  namespacesRequired: includeDefaultNamespaces(['pages.home'])
});

export default Page;

To change the language we use i18n.changeLanguage('en') To get the current language we use i18n.language

Content Management

The app content is controlled by a non-technical content manager through Phrase.com In-Context Editor. Therefore it is necessary to keep the content in sync with Phrase.com.

First setup phrase cli using:

npm run phrase:setup

Then every once in a while, when you have added new keys, run:

npm run phrase:sync

NOTE:

To make sure the content manager's data doesn't get lost in any way, the data in phrase.com has precedence to the local data, in case of conflicts. This has some drawbacks when a key is already published to phrase.com:

  • If you locally edit the value of such a key, it will get overwritten by the value of the key in phrase.com, after running the command.
  • If you locally delete such a key, it will get re-added after running the command.
  • If you locally rename such a key, the new name and the old name will both exist in phrase.com as two keys with the same value, and both will be added back locally after running the command.

Therefore, try to stick with additions only, and for editions or deletions, ask Fardin to fix things in phrase.com. Don't edit or delete locally.

Globals

These are global variables available to you anywhere in your source code.

VariableDescription
process.env.NODE_ENVthe active NODE_ENV when the build started
__DEV__True when process.env.NODE_ENV is development
__PROD__True when process.env.NODE_ENV is production
__TEST__True when process.env.NODE_ENV is test
__LOCAL__True when process.env.NODE_ENV is local
__COVERAGE__True when process.env.NODE_ENV is test and uses the watch flag

Release

To make a new release of the project just run npm run release on master branch and after that git push --follow-tags origin master. The commits should follow the conventional commits standard so it can bump the versions and generate correctly the changelog. To learn more about conventional commits visit the website

Commit message format

semantic-release uses the commit messages to determine the type of changes in the codebase. Following formalized conventions for commit messages, semantic-release automatically determines the next semantic version number, generates a changelog and publishes the release.

By default semantic-release uses Angular Commit Message Conventions. The commit message format can be changed with the preset or config options of the @semantic-release/commit-analyzer and @semantic-release/release-notes-generator plugins.

Here is an example of the release type that will be done based on a commit messages:

Commit messageRelease type
fix(pencil): stop graphite breaking when too much pressure appliedPatch Release
feat(pencil): add 'graphiteWidth' optionMinor Release
perf(pencil): remove graphiteWidth optionBREAKING CHANGE: The graphiteWidth option has been removed.The default graphite width of 10mm is always used for performance reasons.Major Release

We use commitlint to force commit messages. commitlint checks if your commit messages meet the conventional commit format.

In general the pattern mostly looks like this:

type(scope?): subject  #scope is optional

Real world examples can look like this:

chore: run tests on travis ci
fix(server): send cors headers
feat(blog): add comment section

Common types according to commitlint-config-conventional (based on the the Angular convention) can be:

  • build
  • ci
  • chore
  • docs
  • feat
  • fix
  • perf
  • refactor
  • revert
  • style
  • test

Routes

Why use Routing when using Next?

The problem when using Next, blocks us from using translations in the routes.

How to use it?

Instead of using Router.push() we use a method in the file /src/utils/routes.ts, push

Push

const push = (route:  any, options?:  any) => {

Router.push(route, DE_NextConfigRoutes[route.pathname || route], options);

};

What to do

To be able to use route translations, what you need to do is:

  • Add a constant to the routes.ts in english

  • Export the just added english constant

  • Add a constant to the routes.ts in german with DE_ in the back of the name

  • Add both constants as a [KEY] => VALUE to the DE_NextConfigRoutes making the

KEY english and VALUE german

  • Go to where you want to push the route

  • Import the method and the english route

  • Use as below:

...

/**
* ORDER_PROCESS_ROUTE is the english constant
* Use only the route name
*/

push(ORDER_PROCESS_ROUTE)

//OR

/**
* Use with URL options
*/

push({
  pathname: ORDER_PROCESS_ROUTE,
  query: { step: `${stepIndex}` }
});

//OR

/**
* Use with URL options and other options
*/

push({
  pathname: ORDER_PROCESS_ROUTE,
  query: { step: `${stepIndex}` }
}, { shallow: true });

...