[PERF] mail, web: accelerate page loading by lazy-loading emoji data
Previously, the emoji data that is used in the emoji grid was part of the main assets bundle. This file is almost 500kB and the data it needs is only needed when opening the emoji grid. This commit moves this file into its own bundle and only loads it when opening the emoji grid instead. This PR also batches the inserts in the emoji model, bringing the time it takes to do those inserts from ~8000ms to ~800ms. closes odoo/odoo#102562 X-original-commit: e272e4fc6abce3153cce3748d8a5a7df63565916 Related: odoo/enterprise#32468 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
committed by
Alexandre Kühn
parent
9c8bff35be
commit
89013fa42a
@@ -121,9 +121,11 @@ For more specific needs, you may also assign custom-defined actions
|
||||
'mail.assets_messaging': [
|
||||
('include', 'mail.assets_core_messaging'),
|
||||
'mail/static/src/models/*.js',
|
||||
'mail/static/src/models_data/*.js',
|
||||
'mail/static/lib/selfie_segmentation/selfie_segmentation.js',
|
||||
],
|
||||
'mail.assets_model_data': [
|
||||
'mail/static/src/models_data/*.js',
|
||||
],
|
||||
# Custom bundle in case we want to remove things that are later added to web.assets_common
|
||||
'mail.assets_common_discuss_public': [
|
||||
('include', 'web.assets_common'),
|
||||
|
||||
@@ -6,6 +6,14 @@ import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiPickerView',
|
||||
lifecycleHooks: {
|
||||
_created() {
|
||||
if (this.messaging.emojiRegistry.isLoaded || this.messaging.emojiRegistry.isLoading) {
|
||||
return;
|
||||
}
|
||||
this.messaging.emojiRegistry.loadEmojiData();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
activeCategoryByGridViewScroll: one('EmojiPickerView.Category'),
|
||||
activeCategory: one('EmojiPickerView.Category', {
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { many } from '@mail/model/model_field';
|
||||
import { attr, many } from '@mail/model/model_field';
|
||||
import { insert } from '@mail/model/model_field_command';
|
||||
import { emojiCategoriesData, emojisData } from '@mail/models_data/emoji_data';
|
||||
import { getBundle, loadBundle } from '@web/core/assets';
|
||||
|
||||
registerModel({
|
||||
name: 'EmojiRegistry',
|
||||
lifecycleHooks: {
|
||||
_created() {
|
||||
recordMethods: {
|
||||
async loadEmojiData() {
|
||||
this.update({ isLoading: true });
|
||||
await getBundle('mail.assets_model_data').then(loadBundle);
|
||||
const { emojiCategoriesData, emojisData } = await odoo.runtimeImport("@mail/models_data/emoji_data");
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this._populateFromEmojiData(emojiCategoriesData, emojisData);
|
||||
},
|
||||
},
|
||||
recordMethods: {
|
||||
async _populateFromEmojiData(dataCategories, dataEmojis) {
|
||||
await this.messaging.executeGracefully(dataCategories.map(category => () => {
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
dataCategories.map(category => {
|
||||
const emojiCount = dataEmojis.reduce((acc, emoji) => emoji.category === category.name ? acc + 1 : acc, 0);
|
||||
this.update({
|
||||
dataCategories: insert({
|
||||
@@ -27,23 +28,19 @@ registerModel({
|
||||
emojiCount,
|
||||
}),
|
||||
});
|
||||
}));
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
await this.messaging.executeGracefully(dataEmojis.map(emojiData => () => {
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this.models['Emoji'].insert({
|
||||
codepoints: emojiData.codepoints,
|
||||
shortcodes: emojiData.shortcodes,
|
||||
emoticons: emojiData.emoticons,
|
||||
name: emojiData.name,
|
||||
keywords: emojiData.keywords,
|
||||
emojiDataCategory: { name: emojiData.category },
|
||||
});
|
||||
}));
|
||||
});
|
||||
this.models['Emoji'].insert(dataEmojis.map(emojiData => ({
|
||||
codepoints: emojiData.codepoints,
|
||||
shortcodes: emojiData.shortcodes,
|
||||
emoticons: emojiData.emoticons,
|
||||
name: emojiData.name,
|
||||
keywords: emojiData.keywords,
|
||||
emojiDataCategory: { name: emojiData.category },
|
||||
})));
|
||||
this.update({
|
||||
isLoaded: true,
|
||||
isLoading: false,
|
||||
});
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
@@ -59,5 +56,11 @@ registerModel({
|
||||
sort: [['smaller-first', 'codepoints']],
|
||||
}),
|
||||
dataCategories: many('EmojiCategory'),
|
||||
isLoaded: attr({
|
||||
default: false,
|
||||
}),
|
||||
isLoading: attr({
|
||||
default: false,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import { registerPatch } from '@mail/model/model_core';
|
||||
registerPatch({
|
||||
name: 'EmojiRegistry',
|
||||
recordMethods: {
|
||||
async _populateFromEmojiData() {
|
||||
async loadEmojiData() {
|
||||
const dataEmojiCategories = [
|
||||
{
|
||||
"name": "Smileys & Emotion",
|
||||
@@ -95,7 +95,7 @@ registerPatch({
|
||||
]
|
||||
},
|
||||
];
|
||||
this._super(dataEmojiCategories, dataEmojis);
|
||||
this._populateFromEmojiData(dataEmojiCategories, dataEmojis);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -235,7 +235,9 @@
|
||||
factories[name] = factory;
|
||||
|
||||
let promiseResolve;
|
||||
const promise = new Promise(resolve => {promiseResolve = resolve;});
|
||||
const promise = new Promise((resolve) => {
|
||||
promiseResolve = resolve;
|
||||
});
|
||||
jobs.push({
|
||||
name: name,
|
||||
factory: factory,
|
||||
@@ -372,13 +374,20 @@
|
||||
* loaded. The value is equal to the number of services found.
|
||||
*/
|
||||
odoo.ready = async function (serviceName) {
|
||||
function match (name) {
|
||||
return typeof serviceName === 'string' ? name === serviceName : serviceName.test(name);
|
||||
function match(name) {
|
||||
return typeof serviceName === "string" ? name === serviceName : serviceName.test(name);
|
||||
}
|
||||
await Promise.all(jobs.filter(job => match(job.name)).map(job => job.promise));
|
||||
await Promise.all(jobs.filter((job) => match(job.name)).map((job) => job.promise));
|
||||
return Object.keys(factories).filter(match).length;
|
||||
};
|
||||
|
||||
odoo.runtimeImport = function (moduleName) {
|
||||
if (!(moduleName in services)) {
|
||||
throw new Error(`Service "${moduleName} is not defined or isn't finished loading."`);
|
||||
}
|
||||
return services[moduleName];
|
||||
};
|
||||
|
||||
// Automatically log errors detected when loading modules
|
||||
globalThis.addEventListener("load", function logWhenLoaded() {
|
||||
const len = jobPromises.length;
|
||||
|
||||
Reference in New Issue
Block a user