Make page loading faster by deferred script loading:

* Create generalized function for emmitting <script defer src=""> tags to templates
* Remove type attribute from inline_js
* Add defer attribute to external <script> tags

Signed-off-by: Michael Letzgus <michaelletzgus@users.noreply.github.com>
This commit is contained in:
Michael Letzgus 2017-03-08 09:43:51 +01:00
parent 6e3a914f4a
commit fb9f13d4c1
5 changed files with 44 additions and 24 deletions

View file

@ -12,20 +12,13 @@
<link rel="icon" href="<?php print_unescaped(image_path('', 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>">
<link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path('', 'favicon-mask.svg')); ?>" color="<?php p($theme->getColorPrimary()); ?>">
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach ($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>">
<?php endforeach; ?>
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php foreach ($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
<?php emit_script_loading_tags($_); ?>
<?php print_unescaped($_['headers']); ?>
</head>
<body id="body-public">

View file

@ -13,20 +13,13 @@
<link rel="icon" href="<?php print_unescaped(image_path('', 'favicon.ico')); /* IE11+ supports png */ ?>">
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path('', 'favicon-touch.png')); ?>">
<link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path('', 'favicon-mask.svg')); ?>" color="<?php p($theme->getColorPrimary()); ?>">
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>">
<?php endforeach; ?>
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php foreach($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
<?php emit_script_loading_tags($_); ?>
<?php print_unescaped($_['headers']); ?>
</head>
<body id="<?php p($_['bodyid']);?>">

View file

@ -21,20 +21,13 @@
<link rel="apple-touch-icon-precomposed" href="<?php print_unescaped(image_path($_['appid'], 'favicon-touch.png')); ?>">
<link rel="mask-icon" sizes="any" href="<?php print_unescaped(image_path($_['appid'], 'favicon-mask.svg')); ?>" color="<?php p($theme->getColorPrimary()); ?>">
<link rel="manifest" href="<?php print_unescaped(image_path($_['appid'], 'manifest.json')); ?>">
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach($_['cssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>">
<?php endforeach; ?>
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php foreach($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
<?php emit_script_loading_tags($_); ?>
<?php print_unescaped($_['headers']); ?>
</head>
<body id="<?php p($_['bodyid']);?>">

View file

@ -12,6 +12,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Michael Letzgus <develope@michael-letzgus.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Raghu Nayyar <hey@raghunayyar.com>
* @author Robin Appelman <robin@icewind.nl>
@ -208,6 +209,9 @@ class OC_Template extends \OC\Template\Base {
$headers = '';
foreach(OC_Util::$headers as $header) {
$headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
if ( strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes']))) ) {
$headers .= ' defer';
}
foreach($header['attributes'] as $name=>$value) {
$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
}

View file

@ -7,6 +7,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Michael Letzgus <develope@michael-letzgus.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin McCorkell <robin@mccorkell.me.uk>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@ -37,6 +38,42 @@ function p($string) {
print(\OCP\Util::sanitizeHTML($string));
}
/**
* Prints a <script> tag with nonce and defer depending on config
* @param string $src the source URL, ignored when empty
* @param string $script_content the inline script content, ignored when empty
* @param bool $defer_flag deferred loading or not
*/
function emit_script_tag($src, $script_content) {
$defer_str=' defer';
$s='<script nonce="' . \OC::$server->getContentSecurityPolicyNonceManager()->getNonce() . '"';
if (!empty($src)) {
// emit script tag for deferred loading from $src
$s.=$defer_str.' src="' . $src .'">';
} else if (!empty($script_content)) {
// emit script tag for inline script from $script_content without defer (see MDN)
$s.=">\n".$script_content."\n";
} else {
// no $src nor $src_content, really useless empty tag
$s.='>';
}
$s.='</script>';
print_unescaped($s."\n");
}
/**
* Print all <script> tags for loading JS
* @param hash $obj all the script information from template
*/
function emit_script_loading_tags($obj) {
if (!empty($obj['inline_ocjs'])) {
emit_script_tag('', $obj['inline_ocjs']);
}
foreach($obj['jsfiles'] as $jsfile) {
emit_script_tag($jsfile, '');
}
}
/**
* Prints an unsanitized string - usage of this function may result into XSS.
* Consider using p() instead.