Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speedup Lizmap Html page loading by adding preload link #5532

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions assets/src/legacy/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,95 @@ var searchProjects = function(){
}
}

var addPrefetchOnClick = function () {
console.log('Test '+$('a.liz-project-view').length );
const links = [{
url: lizUrls.map,
type: 'text/html',
as: 'document',
params: {},
},{
url: lizUrls.config,
type: 'application/json',
as: 'fetch',
params: {},
},{
url: lizUrls.keyValueConfig,
type: 'application/json',
as: 'fetch',
params: {},
},{
url: lizUrls.ogcService,
type: 'text/xml',
as: 'fetch',
params: {
SERVICE: 'WMS',
REQUEST: 'GetCapabilities',
VERSION: '1.3.0',
},
},{
url: lizUrls.ogcService,
type: 'text/xml',
as: 'fetch',
params: {
SERVICE: 'WFS',
REQUEST: 'GetCapabilities',
VERSION: '1.0.0',
},
},{
url: lizUrls.ogcService,
type: 'text/xml',
as: 'fetch',
params: {
SERVICE: 'WMTS',
REQUEST: 'GetCapabilities',
VERSION: '1.0.0',
},
}];
$('a.liz-project-view').click(function () {
var self = $(this);
var projElem = self.parent().parent().find('div.liz-project');
if (projElem.length < 1) {
alert('no project');
return false;
}
projElem = projElem[0];
var repId = projElem.dataset.lizmapRepository;
var projId = projElem.dataset.lizmapProject;
links.forEach(link => {
const params = new URLSearchParams();
params.append('repository', repId);
params.append('project', projId);
for (const key in link.params) {
params.append(key, link.params[key]);
}
//create link tag
const linkTag = document.createElement('link');
linkTag.rel = 'prefetch';
linkTag.href = link.url+'?'+params;
linkTag.type = link.type;
linkTag.as = link.as;
//inject tag in the head of the document
document.head.appendChild(linkTag);
});

return true;
});
}

window.addEventListener('load', function () {
// Initialize global variables
const lizmapVariablesJSON = document.getElementById('lizmap-vars')?.innerText;
if (lizmapVariablesJSON) {
try {
const lizmapVariables = JSON.parse(lizmapVariablesJSON);
for (const variable in lizmapVariables) {
globalThis[variable] = lizmapVariables[variable];
}
} catch {
console.warn('JSON for Lizmap global variables is not valid!');
}
}
searchProjects();
addPrefetchOnClick();
});
37 changes: 36 additions & 1 deletion lizmap/app/responses/AbstractLizmapHtmlResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,24 @@ class AbstractLizmapHtmlResponse extends jResponseHtml
{
protected $CSPPropName = 'mapCSPHeader';

protected function outputJsScriptTag($fileUrl, $scriptParams)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions will implicitly add a preload tag for each resource loaded with addJSLink/addCssLink, no ?

{
echo '<link rel="preload" href="',htmlspecialchars($fileUrl),'" as="script" ',$this->_endTag;
parent::outputJsScriptTag($fileUrl, $scriptParams);
}

protected function outputCssLinkTag($fileUrl, $cssParams)
{
echo '<link rel="preload" href="',htmlspecialchars($fileUrl),'" as="style" ',$this->_endTag;
parent::outputCssLinkTag($fileUrl, $cssParams);
}

protected function outputIconLinkTag($fileUrl, $iconParams)
{
echo '<link rel="preload" href="',htmlspecialchars($fileUrl),'" as="image" ',$this->_endTag;
parent::outputIconLinkTag($fileUrl, $iconParams);
}

protected function prepareHeadContent()
{
$bp = jApp::urlBasePath();
Expand Down Expand Up @@ -64,8 +82,25 @@ public function addJsVariables(array $variables)
$this->jsVarData = array_merge($this->jsVarData, $variables);
}

protected $preloadLink = array();

public function addPreloadLink($href, $as, $type = null)
{
$this->preloadLink[] = array(
'href' => $href,
'as' => $as,
'type' => $type,
);
}

protected function doAfterActions()
{
$this->addHeadContent('<script id="lizmap-vars" type="application/json">'.json_encode($this->jsVarData).'</script>');
$this->addHeadContent('<!-- Start preload -->');
// other preload links
foreach ($this->preloadLink as $link) {
$this->addHeadContent('<link rel="preload" href="'.$link['href'].'" as="'.$link['as'].'"'.($link['type'] ? ' type="'.$link['type'].'"' : '').'>');
}
$this->addHeadContent('<!-- End preload -->');
$this->addHeadContent('<script id="lizmap-vars" type="application/json">'.json_encode($this->jsVarData).'</script>'."\n");
}
}
21 changes: 20 additions & 1 deletion lizmap/modules/lizmap/lib/Project/Project.php
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,27 @@ public function getWMSGetCapabilitiesUrl()
'repository' => $this->repository->getKey(),
'project' => $this->key,
'SERVICE' => 'WMS',
'REQUEST' => 'GetCapabilities',
'VERSION' => '1.3.0',
)
);
}

/**
* Get the WMS GetCapabilities Url.
*
* @return string
*/
public function getWFSGetCapabilitiesUrl()
{
return $this->appContext->getFullUrl(
'lizmap~service:index',
array(
'repository' => $this->repository->getKey(),
'project' => $this->key,
'SERVICE' => 'WFS',
'REQUEST' => 'GetCapabilities',
'VERSION' => '1.0.0',
)
);
}
Expand All @@ -553,8 +572,8 @@ public function getWMTSGetCapabilitiesUrl()
'repository' => $this->repository->getKey(),
'project' => $this->key,
'SERVICE' => 'WMTS',
'VERSION' => '1.0.0',
'REQUEST' => 'GetCapabilities',
'VERSION' => '1.0.0',
)
);
}
Expand Down
10 changes: 9 additions & 1 deletion lizmap/modules/view/controllers/default.classic.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function index()
jApp::config()->theme = $theme;
}

/** @var jResponseHtml $rep */
/** @var AbstractLizmapHtmlResponse $rep */
$rep = $this->getResponse('html');

// Get lizmap services
Expand Down Expand Up @@ -181,6 +181,14 @@ public function index()
}
$rep->body->assign('showHomeLink', false);

$lizUrls = array(
'map' => jUrl::get('view~map:index'),
'config' => jUrl::get('lizmap~service:getProjectConfig'),
'keyValueConfig' => jUrl::get('lizmap~service:getKeyValueConfig'),
'ogcService' => jUrl::get('lizmap~service:index'),
);
$rep->addJsVariable('lizUrls', $lizUrls);

return $rep;
}

Expand Down
22 changes: 22 additions & 0 deletions lizmap/modules/view/controllers/lizMap.classic.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,27 @@ public function index()
'resourceUrlReplacement' => array(),
);

// Add preload links
$rep->addPreloadLink(
jUrl::get(
'lizmap~service:getProjectConfig',
array('repository' => $repository, 'project' => $project),
),
'fetch',
'application/json',
);
$rep->addPreloadLink(
jUrl::get(
'lizmap~service:getKeyValueConfig',
array('repository' => $repository, 'project' => $project),
),
'fetch',
'application/json',
);
$rep->addPreloadLink($lproj->getWMSGetCapabilitiesUrl(), 'fetch', 'application/xml');
$rep->addPreloadLink($lproj->getWFSGetCapabilitiesUrl(), 'fetch', 'application/xml');
$rep->addPreloadLink($lproj->getWMTSGetCapabilitiesUrl(), 'fetch', 'application/xml');

// Get optional WMS public url list
$lser = lizmap::getServices();
if ($lser->wmsPublicUrlList) {
Expand Down Expand Up @@ -316,6 +337,7 @@ function f($x)
}
}

// Add map theme
$rep->addAssets('maptheme');

// Add dockable css
Expand Down
22 changes: 15 additions & 7 deletions tests/end2end/playwright/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,32 @@ export async function gotoMap(url, page, mapMustLoad = true, layersInTreeView =
// Wait for WMS GetCapabilities promise
let getCapabilitiesWMSPromise = page.waitForRequest(/SERVICE=WMS&REQUEST=GetCapabilities/);

// Wait for WMS GetLegendGraphic promise
// if it is required
let getLegendGraphicPromise = null;
if (mapMustLoad) {
if (waitForGetLegendGraphic) {
getLegendGraphicPromise = page.waitForRequest(
request => request.method() === 'POST' &&
request.postData() != null &&
request.postData()?.includes('GetLegendGraphic') === true
);
}
}

await expect(async () => {
const response = await page.goto(url);
expect(response.status()).toBeLessThan(400);
expect(response?.status()).toBeLessThan(400);
}).toPass({
intervals: [1_000, 2_000, 10_000],
timeout: 60_000
});

// Wait for WMS GetCapabilities
await getCapabilitiesWMSPromise;

if (mapMustLoad) {
if (waitForGetLegendGraphic) {
// Wait for WMS GetLegendGraphic promise
const getLegendGraphicPromise = page.waitForRequest(
request => request.method() === 'POST' &&
request.postData() != null &&
request.postData()?.includes('GetLegendGraphic') === true
);
// Normal check about the map
// Wait for WMS GetLegendGraphic
await getLegendGraphicPromise;
Expand Down
4 changes: 2 additions & 2 deletions tests/end2end/playwright/pages/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class ProjectPage extends BasePage {
* Path to the QGS file
* @type {string}
*/
qgsFile = () => qgsTestFile(this.project, this.repository);
get qgsFile () { return qgsTestFile(this.project, this.repository); }

/**
* Attribute table for the given layer name
Expand Down Expand Up @@ -226,7 +226,7 @@ export class ProjectPage extends BasePage {
* Identify content locator, for a given feature ID and layer ID if necessary
* @param {string} featureId Feature ID, optional
* @param {string} layerId Layer ID, optional
* @returns {Locator} Locator for HTML identify content
* @returns {Promise<Locator>} Locator for HTML identify content
*/
async identifyContentLocator(featureId = '', layerId= '') {
let selector = `div.lizmapPopupSingleFeature`;
Expand Down
26 changes: 20 additions & 6 deletions tests/end2end/playwright/viewport.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,17 @@ test.describe('Viewport devicePixelRatio 1', () => {

// Go to the map
await gotoMap(url, page)
// Wait to let the config loaded
await page.waitForTimeout(1000);
// Check that the get project config has been catched
expect(requests).toHaveLength(1);
// Preload and fetch
let timeCount = 0;
while (requests.length < 2) {
timeCount += 100;
if (timeCount > 1000) {
throw new Error('Timeout');
}
await page.waitForTimeout(100);
}
await expect(requests).toHaveLength(2);

// Wait to let the JS build classes
await page.waitForTimeout(1000);
Expand Down Expand Up @@ -97,10 +104,17 @@ test.describe('Viewport devicePixelRatio 2', () => {

// Go to the map
await gotoMap(url, page)
// Wait to let the config loaded
await page.waitForTimeout(1000);
// Check that the get project config has been catched
expect(requests).toHaveLength(1);
// Preload and fetch
let timeCount = 0;
while (requests.length < 2) {
timeCount += 100;
if (timeCount > 1000) {
throw new Error('Timeout');
}
await page.waitForTimeout(100);
}
expect(requests).toHaveLength(2);

// Wait to let the JS build classes
await page.waitForTimeout(1000);
Expand Down
Loading