Skip to content

Commit

Permalink
Merge pull request #33 from jGleitz/watch
Browse files Browse the repository at this point in the history
Streamlined development process
  • Loading branch information
valentinz committed Nov 10, 2015
2 parents 9b595d7 + 837946e commit 247534d
Show file tree
Hide file tree
Showing 11 changed files with 376 additions and 63 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ before_script:
- "export DISPLAY=:99.0"

script:
- npm run postinstall-deploy -s
- npm run lint -s
- npm test
- npm run browsertest -s
27 changes: 9 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,21 @@ LICENSE file.

4. If you want to use the backend, also install come2help-server. See the tutorial in come2help-server.

5. Install the development dependencies:
5. Install all dependencies:
<pre>npm install</pre>

6. Use bower to install the dependencies:
<pre>bower install</pre>
6. Start the development services:
<pre>npm start</pre> This will start:
* A watch to build all files that need to be built.
* A webserver
* A LiveReload server

7. Run the index.html in a browser of your choice.
Be careful about cross-site script detection, since the server is not running at the same domain as your client.
Maybe you have to use a proxy server like nginx.
If `style.css` is missing, run `npm run build-css` first to transpile SASS to CSS.

8. Start a python Webserver with:
<pre>python -m SimpleHTTPServer</pre>
or
<pre>python3 -m http.server</pre>
No caching alternatives:
<pre>python nocacheserver.py</pre>
or
<pre>python3 nocacheserver3.py</pre>
7. Run `localhost:8000` in a browser of your choice. Install [LiveReload](http://livereload.com/) to have it automatically updated.

8. Start coding!

## Testing
Tests are run through the `npm` interface:
Tests are run through `npm`:

* `npm test`

Expand All @@ -61,4 +53,3 @@ Tests are run through the `npm` interface:
* `npm run lint -s`

Lints the code.

15 changes: 0 additions & 15 deletions nocacheserver.py

This file was deleted.

16 changes: 0 additions & 16 deletions nocacheserver3.py

This file was deleted.

18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,31 @@
"chai": "^3.3.0",
"chai-as-promised": "^5.1.0",
"closurecompiler": "^1.5.2",
"colors": "^1.1.2",
"connect": "^3.4.0",
"date-format-lite": "^0.7.4",
"eslint": "^1.6.0",
"eslint-config-angular": "^0.4.0",
"eslint-plugin-angular": "^0.12.0",
"extend": "^3.0.0",
"js-beautify": "^1.5.10",
"livereload": "^0.4.0",
"mocha": "^2.3.3",
"node-sass": "^3.3.3",
"portfinder": "^0.4.0",
"protractor": "git+https://github.com/jGleitz/protractor.git#browserstack",
"q": "^1.4.1",
"serve-static": "^1.10.0"
"serve-static": "^1.10.0",
"watch": "^0.16.0"
},
"scripts": {
"postinstall": "bower install && npm run install-testdependencies && npm run build-css",
"build-css": "node tasks/sass",
"test": "protractor test/behaviour/protractor.conf",
"chrometest": "protractor test/behaviour/protractor.conf --browser chrome",
"install-testdependencies": "webdriver-manager update --standalone --chrome --browserstacklocal",
"browsertest": "protractor test/behaviour/protractor.browserstack.conf",
"postinstall": "webdriver-manager update --standalone --chrome --browserstacklocal && npm run build-css",
"postinstall-deploy": "npm run lint -s && npm test -s && npm run browsertest -s",
"postinstall-dev": "npm run lint -s && npm run watch-css -s",
"build-css": "node-sass css --output build/css",
"watch-css": "node-sass -w -r css --output build/css",
"lint": "eslint js/**/*.js test/**/*.js"
"chrometest": "protractor test/behaviour/protractor.conf --browser chrome",
"lint": "eslint js/**/*.js test/**/*.js",
"start": "node tasks/watch"
}
}
30 changes: 30 additions & 0 deletions tasks/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"rules": {
"indent": [
2,
"tab", {
"SwitchCase": 1
}
],
"quotes": [
2,
"single"
],
"linebreak-style": [
2,
"unix"
],
"semi": [
2,
"always"
],
"no-mixed-spaces-and-tabs": [
2, "smart-tabs"
]
},
"env": {
"es6": true,
"node": true
},
"extends": "eslint:recommended"
}
22 changes: 22 additions & 0 deletions tasks/.jsbeautifyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"indent_size": 2,
"indent_char": " ",
"eol": "\n",
"indent_level": 0,
"indent_with_tabs": true,
"preserve_newlines": true,
"max_preserve_newlines": 3,
"jslint_happy": false,
"space_after_anon_function": false,
"brace_style": "collapse",
"keep_array_indentation": false,
"keep_function_indentation": false,
"space_before_conditional": true,
"break_chained_methods": false,
"eval_code": false,
"unescape_strings": false,
"wrap_line_length": 0,
"wrap_attributes": "auto",
"wrap_attributes_indent_size": 4,
"end_with_newline": false
}
118 changes: 118 additions & 0 deletions tasks/sass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/**
* Handles SCSS rendering.
*/


var sass = require('node-sass');
var path = require('path');
var fs = require('fs');
var q = require('q');

var basePath = path.resolve(__dirname, '..');
var resolve = path.resolve.bind(path, basePath);

function returnQ(argument) {
return q.bind(q, argument);
}

/**
* Renders the given scss file.
*
* @param {string} filePath The path to .scss file out of the css folder.
* @return {promise<string>} A promise that will be fulfilled with the path to the rendered file when it was rendered.
*/
function renderFile(filePath) {
var outFilePath = getOutputFilePath(filePath);
return q.nfcall(sass.render, {
file: filePath,
outFile: outFilePath
}).then(function(result) {
return mkdirs(path.dirname(outFilePath))
.then(q.nbind(fs.writeFile, fs, outFilePath, result.css));
}).then(returnQ(outFilePath));
}

function getOutputFilePath(filePath) {
filePath = filePath.replace(/.scss$/, '.css');
return resolve('build', path.relative(resolve(''), filePath));
}

/**
* Remove the rendered equivalent of the provided scss file.
*
* @param {string} filePath The path of a scss file that was present in the css folder, but was deleted.
* @return {promise<string>} A promise that will be fulfilled with the path of the rendered file when it was deleted.
*/
function clean(filePath) {
var rendered = getOutputFilePath(filePath);
return q.nfcall(fs.unlink, rendered).then(returnQ(rendered));
}

module.exports = {
render: renderFile,
clean: clean
};

/**
* @param {string} dir A directory
* @return {promise<void>} A promise that will be fulfilled when all directories on the way to dir (including dir itself) exist.
*/
function mkdirs(dir) {
return q.nfcall(fs.stat, dir).catch(function(error) {
if (error.code === 'ENOENT') {
return mkdirs(path.dirname(dir))
.then(q.nbind(fs.mkdir, fs, dir))
.catch(function(error) {
if (error.code !== 'EEXIST') {
throw error;
}
});
} else {
throw error;
}
});
}

/**
* @param {string} dir A directory
* @return {promise<Array<string>>} A promise for all files in that directory, including nested files.
*/
function walk(dir) {
var results = [];
return q.nfcall(fs.readdir, dir).then(function(list) {

if (list.length === 0) {
return list;
}

var promises = list.map(function(file) {
file = path.resolve(dir, file);

return q.nfcall(fs.stat, file).then(function(stat) {
if (stat.isDirectory()) {
return walk(file).then(function(res) {
results = results.concat(res);
});
} else {
results.push(file);
return q();
}
});
});
return q.all(promises).then(function() {
return results;
});
});
}

if (require.main === module) {
walk(resolve('css')).then(function(list) {
var promises = list.map(function(file) {
if (path.extname(file) === '.scss') {
return renderFile(file);
}
return q();
});
return q.all(promises);
}).done(process.exit.bind(process, 0));
}
50 changes: 50 additions & 0 deletions tasks/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Very simple webserver for development purposes.
*/

var connect = require('connect');
var serveStatic = require('serve-static');
var path = require('path');

var baseDir = path.resolve(__dirname, '..');

function getWebserver() {
var setHeaders = function(res) {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
};
return serveStatic(baseDir, {
setHeaders: setHeaders,
etag: false
});
}

/**
* A simple web server that will default to deliver the base directory of this repository. It can be extended through #use.
*/
function Server() {

var server = connect();

/**
* Use the provided middleware. The order of the calls defines the order in which middlewares will be queried.
*
* @param {Object} server A node js server middleware.
* @return {void}
*/
this.use = server.use.bind(server);

/**
* Launch the server and listen on the provided port.
*
* @param {number} port The port to listen on.
* @return {void}
*/
this.listen = function(port) {
server.use(getWebserver());
server.listen(port);
};
}

module.exports = Server;
Loading

0 comments on commit 247534d

Please sign in to comment.