bundler impr

This commit is contained in:
Yuri Kuznetsov
2023-05-31 11:34:39 +03:00
parent 1daac4cfad
commit 5e492d3e3f
19 changed files with 1684 additions and 257 deletions

View File

@@ -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', () => {

View File

@@ -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);

View File

@@ -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",

View File

@@ -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']);

View File

@@ -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;
},
});
});

View File

@@ -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();

View File

@@ -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, _, $);

View File

@@ -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 () {

View File

@@ -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 () {

View File

@@ -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;
},
});
});

View File

@@ -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
}

View File

@@ -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"
}
]

View File

@@ -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}}',

View File

@@ -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;
}

View File

@@ -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);

View 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

File diff suppressed because it is too large Load Diff

View File

@@ -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
View File

@@ -0,0 +1,9 @@
{
"manifest": {
"delete": [
"client/lib/espo.min.js",
"client/lib/espo.min.js.map",
"client/lib/original/espo.js"
]
}
}