diff options
| author | qsm-odoo <qsm@odoo.com> | 2019-03-29 10:59:30 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2019-06-04 07:57:20 +0000 |
| commit | 8132884840b1bee4303b5a4d2ffc12918a259979 (patch) | |
| tree | 2c8095dfdc8f9ed53ca854102b17a915ea19cf31 /addons/web/static/src/js/boot.js | |
| parent | bddac4b602e1c8884c740004fa77f511a3a169e9 (diff) | |
[REF] web: make boot.js independent of libraries
This is a first step towards lazy loading the majority of the JS: the
boot JS code should not depend on any libraries (underscore.js and
jQuery).
Even without lazy loading in mind, this would be a nice-to-have.
Part of https://github.com/odoo/odoo/pull/32181
task-1961045
Diffstat (limited to 'addons/web/static/src/js/boot.js')
| -rw-r--r-- | addons/web/static/src/js/boot.js | 490 |
1 files changed, 265 insertions, 225 deletions
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index cf1cbaba180..8498bf598cf 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -1,10 +1,7 @@ -/*--------------------------------------------------------- - * OpenERP Web Boostrap Code - *---------------------------------------------------------*/ - /** - * @name openerp - * @namespace openerp + *------------------------------------------------------------------------------ + * Odoo Web Boostrap Code + *------------------------------------------------------------------------------ * * Each module can return a promise. In that case, the module is marked as loaded * only when the promise is resolved, and its value is equal to the resolved value. @@ -26,274 +23,317 @@ * Debug: * Non loaded or failed module informations for debugging */ - (function () { "use strict"; + var jobUID = Date.now(); + var jobs = []; var factories = Object.create(null); - var job_names = []; - var job_deps = []; - var job_promise = []; - + var jobDeps = []; + var jobPromises = []; var services = Object.create({}); var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg; var cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g; - var debug = ($.deparam($.param.querystring()).debug !== undefined); + var debug = /\bdebug\b/.test(window.location.search); + + if (!window.odoo) { + window.odoo = {}; + } + var odoo = window.odoo; - var odoo = window.odoo = window.odoo || {}; var didLogInfoResolve; var didLogInfoPromise = new Promise(function (resolve) { didLogInfoResolve = resolve; }); - _.extend(odoo, { - testing: typeof QUnit === "object", - debug: debug, - remaining_jobs: jobs, - - __DEBUG__: { - didLogInfo: didLogInfoPromise, - get_dependencies: function (name, transitive) { - var deps = name instanceof Array ? name : [name], - changed; - do { - changed = false; - _.each(job_deps, function (dep) { - if (_.contains(deps, dep.to) && (!_.contains(deps, dep.from))) { - deps.push(dep.from); - changed = true; - } - }); - } while (changed && transitive); - return deps; - }, - get_dependents: function (name) { - return _.pluck(_.where(job_deps, { from: name }), 'to'); - }, - get_waited_jobs: function () { - return _.uniq(_.map(jobs, function (job) { return job.name; })); - }, - get_missing_jobs: function () { - var self = this; - var waited = this.get_waited_jobs(); - var missing = []; - _.each(waited, function (job) { - _.each(self.get_dependencies(job), function (job) { - if (!(job in self.services)) { - missing.push(job); - } - }); + odoo.testing = typeof QUnit === 'object'; + odoo.debug = debug; + odoo.remainingJobs = jobs; + odoo.__DEBUG__ = { + didLogInfo: didLogInfoPromise, + getDependencies: function (name, transitive) { + var deps = name instanceof Array ? name : [name]; + var changed; + do { + changed = false; + jobDeps.forEach(function (dep) { + if (deps.indexOf(dep.to) >= 0 && deps.indexOf(dep.from) < 0) { + deps.push(dep.from); + changed = true; + } }); - return _.filter(_.difference(_.uniq(missing), waited), function (job) { return !job.error; }); - }, - get_failed_jobs: function () { - return _.filter(jobs, function (job) { return !!job.error; }); - }, - factories: factories, - services: services, + } while (changed && transitive); + return deps; }, - define: function () { - var args = Array.prototype.slice.call(arguments); - var name = typeof args[0] === 'string' ? args.shift() : _.uniqueId('__job'); - var factory = args[args.length - 1]; - var deps; - if (args[0] instanceof Array) { - deps = args[0]; - } else { - deps = []; - factory.toString() - .replace(commentRegExp, '') - .replace(cjsRequireRegExp, function (match, dep) { - deps.push(dep); - }); - } + getDependents: function (name) { + return jobDeps.filter(function (dep) { + return dep.from === name; + }).map(function (dep) { + return dep.to; + }); + }, + getWaitedJobs: function () { + return jobs.map(function (job) { + return job.name; + }).filter(function (item, index, self) { // uniq + return self.indexOf(item) === index; + }); + }, + getMissingJobs: function () { + var self = this; + var waited = this.getWaitedJobs(); + var missing = []; + waited.forEach(function (job) { + self.getDependencies(job).forEach(function (job) { + if (!(job in self.services)) { + missing.push(job); + } + }); + }); + return missing.filter(function (item, index, self) { + return self.indexOf(item) === index; + }).filter(function (item) { + return waited.indexOf(item) < 0; + }).filter(function (job) { + return !job.error; + }); + }, + getFailedJobs: function () { + return jobs.filter(function (job) { + return !!job.error; + }); + }, + factories: factories, + services: services, + }; + odoo.define = function () { + var args = Array.prototype.slice.call(arguments); + var name = typeof args[0] === 'string' ? args.shift() : ('__odoo_job' + (jobUID++)); + var factory = args[args.length - 1]; + var deps; + if (args[0] instanceof Array) { + deps = args[0]; + } else { + deps = []; + factory.toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + } - if (odoo.debug) { - if (!(deps instanceof Array)) { - throw new Error('Dependencies should be defined by an array', deps); - } - if (typeof factory !== 'function') { - throw new Error('Factory should be defined by a function', factory); - } - if (typeof name !== 'string') { - throw new Error("Invalid name definition (should be a string", name); - } - if (name in factories) { - throw new Error("Service " + name + " already defined"); - } + if (odoo.debug) { + if (!(deps instanceof Array)) { + throw new Error('Dependencies should be defined by an array', deps); } + if (typeof factory !== 'function') { + throw new Error('Factory should be defined by a function', factory); + } + if (typeof name !== 'string') { + throw new Error("Invalid name definition (should be a string", name); + } + if (name in factories) { + throw new Error("Service " + name + " already defined"); + } + } - factory.deps = deps; - factories[name] = factory; + factory.deps = deps; + factories[name] = factory; - jobs.push({ - name: name, - factory: factory, - deps: deps, - }); + jobs.push({ + name: name, + factory: factory, + deps: deps, + }); - job_names.push(name); - _.each(deps, function (dep) { - job_deps.push({ from: dep, to: name }); - }); + deps.forEach(function (dep) { + jobDeps.push({from: dep, to: name}); + }); - this.process_jobs(jobs, services); - }, - log: function () { - var missing = []; - var failed = []; + this.processJobs(jobs, services); + }; + odoo.log = function () { + var missing = []; + var failed = []; - if (jobs.length) { - var debug_jobs = {}; - var rejected = []; - var rejected_linked = []; - var job; - var jobdep; + if (jobs.length) { + var debugJobs = {}; + var rejected = []; + var rejectedLinked = []; + var job; + var jobdep; - for (var k = 0; k < jobs.length; k++) { - debug_jobs[jobs[k].name] = job = { - dependencies: jobs[k].deps, - dependents: odoo.__DEBUG__.get_dependents(jobs[k].name), - name: jobs[k].name - }; - if (jobs[k].error) { - job.error = jobs[k].error; - } - if (jobs[k].rejected) { - job.rejected = jobs[k].rejected; - rejected.push(job.name); - } - var deps = odoo.__DEBUG__.get_dependencies(job.name); - for (var i = 0; i < deps.length; i++) { - if (job.name !== deps[i] && !(deps[i] in services)) { - jobdep = debug_jobs[deps[i]] || (deps[i] in factories && _.find(jobs, function (job) { return job.name === deps[i]; })); - if (jobdep && jobdep.rejected) { - if (!job.rejected) { - job.rejected = []; - rejected_linked.push(job.name); - } - job.rejected.push(deps[i]); - } else { - if (!job.missing) { - job.missing = []; + for (var k = 0; k < jobs.length; k++) { + debugJobs[jobs[k].name] = job = { + dependencies: jobs[k].deps, + dependents: odoo.__DEBUG__.getDependents(jobs[k].name), + name: jobs[k].name + }; + if (jobs[k].error) { + job.error = jobs[k].error; + } + if (jobs[k].rejected) { + job.rejected = jobs[k].rejected; + rejected.push(job.name); + } + var deps = odoo.__DEBUG__.getDependencies(job.name); + for (var i = 0; i < deps.length; i++) { + if (job.name !== deps[i] && !(deps[i] in services)) { + jobdep = debugJobs[deps[i]]; + if (!jobdep && deps[i] in factories) { + for (var j = 0; j < jobs.length; j++) { + if (jobs[j].name === deps[i]) { + jobdep = jobs[j]; + break; } - job.missing.push(deps[i]); } } + if (jobdep && jobdep.rejected) { + if (!job.rejected) { + job.rejected = []; + rejectedLinked.push(job.name); + } + job.rejected.push(deps[i]); + } else { + if (!job.missing) { + job.missing = []; + } + job.missing.push(deps[i]); + } } } - missing = odoo.__DEBUG__.get_missing_jobs(); - failed = odoo.__DEBUG__.get_failed_jobs(); - var unloaded = _.filter(debug_jobs, function (job) { return job.missing; }); + } + missing = odoo.__DEBUG__.getMissingJobs(); + failed = odoo.__DEBUG__.getFailedJobs(); + var unloaded = Object.keys(debugJobs) // Object.values is not supported + .map(function (key) { + return debugJobs[key]; + }).filter(function (job) { + return job.missing; + }); - if (odoo.debug || !_.isEmpty(failed) || !_.isEmpty(unloaded)) { - var log = console[_.isEmpty(failed) || _.isEmpty(unloaded) ? 'info' : 'error'].bind(console); - log((_.isEmpty(failed) ? (_.isEmpty(unloaded) ? 'info' : 'warning') : 'error') + ': Some modules could not be started'); - if (missing.length) { - log('Missing dependencies: ', missing); - } - if (!_.isEmpty(failed)) { - log('Failed modules: ', _.pluck(failed, 'name')); - } - if (!_.isEmpty(rejected)) { - log('Rejected modules: ', rejected); - } - if (!_.isEmpty(rejected_linked)) { - log('Rejected linked modules: ', rejected_linked); - } - if (!_.isEmpty(unloaded)) { - log('Non loaded modules: ', _.pluck(unloaded, 'name')); - } - if (odoo.debug && !_.isEmpty(debug_jobs)) { - log('Debug: ', debug_jobs); - } + if (odoo.debug || failed.length || unloaded.length) { + var log = window.console[!failed.length || !unloaded.length ? 'info' : 'error'].bind(window.console); + log((failed.length ? 'error' : (unloaded.length ? 'warning' : 'info')) + ': Some modules could not be started'); + if (missing.length) { + log('Missing dependencies: ', missing); + } + if (failed.length) { + log('Failed modules: ', failed.map(function (fail) { + return fail.name; + })); + } + if (rejected.length) { + log('Rejected modules: ', rejected); + } + if (rejectedLinked.length) { + log('Rejected linked modules: ', rejectedLinked); + } + if (unloaded.length) { + log('Non loaded modules: ', unloaded.map(function (unload) { + return unload.name; + })); + } + if (odoo.debug && Object.keys(debugJobs).length) { + log('Debug: ', debugJobs); } } - odoo.__DEBUG__.js_modules = { - missing: missing, - failed: _.pluck(failed, 'name'), - }; - didLogInfoResolve(); - }, - process_jobs: function (jobs, services) { - var job; + } + odoo.__DEBUG__.jsModules = { + missing: missing, + failed: failed.map(function (fail) { + return fail.name; + }), + }; + didLogInfoResolve(); + }; + odoo.processJobs = function (jobs, services) { + var job; - function process_job(job) { - var require = make_require(job); + function processJob(job) { + var require = makeRequire(job); - var job_exec; - var def = new Promise(function (resolve) { - try { - job_exec = job.factory.call(null, require); - jobs.splice(jobs.indexOf(job), 1); - } catch (e) { - job.error = e; - console.error('Error while loading ' + job.name); - console.error(e.stack); - } - if (!job.error) { - Promise.resolve(job_exec).then( - function (data) { - services[job.name] = data; - resolve(); - odoo.process_jobs(jobs, services); - }).guardedCatch(function (e) { - job.rejected = e || true; - jobs.push(job); - resolve(); - } - ); - } - }); - job_promise.push(def); - } + var jobExec; + var def = new Promise(function (resolve) { + try { + jobExec = job.factory.call(null, require); + jobs.splice(jobs.indexOf(job), 1); + } catch (e) { + job.error = e; + console.error('Error while loading ' + job.name); + console.error(e.stack); + } + if (!job.error) { + Promise.resolve(jobExec).then( + function (data) { + services[job.name] = data; + resolve(); + odoo.processJobs(jobs, services); + }).guardedCatch(function (e) { + job.rejected = e || true; + jobs.push(job); + resolve(); + } + ); + } + }); + jobPromises.push(def); + } - function is_ready(job) { - return !job.error && !job.rejected && _.every(job.factory.deps, function (name) { return name in services; }); - } + function isReady(job) { + return !job.error && !job.rejected && job.factory.deps.every(function (name) { + return name in services; + }); + } - function make_require(job) { - var deps = _.pick(services, job.deps); + function makeRequire(job) { + var deps = {}; + Object.keys(services).filter(function (item) { + return job.deps.indexOf(item) >= 0; + }).forEach(function (key) { + deps[key] = services[key]; + }); - function require(name) { - if (!(name in deps)) { - console.error('Undefined dependency: ', name); - } else { - require.__require_calls++; - } - return deps[name]; + return function require(name) { + if (!(name in deps)) { + console.error('Undefined dependency: ', name); } + return deps[name]; + }; + } - require.__require_calls = 0; - return require; + while (jobs.length) { + job = undefined; + for (var i = 0; i < jobs.length; i++) { + if (isReady(jobs[i])) { + job = jobs[i]; + break; + } } - - while (jobs.length && (job = _.find(jobs, is_ready))) { - process_job(job); + if (!job) { + break; } - - return services; + processJob(job); } - }); + return services; + }; - // automatically log errors detected when loading modules - var log_when_loaded = function () { - _.delay(function () { - var len = job_promise.length; - Promise.all(job_promise).then(function () { - if (len === job_promise.length) { + // Automatically log errors detected when loading modules + window.addEventListener('load', function logWhenLoaded() { + setTimeout(function () { + var len = jobPromises.length; + Promise.all(jobPromises).then(function () { + if (len === jobPromises.length) { odoo.log(); } else { - log_when_loaded(); + logWhenLoaded(); } }); - }, 6000); - }; - $(log_when_loaded); - + }, 9999); + }); })(); |
