diff --git a/.travis.yml b/.travis.yml
index e573baac..1fe8f706 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,9 +9,8 @@ cache:
- node_modules
before_script:
- - npm install -g gulp
- - npm install -g bower
+
script:
- - gulp lint
- - gulp build-prod
- - gulp test
\ No newline at end of file
+ - npm run lint
+ - npm test
+ - npm run build
\ No newline at end of file
diff --git a/devServer.js b/devServer.js
index 4ef236a0..1e65a9ff 100644
--- a/devServer.js
+++ b/devServer.js
@@ -1,27 +1,15 @@
-var path = require('path');
-var express = require('express');
var webpack = require('webpack');
+var WebpackDevServer = require("webpack-dev-server");
var config = require('./webpack.config.dev');
-var app = express();
-var compiler = webpack(config);
-
-app.use(require('webpack-dev-middleware')(compiler, {
- noInfo: true,
- publicPath: config.output.publicPath
-}));
-
-app.use(require('webpack-hot-middleware')(compiler));
-
-app.get('*', function(req, res) {
- res.sendFile(path.join(__dirname, 'src/index.html'));
-});
-
-app.listen(3300, 'localhost', function(err) {
+new WebpackDevServer(webpack(config), {
+ publicPath: config.output.publicPath,
+ hot: true,
+ historyApiFallback: true
+}).listen(3300, "0.0.0.0", function (err, result) {
if (err) {
console.log(err);
- return;
}
- console.log('Listening at http://localhost:3000');
-});
\ No newline at end of file
+ console.log("Listening at localhost:3300");
+});
diff --git a/nginx.conf b/nginx.conf
new file mode 100644
index 00000000..75916e93
--- /dev/null
+++ b/nginx.conf
@@ -0,0 +1,59 @@
+worker_processes 2;
+error_log ./nginx.error.log;
+worker_rlimit_nofile 8192;
+pid nginx.pid;
+
+events {
+ worker_connections 1024;
+ multi_accept on;
+}
+
+http {
+
+ access_log off;
+ charset UTF-8;
+
+ types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml rss;
+ image/gif gif;
+ image/jpeg jpeg jpg;
+ application/x-javascript js;
+ text/plain txt;
+ image/png png;
+ image/svg+xml svg;
+ image/x-icon ico;
+ application/pdf pdf;
+ text/cache-manifest appcache;
+ }
+
+ gzip on;
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_buffers 16 8k;
+ gzip_http_version 1.1;
+ gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
+
+ server {
+ listen 3300;
+ server_name localhost;
+ root ./build/;
+ index index.html;
+
+ location ~* \.(?:manifest|appcache|html?|xml|json|css|js|map|jpg|jpeg|gif|png|ico|svg|eot|ttf|woff|woff2)$ {
+ expires -1;
+ add_header Access-Control-Allow-Origin *;
+ add_header Access-Control-Allow-Credentials true;
+ add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
+ add_header Access-Control-Allow-Headers 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
+ access_log off;
+ }
+
+ location / {
+ try_files $uri $uri/ /index.html =404;
+ }
+ }
+}
+
diff --git a/package.json b/package.json
index 9ac152b2..78966574 100644
--- a/package.json
+++ b/package.json
@@ -12,12 +12,16 @@
"license": "MIT",
"scripts": {
"clean": "rimraf build",
- "build:prod": "NODE_ENV=production webpack --config webpack.config.prod.js",
- "build": "npm run clean && npm run build:prod",
"start": "node devServer.js",
- "lint": "eslint src"
+ "lint": "eslint ./src",
+ "prod-serve": "nginx -p $(pwd) -c nginx.conf",
+ "prod-stop": "kill -QUIT $(cat nginx.pid)",
+ "build": "npm run clean && NODE_ENV=production webpack -d -p --config webpack.config.prod.js",
+ "rsync": "rsync -e 'ssh -i $CORIOLIS_PEM' -a --delete build/ $CORIOLIS_USER@$CORIOLIS_HOST:~/www",
+ "deploy": "npm run lint && npm run build && npm run rsync"
},
"devDependencies": {
+ "appcache-webpack-plugin": "^1.2.1",
"babel-core": "^5.4.7",
"babel-eslint": "^3.1.9",
"babel-loader": "^5.1.2",
@@ -27,11 +31,10 @@
"eslint-plugin-react": "^2.3.0",
"express": "^4.13.3",
"file-loader": "^0.8.4",
- "install": "^0.3.0",
+ "html-webpack-plugin": "^1.7.0",
"json-loader": "^0.5.3",
"less": "^2.5.3",
"less-loader": "^2.2.1",
- "npm": "^3.4.0",
"react-transform-catch-errors": "^1.0.0",
"react-transform-hmr": "^1.0.0",
"redbox-react": "^1.0.1",
@@ -39,12 +42,12 @@
"style-loader": "^0.13.0",
"url-loader": "^0.5.6",
"webpack": "^1.9.6",
- "webpack-dev-middleware": "^1.2.0",
- "webpack-hot-middleware": "^2.0.0"
+ "webpack-dev-server": "^1.14.0"
},
"dependencies": {
"classnames": "^2.2.0",
"d3": "^3.5.9",
+ "extract-text-webpack-plugin": "^0.9.1",
"fbemitter": "^2.0.0",
"lz-string": "^1.4.4",
"react": "^0.14.2",
diff --git a/src/app/components/AvailableModulesMenu.jsx b/src/app/components/AvailableModulesMenu.jsx
index 95bb4bc5..68fc3312 100644
--- a/src/app/components/AvailableModulesMenu.jsx
+++ b/src/app/components/AvailableModulesMenu.jsx
@@ -24,7 +24,6 @@ export default class AvailableModulesMenu extends TranslatedComponent {
for (let i = 0; i < modules.length; i++) {
let m = modules[i];
- let classRating = m.class + m.rating;
let mount = null;
let classes = cn(m.name ? 'lc' : 'c', {
active: mountedModule && mountedModule.id === m.id,
@@ -87,7 +86,6 @@ export default class AvailableModulesMenu extends TranslatedComponent {
list.push(
{translate('empty')}
);
for (let g in modules) {
let grp = modules[g];
- let grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component
list.push({translate(g)}
);
list.push(buildGroup(g, modules[g]));
}
diff --git a/src/app/components/StandardSlotSection.jsx b/src/app/components/StandardSlotSection.jsx
index 1902c3b8..227c2865 100644
--- a/src/app/components/StandardSlotSection.jsx
+++ b/src/app/components/StandardSlotSection.jsx
@@ -36,7 +36,7 @@ export default class StandardSlotSection extends SlotSection {
}
_getSlots() {
- let { formats, translate, units } = this.context.language;
+ let { translate, units } = this.context.language;
let slots = new Array(8);
let open = this._openMenu;
let select = this._selectModule;
@@ -45,7 +45,6 @@ export default class StandardSlotSection extends SlotSection {
let st = ship.standard;
let avail = ship.getAvailableModules().standard;
let bulkheads = ship.bulkheads;
- let bulkheadIndex = bulkheads.id;
let currentMenu = this.state.currentMenu;
slots[0] = (
@@ -61,11 +60,11 @@ export default class StandardSlotSection extends SlotSection {
{currentMenu === bulkheads &&
e.stopPropagation() }>
- {translate('Lightweight Alloy')}
- {translate('Reinforced Alloy')}
- {translate('Military Grade Composite')}
- {translate('Mirrored Surface Composite')}
- {translate('Reactive Surface Composite')}
+ {translate('Lightweight Alloy')}
+ {translate('Reinforced Alloy')}
+ {translate('Military Grade Composite')}
+ {translate('Mirrored Surface Composite')}
+ {translate('Reactive Surface Composite')}
}
diff --git a/src/app/pages/ShipyardPage.jsx b/src/app/pages/ShipyardPage.jsx
index 8cfab978..aede2f8f 100755
--- a/src/app/pages/ShipyardPage.jsx
+++ b/src/app/pages/ShipyardPage.jsx
@@ -136,6 +136,7 @@ export default class ShipyardPage extends Page {
}
render() {
+ let translate = this.context.language.translate;
let shipSummaries = this.shipSummaries;
let shipPredicate = this.state.shipPredicate;
let shipPredicateIndex = this.state.shipPredicateIndex;
@@ -170,11 +171,6 @@ export default class ShipyardPage extends Page {
}
});
- let formats = this.context.language.formats;
- let fInt = formats.int;
- let fRound = formats.round;
- let translate = this.context.language.translate;
-
for (let s of shipSummaries) {
shipRows.push(s.rowElement);
}
diff --git a/src/index.html b/src/index.html
index 6774acfd..f08a1ca9 100755
--- a/src/index.html
+++ b/src/index.html
@@ -1,76 +1,77 @@
-
-
- Coriolis
-
-
-
-
-
-
-
+
+
+ Coriolis
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+ ga('create', '{%= o.htmlWebpackPlugin.options.uaTracking %}', 'auto');
+ var GAPI_KEY = '{%= o.htmlWebpackPlugin.options.gapiKey %}';
+
+ {% } %}
+
diff --git a/webpack.config.dev.js b/webpack.config.dev.js
index 875b0c6a..b629a9ac 100644
--- a/webpack.config.dev.js
+++ b/webpack.config.dev.js
@@ -1,10 +1,13 @@
var path = require('path');
var webpack = require('webpack');
+var pkgJson = require('./package');
+var HtmlWebpackPlugin = require("html-webpack-plugin");
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
devtool: 'eval',
entry: {
- app: [ 'webpack-hot-middleware/client', './src/app/index' ],
+ app: [ 'webpack-dev-server/client?http://localhost:3300', 'webpack/hot/only-dev-server', path.join(__dirname, "src/app/index.js") ],
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
},
resolve: {
@@ -12,7 +15,7 @@ module.exports = {
extensions: ['', '.js', '.jsx', '.json', '.less'],
alias: {
'coriolis-data': path.resolve(__dirname, 'node_modules/coriolis-data')
- },
+ }
},
output: {
path: path.join(__dirname, 'build'),
@@ -21,20 +24,30 @@ module.exports = {
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('lib', 'lib.js'),
+ new HtmlWebpackPlugin({
+ inject: false,
+ template: path.join(__dirname, "src/index.html"),
+ cdn: '',
+ version: pkgJson.version
+ }),
+ new ExtractTextPlugin('app.css', {
+ allChunks: true
+ }),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [
- { test: /\.css$/, loader: 'style-loader!css-loader' },
+ { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader','css-loader') },
+ { test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader','css-loader!less-loader') },
{ test: /\.(js|jsx)$/, loaders: [ 'babel' ], include: path.join(__dirname, 'src') },
- { test: /\.less$/, loader: 'style!css!less' },
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' },
- { test: /\.(png|jpg|jpeg|gif)?$/, loader: 'file' },
+ { test: /\.(png|jpg|jpeg|gif|ico)$/, loader: 'file-loader?name=/images/[name].[ext]' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' },
+ { test: /\.xml$/, loader: 'file' },
{ test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' }
]
}
diff --git a/webpack.config.prod.js b/webpack.config.prod.js
index 393a809c..0e770363 100644
--- a/webpack.config.prod.js
+++ b/webpack.config.prod.js
@@ -1,5 +1,10 @@
var path = require('path');
+var exec = require('child_process').exec;
var webpack = require('webpack');
+var pkgJson = require('./package');
+var HtmlWebpackPlugin = require("html-webpack-plugin");
+var ExtractTextPlugin = require("extract-text-webpack-plugin");
+var AppCachePlugin = require('appcache-webpack-plugin');
var node_modules_dir = path.resolve(__dirname, 'node_modules');
var d3Path = path.resolve(node_modules_dir, 'd3/d3.min.js');
@@ -7,8 +12,20 @@ var reactPath = path.resolve(node_modules_dir, 'react/dist/react.min.js');
var reactDomPath = path.resolve(node_modules_dir, 'react-dom/dist/react-dom.min.js');
var lzStringPath = path.resolve(node_modules_dir, 'lz-string/libs/lz-string.min.js');
+function CopyDirPlugin(source, destination) {
+ this.source = source;
+ this.destination = destination;
+}
+CopyDirPlugin.prototype.apply = function(compiler) {
+ compiler.plugin('done', function() {
+ console.log(compiler.outputPath, this.destination);
+ exec('cp -r ' + this.source + ' ' + path.join(compiler.outputPath, this.destination));
+ }.bind(this));
+};
+
+
module.exports = {
- entry: {
+ entry: {
app: path.resolve(__dirname, 'src/app/index'),
lib: ['d3', 'react', 'react-dom', 'classnames', 'fbemitter', 'lz-string']
},
@@ -24,34 +41,60 @@ module.exports = {
},
output: {
path: path.join(__dirname, 'build'),
- filename: 'app.js'
+ filename: '[name].[hash:6].js',
+ publicPath: '//cdn.coriolis.io/'
},
plugins: [
- new webpack.optimize.CommonsChunkPlugin('lib', 'lib.js'),
+ new webpack.optimize.UglifyJsPlugin({
+ mangle: {
+ except: []
+ },
+ 'screw-ie8': true
+ }),
+ new webpack.optimize.CommonsChunkPlugin('lib', 'lib.[hash:6].js'),
new HtmlWebpackPlugin({
- inject: true,
- template: path.join(__dirname, "src/public/index.html"),
- favicon: path.join(__dirname, "src/assets/images/favicon.png"),
+ inject: false,
+ appCache: 'coriolis.appcache'
minify: {
- removeComments: true,
+ collapseBooleanAttributes: true,
collapseWhitespace: true,
- minifyJS: true
- }
+ removeAttributeQuotes: true,
+ removeComments: true,
+ removeEmptyAttributes: true,
+ removeRedundantAttributes: true,
+ removeScriptTypeAttributes: true,
+ removeStyleLinkTypeAttributes: true
+ },
+ template: path.join(__dirname, "src/index.html"),
+ uaTracking: process.env.CORIOLIS_UA_TRACKING || '',
+ gapiKey: process.env.CORIOLIS_GAPI_KEY || '',
+ version: pkgJson.version
+ }),
+ new ExtractTextPlugin('[contenthash:6].css', {
+ allChunks: true
+ }),
+ new CopyDirPlugin(path.join(__dirname, 'src/schemas'), 'schemas'),
+ new AppCachePlugin({
+ network: ['*'],
+ settings: ['prefer-online'],
+ exclude: ['index.html', /.*\.map$/],
+ output: 'coriolis.appcache'
})
],
module: {
- noParse: [d3Path, reactPath, reactDomPath, lzStringPath],
+ noParse: [d3Path, reactPath, lzStringPath],
loaders: [
- { test: /\.css$/, loader: 'style-loader!css-loader' },
- { test: /\.(js|jsx)$/, loader: 'babel', include: path.join(__dirname, 'src') },
- { test: /\.less$/, loader: 'style!css!less' },
+ { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader','css-loader') },
+ { test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader','css-loader!less-loader') },
+ { test: /\.(js|jsx)$/, loaders: [ 'babel' ], include: path.join(__dirname, 'src') },
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff' },
{ test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' },
- { test: /\.(png|jpg|jpeg|gif)?$/, loader: 'file' },
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' },
- { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' }
+ { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' },
+ { test: /\.xml$/, loader: 'file' },
+ { test: /\.(png|jpg|jpeg|gif|ico)$/, loader: 'file-loader?name=/images/[name].[hash:6].[ext]' }
]
}
};