* Prod build v1

* Work on prod

* More work on prod

* fix merge

* Fix tests to use node config

* update message

* Fixes and buyan logs to file

* Production run electron

* Fix change detection in settings

* Remove show true

* fixes

* Remove console.log

* update readme
This commit is contained in:
Timothee Guerin 2017-03-22 08:22:30 -07:00 коммит произвёл GitHub
Родитель 8d36ded95c
Коммит 067a7d1018
20 изменённых файлов: 363 добавлений и 55 удалений

Просмотреть файл

@ -1,7 +1,7 @@
# BatchLabs
[![Build Status](https://travis-ci.org/Azure/BatchLabs.svg?branch=master)](https://travis-ci.org/Azure/BatchLabs)
**Note: this is in early development and there is no production build available.**
**Note: BatchLabs is in beta. We don't provide any installer/packaged binaries as of now. You will need to build this app yourself.**
## Getting started
**Install node.js version `6.9` or greater.**
@ -18,6 +18,10 @@ npm install -g gulp (Optional)
#### 3. Build and run the application
```
npm run build:prod
npm run electron:prod
# To debug errors
npm run build
npm run electron
```

Просмотреть файл

@ -10,8 +10,9 @@ import "hammerjs";
import "./utils/extensions";
import "font-awesome/css/font-awesome.min.css";
import "roboto-fontface/css/roboto/sass/roboto-fontface.scss";
import "roboto-fontface/css/roboto/roboto-fontface.css";
import "./assets/styles/main.scss";
import "./environment";
const platform = platformBrowserDynamic();

Просмотреть файл

@ -11,7 +11,7 @@ import { Node } from "app/models";
selector: "bl-node-list-display",
templateUrl: "node-list-display.html",
})
export class NodeListDisplayComponent extends ListOrTableBase {
export class NodeListDisplayComponent extends ListOrTableBase {
@Input()
public quickList: boolean;
@ -33,6 +33,10 @@ export class NodeListDisplayComponent extends ListOrTableBase {
@ViewChild(TableComponent)
public table: TableComponent;
constructor() {
super();
}
public isErrorState(node: any) {
if (node.state === "startTaskFailed") {
return true;

Просмотреть файл

@ -32,6 +32,10 @@ export class SubTaskDisplayListComponent extends SelectableList {
@ViewChild(QuickListComponent)
public list: QuickListComponent;
constructor() {
super();
}
public taskStatus(task: SubtaskInformation): QuickListItemStatus {
if (task.state === TaskState.completed && task.exitCode !== 0) {
return QuickListItemStatus.warning;

9
app/environment.ts Normal file
Просмотреть файл

@ -0,0 +1,9 @@
import {
enableProdMode,
} from "@angular/core";
import { Environment } from "app/utils/constants";
if (ENV === Environment.prod) {
enableProdMode();
}

Просмотреть файл

@ -1,4 +1,4 @@
import { Injectable } from "@angular/core";
import { Injectable, NgZone } from "@angular/core";
import * as storage from "electron-json-storage";
import { BehaviorSubject, Observable } from "rxjs";
@ -20,7 +20,7 @@ export class SettingsService {
private _filename = "settings";
private _keybindingsFilename = "keybindings";
constructor() {
constructor(private zone: NgZone) {
this.settingsObs = this._settingsSubject.asObservable();
this.keybindings = this._keybindings.asObservable();
this.hasSettingsLoaded = this._hasSettingsLoaded.asObservable();
@ -38,13 +38,15 @@ export class SettingsService {
});
storage.get(this._keybindingsFilename, (error, data: KeyBindings[]) => {
// If the file has never been init create it
if (!Array.isArray(data)) {
storage.set(this._keybindingsFilename, [], () => {
log.error("Error saving the initial keybinding settings.");
});
}
this._keybindings.next(defaultKeybindings.concat(data));
this.zone.run(() => {
// If the file has never been init create it
if (!Array.isArray(data)) {
storage.set(this._keybindingsFilename, [], () => {
log.error("Error saving the initial keybinding settings.");
});
}
this._keybindings.next(defaultKeybindings.concat(data));
});
});
}
}

Просмотреть файл

@ -112,6 +112,12 @@ export const ODataFields = {
taskExitCode: "executionInfo/exitCode",
};
export const Environment = {
prod: "production" as Environment,
dev: "developement" as Environment,
test: "test" as Environment,
};
export const ServiceUrl = {
arm: "https://management.azure.com",
};

Просмотреть файл

@ -1,15 +1,23 @@
import * as path from "path";
/**
* Root of BatchLabs(This is relative to where this file is when in the build folder)
*/
const root = path.join(__dirname, "../..");
const urls = {
main: {
dev: "http://localhost:3178/index.html",
prod: `file://${__dirname}/../../build/index.html`,
},
splash: {
dev: `file://${__dirname}/../../client/splash-screen/splash-screen.html`,
prod: `file://${__dirname}/../../build/client/splash-screen/splash-screen.html`,
dev: `file://${root}/client/splash-screen/splash-screen.html`,
prod: `file://${root}/build/client/splash-screen/splash-screen.html`,
},
icon: __dirname + "/../assets/images/labs.ico",
};
export const Constants = {
root,
urls,
};

Просмотреть файл

@ -1,4 +1,35 @@
import * as bunyan from "bunyan";
import * as mkdirp from "mkdirp";
import * as path from "path";
export const logger = bunyan.createLogger({ name: "BatchExplorer Main", level: "debug" });
export const renderLogger = bunyan.createLogger({ name: "BatchExplorer Render", level: "debug" });
import { Constants } from "../client-constants";
mkdirp.sync(path.join(Constants.root, "logs"));
export const logger = bunyan.createLogger({
name: "BatchExplorer Main",
level: "debug",
streams: [
{ stream: process.stderr },
{
type: "rotating-file",
path: path.join(Constants.root, "logs/client.log"),
period: "1d", // daily rotation
count: 3, // keep 3 back copies
},
],
});
export const renderLogger = bunyan.createLogger({
name: "BatchExplorer Render",
level: "debug",
streams: [
{ stream: process.stderr },
{
type: "rotating-file",
path: path.join(Constants.root, "logs/app.log"),
period: "1d", // daily rotation
count: 3, // keep 3 back copies
},
],
});

Просмотреть файл

@ -1,6 +1,3 @@
// tslint:disable-next-line
/// <reference path="../definitions/index.d.ts"/>
import { BrowserWindow, app, protocol } from "electron";
import * as path from "path";
@ -60,7 +57,9 @@ function createWindow() {
mainWindow.splashScreen = splashScreen;
// Open the DevTools.
mainWindow.webContents.openDevTools();
if (process.env.NODE_ENV !== "production") {
mainWindow.webContents.openDevTools();
}
// Clear out the main window when the app is closed
mainWindow.on("closed", () => {

Просмотреть файл

@ -29,16 +29,6 @@ const baseConfig = {
loaders: ["awesome-typescript-loader", "angular2-template-loader"],
exclude: [/node_modules/],
},
{
test: /\.scss$/,
loader: "style-loader!css-loader!sass-loader",
exclude: [helpers.root("app", "components")]
},
{
test: /\.scss$/,
use: ["to-string-loader", "css-loader", "sass-loader"],
include: [helpers.root("app", "components")]
},
{
test: /\.html$/,
loader: "raw-loader",
@ -49,10 +39,6 @@ const baseConfig = {
loader: "raw-loader",
exclude: [],
},
{
test: /node_modules.*\.css$/,
loader: "style-loader!css-loader",
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",

Просмотреть файл

@ -3,12 +3,14 @@ const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const helpers = require("./helpers");
const DefinePlugin = require("webpack/lib/DefinePlugin");
const DllBundlesPlugin = require("webpack-dll-bundles-plugin").DllBundlesPlugin;
const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin");
const webpackMergeDll = merge.strategy({ plugins: "replace" });
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ENV = "development";
const host = "localhost";
const port = process.env.PORT || 3178;
@ -25,7 +27,28 @@ module.exports = merge(config, {
sourceMapFilename: "[name].js.map",
chunkFilename: "[id].chunk.js",
},
module: {
rules: [
{
test: /\.scss$/,
loader: "style-loader!css-loader!sass-loader",
exclude: [helpers.root("app", "components")]
},
{
test: /\.scss$/,
use: ["to-string-loader", "css-loader", "sass-loader"],
include: [helpers.root("app", "components")]
},
{
test: /node_modules.*\.css$/,
loader: "style-loader!css-loader",
}
],
},
plugins: [
new DefinePlugin({
"ENV": JSON.stringify(ENV),
}),
new DllBundlesPlugin({
bundles: {
polyfills: [

Просмотреть файл

@ -1,23 +1,174 @@
const config = require("./webpack.config.base");
const helpers = require("./helpers");
const path = require("path");
const DefinePlugin = require("webpack/lib/DefinePlugin");
const webpack = require("webpack");
var merge = require("webpack-merge");
var failPlugin = require("webpack-fail-plugin");
const LoaderOptionsPlugin = require("webpack/lib/LoaderOptionsPlugin");
const merge = require("webpack-merge");
const OptimizeJsPlugin = require("optimize-js-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ENV = "production";
const UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = merge(config, {
devtool: "cheap-module-source-map",
debug: true,
devServer: { host, port },
devtool: "source-map",
output: {
path: path.join(__dirname, "../build/"),
filename: "[name].js",
sourceMapFilename: "[name].js.map",
chunkFilename: "[id].chunk.js",
/**
* The output directory as absolute path (required).
*
* @see http://webpack.github.io/docs/configuration.html#output-path
*/
path: helpers.root("build"),
/**
* Specifies the name of each output file on disk.
* IMPORTANT: You must not specify an absolute path here!
*
* @see http://webpack.github.io/docs/configuration.html#output-filename
*/
filename: "[name].[chunkhash].bundle.js",
/**
* The filename of the SourceMaps for the JavaScript files.
* They are inside the output.path directory.
*
* @see http://webpack.github.io/docs/configuration.html#output-sourcemapfilename
*/
sourceMapFilename: "[name].[chunkhash].bundle.map",
/**
* The filename of non-entry chunks as relative path
* inside the output.path directory.
*
* @see http://webpack.github.io/docs/configuration.html#output-chunkfilename
*/
chunkFilename: "[id].[chunkhash].chunk.js"
},
module: {
rules: [
/**
* Extract CSS files from node_modules and the assets directory to external CSS file
*/
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
}),
include: [/node_modules/, helpers.root("app", "assets", "styles")]
},
/**
* Extract and compile SCSS files from .node_modules and the assets directory to external CSS file
*/
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader!sass-loader"
}),
include: [/node_modules/, helpers.root("app", "assets", "styles")]
},
]
},
plugins: [
new CommonsChunkPlugin({ name: "polyfills", filename: "polyfills.js", minChunk: Infinity }),
failPlugin,
/**
* Webpack plugin to optimize a JavaScript file for faster initial load
* by wrapping eagerly-invoked functions.
*
* @see https://github.com/vigneshshanmugam/optimize-js-plugin
*/
new OptimizeJsPlugin({
sourceMap: false
}),
/**
* Plugin: ExtractTextPlugin
* Description: Extracts imported CSS files into external stylesheet
*
* @see https://github.com/webpack/extract-text-webpack-plugin
*/
new ExtractTextPlugin("[name].[contenthash].css"),
new DefinePlugin({
"ENV": JSON.stringify(ENV),
"process.env": {
"ENV": JSON.stringify(ENV),
"NODE_ENV": JSON.stringify(ENV),
}
}),
/**
* Plugin: UglifyJsPlugin
* Description: Minimize all JavaScript output of chunks.
* Loaders are switched into minimizing mode.
*
* See: https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
*/
// NOTE: To debug prod builds uncomment //debug lines and comment //prod lines
new UglifyJsPlugin({
beautify: true, // debug
// mangle: false, //debug
// compress: {
// screw_ie8: true,
// keep_fnames: true,
// drop_debugger: false,
// dead_code: false,
// unused: false
// }, // debug
// output: {
// comments: true
// }, // Debug
// beautify: false, //prod
output: {
comments: false
}, //prod
mangle: {
screw_ie8: true,
keep_fnames: true,
}, //prod
compress: {
screw_ie8: true,
warnings: false,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true,
negate_iife: false // we need this for lazy v8
},
}),
new LoaderOptionsPlugin({
minimize: true,
debug: false,
options: {
/**
* Html loader advanced options
*
* See: https://github.com/webpack/html-loader#advanced-options
*/
// TODO: Need to workaround Angular 2's html syntax => #id [bind] (event) *ngFor
htmlLoader: {
minimize: true,
removeAttributeQuotes: false,
caseSensitive: true,
customAttrSurround: [
[/#/, /(?:)/],
[/\*/, /(?:)/],
[/\[?\(?/, /(?:)/]
],
customAttrAssign: [/\)?\]?=/]
},
}
}),
],
});

Просмотреть файл

@ -1,12 +1,31 @@
const DefinePlugin = require("webpack/lib/DefinePlugin");
const config = require("./webpack.config.base");
const webpack = require("webpack");
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
const ENV = "test";
// We need to remove the app entry from the default config as this is defined in karma
delete config.entry;
config.devtool = "inline-source-map";
// Karma webpack doesn't support CommonChunkPlugin yet https://github.com/webpack-contrib/karma-webpack/issues/24
config.plugins = config.plugins.filter(x => !(x instanceof CommonsChunkPlugin));
config.plugins = config.plugins.filter(x => !(x instanceof CommonsChunkPlugin)).concat([
new DefinePlugin({
"ENV": JSON.stringify(ENV),
}),
]);
config.module.rules = config.module.rules.concat(
[
{
test: /\.scss$/,
loader: "style-loader!css-loader!sass-loader",
},
{
test: /node_modules.*\.css$/,
loader: "style-loader!css-loader",
},
]
);
module.exports = config;

5
definitions/index.d.ts поставляемый
Просмотреть файл

@ -25,5 +25,10 @@ declare module "mousetrap" {
function reset();
}
declare type Environment = "production" | "development" | "test";
// Gloval variables set by webpack
declare const ENV: Environment;
type StringMap<V> = { [key: string]: V };

Просмотреть файл

@ -3,7 +3,7 @@ const childProcess = require("child_process");
const gulp = require("gulp");
const sourcemaps = require("gulp-sourcemaps");
const ts = require("gulp-typescript");
const tsProject = ts.createProject("tsconfig.json");
const tsProject = ts.createProject("tsconfig.node.json");
const merge = require("merge2");
const path = require("path");

Просмотреть файл

@ -8,7 +8,8 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "npm run test-client && npm run test-browser",
"clean": "rimraf build/* dll/*",
"test": "npm run test-client && npm run test-app",
"test-app": "karma start",
"test-app:mem": "cross-env DEBUG_MEM=1 npm run test-app",
"test-app-watch": "karma start --auto-watch --no-single-run",
@ -19,9 +20,11 @@
"test-client-watch": "npm run test-client -- --watch",
"build-node-ts": "gulp build-node-ts",
"build-app": "webpack --progress --profile --colors --display-error-details --display-cached",
"build": "npm run build-node-ts && npm run build-app",
"build": "npm run clean && npm run build-node-ts && npm run build-app",
"build:prod": "cross-env NODE_ENV=production npm run build",
"watch": "webpack --watch --progress --profile --colors --display-error-details --display-cached",
"electron": "electron build/client/main.js",
"electron:prod": "cross-env NODE_ENV=production electron build/client/main.js",
"dev": "concurrently --kill-others \"npm run dev-server\" \"npm run dev-electron\"",
"dev-electron": "cross-env HOT=1 electron build/client/main.js",
"dev-server": "node_modules/.bin/webpack-dev-server --hot --inline --colors --content-base app/",
@ -75,8 +78,10 @@
"karma-webpack": "^2.0.1",
"merge2": "^1.0.2",
"node-sass": "~4.5.0",
"optimize-js-plugin": "0.0.4",
"raw-loader": "^0.5.1",
"sass-loader": "~6.0.2",
"rimraf": "^2.5.4",
"style-loader": "^0.13.1",
"stylelint": "~7.9.0",
"to-string-loader": "^1.1.5",

Просмотреть файл

@ -1 +1,5 @@
require("ts-node/register");
const path = require("path");
require("ts-node").register({
project: path.join(__dirname, "../../tsconfig.node.json"),
});

Просмотреть файл

@ -1,11 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es6", "es2016", "dom"],
"target": "es5", // Uglify doesn't support es6 yet so we can't have the prod build use es6 https://github.com/mishoo/UglifyJS2/issues/448
"module": "es2015",
"lib": [
"es6",
"es2016",
"dom"
],
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"noImplicitAny": false,
"moduleResolution": "node",
@ -42,5 +47,9 @@
"./client/**/*.ts",
"./app/**/*.ts",
"./test/**/*.ts"
]
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useWebpackText": true
}
}

38
tsconfig.node.json Normal file
Просмотреть файл

@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"lib": [
"es6",
"es2016",
"dom"
],
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"noImplicitAny": false,
"moduleResolution": "node",
"listEmittedFiles": true, // debug option
"listFiles": true, // debug option
"outDir": "build/client",
"types": [
"node",
"electron",
"jasmine",
"hammerjs",
"moment-duration-format"
],
"typeRoots": [
"./node_modules/@types"
]
},
"files": [
"./definitions/index.d.ts"
],
// This is not actually used for building but to let the editor know what files use this config
"include": [
"./client/**/*.ts"
]
}