mirror of
https://github.com/espocrm/espocrm.git
synced 2026-03-03 02:27:01 +00:00
bundler impr
This commit is contained in:
28
Gruntfile.js
28
Gruntfile.js
@@ -42,7 +42,15 @@ module.exports = grunt => {
|
||||
|
||||
const originalLibDir = 'client/lib/original';
|
||||
|
||||
let bundleJsFileList = buildUtils.getPreparedBundleLibList(libs).concat(originalLibDir + '/espo.js');
|
||||
let bundleFileMap = {'client/lib/espo-libs.min.js': buildUtils.getPreparedBundleLibList(libs)};
|
||||
|
||||
for (let i = 0; i < bundleConfig.chunkNumber; i++) {
|
||||
let bundleFile = originalLibDir + `/espo-${i}.js`;
|
||||
let minFile = `client/lib/espo-${i}.min.js`;
|
||||
|
||||
bundleFileMap[minFile] = [bundleFile];
|
||||
}
|
||||
|
||||
let copyJsFileList = buildUtils.getCopyLibDataList(libs);
|
||||
|
||||
let minifyLibFileList = copyJsFileList
|
||||
@@ -142,9 +150,7 @@ module.exports = grunt => {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
|
||||
},
|
||||
files: {
|
||||
'client/lib/espo.min.js': bundleJsFileList,
|
||||
},
|
||||
files: bundleFileMap,
|
||||
},
|
||||
lib: {
|
||||
files: minifyLibFileList,
|
||||
@@ -252,13 +258,23 @@ module.exports = grunt => {
|
||||
grunt.registerTask('espo-bundle', () => {
|
||||
const Bundler = require('./js/bundler');
|
||||
|
||||
let contents = (new Bundler()).bundle(bundleConfig.jsFiles);
|
||||
let chunks = (new Bundler()).bundle({
|
||||
files: bundleConfig.files,
|
||||
patterns: bundleConfig.patterns,
|
||||
allPatterns: ['client/src/**/*.js'],
|
||||
chunkNumber: bundleConfig.chunkNumber,
|
||||
libs: libs,
|
||||
});
|
||||
|
||||
if (!fs.existsSync(originalLibDir)) {
|
||||
fs.mkdirSync(originalLibDir);
|
||||
}
|
||||
|
||||
fs.writeFileSync(originalLibDir + '/espo.js', contents, 'utf8');
|
||||
chunks.forEach((chunk, i) => {
|
||||
let file = originalLibDir + `/espo-${i}.js`;
|
||||
|
||||
fs.writeFileSync(file, chunk, 'utf8');
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('prepare-lib-original', () => {
|
||||
|
||||
@@ -179,6 +179,7 @@ class ClientManager
|
||||
|
||||
$cssFileList = $this->metadata->get(['app', 'client', 'cssList'], []);
|
||||
$linkList = $this->metadata->get(['app', 'client', 'linkList'], []);
|
||||
$jsLibs = $this->metadata->get(['app', 'jsLibs'], []);
|
||||
|
||||
$scriptsHtml = '';
|
||||
|
||||
@@ -252,6 +253,12 @@ class ClientManager
|
||||
'internalModuleList' => Json::encode($internalModuleList),
|
||||
'applicationDescription' => $this->config->get('applicationDescription') ?? self::APP_DESCRIPTION,
|
||||
'nonce' => $this->nonce,
|
||||
'jsLibs' => Json::encode($jsLibs),
|
||||
'loaderParams' => Json::encode([
|
||||
'basePath' => $this->basePath,
|
||||
'cacheTimestamp' => $loaderCacheTimestamp,
|
||||
'internalModuleList' => $internalModuleList,
|
||||
]),
|
||||
];
|
||||
|
||||
$html = $this->fileManager->getContents($htmlFilePath);
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"scriptList": [
|
||||
"client/lib/espo.min.js"
|
||||
"client/lib/espo-libs.min.js",
|
||||
"client/lib/espo-0.min.js",
|
||||
"client/lib/espo-1.min.js",
|
||||
"client/lib/espo-2.min.js",
|
||||
"client/lib/espo-3.min.js"
|
||||
],
|
||||
"developerModeScriptList": [
|
||||
"client/src/loader.js",
|
||||
|
||||
@@ -90,8 +90,6 @@ class SettingsService
|
||||
{
|
||||
$data = (object) [];
|
||||
|
||||
$data->jsLibs = $this->metadata->get(['app', 'jsLibs']);
|
||||
|
||||
unset($data->loginView);
|
||||
|
||||
$loginView = $this->metadata->get(['clientDefs', 'App', 'loginView']);
|
||||
|
||||
@@ -26,128 +26,10 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/mass-email/fields/smtp-account', ['views/fields/enum'], function (Dep) {
|
||||
define('crm:views/mass-email/fields/smtp-account', ['views/lead-capture/fields/smtp-account'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
dataUrl: 'MassEmail/action/smtpAccountDataList',
|
||||
|
||||
getAttributeList: function () {
|
||||
return [this.name, 'inboundEmailId'];
|
||||
},
|
||||
|
||||
data: function () {
|
||||
var data = Dep.prototype.data.call(this);
|
||||
|
||||
data.valueIsSet = true;
|
||||
data.isNotEmpty = true;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
setupOptions: function () {
|
||||
Dep.prototype.setupOptions.call(this);
|
||||
|
||||
this.params.options = [];
|
||||
this.translatedOptions = {};
|
||||
|
||||
this.params.options.push('system');
|
||||
|
||||
if (!this.loadedOptionList) {
|
||||
if (this.model.get('inboundEmailId')) {
|
||||
var item = 'inboundEmail:' + this.model.get('inboundEmailId');
|
||||
|
||||
this.params.options.push(item);
|
||||
|
||||
this.translatedOptions[item] =
|
||||
(this.model.get('inboundEmailName') || this.model.get('inboundEmailId')) +
|
||||
' (' + this.translate('group', 'labels', 'MassEmail') + ')';
|
||||
}
|
||||
} else {
|
||||
this.loadedOptionList.forEach((item) => {
|
||||
this.params.options.push(item);
|
||||
|
||||
this.translatedOptions[item] =
|
||||
(this.loadedOptionTranslations[item] || item) +
|
||||
' (' + this.translate('group', 'labels', 'MassEmail') + ')';
|
||||
});
|
||||
}
|
||||
|
||||
this.translatedOptions['system'] =
|
||||
this.getConfig().get('outboundEmailFromAddress') +
|
||||
' (' + this.translate('system', 'labels', 'MassEmail') + ')';
|
||||
},
|
||||
|
||||
getValueForDisplay: function () {
|
||||
if (!this.model.has(this.name) && this.isReadMode()) {
|
||||
if (this.model.has('inboundEmailId')) {
|
||||
if (this.model.get('inboundEmailId')) {
|
||||
return 'inboundEmail:' + this.model.get('inboundEmailId');
|
||||
} else {
|
||||
return 'system';
|
||||
}
|
||||
} else {
|
||||
return '...';
|
||||
}
|
||||
}
|
||||
|
||||
return this.model.get(this.name);
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
if (
|
||||
this.getAcl().checkScope('MassEmail', 'create') ||
|
||||
this.getAcl().checkScope('MassEmail', 'edit')
|
||||
) {
|
||||
|
||||
Espo.Ajax.getRequest(this.dataUrl).then(dataList => {
|
||||
if (!dataList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedOptionList = [];
|
||||
|
||||
this.loadedOptionTranslations = {};
|
||||
this.loadedOptionAddresses = {};
|
||||
this.loadedOptionFromNames = {};
|
||||
|
||||
dataList.forEach(item => {
|
||||
this.loadedOptionList.push(item.key);
|
||||
|
||||
this.loadedOptionTranslations[item.key] = item.emailAddress;
|
||||
this.loadedOptionAddresses[item.key] = item.emailAddress;
|
||||
this.loadedOptionFromNames[item.key] = item.fromName || '';
|
||||
});
|
||||
|
||||
this.setupOptions();
|
||||
this.reRender();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fetch: function () {
|
||||
var data = {};
|
||||
var value = this.$element.val();
|
||||
|
||||
data[this.name] = value;
|
||||
|
||||
if (!value || value === 'system') {
|
||||
data.inboundEmailId = null;
|
||||
data.inboundEmailName = null;
|
||||
}
|
||||
else {
|
||||
var arr = value.split(':');
|
||||
|
||||
if (arr.length > 1) {
|
||||
data.inboundEmailId = arr[1];
|
||||
data.inboundEmailName = this.translatedOptions[data.inboundEmailId] || data.inboundEmailId;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -451,7 +451,6 @@ function (
|
||||
])
|
||||
.then(() => {
|
||||
this.loader.setIsDeveloperMode(this.settings.get('isDeveloperMode'));
|
||||
this.loader.addLibsConfig(this.settings.get('jsLibs') || {});
|
||||
|
||||
this.user = new User();
|
||||
this.preferences = new Preferences();
|
||||
|
||||
@@ -924,4 +924,21 @@
|
||||
loader.define(subject, dependency, callback);
|
||||
};
|
||||
|
||||
(() => {
|
||||
let loaderParamsTag = document.querySelector('script[data-name="loader-params"]');
|
||||
|
||||
if (loaderParamsTag) {
|
||||
let params = JSON.parse(loaderParamsTag.textContent);
|
||||
|
||||
Espo.loader.setCacheTimestamp(params.cacheTimestamp);
|
||||
Espo.loader.setBasePath(params.basePath);
|
||||
Espo.loader.setInternalModuleList(params.internalModuleList);
|
||||
}
|
||||
|
||||
let jsLibsTag = document.querySelector('script[data-name="js-libs"]');
|
||||
if (jsLibsTag) {
|
||||
Espo.loader.addLibsConfig(JSON.parse(jsLibsTag.textContent));
|
||||
}
|
||||
})();
|
||||
|
||||
}).call(window, _, $);
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/admin/layouts/grid',
|
||||
['views/admin/layouts/base', 'res!client/css/misc/layout-manager-grid.css'],
|
||||
function (Dep, styleCss) {
|
||||
define('views/admin/layouts/grid', ['views/admin/layouts/base'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -247,7 +245,9 @@ function (Dep, styleCss) {
|
||||
|
||||
this.panelsData = {};
|
||||
|
||||
this.$style = $('<style>').html(styleCss).appendTo($('body'));
|
||||
require('res!client/css/misc/layout-manager-grid.css', styleCss => {
|
||||
this.$style = $('<style>').html(styleCss).appendTo($('body'));
|
||||
});
|
||||
},
|
||||
|
||||
onRemove: function () {
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/admin/layouts/rows',
|
||||
['views/admin/layouts/base', 'res!client/css/misc/layout-manager-rows.css'],
|
||||
function (Dep, styleCss) {
|
||||
define('views/admin/layouts/rows', ['views/admin/layouts/base'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
@@ -68,7 +66,13 @@ function (Dep, styleCss) {
|
||||
this.itemsData[name] = Espo.Utils.cloneDeep(attributes);
|
||||
});
|
||||
|
||||
this.$style = $('<style>').html(styleCss).appendTo($('body'));
|
||||
this.wait(
|
||||
Espo.loader.requirePromise()
|
||||
);
|
||||
|
||||
require('res!client/css/misc/layout-manager-rows.css', styleCss => {
|
||||
this.$style = $('<style>').html(styleCss).appendTo($('body'));
|
||||
});
|
||||
},
|
||||
|
||||
onRemove: function () {
|
||||
|
||||
@@ -26,10 +26,127 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/lead-capture/fields/smtp-account', ['crm:views/mass-email/fields/smtp-account'], function (Dep) {
|
||||
define('views/lead-capture/fields/smtp-account', ['views/fields/enum'], function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
dataUrl: 'LeadCapture/action/smtpAccountDataList',
|
||||
|
||||
getAttributeList: function () {
|
||||
return [this.name, 'inboundEmailId'];
|
||||
},
|
||||
|
||||
data: function () {
|
||||
var data = Dep.prototype.data.call(this);
|
||||
|
||||
data.valueIsSet = true;
|
||||
data.isNotEmpty = true;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
setupOptions: function () {
|
||||
Dep.prototype.setupOptions.call(this);
|
||||
|
||||
this.params.options = [];
|
||||
this.translatedOptions = {};
|
||||
|
||||
this.params.options.push('system');
|
||||
|
||||
if (!this.loadedOptionList) {
|
||||
if (this.model.get('inboundEmailId')) {
|
||||
var item = 'inboundEmail:' + this.model.get('inboundEmailId');
|
||||
|
||||
this.params.options.push(item);
|
||||
|
||||
this.translatedOptions[item] =
|
||||
(this.model.get('inboundEmailName') || this.model.get('inboundEmailId')) +
|
||||
' (' + this.translate('group', 'labels', 'MassEmail') + ')';
|
||||
}
|
||||
} else {
|
||||
this.loadedOptionList.forEach((item) => {
|
||||
this.params.options.push(item);
|
||||
|
||||
this.translatedOptions[item] =
|
||||
(this.loadedOptionTranslations[item] || item) +
|
||||
' (' + this.translate('group', 'labels', 'MassEmail') + ')';
|
||||
});
|
||||
}
|
||||
|
||||
this.translatedOptions['system'] =
|
||||
this.getConfig().get('outboundEmailFromAddress') +
|
||||
' (' + this.translate('system', 'labels', 'MassEmail') + ')';
|
||||
},
|
||||
|
||||
getValueForDisplay: function () {
|
||||
if (!this.model.has(this.name) && this.isReadMode()) {
|
||||
if (this.model.has('inboundEmailId')) {
|
||||
if (this.model.get('inboundEmailId')) {
|
||||
return 'inboundEmail:' + this.model.get('inboundEmailId');
|
||||
} else {
|
||||
return 'system';
|
||||
}
|
||||
} else {
|
||||
return '...';
|
||||
}
|
||||
}
|
||||
|
||||
return this.model.get(this.name);
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
if (
|
||||
this.getAcl().checkScope('MassEmail', 'create') ||
|
||||
this.getAcl().checkScope('MassEmail', 'edit')
|
||||
) {
|
||||
|
||||
Espo.Ajax.getRequest(this.dataUrl).then(dataList => {
|
||||
if (!dataList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadedOptionList = [];
|
||||
|
||||
this.loadedOptionTranslations = {};
|
||||
this.loadedOptionAddresses = {};
|
||||
this.loadedOptionFromNames = {};
|
||||
|
||||
dataList.forEach(item => {
|
||||
this.loadedOptionList.push(item.key);
|
||||
|
||||
this.loadedOptionTranslations[item.key] = item.emailAddress;
|
||||
this.loadedOptionAddresses[item.key] = item.emailAddress;
|
||||
this.loadedOptionFromNames[item.key] = item.fromName || '';
|
||||
});
|
||||
|
||||
this.setupOptions();
|
||||
this.reRender();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
fetch: function () {
|
||||
var data = {};
|
||||
var value = this.$element.val();
|
||||
|
||||
data[this.name] = value;
|
||||
|
||||
if (!value || value === 'system') {
|
||||
data.inboundEmailId = null;
|
||||
data.inboundEmailName = null;
|
||||
}
|
||||
else {
|
||||
var arr = value.split(':');
|
||||
|
||||
if (arr.length > 1) {
|
||||
data.inboundEmailId = arr[1];
|
||||
data.inboundEmailName = this.translatedOptions[data.inboundEmailId] || data.inboundEmailId;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,47 +1,29 @@
|
||||
{
|
||||
"jsFiles": [
|
||||
"files": [
|
||||
"client/src/namespace.js",
|
||||
"client/src/loader.js",
|
||||
"client/src/loader-init-libs.js",
|
||||
"client/src/exceptions.js",
|
||||
"client/src/utils.js",
|
||||
|
||||
"client/src/acl.js",
|
||||
"client/src/model.js",
|
||||
"client/src/model-offline.js",
|
||||
"client/src/ajax.js",
|
||||
"client/src/controller.js",
|
||||
|
||||
"client/src/ui.js",
|
||||
"client/src/acl-manager.js",
|
||||
"client/src/cache.js",
|
||||
"client/src/storage.js",
|
||||
"client/src/models/settings.js",
|
||||
"client/src/language.js",
|
||||
"client/src/metadata.js",
|
||||
"client/src/field-manager.js",
|
||||
"client/src/models/user.js",
|
||||
"client/src/models/preferences.js",
|
||||
"client/src/model-factory.js",
|
||||
"client/src/collection-factory.js",
|
||||
"client/src/pre-loader.js",
|
||||
"client/src/controllers/base.js",
|
||||
"client/src/router.js",
|
||||
"client/src/date-time.js",
|
||||
"client/src/layout-manager.js",
|
||||
"client/src/theme-manager.js",
|
||||
"client/src/session-storage.js",
|
||||
"client/src/view-helper.js",
|
||||
"client/src/page-title.js",
|
||||
"client/src/broadcast-channel.js",
|
||||
"client/src/web-socket-manager.js",
|
||||
"client/src/number.js",
|
||||
|
||||
"client/src/helpers/file-upload.js",
|
||||
"client/src/helpers/mass-action.js",
|
||||
"client/src/helpers/export.js",
|
||||
"client/src/helpers/action-item-setup.js",
|
||||
|
||||
"client/src/app.js"
|
||||
]
|
||||
"client/src/utils.js"
|
||||
],
|
||||
"patterns": [
|
||||
"client/src/*.js",
|
||||
"client/src/ui/**/*.js",
|
||||
"client/src/views/*.js",
|
||||
"client/src/views/site/*.js",
|
||||
"client/src/views/fields/*.js",
|
||||
"client/src/views/record/**/*.js",
|
||||
"client/src/views/search/**/*.js",
|
||||
"client/src/views/modals/*.js",
|
||||
"client/src/views/dashlets/**/*.js",
|
||||
"client/src/views/global-search/*.js",
|
||||
"client/src/views/stream/*.js",
|
||||
"client/src/views/note/*.js",
|
||||
"client/src/views/notification/*.js",
|
||||
"client/src/controllers/*.js",
|
||||
"client/src/models/*.js",
|
||||
"client/src/collections/*.js",
|
||||
"client/src/acl/*.js"
|
||||
],
|
||||
"chunkNumber": 4
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
[
|
||||
{
|
||||
"src": "node_modules/jquery/dist/jquery.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "jquery"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/underscore/underscore.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "underscore"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/es6-promise/dist/es6-promise.js",
|
||||
@@ -13,19 +15,23 @@
|
||||
},
|
||||
{
|
||||
"src": "node_modules/backbone/backbone.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "backbone"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/handlebars/dist/handlebars.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "handlebars"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/bullbone/dist/bullbone.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "bullbone"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/js-base64/base64.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "Base64"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/moment/moment.js",
|
||||
@@ -49,7 +55,8 @@
|
||||
},
|
||||
{
|
||||
"src": "node_modules/jquery-textcomplete/dist/jquery.textcomplete.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "Textcomplete"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/bootstrap/dist/js/bootstrap.js",
|
||||
@@ -61,11 +68,13 @@
|
||||
},
|
||||
{
|
||||
"src": "node_modules/marked/lib/marked.umd.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "marked"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/dompurify/dist/purify.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "dompurify"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/autobahn-espo/autobahn.js",
|
||||
@@ -86,48 +95,62 @@
|
||||
"src": "node_modules/gridstack/dist/gridstack-jq.js"
|
||||
}
|
||||
],
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "gridstack"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/selectize/dist/js/standalone/selectize.js",
|
||||
"bundle": true
|
||||
"bundle": true,
|
||||
"key": "Selectize"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/autonumeric/dist/autoNumeric.js",
|
||||
"bundle": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/cropper/dist/cropper.js"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/cronstrue/dist/cronstrue-i18n.js",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/exif-js/exif.js",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/jsbarcode/dist/JsBarcode.all.js",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/qrcodejs/qrcode.js"
|
||||
"bundle": true,
|
||||
"key": "autonumeric"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/summernote/dist/summernote.js",
|
||||
"key": "Summernote",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/espo-funnel-chart/build/espo-funnel-chart.js"
|
||||
"src": "node_modules/espo-funnel-chart/build/espo-funnel-chart.js",
|
||||
"key": "espo-funnel-chart",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/flotr2/flotr2.js",
|
||||
"key": "Flotr",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js",
|
||||
"key": "Colorpicker"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/cropper/dist/cropper.js",
|
||||
"key": "Cropper",
|
||||
"minify": true
|
||||
},
|
||||
{
|
||||
"src": "node_modules/cronstrue/dist/cronstrue-i18n.js",
|
||||
"minify": true,
|
||||
"key": "cronstrue"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/exif-js/exif.js",
|
||||
"minify": true,
|
||||
"key": "exif"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/jsbarcode/dist/JsBarcode.all.js",
|
||||
"minify": true,
|
||||
"key": "JsBarcode"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/qrcodejs/qrcode.js",
|
||||
"key": "qrcode"
|
||||
},
|
||||
{
|
||||
"name": "ace-builds",
|
||||
"files": [
|
||||
@@ -147,16 +170,19 @@
|
||||
"src": "node_modules/ace-builds/src-noconflict/theme-tomorrow_night.js",
|
||||
"dest": "client/lib/ace-theme-tomorrow_night.js"
|
||||
}
|
||||
]
|
||||
],
|
||||
"key": "ace"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/fullcalendar/dist/fullcalendar.js",
|
||||
"dest": "client/modules/crm/lib/fullcalendar.js",
|
||||
"minify": true
|
||||
"minify": true,
|
||||
"key": "full-calendar"
|
||||
},
|
||||
{
|
||||
"src": "node_modules/vis/dist/vis.js",
|
||||
"dest": "client/modules/crm/lib/vis.js",
|
||||
"minify": true
|
||||
"minify": true,
|
||||
"key": "vis"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{applicationName}}</title>{{scriptsHtml}}
|
||||
<title>{{applicationName}}</title>
|
||||
<script type="application/json" data-name="loader-params">{{loaderParams}}</script>
|
||||
<script type="application/json" data-name="js-libs">{{jsLibs}}</script>{{scriptsHtml}}
|
||||
<link href="{{basePath}}{{stylesheet}}?r={{cacheTimestamp}}" rel="stylesheet" id='main-stylesheet'>{{additionalStyleSheetsHtml}}{{linksHtml}}
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
@@ -14,10 +16,6 @@
|
||||
<link rel="shortcut icon" href="{{basePath}}{{faviconPath}}" type="image/x-icon">
|
||||
<script type="text/javascript" nonce="{{nonce}}">
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
Espo.loader.setCacheTimestamp({{loaderCacheTimestamp}});
|
||||
Espo.loader.setBasePath('{{basePath}}');
|
||||
Espo.loader.setInternalModuleList({{internalModuleList}});
|
||||
|
||||
require('{{appClientClassName}}', App => {
|
||||
new App({
|
||||
id: '{{applicationId}}',
|
||||
|
||||
312
js/bundler.js
312
js/bundler.js
@@ -28,9 +28,13 @@
|
||||
|
||||
const typescript = require('typescript');
|
||||
const fs = require('fs');
|
||||
const {globSync} = require('glob');
|
||||
|
||||
/**
|
||||
* Normalizes and concatenates Espo modules.
|
||||
*
|
||||
* Modules dependent on not bundled libs are ignored. Modules dependent on such modules
|
||||
* are ignored as well and so on.
|
||||
*/
|
||||
class Bundler {
|
||||
|
||||
@@ -41,17 +45,304 @@ class Bundler {
|
||||
basePath = 'client/src'
|
||||
|
||||
/**
|
||||
* @param {string[]} pathList
|
||||
* @return {string}
|
||||
* Bundles Espo js files into chunks.
|
||||
*
|
||||
* @param {{
|
||||
* files: string[],
|
||||
* patterns: string[],
|
||||
* allPatterns: string[],
|
||||
* chunkNumber: number,
|
||||
* libs: {
|
||||
* src?: string,
|
||||
* bundle?: boolean,
|
||||
* key?: string,
|
||||
* }[],
|
||||
* }} params
|
||||
* @return {string[]}
|
||||
*/
|
||||
bundle(pathList) {
|
||||
let bundleContents = '';
|
||||
bundle(params) {
|
||||
let files = []
|
||||
.concat(params.files)
|
||||
.concat(this.#obtainFiles(params.patterns, params.files));
|
||||
|
||||
pathList.forEach(path => {
|
||||
bundleContents += this.normalizeSourceFile(path);
|
||||
})
|
||||
let allFiles = this.#obtainFiles(params.allPatterns);
|
||||
|
||||
return bundleContents;
|
||||
let ignoreLibs = params.libs
|
||||
.filter(item => item.key && !item.bundle)
|
||||
.map(item => 'lib!' + item.key);
|
||||
|
||||
let sortedFiles = this.#sortFiles(files, allFiles, ignoreLibs);
|
||||
|
||||
let portions = [];
|
||||
let portionSize = Math.floor(sortedFiles.length / params.chunkNumber);
|
||||
|
||||
for (let i = 0; i < params.chunkNumber; i++) {
|
||||
let end = i === params.chunkNumber - 1 ?
|
||||
sortedFiles.length :
|
||||
(i + 1) * portionSize;
|
||||
|
||||
portions.push(sortedFiles.slice(i * portionSize, end));
|
||||
}
|
||||
|
||||
let chunks = [];
|
||||
|
||||
portions.forEach(portion => {
|
||||
let chunk = '';
|
||||
|
||||
portion.forEach(file => chunk += this.normalizeSourceFile(file));
|
||||
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} patterns
|
||||
* @param {string[]} [ignoreFiles]
|
||||
* @return {string[]}
|
||||
*/
|
||||
#obtainFiles(patterns, ignoreFiles) {
|
||||
let files = [];
|
||||
ignoreFiles = ignoreFiles || [];
|
||||
|
||||
patterns.forEach(pattern => {
|
||||
let itemFiles = globSync(pattern, {})
|
||||
.map(file => file.replaceAll('\\', '/'))
|
||||
.filter(file => !ignoreFiles.includes(file));
|
||||
|
||||
files = files.concat(itemFiles);
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} files
|
||||
* @param {string[]} allFiles
|
||||
* @param {string[]} ignoreLibs
|
||||
* @return {string[]}
|
||||
*/
|
||||
#sortFiles(files, allFiles, ignoreLibs) {
|
||||
/** @var {Object.<string, string[]>} */
|
||||
let map = {};
|
||||
|
||||
let standalonePathList = [];
|
||||
|
||||
let modules = [];
|
||||
let moduleFileMap = {};
|
||||
|
||||
allFiles.forEach(file => {
|
||||
let data = this.#obtainModuleData(file);
|
||||
|
||||
let isTarget = files.includes(file);
|
||||
|
||||
if (!data) {
|
||||
if (isTarget) {
|
||||
standalonePathList.push(file);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
map[data.name] = data.deps;
|
||||
moduleFileMap[data.name] = file;
|
||||
|
||||
if (isTarget) {
|
||||
modules.push(data.name);
|
||||
}
|
||||
});
|
||||
|
||||
let depModules = [];
|
||||
|
||||
modules
|
||||
.forEach(name => {
|
||||
let deps = this.#obtainAllDeps(name, map);
|
||||
|
||||
deps
|
||||
.filter(item => !item.includes('!'))
|
||||
.filter(item => !modules.includes(item))
|
||||
.filter(item => !depModules.includes(item))
|
||||
.forEach(item => {
|
||||
depModules.push(item);
|
||||
});
|
||||
});
|
||||
|
||||
modules = modules.concat(depModules);
|
||||
|
||||
/** @var {string[]} */
|
||||
let discardedModules = [];
|
||||
/** @var {Object.<string, number>} */
|
||||
let depthMap = {};
|
||||
|
||||
for (let name of modules) {
|
||||
this.#buildTreeItem(
|
||||
name,
|
||||
map,
|
||||
depthMap,
|
||||
ignoreLibs,
|
||||
discardedModules
|
||||
);
|
||||
}
|
||||
|
||||
modules.sort((v1, v2) => {
|
||||
return depthMap[v2] - depthMap[v1];
|
||||
});
|
||||
|
||||
modules = modules.filter(item => !discardedModules.includes(item));
|
||||
|
||||
let modulePaths = modules.map(name => {
|
||||
return moduleFileMap[name];
|
||||
});
|
||||
|
||||
return standalonePathList.concat(modulePaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Object.<string, string[]>} map
|
||||
* @param {string[]} [list]
|
||||
*/
|
||||
#obtainAllDeps(name, map, list) {
|
||||
if (!list) {
|
||||
list = [];
|
||||
}
|
||||
|
||||
let deps = map[name] || [];
|
||||
|
||||
deps.forEach(depName => {
|
||||
if (!list.includes(depName)) {
|
||||
list.push(depName);
|
||||
}
|
||||
|
||||
if (depName.includes('!')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#obtainAllDeps(depName, map, list);
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Object.<string, string[]>} map
|
||||
* @param {Object.<string, number>} depthMap
|
||||
* @param {string[]} ignoreLibs
|
||||
* @param {string[]} discardedModules
|
||||
* @param {number} [depth]
|
||||
* @param {string[]} [path]
|
||||
*/
|
||||
#buildTreeItem(
|
||||
name,
|
||||
map,
|
||||
depthMap,
|
||||
ignoreLibs,
|
||||
discardedModules,
|
||||
depth,
|
||||
path
|
||||
) {
|
||||
/** @var {string[]} */
|
||||
let deps = map[name] || [];
|
||||
depth = depth || 0;
|
||||
path = [].concat(path || []);
|
||||
|
||||
path.push(name);
|
||||
|
||||
if (!(name in depthMap)) {
|
||||
depthMap[name] = depth;
|
||||
}
|
||||
else if (depth > depthMap[name]) {
|
||||
depthMap[name] = depth;
|
||||
}
|
||||
|
||||
if (deps.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let depName of deps) {
|
||||
if (ignoreLibs.includes(depName)) {
|
||||
path
|
||||
.filter(item => !discardedModules.includes(item))
|
||||
.forEach(item => discardedModules.push(item));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
deps.forEach(depName => {
|
||||
if (depName.includes('!')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#buildTreeItem(
|
||||
depName,
|
||||
map,
|
||||
depthMap,
|
||||
ignoreLibs,
|
||||
discardedModules,
|
||||
depth + 1,
|
||||
path
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @return {{deps: string[], name: string}|null}
|
||||
*/
|
||||
#obtainModuleData(path) {
|
||||
if (!this.#isClientJsFile(path)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let tsSourceFile = typescript.createSourceFile(
|
||||
path,
|
||||
fs.readFileSync(path, 'utf-8'),
|
||||
typescript.ScriptTarget.Latest
|
||||
);
|
||||
|
||||
let rootStatement = tsSourceFile.statements[0];
|
||||
|
||||
if (
|
||||
!rootStatement.expression ||
|
||||
!rootStatement.expression.expression ||
|
||||
rootStatement.expression.expression.escapedText !== 'define'
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let moduleName = path.slice(this._getBathPath().length, -3);
|
||||
|
||||
let deps = [];
|
||||
|
||||
let argumentList = rootStatement.expression.arguments;
|
||||
|
||||
for (let argument of argumentList.slice(0, 2)) {
|
||||
if (argument.elements) {
|
||||
argument.elements.forEach(node => {
|
||||
if (!node.text) {
|
||||
return;
|
||||
}
|
||||
|
||||
deps.push(node.text);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: moduleName,
|
||||
deps: deps,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @return {boolean}
|
||||
*/
|
||||
#isClientJsFile(path) {
|
||||
return path.indexOf(this._getBathPath()) === 0 && path.slice(-3) === '.js';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,10 +354,7 @@ class Bundler {
|
||||
let sourceCode = fs.readFileSync(path, 'utf-8');
|
||||
let basePath = this._getBathPath();
|
||||
|
||||
if (
|
||||
path.indexOf(basePath) !== 0 ||
|
||||
path.slice(-3) !== '.js'
|
||||
) {
|
||||
if (!this.#isClientJsFile(path)) {
|
||||
return sourceCode;
|
||||
}
|
||||
|
||||
|
||||
14
js/diff.js
14
js/diff.js
@@ -34,6 +34,8 @@ const buildUtils = require('./build-utils');
|
||||
|
||||
const exec = cp.exec;
|
||||
|
||||
const bundleConfig = require('./../frontend/bundle-config.json');
|
||||
|
||||
/**
|
||||
* Builds upgrade packages.
|
||||
*/
|
||||
@@ -279,9 +281,15 @@ class Diff
|
||||
|
||||
libData.filesToCopy.forEach(item => fileList.push(item));
|
||||
|
||||
fileList.push('client/lib/espo.min.js');
|
||||
fileList.push('client/lib/espo.min.js.map');
|
||||
fileList.push('client/lib/original/espo.js');
|
||||
fileList.push('client/lib/espo-libs.min.js');
|
||||
fileList.push('client/lib/espo-libs.min.js.map');
|
||||
|
||||
for (let i = 0; i < bundleConfig.chunkNumber; i++) {
|
||||
fileList.push(`client/lib/espo-${i}.min.js`);
|
||||
fileList.push(`client/lib/espo-${i}.min.js.map`);
|
||||
}
|
||||
|
||||
//fileList.push('client/lib/original/espo.js');
|
||||
|
||||
fs.readdirSync('client/css/espo/').forEach(file => {
|
||||
fileList.push('client/css/espo/' + file);
|
||||
|
||||
@@ -30,6 +30,7 @@ const fs = require('fs');
|
||||
const buildUtils = require('../build-utils');
|
||||
|
||||
const libs = require('./../../frontend/libs.json');
|
||||
const bundleConfig = require('./../../frontend/bundle-config.json');
|
||||
|
||||
const libDir = './client/lib';
|
||||
const originalLibDir = './client/lib/original';
|
||||
@@ -38,10 +39,15 @@ const originalLibCrmDir = './client/modules/crm/lib/original';
|
||||
|
||||
[libDir, originalLibDir, libCrmDir, originalLibCrmDir]
|
||||
.filter(path => !fs.existsSync(path))
|
||||
.forEach(path => fs.mkdirSync(path))
|
||||
.forEach(path => fs.mkdirSync(path));
|
||||
|
||||
let bundleFiles = [];
|
||||
for (let i = 0; i < bundleConfig.chunkNumber; i++) {
|
||||
bundleFiles.push(`espo-${i}.js`)
|
||||
}
|
||||
|
||||
fs.readdirSync(originalLibDir)
|
||||
.filter(file => file !== 'espo.js')
|
||||
.filter(file => !bundleFiles.includes(file))
|
||||
.forEach(file => fs.unlinkSync(originalLibDir + '/' + file));
|
||||
|
||||
fs.readdirSync(originalLibCrmDir)
|
||||
|
||||
1103
package-lock.json
generated
1103
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
||||
"devDependencies": {
|
||||
"archiver": "^5.3.0",
|
||||
"fstream": ">=1.0.12",
|
||||
"glob": "^10.2.6",
|
||||
"grunt": "^1.5.3",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-concat": "^2.0.0",
|
||||
|
||||
9
upgrades/7.6/data.json
Normal file
9
upgrades/7.6/data.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"manifest": {
|
||||
"delete": [
|
||||
"client/lib/espo.min.js",
|
||||
"client/lib/espo.min.js.map",
|
||||
"client/lib/original/espo.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user