Merge pull request #60 from minrk/build-js

build main.min.js with r.js
This commit is contained in:
Jonathan Frederic 2015-05-23 17:39:54 -07:00
commit e41d1f0075
16 changed files with 239 additions and 31 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ docs/source/api/generated
docs/gh-pages
notebook/static/components
notebook/static/style/*.min.css*
notebook/static/*/js/main.min.js*
node_modules
*.py[co]
__pycache__

57
build-main.js Normal file
View File

@ -0,0 +1,57 @@
// build main.min.js
// spawned by gulp to allow parallelism
var rjs = require('requirejs').optimize;
var name = process.argv[2];
var rjs_config = {
name: name + '/js/main',
out: './notebook/static/' + name + '/js/main.min.js',
baseUrl: 'notebook/static',
preserveLicenseComments: false, // license comments conflict with sourcemap generation
generateSourceMaps: true,
optimize: "uglify2",
paths: {
underscore : 'components/underscore/underscore-min',
backbone : 'components/backbone/backbone-min',
jquery: 'components/jquery/jquery.min',
bootstrap: 'components/bootstrap/js/bootstrap.min',
bootstraptour: 'components/bootstrap-tour/build/js/bootstrap-tour.min',
jqueryui: 'components/jquery-ui/ui/minified/jquery-ui.min',
moment: 'components/moment/moment',
codemirror: 'components/codemirror',
termjs: 'components/term.js/src/term',
contents: 'empty:'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
bootstrap: {
deps: ["jquery"],
exports: "bootstrap"
},
bootstraptour: {
deps: ["bootstrap"],
exports: "Tour"
},
jqueryui: {
deps: ["jquery"],
exports: "$"
}
},
exclude: [
"custom/custom",
]
};
rjs(rjs_config, console.log, function (err) {
console.log("Failed to build", name, err);
process.exit(1);
});

View File

@ -1,13 +1,18 @@
var fork = require('child_process').fork;
var fs = require('fs');
var path = require('path');
var through = require('through');
var gulp = require('gulp');
var less = require('gulp-less');
var path = require('path');
var minifyCSS = require('gulp-minify-css');
var newer = require('gulp-newer');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
// now some dev nice utilities.
var livereload = require('gulp-livereload');
gulp.task('css', function () {
return gulp.src('./notebook/static/style/*.less')
.pipe(sourcemaps.init())
@ -23,9 +28,88 @@ gulp.task('css', function () {
.pipe(livereload());
});
function build_main(name, callback) {
// build main.min.js for a given application name
// run in a subprocess to allow parallel builds
// clone requirejs config
var p = fork('./build-main.js', [name]);
p.on('exit', function (code, status) {
if (code) {
callback(new Error("Build failed"));
} else {
callback();
}
});
return;
}
// build notebook-js, edit-js, etc. tasks
// which enables parallelism
var apps = ['notebook', 'tree', 'edit', 'terminal', 'auth'];
apps.map(function (name) {
gulp.task(name + '-js', function (finish) {
var s = path.join('notebook', 'static');
var src = path.join(s, name, 'js', 'main.js');
var rel_dest = path.join(name, 'js', 'main.min.js');
var dest = path.join(s, rel_dest);
var sources = [
path.join(s, name, 'js', '*.js'),
path.join(s, "base", 'js', '*.js'),
path.join(s, "auth", 'js', '*.js'),
path.join(s, "services", 'config.js'),
];
// for required_components
if (name === 'notebook') {
sources.push(path.join(s, "services", '**', '*.js'));
}
fs.readdirSync(path.join(s, 'components')).map(function (c) {
if (c !== 'MathJax') {
// skip MathJax because it has tons of files and makes everything super slow
sources.push(path.join(s, 'components', c, '**', '*.js'));
}
});
// sources is a greedy list, containing all dependencies plus some for simplicity.
gulp.src(sources, {base: s})
.pipe(newer(dest))
.pipe(through(function(file) {
// if any dependency changed, update main.min.js
console.log("A dependency has changed, updating " + rel_dest);
// pause halts the pipeline
this.pause();
build_main(name, finish);
return;
}))
.on('end', function () {
// if we get here, no dependency is newer than the target
console.log(rel_dest + " up to date");
finish();
});
});
});
gulp.task('js', apps.map(function (name) { return name + '-js'; }));
gulp.task('watch', function() {
livereload.listen();
gulp.watch('notebook/static/**/*.less', ['css']);
var s = path.join('notebook', 'static');
function alljs(name) {
return path.join(s, name, '**', '*.js');
}
var common_js = ['components', 'base', 'auth', 'services'].map(alljs);
gulp.watch(common_js, ['js']);
apps.map(function (name) {
gulp.watch([
alljs(name),
'!' + path.join(s, name, 'js', 'main.min.js'),
], [name + '-js']);
});
});

View File

@ -1,12 +1,14 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
var ipython = ipython || {};
require(['base/js/page'], function(page) {
var page_instance = new page.Page();
$('button#login_submit').addClass("btn btn-default");
page_instance.show();
$('input#password_input').focus();
define(['base/js/namespace', 'base/js/page'], function(IPython, page) {
function login_main() {
var page_instance = new page.Page();
$('button#login_submit').addClass("btn btn-default");
page_instance.show();
$('input#password_input').focus();
ipython.page = page_instance;
IPython.page = page_instance;
}
return login_main;
});

View File

@ -1,10 +1,12 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
var ipython = ipython || {};
require(['base/js/page'], function(page) {
var page_instance = new page.Page();
page_instance.show();
define(['base/js/namespace', 'base/js/page'], function(IPython, page) {
function logout_main() {
var page_instance = new page.Page();
page_instance.show();
ipython.page = page_instance;
IPython.page = page_instance;
}
return logout_main;
});

View File

@ -0,0 +1,9 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
define(['./loginmain', './logoutmain'], function (login_main, logout_main) {
return {
login_main: login_main,
logout_main: logout_main
};
});

View File

@ -95,5 +95,5 @@ data-file-path="{{file_path}}"
{{super()}}
<script src="{{ static_url("edit/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("edit/js/main.min.js") }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}

View File

@ -48,6 +48,10 @@
{% block script %}
{{super()}}
<script src="{{static_url("auth/js/loginmain.js") }}" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
require(["auth/js/main"], function (auth) {
auth.login_main();
});
</script>
{% endblock %}

View File

@ -34,6 +34,10 @@
{% block script %}
{{super()}}
<script src="{{static_url("auth/js/logoutmain.js") }}" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
require(["auth/js/main"], function (auth) {
auth.logout_main();
});
</script>
{% endblock %}

View File

@ -324,6 +324,6 @@ data-notebook-path="{{notebook_path}}"
<script src="{{ static_url("components/text-encoding/lib/encoding.js") }}" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/main.js") }}" charset="utf-8"></script>
<script src="{{ static_url("notebook/js/main.min.js") }}" charset="utf-8"></script>
{% endblock %}

View File

@ -23,6 +23,7 @@
{% endif %}
baseUrl: '{{static_url("", include_version=False)}}',
paths: {
'auth/js/main': 'auth/js/main.min',
custom : '{{ base_url }}custom',
nbextensions : '{{ base_url }}nbextensions',
widgets : '{{ base_url }}deprecatedwidgets',

View File

@ -60,5 +60,5 @@ data-ws-path="{{ws_path}}"
{{super()}}
<script src="{{ static_url("terminal/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("terminal/js/main.min.js") }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}

View File

@ -183,5 +183,5 @@ data-terminals-available="{{terminals_available}}"
{% block script %}
{{super()}}
<script src="{{ static_url("tree/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
<script src="{{ static_url("tree/js/main.min.js") }}" type="text/javascript" charset="utf-8"></script>
{% endblock %}

View File

@ -14,9 +14,12 @@
"gulp-less": "^3.0.2",
"gulp-livereload": "^3.8.0",
"gulp-minify-css": "^1.0.0",
"gulp-newer": "^0.5.0",
"gulp-rename": "^1.2.2",
"gulp-sourcemaps": "^1.5.1",
"less": "~2",
"source-map": "^0.4.2"
"requirejs": "^2.1.17",
"source-map": "^0.4.2",
"through": "^2.3.7"
}
}

View File

@ -54,6 +54,7 @@ from setupbase import (
find_package_data,
check_package_data_first,
CompileCSS,
CompileJS,
Bower,
JavascriptVersion,
css_js_prerelease,
@ -107,9 +108,10 @@ from distutils.command.sdist import sdist
setup_args['cmdclass'] = {
'build_py': css_js_prerelease(
check_package_data_first(build_py)),
'sdist' : css_js_prerelease(sdist),
'sdist' : css_js_prerelease(sdist, strict=True),
'css' : CompileCSS,
'js' : Bower,
'js' : CompileJS,
'jsdeps' : Bower,
'jsversion' : JavascriptVersion,
}

View File

@ -107,7 +107,12 @@ def find_package_data():
continue
for f in files:
static_data.append(pjoin(parent, f))
# for verification purposes, explicitly add main.min.js
# so that installation will fail if they are missing
for app in ['auth', 'edit', 'notebook', 'terminal', 'tree']:
static_data.append(pjoin('static', app, 'js', 'main.min.js'))
components = pjoin("static", "components")
# select the components we actually need to install
# (there are lots of resources we bundle for sdist-reasons that we don't actually use)
@ -361,14 +366,41 @@ class CompileCSS(Command):
pass
def run(self):
self.run_command('js')
self.run_command('jsdeps')
env = os.environ.copy()
env['PATH'] = npm_path
try:
check_call(['gulp','css'], cwd=repo_root, env=env)
except OSError as e:
print("Failed to run gulp: %s" % e, file=sys.stderr)
print("Failed to run gulp css: %s" % e, file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr)
raise
# update package data in case this created new files
update_package_data(self.distribution)
class CompileJS(Command):
"""Rebuild minified Notebook Javascript
Calls `gulp js`
"""
description = "Rebuild Notebook Javascript"
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
self.run_command('jsdeps')
env = os.environ.copy()
env['PATH'] = npm_path
try:
check_call(['gulp','js'], cwd=repo_root, env=env)
except OSError as e:
print("Failed to run gulp js: %s" % e, file=sys.stderr)
print("You can install js dependencies with `npm install`", file=sys.stderr)
raise
# update package data in case this created new files
@ -401,19 +433,26 @@ class JavascriptVersion(Command):
raise RuntimeError("Didn't find IPython.version line in %s" % nsfile)
def css_js_prerelease(command):
"""decorator for building js/minified css prior to another command"""
def css_js_prerelease(command, strict=False):
"""decorator for building minified js/css prior to another command"""
class DecoratedCommand(command):
def run(self):
self.distribution.run_command('jsversion')
jsdeps = self.distribution.get_command_obj('jsdeps')
jsdeps.force = True
js = self.distribution.get_command_obj('js')
js.force = True
css = self.distribution.get_command_obj('css')
css.force = True
try:
self.distribution.run_command('css')
self.distribution.run_command('js')
except Exception as e:
log.warn("rebuilding css and sourcemaps failed (not a problem)")
log.warn(str(e))
if strict:
log.warn("rebuilding js and css failed")
raise e
else:
log.warn("rebuilding js and css failed (not a problem)")
log.warn(str(e))
command.run(self)
return DecoratedCommand