diff --git a/.babelrc b/.babelrc index 9a8be8c392..4104471e0a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,8 @@ { - "presets": [ "es3", ["es2015", {"loose": true}] ], - "plugins": ["inline-json"] + "presets": [ + "es3", + ["es2015", { + "loose": true + }] + ] } diff --git a/.travis.yml b/.travis.yml index be3db58d1a..fddf1c1368 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,10 @@ before_install: - export CHROME_BIN=chromium-browser - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start +after_failure: + - npm ls --depth=1 +after_success: + - npm run assets notifications: irc: channels: diff --git a/build/assets.js b/build/assets.js new file mode 100644 index 0000000000..77f3653367 --- /dev/null +++ b/build/assets.js @@ -0,0 +1,65 @@ +const fs = require('fs'); +const zlib = require('zlib'); +const Promise = require('bluebird'); +const klawSync = require('klaw-sync'); +const filesize = require('filesize'); +const Table = require('cli-table'); + +const files = klawSync('dist/', { + ignore: ['examples', 'lang', 'font', 'ie8', '*.zip', '*.gz'], + nodir: true +}); + +Promise.all(files.map(gzipAndStat)) +.then(mapFiles) +.then(function(files) { + logTable(files); + + return files; +}) +.then(cleanup) +.catch(function(err) { + console.error(err.stack); +}); + +function cleanup(files) { + files.forEach(function(file) { + fs.unlinkSync('dist/' + file[0] + '.gz'); + }); +} + +function mapFiles(files) { + return files.map(function(file) { + const path = file[0].path; + const fileStat = file[0].stats; + const gzStat = file[1]; + return [file[0].path.split('dist/')[1], filesize(fileStat.size), filesize(gzStat.size)]; + }); +} + +function gzipAndStat(file) { + return new Promise(function(resolve, reject) { + const readStream = fs.createReadStream(file.path); + const writeStream = fs.createWriteStream(file.path + '.gz'); + const gzip = zlib.createGzip(); + readStream.pipe(gzip).pipe(writeStream).on('close', function() { + const gzStat = fs.statSync(file.path + '.gz'); + + resolve([file, gzStat]); + }) + .on('error', reject); + }); +} + +function logTable(files) { + const table = new Table({ + head: ['filename', 'size', 'gzipped'], + colAligns: ['left', 'right', 'right'], + style: { + border: ['white'] + } + }); + + table.push.apply(table, files); + console.log(table.toString()); +} diff --git a/build/grunt.js b/build/grunt.js index cbb37c494a..4be8444e5c 100644 --- a/build/grunt.js +++ b/build/grunt.js @@ -408,8 +408,7 @@ module.exports = function(grunt) { ], dev: [ 'shell:babel', - 'browserify:watch', - 'browserify:watchnovtt', + 'shell:rollupwatch', 'browserify:tests', 'watch:skin', 'watch:lang', @@ -448,6 +447,24 @@ module.exports = function(grunt) { } }, shell: { + rollup: { + command: 'npm run rollup', + options: { + preferLocal: true + } + }, + rollupall: { + command: 'npm run rollup -- --no-progress && npm run rollup-minify -- --no-progress', + options: { + preferLocal: true + } + }, + rollupwatch: { + command: 'npm run rollup-dev', + optoins: { + preferLocal: true + } + }, babel: { command: 'npm run babel -- --watch', options: { @@ -509,12 +526,7 @@ module.exports = function(grunt) { 'shell:lint', 'clean:build', - 'babel:es5', - 'browserify:build', - 'browserify:buildnovtt', - 'usebanner:novtt', - 'usebanner:vtt', - 'uglify', + 'shell:rollupall', 'skin', 'version:css', diff --git a/build/rollup.js b/build/rollup.js new file mode 100644 index 0000000000..883b24818e --- /dev/null +++ b/build/rollup.js @@ -0,0 +1,205 @@ +import { rollup } from 'rollup'; +import duration from 'humanize-duration'; +import watch from 'rollup-watch'; +import babel from 'rollup-plugin-babel'; +import resolve from 'rollup-plugin-node-resolve'; +import commonjs from 'rollup-plugin-commonjs'; +import json from 'rollup-plugin-json'; +import filesize from 'rollup-plugin-filesize'; +import progress from 'rollup-plugin-progress'; +import ignore from 'rollup-plugin-ignore'; +import uglify from 'rollup-plugin-uglify'; +import minimist from 'minimist'; +import _ from 'lodash'; +import pkg from '../package.json'; +import fs from 'fs'; + +const args = minimist(process.argv.slice(2), { + boolean: ['watch', 'minify', 'progress'], + default: { + progress: true + }, + alias: { + w: 'watch', + m: 'minify', + p: 'progress' + } +}); + +const compiledLicense = _.template(fs.readFileSync('./build/license-header.txt', 'utf8')); +const bannerData = _.pick(pkg, ['version', 'copyright']); + +const primedResolve = resolve({ + jsnext: true, + main: true, + browser: true +}); +const primedCjs = commonjs({ + sourceMap: false +}); +const primedBabel = babel({ + babelrc: false, + exclude: 'node_modules/**', + presets: [ + 'es3', + ['es2015', { + loose: true, + modules: false + }] + ], + plugins: ['external-helpers'] +}); + +const es = { + options: { + entry: 'src/js/video.js', + plugins: [ + json(), + primedBabel, + args.progress ? progress() : {}, + filesize() + ], + onwarn(warning) { + if (warning.code === 'UNUSED_EXTERNAL_IMPORT' || + warning.code === 'UNRESOLVED_IMPORT') { + return; + } + + // eslint-disable-next-line no-console + console.warn(warning.message); + }, + legacy: true + }, + banner: compiledLicense(Object.assign({includesVtt: true}, bannerData)), + format: 'es', + dest: 'dist/video.es.js' +}; + +const cjs = Object.assign({}, es, { + format: 'cjs', + dest: 'dist/video.cjs.js' +}); + +const umd = { + options: { + entry: 'src/js/video.js', + plugins: [ + primedResolve, + json(), + primedCjs, + primedBabel, + args.progress ? progress() : {}, + filesize() + ], + legacy: true + }, + banner: compiledLicense(Object.assign({includesVtt: true}, bannerData)), + format: 'umd', + dest: 'dist/video.js' +}; + +const minifiedUmd = Object.assign({}, _.cloneDeep(umd), { + dest: 'dist/video.min.js' +}); + +minifiedUmd.options.plugins.splice(4, 0, uglify({ + preserveComments: 'some', + screwIE8: false, + mangle: true, + compress: { + /* eslint-disable camelcase */ + sequences: true, + dead_code: true, + conditionals: true, + booleans: true, + unused: true, + if_return: true, + join_vars: true, + drop_console: true + /* eslint-enable camelcase */ + } +})); + +const novttUmd = Object.assign({}, _.cloneDeep(umd), { + banner: compiledLicense(Object.assign({includesVtt: false}, bannerData)), + dest: 'dist/alt/video.novtt.js' +}); + +novttUmd.options.plugins.unshift(ignore(['videojs-vtt.js'])); + +const minifiedNovttUmd = Object.assign({}, _.cloneDeep(minifiedUmd), { + banner: compiledLicense(Object.assign({includesVtt: false}, bannerData)), + dest: 'dist/alt/video.novtt.min.js' +}); + +minifiedNovttUmd.options.plugins.unshift(ignore(['videojs-vtt.js'])); + +function runRollup({options, format, dest, banner}) { + rollup(options) + .then(function(bundle) { + bundle.write({ + format, + dest, + banner, + moduleName: 'videojs', + sourceMap: false + }); + }, function(err) { + // eslint-disable-next-line no-console + console.error(err); + }); +} + +if (!args.watch) { + if (args.minify) { + runRollup(minifiedUmd); + runRollup(minifiedNovttUmd); + } else { + runRollup(es); + runRollup(cjs); + runRollup(umd); + runRollup(novttUmd); + } +} else { + const props = ['format', 'dest', 'banner']; + const watchers = [ + ['es', watch({rollup}, + Object.assign({}, + es.options, + _.pick(es, props)))], + ['cjs', watch({rollup}, + Object.assign({}, + cjs.options, + _.pick(cjs, props)))], + ['umd', watch({rollup}, + Object.assign({moduleName: 'videojs'}, + umd.options, + _.pick(umd, props)))], + ['novtt', watch({rollup}, + Object.assign({moduleName: 'videojs'}, + novttUmd.options, + _.pick(novttUmd, props)))] + ]; + + watchers.forEach(function([type, watcher]) { + watcher.on('event', (details) => { + if (details.code === 'BUILD_START') { + // eslint-disable-next-line no-console + console.log(`Bundling ${type}...`); + return; + } + + if (details.code === 'BUILD_END') { + // eslint-disable-next-line no-console + console.log(`Bundled ${type} in %s`, duration(details.duration)); + return; + } + + if (details.code === 'ERROR') { + // eslint-disable-next-line no-console + console.error(details.error.toString()); + return; + } + }); + }); +} diff --git a/package.json b/package.json index 28b45a1fa5..8836597eed 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,8 @@ "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", "version": "6.1.0", - "main": "./es5/video.js", + "main": "./dist/video.cjs.js", + "module": "./dist/video.es.js", "style": "./dist/video-js.css", "copyright": "Copyright Brightcove, Inc. ", "license": "Apache-2.0", @@ -18,6 +19,11 @@ "scripts": { "changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", "build": "grunt dist", + "rollup-all": "npm run rollup && npm run rollup-minify", + "rollup": "babel-node build/rollup.js", + "rollup-minify": "babel-node build/rollup.js --minify", + "rollup-dev": "babel-node build/rollup.js --watch", + "assets": "node build/assets.js", "change": "grunt chg-add", "clean": "grunt clean", "grunt": "grunt", @@ -47,28 +53,31 @@ "tsml": "1.0.1", "videojs-font": "2.0.0", "videojs-ie8": "1.1.2", - "videojs-vtt.js": "0.12.3", + "videojs-vtt.js": "0.12.4", "xhr": "2.4.0" }, "devDependencies": { "aliasify": "^2.1.0", "babel-cli": "^6.11.4", - "babel-plugin-inline-json": "^1.1.1", + "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-runtime": "^6.9.0", "babel-preset-es2015": "^6.14.0", "babel-preset-es3": "^1.0.1", "babel-register": "^6.9.0", "babelify": "^7.3.0", "blanket": "^1.1.6", + "bluebird": "^3.5.0", "browserify-derequire": "^0.9.4", "browserify-istanbul": "^2.0.0", "browserify-versionify": "^1.0.4", "bundle-collapser": "^1.2.1", "chg": "^0.3.2", + "cli-table": "^0.3.1", "conventional-changelog-cli": "^1.2.0", "conventional-changelog-videojs": "^3.0.0", "es5-shim": "^4.1.3", "es6-shim": "^0.35.1", + "filesize": "^3.5.6", "grunt": "^0.4.5", "grunt-accessibility": "^5.0.0", "grunt-babel": "^6.0.0", @@ -92,6 +101,7 @@ "grunt-version": "~1.1.1", "grunt-videojs-languages": "0.0.4", "grunt-zip": "0.17.1", + "humanize-duration": "^3.10.0", "husky": "^0.13.1", "in-publish": "^2.0.0", "istanbul": "^0.4.5", @@ -108,9 +118,11 @@ "karma-qunit": "^1.2.0", "karma-safari-launcher": "^1.0.0", "karma-sinon": "^1.0.5", + "klaw-sync": "^1.1.2", "load-grunt-tasks": "^3.1.0", "lodash": "^4.16.6", "markdown-table": "^1.0.0", + "minimist": "^1.2.0", "npm-run": "^4.1.0", "npm-run-all": "^4.0.2", "proxyquireify": "^3.0.0", @@ -120,6 +132,16 @@ "remark-toc": "^4.0.0", "remark-validate-links": "^6.0.0", "replace": "^0.3.0", + "rollup": "^0.41.6", + "rollup-plugin-babel": "^2.7.1", + "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-filesize": "^1.2.1", + "rollup-plugin-ignore": "^1.0.3", + "rollup-plugin-json": "^2.1.1", + "rollup-plugin-node-resolve": "^3.0.0", + "rollup-plugin-progress": "^0.2.1", + "rollup-plugin-uglify": "^1.0.2", + "rollup-watch": "^3.2.2", "shelljs": "^0.7.5", "sinon": "^1.16.1", "time-grunt": "^1.1.1", @@ -128,13 +150,14 @@ "videojs-doc-generator": "0.0.1", "videojs-flash": "^2.0.0", "videojs-standard": "^6.0.1", - "webpack": "^2.3.0" + "webpack": "^1.15.0" }, "vjsstandard": { "ignore": [ "**/Gruntfile.js", "**/es5/**", "**/build/**", + "!build/rollup.js", "**/dist/**", "**/docs/**", "**/lang/**", diff --git a/sandbox/index.html.example b/sandbox/index.html.example index 60c20d56f2..289284932c 100644 --- a/sandbox/index.html.example +++ b/sandbox/index.html.example @@ -9,7 +9,7 @@ - + diff --git a/src/js/player.js b/src/js/player.js index af8f42fe9a..67c6c01a1c 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -4,6 +4,7 @@ // Subclasses Component import Component from './component.js'; +import {version} from '../../package.json'; import document from 'global/document'; import window from 'global/window'; import tsml from 'tsml'; @@ -443,7 +444,7 @@ class Player extends Component { Player.players[this.id_] = this; // Add a major version class to aid css in plugins - const majorVersion = require('../../package.json').version.split('.')[0]; + const majorVersion = version.split('.')[0]; this.addClass(`vjs-v${majorVersion}`); diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index 5a04a8e1c1..c0501af6bb 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -14,6 +14,7 @@ import document from 'global/document'; import {isPlain} from '../utils/obj'; import * as TRACK_TYPES from '../tracks/track-types'; import toTitleCase from '../utils/to-title-case'; +import vtt from 'videojs-vtt.js'; /** * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string @@ -516,7 +517,6 @@ class Tech extends Component { // signals that the Tech is ready at which point Tech.el_ is part of the DOM // before inserting the WebVTT script if (document.body.contains(this.el())) { - const vtt = require('videojs-vtt.js'); // load via require if available and vtt.js script location was not passed in // as an option. novtt builds will turn the above require call into an empty object @@ -530,7 +530,7 @@ class Tech extends Component { // passed in const script = document.createElement('script'); - script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js'; + script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.4/vtt.min.js'; script.onload = () => { /** * Fired when vtt.js is loaded. diff --git a/src/js/video.js b/src/js/video.js index beafff30e0..5507895a6f 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -2,6 +2,7 @@ * @file video.js * @module videojs */ +import {version} from '../../package.json'; import window from 'global/window'; import document from 'global/document'; import * as setup from './setup'; @@ -225,7 +226,7 @@ setup.autoSetupTimeout(1, videojs); * * @type {string} */ -videojs.VERSION = require('../../package.json').version; +videojs.VERSION = version; /** * The global options object. These are the settings that take effect @@ -722,7 +723,5 @@ videojs.dom = Dom; */ videojs.url = Url; -// We use Node-style module.exports here instead of ES6 because it is more -// compatible with different module systems. -module.exports = videojs; +export default videojs; diff --git a/test/karma.conf.js b/test/karma.conf.js index 3422d2761b..161f974703 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -10,7 +10,7 @@ module.exports = function(config) { // Compling tests here files: [ '../build/temp/video-js.css', - '../build/temp/ie8/videojs-ie8.min.js', + '../build/temp/ie8/videojs-ie8.js', '../test/globals-shim.js', '../test/unit/**/*.js', '../build/temp/browserify.js',