All git commits should conform to idiomatic git commit message style described by Tim Pope and expanded on by others.
Gradle can be used to bootstrap a node and npm environment from scratch. Gradle
itself can bootstrap using the gradlew
script. If the required versions of
node and npm are already installed at a system level, this step can be skipped.
Bootstrap gradle:
./gradlew wrapper
Bootstrap node and npm:
./gradlew npmSetup
NPM is used to manage Javascript dependencies. The gradle build will install the
correct version of npm
, and related dependencies.
NPM will use whichever version of node is in the PATH, which will likely be the default system install rather than the project version, if different.
To solve this, execute all binaries via the ./nodew
script at the root of the
project.
./nodew npm ... ./nodew node ... ./nodew gulp ... ./nodew karma ...
Warning
|
Under Windows Cygwin, the platform and architecture detection in
nodew is unlikely to work correctly. Set NODE_HOME to override it, and check
the settings are correct with ./nodew npm version .
|
Shell function definitions for node, npm, gulp, etc. similar to the following may be useful:
npm() {
if [[ -f "./nodew" ]]; then
./nodew npm $*
elif [[ -f "./npm" ]]; then
./npm $*
elif [[ -f "./node_modules/.bin/npm" ]]; then
./node_modules/.bin/npm $*
elif [[ -f /usr/bin/npm ]]; then
/usr/bin/npm $*
else
echo >&2 "npm not found."
fi
}
To test for blacklisted modules (listed in package.json):
npm run-script check-blacklisted
To test for latest versions of build packages (listed in package.json):
npm outdated
Other available scripts include lint
, lintdev
, and test
. Scripts are
listed in package.json
.
Gulp is the build system used for the frontend.
To create a minified and compiled version of all assets (including CSS preprocessors such as less and sass, and compilation of typescript files), run:
gulp build --release
Or to produce non-minified CSS and JS files in the build:
gulp build
To deploy documentation to GitHub pages (use --production
or --staging
as
necessary, see the build file):
gulp deploy # or, `gulp deploy --production`
To watch source files for changes and automatically update the compiled build (to see changes immediately in Play, for example), leave the gulp serve task running:
gulp serve
Specify the task before other arguments: e.g.
gulp build --verbose
The client is best debugged via browser developer tools.
The server can be debugged and profiled using node-inspector.
npm install -g node-inspector ./nodew node-inspector
Then start the server in debug mode (or for a running server send the server process a USR1 signal):
gulp serve --debug
or
gulp serve --debugbrk
The default server-side database is Redis. See swarmserver.js for the Redis connection details.
-
Delete several keys matching a wildcard:
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 "/Cursor#*"
-
Copy the state of editor 10 to 11 for debugging:
SCRIPT LOAD "return redis.call('restore', ARGV[2], 0, redis.call('dump', ARGV[1]))" EVALSHA "bfb3fde399b1b363c6d5617b8d955bb4f7aea907" 0 "/Text#10" "/Text#11" EVALSHA "bfb3fde399b1b363c6d5617b8d955bb4f7aea907" 0 "/Text#10:log" "/Text#11:log"
Javascript unit tests are written using Mocha and
assertions using Chai. Tests are named
<something>-test.js
.
To execute:
npm test
Note
|
The default Facebook library for testing React applications is Jest, but Jest is slow and classes under test had strange issues like array pushes failing. Mocha seems to be more consistent. IntelliJ IDEA can also run and debug Mocha tests. |
Note
|
jsdom is limited to version 3.x. 4.x and above only works with io.js
and not with NodeJS.
|
More information:
In cases where a browser API is required for the test, the unit tests are named
<something>-testb.js
. Tests are executed via the
Karma runner.
To execute:
npm run-script testb
(testb stands for "test in browser")
Running the application via gulp sync
will run a
BrowserSync session. This provides live reload
functionality in the browser when changes are made to server-side code. It will
also synchronize multiple browsers (clicks, scrolling, and so forth), which is
useful for multi-browser verification.
Warning
|
Current BrowserSync does not support websocket connections. Therefore
gulp sync is not yet useful.
|
IntelliJ can debug Javascript with the appropriate plugins installed in IDEA. Note that if you use Chrome for normal browsing, you should use a different Chrome profile for IDEA — set this in Settings, Web Browsers, Chrome, Edit
Debug client-side Javascript in IDEA using the run configuration Debug Frontend
(npm start)
. Debug server-side Javascript (NodeJS) by using the run
configuration NodeJS Remote Debug
, and start the server with a --debug
flag
e.g. ./gulp serve --debug
.
Warning
|
There appears to be a bug in IntelliJ that causes it to not use the
source map between the Javascript file in the src directory vs the one
actually being executed (after processing by webpack) in the build
directory (possibly this one).
To work around this, set the breakpoints in the <build>/…/whatever.js
file instead of the original file. Once they are set, the breakpoints will still
trigger in the original src file.
|
ESLint is used for checking JavaScript styles and for common
errors. The project’s rules are defined in `.eslintrc
.
EditorConfig is used to maintain consistent coding
styles between various editors and IDEs. The project’s rules are defined in
.editorconfig
.
Use ES6 module export and import syntax. Webpack with an ES6 transpiler is fully capable of handling this.
Use the npm coding style. Note, as per npm, we don’t use semi-colon termination. We do use semi-colon prefixes when required. Exceptions:
-
Line lengths <~ 120 (not a strict limit, but a useful guideline)
-
"," at the end of comma-separated values as is normal (the benefit of putting them at the beginning is clear, but it just plain makes code look weird)
React components should be declared in .js
files and use JSX syntax. Use the
following conventions:
-
Layout the React component methods in rough lifecycle order (
displayName
is not necessary when using JSX):React.createClass({ propTypes: {}, mixins : [], getDefaultProps() {}, getInitialState() {}, componentWillMount() {}, componentDidMount() {}, componentWillReceiveProps(nextProps) {}, shouldComponentUpdate(nextProps, nextState) {}, componentWillUpdate(nextProps, nextState) {}, componentDidUpdate(prevProps, prevState) {}, componentWillUnmount() {}, // other public methods _parseData() {}, _onSelect() {}, render() {} });
NoteThe above uses ES6 object initializer method definitions as a function declaration shorthand. Custom functions should be prefixed with
_
and placed above the render method. -
Variables containing conditional HTML should be suffixed with
Html
e.g.:var dinosaurHtml = ''; if (this.state.showDinosaurs) { dinosaurHtml = ( <section> <DinosaurTable /> <DinosaurPager /> </section> ); } return ( <div> ... {dinosaurHtml} ... </div> );
-
JSX spanning multiple lines should be wrapped in parentheses as above.
-
List iterations can be done inline using an ES6
map
function.