From b5d069069797761d639d64ca9c7a136795d683a3 Mon Sep 17 00:00:00 2001 From: Ezra Brooks Date: Fri, 24 Nov 2017 12:50:38 -0500 Subject: [PATCH 1/2] refactor: move compile step to first run of server --- .npmignore | 3 ++- gruntfile.js | 21 ++-------------- lib/server.js | 69 ++++++++++++++++++++++++++++++++++++++++----------- package.json | 7 +++--- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/.npmignore b/.npmignore index e24e1044f..2e3384c17 100644 --- a/.npmignore +++ b/.npmignore @@ -5,7 +5,6 @@ tmp test tasks docs -client logo integration-tests @@ -15,6 +14,8 @@ Gruntfile.coffee credentials Karma.sublime-* +static/karma.js +static/context.js static/karma.src.js static/karma.wrapper test-results.xml diff --git a/gruntfile.js b/gruntfile.js index 0a1b6f1ce..3a8f44b95 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -10,25 +10,11 @@ module.exports = function (grunt) { grunt: ['grunt.js', 'tasks/*.js'], scripts: ['scripts/init-dev-env.js'] }, - browserify: { - client: { - files: { - 'static/karma.js': ['client/main.js'], - 'static/context.js': ['context/main.js'] - } - } - }, test: { unit: 'mochaTest:unit', client: 'test/client/karma.conf.js', e2e: 'cucumberjs:ci' }, - watch: { - client: { - files: '<%= files.client %>', - tasks: 'browserify:client' - } - }, mochaTest: { options: { reporter: 'dot', @@ -85,7 +71,6 @@ module.exports = function (grunt) { }, 'npm-publish': { options: { - requires: ['build'], abortIfDirty: true, tag: 'latest' } @@ -135,15 +120,13 @@ module.exports = function (grunt) { require('load-grunt-tasks')(grunt) grunt.registerTask('lint', ['eslint']) - grunt.registerTask('build', ['browserify:client']) - grunt.registerTask('default', ['build', 'lint', 'test']) + grunt.registerTask('default', ['lint', 'test']) grunt.registerTask('test-appveyor', ['test:unit', 'test:client']) - grunt.registerTask('release', 'Build, bump and publish to NPM.', function (type) { + grunt.registerTask('release', 'Bump and publish to NPM.', function (type) { grunt.task.run([ 'npm-contributors', 'bump:' + (type || 'patch') + ':bump-only', - 'build', 'conventionalChangelog', 'bump-commit', 'conventionalGithubReleaser', diff --git a/lib/server.js b/lib/server.js index b68631b0e..d2fab260f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -27,6 +27,29 @@ var Browser = require('./browser') var BrowserCollection = require('./browser_collection') var EmitterWrapper = require('./emitter_wrapper') var processWrapper = new EmitterWrapper(process) +var browserify = require('browserify') + +const karmaJsPath = path.join(__dirname, '/../static/karma.js') +const contextJsPath = path.join(__dirname, '/../static/context.js') + +/** + * Bundles a static resource using Browserify. + * @param {string} inPath the path to the file to browserify + * @param {string} outPath the path to output the bundle to + * @returns {Promise} + */ +function bundleResource (inPath, outPath) { + return new Promise((resolve, reject) => { + var bundler = browserify(inPath) + bundler.bundle().pipe(fs.createWriteStream(outPath)) + .once('finish', () => { + resolve() + }) + .once('error', (e) => { + reject(e) + }) + }) +} function createSocketIoServer (webServer, executor, config) { var server = new SocketIO(webServer, { @@ -171,23 +194,41 @@ Server.prototype._start = function (config, launcher, preprocess, fileList, self._injector.invoke(watcher.watch) } - webServer.listen(config.port, config.listenAddress, function () { - self.log.info('Karma v%s server started at %s//%s:%s%s', constant.VERSION, - config.protocol, config.listenAddress, config.port, config.urlRoot) + var startWebServer = function () { + webServer.listen(config.port, config.listenAddress, function () { + self.log.info('Karma v%s server started at %s//%s:%s%s', constant.VERSION, + config.protocol, config.listenAddress, config.port, config.urlRoot) - self.emit('listening', config.port) - if (config.browsers && config.browsers.length) { - self._injector.invoke(launcher.launch, launcher).forEach(function (browserLauncher) { - singleRunDoneBrowsers[browserLauncher.id] = false - }) - } - var noLoadErrors = self.loadErrors.length - if (noLoadErrors > 0) { - self.log.error('Found %d load error%s', noLoadErrors, noLoadErrors === 1 ? '' : 's') + self.emit('listening', config.port) + if (config.browsers && config.browsers.length) { + self._injector.invoke(launcher.launch, launcher).forEach(function (browserLauncher) { + singleRunDoneBrowsers[browserLauncher.id] = false + }) + } + var noLoadErrors = self.loadErrors.length + if (noLoadErrors > 0) { + self.log.error('Found %d load error%s', noLoadErrors, noLoadErrors === 1 ? '' : 's') + process.exitCode = 1 + process.kill(process.pid, 'SIGINT') + } + }) + } + + // Check if the static files haven't been compiled + if (!(fs.existsSync(karmaJsPath) && fs.existsSync(contextJsPath))) { + self.log.info('Front-end scripts not present. Compiling...') + var mainPromise = bundleResource(path.join(__dirname, '/../client/main.js'), karmaJsPath) + var contextPromise = bundleResource(path.join(__dirname, '/../context/main.js'), contextJsPath) + Promise.all([mainPromise, contextPromise]).then(() => { + startWebServer() + }).catch((error) => { + self.log.error('Front-end script compile failed with error: ' + error) process.exitCode = 1 process.kill(process.pid, 'SIGINT') - } - }) + }) + } else { + startWebServer() + } } fileList.refresh().then(afterPreprocess, afterPreprocess) diff --git a/package.json b/package.json index c6faad3a1..4db405b01 100644 --- a/package.json +++ b/package.json @@ -329,6 +329,7 @@ "dependencies": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", + "browserify": "^14.5.0", "chokidar": "^1.4.1", "colors": "^1.1.0", "combine-lists": "^1.0.0", @@ -372,7 +373,6 @@ "eslint-plugin-standard": "^3.0.1", "grunt": "^1.0.0", "grunt-auto-release": "^0.0.7", - "grunt-browserify": "^5.0.0", "grunt-bump": "^0.8.0", "grunt-cli": "^1.1.0", "grunt-contrib-watch": "^1.0.0", @@ -434,15 +434,14 @@ "scripts": { "lint": "eslint client/**/*.js common/**/*.js context/**/*.js gruntfile.js wallaby.js lib/**/*.js test/unit/**/*.js test/client/*.js test/e2e/**/*.js static/debug.js", "test": "grunt test", - "build": "grunt build", "test:appveyor": "grunt test-appveyor", "test:integration": "./scripts/integration-tests.sh", "link": "node --eval \"path=require('path'); require('fs').symlinkSync(path.resolve(__dirname), path.resolve(__dirname, 'node_modules', 'karma'), 'junction')\"", "unlink": "node --eval \"require('fs').unlinkSync(require('path').resolve(__dirname, 'node_modules', 'karma'))\"", "init": "rm -rf node_modules/karma && cd node_modules && ln -nsf ../ karma && cd ../", "init:windows": "(IF EXIST node_modules\\karma (rmdir node_modules\\karma /S /q)) && npm run link", - "appveyor": "npm run build && npm run test:appveyor", - "travis": "npm run build && npm test && npm run test:integration", + "appveyor": "npm run test:appveyor", + "travis": "npm test && npm run test:integration", "commitmsg": "validate-commit-msg", "precommit": "npm run lint" } From e7433fc41ca208a194f62c11f6ffb9854526c1f2 Mon Sep 17 00:00:00 2001 From: Ezra Brooks Date: Sun, 26 Nov 2017 11:36:15 -0500 Subject: [PATCH 2/2] test: Add test for first-run compile of static resources --- test/unit/server.spec.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/unit/server.spec.js b/test/unit/server.spec.js index c362f1aed..2274355db 100644 --- a/test/unit/server.spec.js +++ b/test/unit/server.spec.js @@ -1,5 +1,7 @@ var Server = require('../../lib/server') var BrowserCollection = require('../../lib/browser_collection') +var fs = require('fs') +var path = require('path') describe('server', () => { var mockConfig @@ -103,6 +105,17 @@ describe('server', () => { // server._start() // ============================================================================ describe('_start', () => { + it('should compile static resources on first run', function (done) { + this.timeout(5000) + server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, doneSpy) + fileListOnResolve() + + setTimeout(() => { + expect(fs.existsSync(path.join(__dirname, '/../../static/karma.js')) && fs.existsSync(path.join(__dirname, '/../../static/context.js'))).to.be.true + done() + }, 4000) + }) + it('should start the web server after all files have been preprocessed successfully', () => { server._start(mockConfig, mockLauncher, null, mockFileList, browserCollection, mockExecutor, doneSpy)