mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-24 17:04:14 +01:00
generate a non-request specific importmap, as we ajax_exec apps and then not reload importmap
This commit is contained in:
parent
42305a6562
commit
40cac6f964
@ -13,6 +13,7 @@
|
||||
|
||||
namespace EGroupware\Api;
|
||||
|
||||
use EGroupware\Api\Framework\Bundle;
|
||||
use EGroupware\Api\Header\ContentSecurityPolicy;
|
||||
|
||||
/**
|
||||
@ -164,7 +165,7 @@ abstract class Framework extends Framework\Extra
|
||||
// We need LABjs, but putting it through Framework\IncludeMgr causes it to re-load itself
|
||||
//'/api/js/labjs/LAB.src.js',
|
||||
|
||||
// allways load jquery (not -ui) first
|
||||
// always load jquery (not -ui) first
|
||||
'/vendor/bower-asset/jquery/dist/jquery.js',
|
||||
'/api/js/jquery/jquery.noconflict.js',
|
||||
// always include javascript helper functions
|
||||
@ -1082,7 +1083,7 @@ abstract class Framework extends Framework\Extra
|
||||
|
||||
// add import-map before (!) first module
|
||||
$java_script .= '<script type="importmap" nonce="'.htmlspecialchars(ContentSecurityPolicy::addNonce('script-src')).'">'."\n".
|
||||
json_encode(self::getImportMap($map), JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT)."\n".
|
||||
json_encode(self::getImportMap(), JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT)."\n".
|
||||
"</script>\n";
|
||||
|
||||
// load our clientside entrypoint egw.js
|
||||
@ -1123,28 +1124,14 @@ abstract class Framework extends Framework\Extra
|
||||
/**
|
||||
* Add EGroupware URL prefix eg. '/egroupware' to files AND bundles
|
||||
*
|
||||
* @param array $map
|
||||
* @return array
|
||||
*/
|
||||
protected static function getImportMap(array $map)
|
||||
public static function getImportMap()
|
||||
{
|
||||
if (substr($prefix = $GLOBALS['egw_info']['server']['webserver_url'], 0, 4) === 'http')
|
||||
{
|
||||
$prefix = parse_url($prefix, PHP_URL_PATH);
|
||||
}
|
||||
$imports = [];
|
||||
foreach($map as $file => $bundle)
|
||||
{
|
||||
$imports[$prefix.$file] = $prefix.$bundle;
|
||||
$imports = Bundle::getImportMap();
|
||||
|
||||
// typescript unfortunately has currently no option to add ".js" to it's es6 import statements
|
||||
// therefore we add extra entries without .js extension to the map
|
||||
if (file_exists(EGW_SERVER_ROOT.substr($file, 0, -3).'.ts'))
|
||||
{
|
||||
$imports[$prefix.substr($file, 0, -3)] = $prefix.$bundle;
|
||||
}
|
||||
}
|
||||
// adding some extra mappings
|
||||
if (($prefix = parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_PATH)) === '/') $prefix = '';
|
||||
$imports['jquery'] = $imports[$prefix.'/vendor/bower-asset/jquery/dist/jquery.js'];
|
||||
$imports['jqueryui'] = $imports[$prefix.'/vendor/bower-asset/jquery-ui/jquery-ui.js'];
|
||||
|
||||
@ -1154,10 +1141,6 @@ abstract class Framework extends Framework\Extra
|
||||
|
||||
// @todo: add all node_modules as bare imports
|
||||
|
||||
// debug-output to tmp dir
|
||||
file_put_contents($GLOBALS['egw_info']['server']['temp_dir'].'/'.substr(str_replace(['/', '.php'], ['-', '.json'], $_SERVER['PHP_SELF']), 1),
|
||||
json_encode(['imports' => $imports], JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT));
|
||||
|
||||
return ['imports' => $imports];
|
||||
}
|
||||
|
||||
|
@ -199,14 +199,22 @@ class Bundle
|
||||
*/
|
||||
const MAX_BUNDLE_FILES = 50;
|
||||
|
||||
/**
|
||||
* Apps which should be their own bundle:
|
||||
* - own eT2 widgets
|
||||
* - not just an app.js or a huge one
|
||||
*/
|
||||
const BUNDLE_APPS = ['calendar', 'mail', 'projectmanager', 'smallpart'];
|
||||
|
||||
/**
|
||||
* Return all bundels we use:
|
||||
* - api stuff phpgwapi/js/jsapi/* and it's dependencies incl. jquery
|
||||
* - etemplate2 stuff not including api bundle, but jquery-ui
|
||||
*
|
||||
* @param bool $all_apps=false true: return bundle for every app with an app.js/ts
|
||||
* @return array bundle-url => array of contained files
|
||||
*/
|
||||
public static function all()
|
||||
public static function all(bool $all_apps = false)
|
||||
{
|
||||
$inc_mgr = new IncludeMgr();
|
||||
$bundles = array();
|
||||
@ -245,17 +253,17 @@ class Bundle
|
||||
$stock_files = array_merge(...array_values($bundles));
|
||||
|
||||
// generate template and app bundles, if installed
|
||||
foreach(array(
|
||||
foreach([
|
||||
'jdots' => '/jdots/js/fw_jdots.js',
|
||||
'mobile' => '/pixelegg/js/fw_mobile.js',
|
||||
'pixelegg' => '/pixelegg/js/fw_pixelegg.js',
|
||||
'calendar' => '/calendar/js/app.js',
|
||||
'mail' => '/mail/js/app.js',
|
||||
'projectmanager' => '/projectmanager/js/app.js',
|
||||
'messenger' => '/messenger/js/app.js',
|
||||
'smallpart' => '/smallpart/js/app.js',
|
||||
) as $bundle => $file)
|
||||
]+($all_apps ? scandir(EGW_SERVER_ROOT) : self::BUNDLE_APPS) as $bundle => $file)
|
||||
{
|
||||
if (is_int($bundle))
|
||||
{
|
||||
$bundle = $file;
|
||||
$file = "/$bundle/js/app.js";
|
||||
}
|
||||
if (@file_exists(EGW_SERVER_ROOT.$file))
|
||||
{
|
||||
$inc_mgr = new IncludeMgr($stock_files); // reset loaded files to stock files
|
||||
@ -282,4 +290,103 @@ class Bundle
|
||||
//error_log(__METHOD__."() returning ".array2string($bundles));
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* some files are not in a bundle, because loaded otherwise or are big enough themselves
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static public $exclude = [
|
||||
// api/js/jsapi/egw.js loaded via own tag, and we must not load it twice!
|
||||
'api/js/jsapi/egw.js',
|
||||
// TinyMCE is loaded separate before the bundle
|
||||
'vendor/tinymce/tinymce/tinymce.min.js',
|
||||
// CRM.js from addressbook is also used in infolog, so it can't be bundled with either!
|
||||
'addressbook/js/CRM.js',
|
||||
];
|
||||
|
||||
/**
|
||||
* Generate importmap for whole instance
|
||||
*
|
||||
* It need to be for the whole instance incl. all app.js, as it does not get reloaded, when we execute
|
||||
* apps via ajax!
|
||||
*
|
||||
* @ToDo new-js-loader: use static file in filesystem updated when js-files get minified (for minified only!)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getImportMap()
|
||||
{
|
||||
$minified = empty($GLOBALS['egw_info']['server']['debug_minify']);
|
||||
|
||||
// cache map for the whole tree to use
|
||||
return Cache::getTree('api', 'importmap'.($minified?'-minified':''), static function()
|
||||
{
|
||||
$gruntfile = EGW_SERVER_ROOT . '/Gruntfile.js';
|
||||
if (!($content = @file_get_contents($gruntfile)))
|
||||
{
|
||||
die("\nFile '$gruntfile' not found!\n\n");
|
||||
}
|
||||
|
||||
if (!preg_match('/grunt\.initConfig\(({.+})\);/s', $content, $matches) ||
|
||||
!($json = preg_replace('/^(\s*)([a-z0-9_-]+):/mi', '$1"$2":', $matches[1])) ||
|
||||
!($config = json_decode($json, true)))
|
||||
{
|
||||
die("\nCan't parse $gruntfile!\n\n");
|
||||
}
|
||||
|
||||
if (($prefix = parse_url($GLOBALS['egw_info']['server']['webserver_url'], PHP_URL_PATH)) === '/') $prefix = '';
|
||||
$uglify = $config['terser'];
|
||||
unset($config, $uglify['options']);
|
||||
$map = [];
|
||||
foreach (self::all(true) as $name => $files)
|
||||
{
|
||||
if ($name == '.ts') continue; // ignore timestamp
|
||||
|
||||
// some files are not in a bundle, because they are big enough themselves or otherwise excluded
|
||||
foreach (self::$exclude as $file)
|
||||
{
|
||||
if (($key = array_search($file, $files)))
|
||||
{
|
||||
$map[$prefix . $file] = $prefix . $file . '?' . filemtime(EGW_SERVER_ROOT . $file);
|
||||
unset($files[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($uglify[$name]))
|
||||
{
|
||||
$target = key($uglify[$name]['files']);
|
||||
$uglify[$name]['files'][$target] = array_values($files);
|
||||
}
|
||||
elseif (isset($uglify[$append = substr($name, 0, -1)]))
|
||||
{
|
||||
reset($uglify[$append]['files']);
|
||||
$target = key($uglify[$append]['files']);
|
||||
$uglify[$append]['files'][$target] = array_merge($uglify[$append]['files'][$target], array_values($files));
|
||||
}
|
||||
else // create new bundle using last file as target
|
||||
{
|
||||
$target = str_replace('.js', '.min.js', end($files));
|
||||
$uglify[$name]['files'][$target] = array_values($files);
|
||||
}
|
||||
if ($target[0] !== '/') $target = '/' . $target;
|
||||
|
||||
$use_bundle = in_array($name, array_merge(['api', 'et2'], Bundle::BUNDLE_APPS)) &&
|
||||
empty($GLOBALS['egw_info']['server']['debug_minify']);
|
||||
|
||||
foreach ($files as $file)
|
||||
{
|
||||
// use bundle / minified url as target or not
|
||||
if (!$use_bundle) $target = $file;
|
||||
$map[$prefix . $file] = $prefix.$target.'?'.filemtime(EGW_SERVER_ROOT.$target);
|
||||
// typescript unfortunately has currently no option to add ".js" to it's es6 import statements
|
||||
// therefore we add extra entries without .js extension to the map if (file_exists(EGW_SERVER_ROOT.substr($file, 0, -3) . '.ts'))
|
||||
{
|
||||
$map[$prefix . substr($file, 0, -3)] = $prefix.$target.'?'.filemtime(EGW_SERVER_ROOT.$target);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $map;
|
||||
}, [], 30);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ $GLOBALS['egw_info'] = array(
|
||||
);
|
||||
include(__DIR__.'/header.inc.php');
|
||||
|
||||
$gruntfile = __DIR__.'/Gruntfile.js';
|
||||
$gruntfile = EGW_SERVER_ROOT.'/Gruntfile.js';
|
||||
if (!($content = @file_get_contents($gruntfile)))
|
||||
{
|
||||
die("\nFile '$gruntfile' not found!\n\n");
|
||||
@ -33,20 +33,12 @@ if (!preg_match('/grunt\.initConfig\(({.+})\);/s', $content, $matches) ||
|
||||
!($json = preg_replace('/^(\s*)([a-z0-9_-]+):/mi', '$1"$2":', $matches[1])) ||
|
||||
!($config = json_decode($json, true)))
|
||||
{
|
||||
die("\nCan't parse $path!\n\n");
|
||||
die("\nCan't parse $gruntfile!\n\n");
|
||||
}
|
||||
//print_r($config); exit;
|
||||
|
||||
$uglify =& $config['terser'];
|
||||
|
||||
// some files are not in a bundle, because loaded otherwise or are big enough themselfs
|
||||
$exclude = array(
|
||||
// api/js/jsapi/egw.js loaded via own tag, and we must not load it twice!
|
||||
'api/js/jsapi/egw.js',
|
||||
// TinyMCE is loaded separate before the bundle
|
||||
'vendor/tinymce/tinymce/tinymce.min.js',
|
||||
);
|
||||
|
||||
foreach(Bundle::all() as $name => $files)
|
||||
{
|
||||
if ($name == '.ts') continue; // ignore timestamp
|
||||
@ -57,8 +49,8 @@ foreach(Bundle::all() as $name => $files)
|
||||
if ($path[0] == '/') $path = substr($path, 1);
|
||||
});
|
||||
|
||||
// some files are not in a bundle, because they are big enough themselfs
|
||||
foreach($exclude as $file)
|
||||
// some files are not in a bundle, because they are big enough themselves
|
||||
foreach(Bundle::$exclude as $file)
|
||||
{
|
||||
if (($key = array_search($file, $files))) unset($files[$key]);
|
||||
}
|
||||
@ -66,13 +58,13 @@ foreach(Bundle::all() as $name => $files)
|
||||
//var_dump($name, $files);
|
||||
if (isset($uglify[$name]))
|
||||
{
|
||||
list($target) = each($uglify[$name]['files']);
|
||||
$target = key($uglify[$name]['files']);
|
||||
$uglify[$name]['files'][$target] = array_values($files);
|
||||
}
|
||||
elseif (isset($uglify[$append = substr($name, 0, -1)]))
|
||||
{
|
||||
reset($uglify[$append]['files']);
|
||||
list($target) = each($uglify[$append]['files']);
|
||||
$target = key($uglify[$append]['files']);
|
||||
$uglify[$append]['files'][$target] = array_merge($uglify[$append]['files'][$target], array_values($files));
|
||||
}
|
||||
else // create new bundle using last file as target
|
||||
|
Loading…
Reference in New Issue
Block a user