switch back to a file based optimizer in dev mode

This commit is contained in:
spalger 2015-08-07 16:08:42 -07:00
parent 12466d6969
commit 25bd4ecb18
13 changed files with 156 additions and 158 deletions

View file

@ -16,7 +16,6 @@ module.exports = class ClusterManager {
title: 'optimizer',
log: this.log,
argv: compact([
(opts.quiet || opts.silent || opts.verbose) ? null : '--quiet',
'--plugins.initialize=false',
'--server.autoListen=false'
]),
@ -45,8 +44,6 @@ module.exports = class ClusterManager {
let fromRoot = utils('fromRoot');
this.watcher = chokidar.watch([
'src/cli',
'src/optimize',
'src/plugins',
'src/server',
'src/ui',

View file

@ -5,8 +5,12 @@ let BaseOptimizer = require('./BaseOptimizer');
let fromRoot = require('../utils/fromRoot');
module.exports = class FsOptimizer extends BaseOptimizer {
async run() {
async init() {
await this.initCompiler();
}
async run() {
if (!this.compiler) await this.init();
let stats = await fromNode(cb => {
this.compiler.run((err, stats) => {
@ -33,13 +37,11 @@ module.exports = class FsOptimizer extends BaseOptimizer {
);
});
}
this.compiler = null;
}
getConfig() {
let config = BaseOptimizer.prototype.getConfig.call(this);
config.cache = false;
config.cache = true;
return config;
}
};

View file

@ -1,104 +0,0 @@
let { contains } = require('lodash');
let { join } = require('path');
let { fromNode } = require('bluebird');
let webpack = require('webpack');
let Boom = require('boom');
let MemoryFileSystem = require('memory-fs');
let BaseOptimizer = require('./BaseOptimizer');
module.exports = class LiveOptimizer extends BaseOptimizer {
async init() {
await this.bundles.writeEntryFiles();
await this.initCompiler();
this.outFs = this.compiler.outputFileSystem = new MemoryFileSystem();
}
async compile() {
let stats = await fromNode(cb => this.compiler.run(cb));
if (stats.hasErrors() || stats.hasWarnings()) {
let err = new Error('optimization failure');
err.stats = stats;
throw err;
}
return stats;
}
async start() {
let prom = null;
try {
prom = this.current = this.compile();
return await prom;
}
catch (e) {
if (e.stats && this.current === prom) {
console.log(e.stats.toString({ colors: true }));
}
throw e;
}
finally {
this.current = null;
}
}
/**
* Read a file from the in-memory bundles, paths just like those
* produces by the FsOptimizer are used to access files. The first time
* a file is requested it is marked as "sent". If that same file is requested
* a second time then we will rerun the compiler.
*
* !!!ONLY ONE BROWSER TAB SHOULD ACCESS THE IN-MEMORY OPTIMIZERS FILES AT A TIME!!!
*
* @param {[type]} relativePath [description]
* @return {[type]} [description]
*/
async get(relativePath) {
try {
let fs = this.outFs;
let path = join(this.compiler.outputPath, relativePath);
let restart = contains(this.sent, path);
if (!this.sent || restart) {
this.sent = [];
this.current = null;
}
await (this.current || this.start());
let content = fs.readFileSync(path); // may throw "Path doesn't exist"
this.sent.push(path);
return content || '';
}
catch (error) {
if (error && error.message.match(/path doesn't exist/i)) {
error = Boom.notFound(error.message);
} else {
console.log(error.stack);
}
throw error;
}
}
bindToServer(server) {
server.route({
path: '/bundles/{path*}',
method: 'GET',
handler: async (request, reply) => {
let path = request.params.path;
let mimeType = server.mime.path(path).type;
try {
let content = await this.get(path);
return reply(content).type(mimeType);
} catch (error) {
return reply(Boom.wrap(error, 500));
}
}
});
}
};

View file

@ -15,6 +15,7 @@ module.exports = async (kbnServer, server, config) => {
}
let bundles = kbnServer.bundles;
server.exposeStaticDir('/bundles/{path*}', bundles.env.workingDir);
await bundles.writeEntryFiles();
// in prod, only bundle what looks invalid or missing
@ -40,8 +41,6 @@ module.exports = async (kbnServer, server, config) => {
profile: config.get('optimize.profile')
});
server.exposeStaticDir('/bundles/{path*}', bundles.env.workingDir);
try {
server.log(
['info', 'optimize'],

View file

@ -0,0 +1,92 @@
let { contains } = require('lodash');
let { join } = require('path');
let { fromNode } = require('bluebird');
let Boom = require('boom');
let FsOptimizer = require('../FsOptimizer');
module.exports = class LazyOptimizer extends FsOptimizer {
constructor(opts) {
super(opts);
this.sent = [];
this.log = opts.log || (() => null);
}
async init() {
await this.bundles.writeEntryFiles();
await this.initCompiler();
}
start() {
this.log(['info', 'optimize'], 'starting live optimization');
let start = Date.now();
let prom = this.current = (async () => {
try {
let stats = await fromNode(cb => this.compiler.run(cb));
if (stats.hasErrors() || stats.hasWarnings()) {
let err = new Error('optimization failure');
err.stats = stats;
throw err;
}
return stats;
} catch (e) {
if (e.stats && this.current === prom) {
this.log(['warning', 'optimize'], e.stats.toString({ colors: true }));
}
throw e;
}
}())
.then(() => {
let seconds = ((Date.now() - start) / 1000).toFixed(2);
this.log(['info', 'optimize'], `live optimization complete in ${seconds} seconds.`);
});
return prom;
}
/**
* Read a file from the in-memory bundles, paths just like those
* produces by the FsOptimizer are used to access files. The first time
* a file is requested it is marked as "sent". If that same file is requested
* a second time then we will rerun the compiler.
*
* !!!ONLY ONE BROWSER TAB SHOULD ACCESS THE IN-MEMORY OPTIMIZERS FILES AT A TIME!!!
*
* @param {[type]} relativePath [description]
* @return {[type]} [description]
*/
async getPath(relativePath) {
let path = join(this.compiler.outputPath, relativePath);
let resend = contains(this.sent, path);
if (resend) {
this.sent = [];
this.current = null;
}
if (!this.current) this.start();
await this.current;
this.sent.push(path);
return path;
}
bindToServer(server) {
server.route({
path: '/bundles/{asset*}',
method: 'GET',
handler: async (request, reply) => {
try {
let path = await this.getPath(request.params.asset);
return reply.file(path);
} catch (error) {
console.log(error.stack);
return reply(error);
}
}
});
}
};

View file

@ -7,7 +7,7 @@ let Boom = require('boom');
module.exports = class LazyServer {
constructor(host, port, optimizer) {
this.optimizer = optimizer;
this.server = new Server({ minimal: true });
this.server = new Server();
this.server.connection({
host: host,
port: port

View file

@ -3,12 +3,13 @@ module.exports = async (kbnServer, kibanaHapiServer, config) => {
let src = require('requirefrom')('src');
let fromRoot = src('utils/fromRoot');
let LazyServer = require('./LazyServer');
let LiveOptimizer = require('../LiveOptimizer');
let LiveOptimizer = require('./LazyOptimizer');
let server = new LazyServer(
config.get('optimize.lazyHost'),
config.get('optimize.lazyPort'),
new LiveOptimizer({
log: (tags, data) => kibanaHapiServer.log(tags, data),
env: kbnServer.bundles.env,
bundles: kbnServer.bundles,
sourceMaps: config.get('optimize.sourceMaps')

View file

@ -1,51 +1,10 @@
module.exports = (kibana) => {
if (!kibana.config.get('env.dev')) return;
let { union } = require('lodash');
let utils = require('requirefrom')('src/utils');
let fromRoot = utils('fromRoot');
let findSourceFiles = utils('findSourceFiles');
return new kibana.Plugin({
uiExports: {
spyModes: [
'plugins/devMode/visDebugSpyPanel'
],
bundle: async (UiBundle, env, apps) => {
let modules = [];
// add the modules from all of the apps
for (let app of apps) {
modules = union(modules, app.getModules());
}
let testFiles = await findSourceFiles([
'src/**/public/**/__tests__/**/*.js',
'installedPlugins/*/public/**/__tests__/**/*.js'
]);
for (let f of testFiles) modules.push(f);
return new UiBundle({
id: 'tests',
modules: modules,
template: require('./testsEntryTemplate'),
env: env
});
},
modules: {
ngMock$: fromRoot('src/plugins/devMode/public/ngMock'),
fixtures: fromRoot('src/fixtures'),
testUtils: fromRoot('src/testUtils'),
'angular-mocks': {
path: require.resolve('angular-mocks'),
imports: 'angular'
},
}
]
}
});
};

View file

@ -0,0 +1,47 @@
module.exports = (kibana) => {
if (!kibana.config.get('optimize.tests')) return;
let { union } = require('lodash');
let utils = require('requirefrom')('src/utils');
let fromRoot = utils('fromRoot');
let findSourceFiles = utils('findSourceFiles');
return new kibana.Plugin({
uiExports: {
bundle: async (UiBundle, env, apps) => {
let modules = [];
// add the modules from all of the apps
for (let app of apps) {
modules = union(modules, app.getModules());
}
let testFiles = await findSourceFiles([
'src/**/public/**/__tests__/**/*.js',
'installedPlugins/*/public/**/__tests__/**/*.js'
]);
for (let f of testFiles) modules.push(f);
return new UiBundle({
id: 'tests',
modules: modules,
template: require('./testsEntryTemplate'),
env: env
});
},
modules: {
ngMock$: fromRoot('src/plugins/devMode/public/ngMock'),
fixtures: fromRoot('src/fixtures'),
testUtils: fromRoot('src/testUtils'),
'angular-mocks': {
path: require.resolve('angular-mocks'),
imports: 'angular'
},
}
}
});
};

View file

@ -0,0 +1,4 @@
{
"name": "tests_bundle",
"version": "0.0.0"
}

View file

@ -84,6 +84,7 @@ module.exports = Joi.object({
lazyHost: Joi.string().hostname().default('0.0.0.0'),
sourceMaps: Joi.boolean().default(Joi.ref('$dev')),
profile: Joi.boolean().default(false),
tests: Joi.boolean().default(false),
}).default()
}).default();

View file

@ -1,7 +1,7 @@
extends ./chrome.jade
block head
link(rel='stylesheet', href='/bundles/commons.js.style.css')
link(rel='stylesheet', href='/bundles/commons.bundle.js.style.css')
link(rel='stylesheet', href='/bundles/#{app.id}.style.css')
block content