Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modular architecture with appmodules #7

Merged
merged 17 commits into from
Oct 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@
"presets": [ "react", "es2015", "stage-2" ],
"plugins": [
"add-module-exports"
]
}
],
"env": {
"test": {
"plugins": [
[
"babel-plugin-webpack-loaders",
{
"config": "../../webpack.config.test.js",
"verbose": false
}
]
]
}
}
}
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ The application needs to be able to load nrfjprog libraries. This is currently n

tar xf nrfjprog/nRF5x-Command-Line-Tools_8_5_0_Linux-x86_64.tar --strip-components=2 -C node_modules/electron-prebuilt/dist

## Working with appmodules

This project is split into multiple [appmodules](doc/README.md) inside the `packages` directory. When running `npm start` from the root directory, the appmodule loader will be started. When choosing an appmodule, a *pre-built version* of that appmodule will be loaded. If you modify the code, it will not have any effect unless you `npm run build` the appmodule and restart the application.

When working with appmodules it is normally recommended to navigate to the appmodule directory before running `npm start`. When doing this, the application will hot-reload any changes that are made to the code, providing instant feedback during development.

cd packages/nrfconnect-appmodule-ble
npm start

## Testing

Unit testing of all packages can be performed by running:

npm test

Testing of individual packages can be done by navigating to the package directory before running `npm test`:

cd packages/nrfconnect-appmodule-ble
npm test

## Creating release packages
Scripts have been included in the reop to create release packages. Different artifacts will be created depending on the type of operating system:

Expand All @@ -75,7 +95,7 @@ The build scripts will set the required environment variables, build nRF Connect
Since the build scripts delete the cache folder *node_modules* and reinstalls in production mode it can be a good idea to run the scripts from a separate repository clone folder.

## Color definitions
The main colors used in nRF Connect are defined in the file css/brand.less. The colors defined in the source code base have been modified from the colors used in the official release builds of nRF Connect. This has been done to differentiate the Nordic releases from other source code builds. Please feel free to modify the color definitions to your own liking.
The main colors used in nRF Connect are defined in the file [packages/nrfconnect-core/css/brand.less](packages/nrfconnect-core/css/brand.less). The colors defined in the source code base have been modified from the colors used in the official release builds of nRF Connect. This has been done to differentiate the Nordic releases from other source code builds. Please feel free to modify the color definitions to your own liking.

# Related projects
nRF Connect builds on top of other sub components that live in their own GitHub repositories:
Expand Down
187 changes: 187 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# nRF Connect Documentation

## Application Modules (appmodules)

nRF Connect is modularized into application modules (appmodules). Each
appmodule provides a certain set of features. The appmodules are developed
independently, but may share some common components and resources from the core
module located in `packages/nrfconnect-core`.

### Loader

When starting the application, the users will be able to choose which appmodule
they want to load.

![Loader](nrfconnect-loader.png)

The appmodule loader is located in `packages/nrfconnect-loader`. The
`package.json` in this directory has dependencies to all appmodules that should be
used by the application. The loader will only display appmodules that are
defined in the `appmodules` field in `package.json`, f.ex:

```
"appmodules": [
"nrfconnect-appmodule-ble",
"nrfconnect-appmodule-sample"
]
```

If only one appmodule is defined here, then the loader UI will be skipped, and
the appmodule will be loaded immediately.

### Configuration

The appmodules are located in the `packages` directory. Each appmodule has its own
directory containing code and resources, plus a `package.json` where
metadata for the appmodule can be configured.

Example:

```
{
"name": "nrfconnect-appmodule-ble",
"version": "1.0.0",
"description": "A natural first choice for BLE development",
"homepage": "http://infocenter.nordicsemi.com/nrf-connect/ble",
"main": "index.js",
"author": "Nordic Semiconductor ASA",
"config": {
"title": "Bluetooth Low Energy (BLE)",
"icon": "resources/icon.png"
},
scripts: {
...
},
dependencies: {
...
}
}
```

Fields that are relevant for the nRF Connect application:

| Field | Required | Description |
| --- | --- | --- |
| `name` | Yes | The name of the appmodule. This name is used to reference the appmodule as a dependency in the main `package.json` file of the application. |
| `version` | Yes | The version of the appmodule. |
| `description` | Yes | The appmodule description. This is displayed in the loader UI. |
| `main` | Yes | The entrypoint of the appmodule. This file should contain code that is run by the Electron main process, which sets up events and initializes the browser window. This is invoked by the loader. |
| `homepage` | No | An URL that contains more information about the appmodule. Currently not in use, but in the future it may be used as a link in the loader UI, and the appmodule's "help" menu. |
| `author` | No | The author of the appmodule. Currently not in use, but in the future it may be displayed in the loader UI, and the appmodule's "about" menu. |
| `config.title` | Yes | The appmodule title. Will be displayed as name of the appmodule in the loader UI. |
| `config.icon` | Yes | Path to an image that will be used as an icon in the loader UI. |

### Sample appmodule

When developing a new appmodule, it is recommended to use
[packages/nrfconnect-appmodule-sample](packages/nrfconnect-appmodule-sample)
as a starting point. You can fork this repository and create a copy of
the sample appmodule inside `packages`.

```
cp -a packages/nrfconnect-appmodule-sample packages/nrfconnect-appmodule-<name>
```

Then edit the relevant fields (author, title, icon, etc.) in `package.json`.
You can then start developing your own components, reducers, and actions
in the `js` directory. Unit testing with jest is enabled, and there is
an example test in the `components` directory.

You can start the appmodule by running `npm start` in the appmodule directory.
You can also test how the appmodule looks in the loader UI. In that case,
add your appmodule as a dependency in `nrfconnect-loader/package.json` and
add it to the `appmodules` array in the same file. Go to the root of the
project and run `npm run bootstrap` so that the loader and appmodule are
linked. Then run `npm start` in the `nrfconnect-loader` directory.

### Create appmodule from scratch

If you want to create an appmodule from scratch, you can create a separate Git
repository and add `nrfconnect-core` as a dependency. You can use
whatever libraries and development tools you desire as long as you
remember the following:
- Your `package.json` must contain the required fields as described in the [configuration section](#configuration).
- The appmodule should follow the naming convention `nrfconnect-appmodule-<name>`.

The file you specify as `main` in `package.json` is loaded by the appmodule
loader. The code in this file is run by the Electron main process. This code
should create the browser window and load an html file, which finally loads
your JavaScript app. The `nrfconnect-core` module contains a
`createBrowserWindow` function that simplifies this, described in the section
below.

#### createBrowserWindow

With `createBrowserWindow` you can easily initialize the Electron browser
window for use with nRF Connect. The behavior of this function can be
configured by passing in a set of options:

| Option | Required | Default value | Description |
| --- | --- | --- | --- |
| `url` | Yes | - | Path to the html file that should be loaded in the browser window. |
| `title` | No | nRF Connect vX | The title that should be visible in the window title bar. |
| `keepWindowSettings` | No | `true` | If `true`, the window size and maximized status is kept and reused next time the window is opened. |
| *standard Electron option* | - | - | Any standard option from the [Electron BrowserWindow API](https://github.com/electron/electron/blob/master/docs/api/browser-window.md) |

Example usage:

```
var electron = require('electron');
var core = require('nrfconnect-core/index');

if (electron.app.isReady()) {
initBrowserWindow();
} else {
electron.app.on('ready', function () {
initBrowserWindow();
});
}

function initBrowserWindow() {
core.createBrowserWindow({
title: 'My nRF Connect appmodule',
url: 'file://' + __dirname + '/index.html',
icon: __dirname + '/resources/icon.png'
});
}
```

If the application is already ready, f.ex. if the appmodule is being loaded from
the nRF Connect loader, we load the browser window immediately. If not,
we wait until the application is ready before loading the window. This allows
us to support loading the appmodule either through the loader or as a
standalone application.

You can also reuse metadata from your `package.json` when creating the browser
window. Simply require it, and supply the relevant values:

```
var packageJson = require('./package.json');

core.createBrowserWindow({
title: packageJson.config.title,
url: 'file://' + __dirname + '/index.html',
icon: __dirname + '/' + packageJson.config.icon
});
```

The `createBrowserWindow` function returns the browser window instance. Refer
to the [Electron BrowserWindow API](https://github.com/electron/electron/blob/master/docs/api/browser-window.md)
to see available events, functions, and properties for this instance. Events can
f.ex. be configured like this:

```
var browserWindow = core.createBrowserWindow({...});

browserWindow.webContents.on('new-window', function (e, url) {
e.preventDefault();
shell.openExternal(url);
});
```

### Remaining work

The following work is planned, but not completed yet:
- Ability to go back to the loader after having selected an appmodule.
- Mechanism for remembering which appmodule the user has selected, so that it can be loaded by default the next time the application starts.
- Online update mechanism for appmodules.
Binary file added doc/nrfconnect-loader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions lerna.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lerna": "2.0.0-beta.30",
"version": "0.0.0"
}
53 changes: 14 additions & 39 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,23 @@
},
"main": "index.js",
"scripts": {
"start": "concurrently -k \"node server.js\" \"cross-env ENV=development electron .\"",
"build": "webpack --config webpack.config.production.js"
"start": "cd packages/nrfconnect-loader && npm start",
"build": "lerna-run npm run build",
"postinstall": "npm run bootstrap && npm run build",
"bootstrap": "lerna bootstrap",
"updated": "lerna updated",
"test": "lerna-run npm test",
"clean": "npm install lerna lerna-run && lerna-run npm run clean && rimraf node_modules"
},
"author": "Nordic Semiconductor ASA",
"license": "Proprietary",
"devDependencies": {
"asar": "0.12.3",
"babel-core": "6.14.0",
"babel-jest": "15.0.0",
"babel-loader": "6.2.5",
"babel-plugin-add-module-exports": "0.2.1",
"babel-plugin-webpack-loaders": "0.7.1",
"babel-preset-es2015": "6.14.0",
"babel-preset-react": "6.11.1",
"babel-preset-stage-2": "6.13.0",
Expand All @@ -29,52 +36,20 @@
"express": "4.14.0",
"file-loader": "0.9.0",
"install": "0.8.1",
"jest": "15.1.1",
"json-loader": "0.5.4",
"lerna": "2.0.0-beta.30",
"lerna-run": "0.0.2",
"less": "^2.7.1",
"less-loader": "2.2.3",
"q": "1.4.1",
"redux-devtools": "3.3.1",
"redux-devtools-dock-monitor": "1.1.1",
"redux-devtools-log-monitor": "1.0.11",
"rimraf": "^2.5.4",
"run-sequence": "1.2.2",
"style-loader": "0.13.1",
"webpack": "1.13.2",
"webpack-dev-middleware": "1.7.0",
"webpack-hot-middleware": "2.12.2",
"webpack-target-electron-renderer": "0.4.0",
"yargs": "5.0.0"
},
"dependencies": {
"atom-keymap": "6.3.2",
"babel-polyfill": "6.13.0",
"bootstrap": "3.3.7",
"change-case": "3.0.0",
"immutable": "3.8.1",
"jquery": "3.1.0",
"less": "2.7.1",
"moment": "2.14.1",
"open": "0.0.5",
"pc-ble-driver-js": "https://github.com/NordicSemiconductor/pc-ble-driver-js.git#v0.9.0",
"pc-nrfjprog-js": "https://github.com/NordicSemiconductor/pc-nrfjprog-js.git#v0.3.0",
"react": "15.3.1",
"react-addons-linked-state-mixin": "15.3.1",
"react-bootstrap": "0.30.3",
"react-dom": "15.3.1",
"react-infinite": "NordicSemiconductor/react-infinite#upgrade-to-react-15",
"react-onclickoutside": "5.5.0",
"react-redux": "4.4.5",
"react-textarea-autosize": "4.0.5",
"redux": "3.6.0",
"redux-logger": "2.6.1",
"redux-promise-middleware": "4.0.0",
"redux-storage": "4.1.1",
"redux-thunk": "2.1.0",
"semver": "5.3.0",
"serialport": "^3.1.2",
"sqlite3": "3.1.4",
"tween.js": "16.3.5",
"underscore": "1.8.3",
"util": "0.10.3",
"uuid-v4": "0.1.0",
"winston": "2.2.0"
}
}
19 changes: 19 additions & 0 deletions packages/nrfconnect-appmodule-ble/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"presets": [ "react", "es2015", "stage-2" ],
"plugins": [
"add-module-exports"
],
"env": {
"test": {
"plugins": [
[
"babel-plugin-webpack-loaders",
{
"config": "../../webpack.config.test.js",
"verbose": false
}
]
]
}
}
}
3 changes: 3 additions & 0 deletions packages/nrfconnect-appmodule-ble/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
runtime = electron
target = 1.2.8
disturl = https://atom.io/download/atom-shell
Loading