tutorials: support arbitrary hosting directory (#1097)

* Include all bundles in artifact

change bundle registry such that all bundles are immediately registered,
but must be specifically enabled.  A default registry class enables bundles
that make sense for demonstration purposes.

Added methods to the registry to allow enabling and disabling of bundles
without having to load additional files.

* support alternate asset/worker paths

Change the gulp glob for assets to copy over a more minimal
set of files-- only css, fonts, and images.  Results in a
smaller distributable archive.

Update stylesheet loader to use a constant for the assets path.

This can be customized at run time via MCT.setAssetPath() to
allow MCT to be hosted in various locations.

Update worker loader to support loading workers from blobs to
support packaging as standalone file.

* Load templates via requirejs

* [gulp] lazy-require where reasonable

Require things right before starting tasks to reduce gulp start up time.

* document setAssetPath
This commit is contained in:
Pete Richards
2016-07-25 14:38:44 -07:00
committed by GitHub
parent 719f9f45e8
commit 1147f3aa47
13 changed files with 222 additions and 81 deletions

6
API.md
View File

@ -106,3 +106,9 @@ Install a plugin in MCT. Must be called before calling `run`. Plugins are func
For an example of writing a plugin, check out [plugin-example.html](plugin-example.html) For an example of writing a plugin, check out [plugin-example.html](plugin-example.html)
### `MCT.setAssetPath(path)`
Sets the path (absolute or relative) at which the Open MCT static files are being hosted. The default value is '.'.
Note that this API is transitional and will be removed in a future version.

View File

@ -36,7 +36,7 @@ define([
legacyRegistry legacyRegistry
) { ) {
"use strict"; "use strict";
legacyRegistry.register("example/notifications", { legacyRegistry.register("example/msl-adapter", {
"name" : "Mars Science Laboratory Data Adapter", "name" : "Mars Science Laboratory Data Adapter",
"extensions" : { "extensions" : {
"types": [ "types": [

View File

@ -21,36 +21,24 @@
*****************************************************************************/ *****************************************************************************/
/*global require,__dirname*/ /*global require,__dirname*/
var gulp = require('gulp'), var gulp = require('gulp'),
requirejsOptimize = require('gulp-requirejs-optimize'),
sourcemaps = require('gulp-sourcemaps'), sourcemaps = require('gulp-sourcemaps'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
bourbon = require('node-bourbon'),
jshint = require('gulp-jshint'),
jscs = require('gulp-jscs'),
replace = require('gulp-replace-task'),
karma = require('karma'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
git = require('git-rev-sync'), git = require('git-rev-sync'),
moment = require('moment'), moment = require('moment'),
merge = require('merge-stream'),
project = require('./package.json'), project = require('./package.json'),
_ = require('lodash'), _ = require('lodash'),
paths = { paths = {
main: 'main.js', main: 'main.js',
dist: 'dist', dist: 'dist',
assets: 'dist/assets',
scss: ['./platform/**/*.scss', './example/**/*.scss'], scss: ['./platform/**/*.scss', './example/**/*.scss'],
assets: [
'./{example,platform}/**/*.{css,css.map,png,svg,ico,woff,eot,ttf}'
],
scripts: [ 'main.js', 'platform/**/*.js', 'src/**/*.js' ], scripts: [ 'main.js', 'platform/**/*.js', 'src/**/*.js' ],
specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ], specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ],
static: [
'index.html',
'platform/**/*',
'example/**/*',
'bower_components/**/*'
]
}, },
options = { options = {
requirejsOptimize: { requirejsOptimize: {
@ -68,7 +56,6 @@ var gulp = require('gulp'),
singleRun: true singleRun: true
}, },
sass: { sass: {
includePaths: bourbon.includePaths,
sourceComments: true sourceComments: true
}, },
replace: { replace: {
@ -82,6 +69,8 @@ var gulp = require('gulp'),
}; };
gulp.task('scripts', function () { gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
var replace = require('gulp-replace-task');
return gulp.src(paths.main) return gulp.src(paths.main)
.pipe(sourcemaps.init()) .pipe(sourcemaps.init())
.pipe(requirejsOptimize(options.requirejsOptimize)) .pipe(requirejsOptimize(options.requirejsOptimize))
@ -91,10 +80,16 @@ gulp.task('scripts', function () {
}); });
gulp.task('test', function (done) { gulp.task('test', function (done) {
var karma = require('karma');
new karma.Server(options.karma, done).start(); new karma.Server(options.karma, done).start();
}); });
gulp.task('stylesheets', function () { gulp.task('stylesheets', function () {
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var bourbon = require('node-bourbon');
options.sass.includePaths = bourbon.includePaths;
return gulp.src(paths.scss, {base: '.'}) return gulp.src(paths.scss, {base: '.'})
.pipe(sourcemaps.init()) .pipe(sourcemaps.init())
.pipe(sass(options.sass).on('error', sass.logError)) .pipe(sass(options.sass).on('error', sass.logError))
@ -108,6 +103,9 @@ gulp.task('stylesheets', function () {
}); });
gulp.task('lint', function () { gulp.task('lint', function () {
var jshint = require('gulp-jshint');
var merge = require('merge-stream');
var nonspecs = paths.specs.map(function (glob) { var nonspecs = paths.specs.map(function (glob) {
return "!" + glob; return "!" + glob;
}), }),
@ -122,6 +120,8 @@ gulp.task('lint', function () {
}); });
gulp.task('checkstyle', function () { gulp.task('checkstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts) return gulp.src(paths.scripts)
.pipe(jscs()) .pipe(jscs())
.pipe(jscs.reporter()) .pipe(jscs.reporter())
@ -129,18 +129,20 @@ gulp.task('checkstyle', function () {
}); });
gulp.task('fixstyle', function () { gulp.task('fixstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts, { base: '.' }) return gulp.src(paths.scripts, { base: '.' })
.pipe(jscs({ fix: true })) .pipe(jscs({ fix: true }))
.pipe(gulp.dest('.')); .pipe(gulp.dest('.'));
}); });
gulp.task('static', ['stylesheets'], function () { gulp.task('assets', ['stylesheets'], function () {
return gulp.src(paths.static, { base: '.' }) return gulp.src(paths.assets)
.pipe(gulp.dest(paths.dist)); .pipe(gulp.dest(paths.dist));
}); });
gulp.task('watch', function () { gulp.task('watch', function () {
gulp.watch(paths.scss, ['stylesheets']); return gulp.watch(paths.scss, ['stylesheets', 'assets']);
}); });
gulp.task('serve', function () { gulp.task('serve', function () {
@ -148,9 +150,9 @@ gulp.task('serve', function () {
var app = require('./app.js'); var app = require('./app.js');
}); });
gulp.task('develop', ['serve', 'stylesheets', 'watch']); gulp.task('develop', ['serve', 'install', 'watch']);
gulp.task('install', [ 'static', 'scripts' ]); gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]); gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);

47
main.js
View File

@ -65,49 +65,12 @@ requirejs.config({
define([ define([
'./platform/framework/src/Main', './platform/framework/src/Main',
'legacyRegistry', './src/defaultRegistry',
'./src/MCT', './src/MCT'
], function (Main, defaultRegistry, MCT) {
'./src/adapter/bundle',
'./platform/framework/bundle',
'./platform/core/bundle',
'./platform/representation/bundle',
'./platform/commonUI/about/bundle',
'./platform/commonUI/browse/bundle',
'./platform/commonUI/edit/bundle',
'./platform/commonUI/dialog/bundle',
'./platform/commonUI/formats/bundle',
'./platform/commonUI/general/bundle',
'./platform/commonUI/inspect/bundle',
'./platform/commonUI/mobile/bundle',
'./platform/commonUI/themes/espresso/bundle',
'./platform/commonUI/notification/bundle',
'./platform/containment/bundle',
'./platform/execution/bundle',
'./platform/exporters/bundle',
'./platform/telemetry/bundle',
'./platform/features/clock/bundle',
'./platform/features/imagery/bundle',
'./platform/features/layout/bundle',
'./platform/features/pages/bundle',
'./platform/features/plot/bundle',
'./platform/features/timeline/bundle',
'./platform/features/table/bundle',
'./platform/forms/bundle',
'./platform/identity/bundle',
'./platform/persistence/aggregator/bundle',
'./platform/persistence/local/bundle',
'./platform/persistence/queue/bundle',
'./platform/policy/bundle',
'./platform/entanglement/bundle',
'./platform/search/bundle',
'./platform/status/bundle',
'./platform/commonUI/regions/bundle'
], function (Main, legacyRegistry, MCT) {
var mct = new MCT(); var mct = new MCT();
mct.legacyRegistry = legacyRegistry; mct.legacyRegistry = defaultRegistry;
mct.run = function (domElement) { mct.run = function (domElement) {
if (!domElement) { domElement = document.body; } if (!domElement) { domElement = document.body; }
var appDiv = document.createElement('div'); var appDiv = document.createElement('div');
@ -117,7 +80,7 @@ define([
mct.start(); mct.start();
}; };
mct.on('start', function () { mct.on('start', function () {
return new Main().run(legacyRegistry); return new Main().run(defaultRegistry);
}); });
return mct; return mct;

View File

@ -39,6 +39,7 @@ define([
"text!./res/templates/items/items.html", "text!./res/templates/items/items.html",
"text!./res/templates/browse/object-properties.html", "text!./res/templates/browse/object-properties.html",
"text!./res/templates/browse/inspector-region.html", "text!./res/templates/browse/inspector-region.html",
"text!./res/templates/view-object.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
BrowseController, BrowseController,
@ -59,6 +60,7 @@ define([
itemsTemplate, itemsTemplate,
objectPropertiesTemplate, objectPropertiesTemplate,
inspectorRegionTemplate, inspectorRegionTemplate,
viewObjectTemplate,
legacyRegistry legacyRegistry
) { ) {
@ -129,7 +131,7 @@ define([
"representations": [ "representations": [
{ {
"key": "view-object", "key": "view-object",
"templateUrl": "templates/view-object.html" "template": viewObjectTemplate
}, },
{ {
"key": "browse-object", "key": "browse-object",

View File

@ -148,7 +148,8 @@ define([
"depends": [ "depends": [
"stylesheets[]", "stylesheets[]",
"$document", "$document",
"THEME" "THEME",
"ASSETS_PATH"
] ]
}, },
{ {
@ -406,6 +407,11 @@ define([
"key": "THEME", "key": "THEME",
"value": "unspecified", "value": "unspecified",
"priority": "fallback" "priority": "fallback"
},
{
"key": "ASSETS_PATH",
"value": ".",
"priority": "fallback"
} }
], ],
"containers": [ "containers": [

View File

@ -38,7 +38,7 @@ define(
* @param $document Angular's jqLite-wrapped document element * @param $document Angular's jqLite-wrapped document element
* @param {string} activeTheme the theme in use * @param {string} activeTheme the theme in use
*/ */
function StyleSheetLoader(stylesheets, $document, activeTheme) { function StyleSheetLoader(stylesheets, $document, activeTheme, assetPath) {
var head = $document.find('head'), var head = $document.find('head'),
document = $document[0]; document = $document[0];
@ -47,6 +47,7 @@ define(
// Create a link element, and construct full path // Create a link element, and construct full path
var link = document.createElement('link'), var link = document.createElement('link'),
path = [ path = [
assetPath,
stylesheet.bundle.path, stylesheet.bundle.path,
stylesheet.bundle.resources, stylesheet.bundle.resources,
stylesheet.stylesheetUrl stylesheet.stylesheetUrl

View File

@ -42,11 +42,19 @@ define(
function addWorker(worker) { function addWorker(worker) {
var key = worker.key; var key = worker.key;
if (!workerUrls[key]) { if (!workerUrls[key]) {
workerUrls[key] = [ if (worker.scriptUrl) {
worker.bundle.path, workerUrls[key] = [
worker.bundle.sources, worker.bundle.path,
worker.scriptUrl worker.bundle.sources,
].join("/"); worker.scriptUrl
].join("/");
} else if (worker.scriptText) {
var blob = new Blob(
[worker.scriptText],
{type: 'application/javascript'}
);
workerUrls[key] = URL.createObjectURL(blob);
}
sharedWorkers[key] = worker.shared; sharedWorkers[key] = worker.shared;
} }
} }

View File

@ -27,6 +27,9 @@ define([
"./src/controllers/TableOptionsController", "./src/controllers/TableOptionsController",
'../../commonUI/regions/src/Region', '../../commonUI/regions/src/Region',
'../../commonUI/browse/src/InspectorRegion', '../../commonUI/browse/src/InspectorRegion',
"text!./res/templates/table-options-edit.html",
"text!./res/templates/rt-table.html",
"text!./res/templates/historical-table.html",
"legacyRegistry" "legacyRegistry"
], function ( ], function (
MCTTable, MCTTable,
@ -35,6 +38,9 @@ define([
TableOptionsController, TableOptionsController,
Region, Region,
InspectorRegion, InspectorRegion,
tableOptionsEditTemplate,
rtTableTemplate,
historicalTableTemplate,
legacyRegistry legacyRegistry
) { ) {
/** /**
@ -128,7 +134,7 @@ define([
"name": "Historical Table", "name": "Historical Table",
"key": "table", "key": "table",
"glyph": "\ue604", "glyph": "\ue604",
"templateUrl": "templates/historical-table.html", "template": historicalTableTemplate,
"needs": [ "needs": [
"telemetry" "telemetry"
], ],
@ -139,7 +145,7 @@ define([
"name": "Real-time Table", "name": "Real-time Table",
"key": "rt-table", "key": "rt-table",
"glyph": "\ue620", "glyph": "\ue620",
"templateUrl": "templates/rt-table.html", "template": rtTableTemplate,
"needs": [ "needs": [
"telemetry" "telemetry"
], ],
@ -157,7 +163,7 @@ define([
"representations": [ "representations": [
{ {
"key": "table-options-edit", "key": "table-options-edit",
"templateUrl": "templates/table-options-edit.html" "template": tableOptionsEditTemplate
} }
], ],
"stylesheets": [ "stylesheets": [

View File

@ -28,6 +28,7 @@ define([
"text!./res/templates/search-item.html", "text!./res/templates/search-item.html",
"text!./res/templates/search.html", "text!./res/templates/search.html",
"text!./res/templates/search-menu.html", "text!./res/templates/search-menu.html",
"text!./src/services/GenericSearchWorker.js",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
SearchController, SearchController,
@ -37,6 +38,7 @@ define([
searchItemTemplate, searchItemTemplate,
searchTemplate, searchTemplate,
searchMenuTemplate, searchMenuTemplate,
searchWorkerText,
legacyRegistry legacyRegistry
) { ) {
@ -114,7 +116,7 @@ define([
"workers": [ "workers": [
{ {
"key": "genericSearchWorker", "key": "genericSearchWorker",
"scriptUrl": "services/GenericSearchWorker.js" "scriptText": searchWorkerText
} }
] ]
} }

View File

@ -24,10 +24,27 @@ define(function () {
function BundleRegistry() { function BundleRegistry() {
this.bundles = {}; this.bundles = {};
this.knownBundles = {};
} }
BundleRegistry.prototype.register = function (path, definition) { BundleRegistry.prototype.register = function (path, definition) {
this.bundles[path] = definition; if (this.knownBundles.hasOwnProperty(path)) {
throw new Error('Cannot register bundle with duplicate path', path);
}
this.knownBundles[path] = definition;
};
BundleRegistry.prototype.enable = function (path) {
if (!this.knownBundles[path]) {
throw new Error('Unknown bundle ' + path);
}
this.bundles[path] = this.knownBundles[path];
};
BundleRegistry.prototype.disable = function (path) {
if (!this.bundles[path]) {
throw new Error('Tried to disable inactive bundle ' + path);
}
}; };
BundleRegistry.prototype.contains = function (path) { BundleRegistry.prototype.contains = function (path) {
@ -42,8 +59,14 @@ define(function () {
return Object.keys(this.bundles); return Object.keys(this.bundles);
}; };
BundleRegistry.prototype.remove = function (path) { BundleRegistry.prototype.remove = BundleRegistry.prototype.disable;
BundleRegistry.prototype.delete = function (path) {
if (!this.knownBundles[path]) {
throw new Error('Cannot remove Unknown Bundle ' + path);
}
delete this.bundles[path]; delete this.bundles[path];
delete this.knownBundles[path];
}; };
return BundleRegistry; return BundleRegistry;

View File

@ -6,7 +6,6 @@ define([
'text!./adapter/templates/edit-object-replacement.html', 'text!./adapter/templates/edit-object-replacement.html',
'./ui/Dialog', './ui/Dialog',
'./Selection', './Selection',
'./api/objects/bundle',
'./api/objects/object-utils' './api/objects/object-utils'
], function ( ], function (
EventEmitter, EventEmitter,
@ -16,7 +15,6 @@ define([
editObjectTemplate, editObjectTemplate,
Dialog, Dialog,
Selection, Selection,
objectAPIBundle,
objectUtils objectUtils
) { ) {
function MCT() { function MCT() {
@ -40,6 +38,16 @@ define([
this.legacyBundle.extensions[category].push(extension); this.legacyBundle.extensions[category].push(extension);
}; };
/**
* Set path to where assets are hosted. This should be the path to main.js.
*/
MCT.prototype.setAssetPath = function (path) {
this.legacyExtension('constants', {
key: "ASSETS_PATH",
value: path
});
};
/** /**
* Register a new type of view. * Register a new type of view.
* *
@ -123,6 +131,7 @@ define([
}); });
legacyRegistry.register('adapter', this.legacyBundle); legacyRegistry.register('adapter', this.legacyBundle);
legacyRegistry.enable('adapter');
this.emit('start'); this.emit('start');
}; };

113
src/defaultRegistry.js Normal file
View File

@ -0,0 +1,113 @@
define([
'legacyRegistry',
'../src/adapter/bundle',
'../src/api/objects/bundle',
'../example/builtins/bundle',
'../example/composite/bundle',
'../example/eventGenerator/bundle',
'../example/export/bundle',
'../example/extensions/bundle',
'../example/forms/bundle',
'../example/generator/bundle',
'../example/identity/bundle',
'../example/imagery/bundle',
'../example/mobile/bundle',
'../example/msl/bundle',
'../example/notifications/bundle',
'../example/persistence/bundle',
'../example/plotOptions/bundle',
'../example/policy/bundle',
'../example/profiling/bundle',
'../example/scratchpad/bundle',
'../example/taxonomy/bundle',
'../example/worker/bundle',
'../platform/commonUI/about/bundle',
'../platform/commonUI/browse/bundle',
'../platform/commonUI/dialog/bundle',
'../platform/commonUI/edit/bundle',
'../platform/commonUI/formats/bundle',
'../platform/commonUI/general/bundle',
'../platform/commonUI/inspect/bundle',
'../platform/commonUI/mobile/bundle',
'../platform/commonUI/notification/bundle',
'../platform/commonUI/regions/bundle',
'../platform/commonUI/themes/espresso/bundle',
'../platform/commonUI/themes/snow/bundle',
'../platform/containment/bundle',
'../platform/core/bundle',
'../platform/entanglement/bundle',
'../platform/execution/bundle',
'../platform/exporters/bundle',
'../platform/features/clock/bundle',
'../platform/features/conductor/bundle',
'../platform/features/imagery/bundle',
'../platform/features/layout/bundle',
'../platform/features/pages/bundle',
'../platform/features/plot/bundle',
'../platform/features/static-markup/bundle',
'../platform/features/table/bundle',
'../platform/features/timeline/bundle',
'../platform/forms/bundle',
'../platform/framework/bundle',
'../platform/framework/src/load/Bundle',
'../platform/identity/bundle',
'../platform/persistence/aggregator/bundle',
'../platform/persistence/couch/bundle',
'../platform/persistence/elastic/bundle',
'../platform/persistence/local/bundle',
'../platform/persistence/queue/bundle',
'../platform/policy/bundle',
'../platform/representation/bundle',
'../platform/search/bundle',
'../platform/status/bundle',
'../platform/telemetry/bundle',
], function (legacyRegistry) {
var DEFAULTS = [
'src/adapter',
'src/api/objects',
'platform/framework',
'platform/core',
'platform/representation',
'platform/commonUI/about',
'platform/commonUI/browse',
'platform/commonUI/edit',
'platform/commonUI/dialog',
'platform/commonUI/formats',
'platform/commonUI/general',
'platform/commonUI/inspect',
'platform/commonUI/mobile',
'platform/commonUI/themes/espresso',
'platform/commonUI/notification',
'platform/containment',
'platform/execution',
'platform/exporters',
'platform/telemetry',
'platform/features/clock',
'platform/features/imagery',
'platform/features/layout',
'platform/features/pages',
'platform/features/plot',
'platform/features/timeline',
'platform/features/table',
'platform/forms',
'platform/identity',
'platform/persistence/aggregator',
'platform/persistence/local',
'platform/persistence/queue',
'platform/policy',
'platform/entanglement',
'platform/search',
'platform/status',
'platform/commonUI/regions'
];
DEFAULTS.forEach(function (bundlePath) {
legacyRegistry.enable(bundlePath);
});
return legacyRegistry;
});