Skip to content

Commit bb2e38c

Browse files
authored
Merge pull request #1596 from algolia/feature/MAGE-1000-mustache
Feature/mage 1000 - Mustache alt
2 parents b1f69b7 + 1aec64d commit bb2e38c

File tree

5 files changed

+129
-21
lines changed

5 files changed

+129
-21
lines changed

view/frontend/requirejs-config.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ var config = {
1616
'additionalHtml' : 'Algolia_AlgoliaSearch/js/template/autocomplete/additional-section',
1717

1818
// Recommend templates
19-
'recommendProductsHtml': 'Algolia_AlgoliaSearch/js/template/recommend/products'
19+
'recommendProductsHtml': 'Algolia_AlgoliaSearch/js/template/recommend/products',
20+
21+
// Unbundling
22+
'algoliaTemplateEngine': 'Algolia_AlgoliaSearch/js/internals/template-engine'
2023
}
2124
},
2225
paths : {
@@ -27,6 +30,9 @@ var config = {
2730
'recommend' : 'Algolia_AlgoliaSearch/js/internals/recommend.min',
2831
'recommendJs' : 'Algolia_AlgoliaSearch/js/internals/recommend-js.min',
2932
'rangeSlider' : 'Algolia_AlgoliaSearch/js/navigation/range-slider-widget',
33+
// Legacy
34+
'algoliaHoganLib' : 'Algolia_AlgoliaSearch/js/lib/hogan.min',
35+
'algoliaMustacheLib' : 'Algolia_AlgoliaSearch/js/lib/mustache.min'
3036
},
3137
deps : [
3238
'algoliaInstantSearch',
@@ -38,5 +44,10 @@ var config = {
3844
'Algolia_AlgoliaSearch/js/insights/add-to-cart-mixin': true
3945
}
4046
}
47+
},
48+
shim: {
49+
'algoliaHoganLib': {
50+
exports: 'Hogan'
51+
}
4152
}
4253
};

view/frontend/web/js/instantsearch.js

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
define([
22
'jquery',
33
'algoliaBundle',
4+
'algoliaTemplateEngine',
45
'Magento_Catalog/js/price-utils',
56
'algoliaCommon',
67
'algoliaInsights',
78
'algoliaHooks',
8-
], function ($, algoliaBundle, priceUtils) {
9-
$(function ($) {
9+
], function ($, algoliaBundle, templateEngine, priceUtils) {
10+
$(async function ($) {
11+
const templateProcessor = await templateEngine.getSelectedEngineAdapter();
12+
1013
/** We have nothing to do here if instantsearch is not enabled **/
1114
if (
1215
typeof algoliaConfig === 'undefined' ||
@@ -82,10 +85,10 @@ define([
8285
*
8386
* For templating is used Hogan library
8487
* Docs: http://twitter.github.io/hogan.js/
88+
*
89+
* Alternatively use Mustache
90+
* https://github.com/janl/mustache.js
8591
**/
86-
var wrapperTemplate = algoliaBundle.Hogan.compile(
87-
$('#instant_wrapper_template').html()
88-
);
8992
var instant_selector = '#instant-search-bar';
9093

9194
var div = document.createElement('div');
@@ -99,16 +102,17 @@ define([
99102
$('.algolia-instant-results-wrapper').append(
100103
'<div class="algolia-instant-selector-results"></div>'
101104
);
102-
$('.algolia-instant-selector-results')
103-
.html(
104-
wrapperTemplate.render({
105-
second_bar : algoliaConfig.instant.enabled,
106-
findAutocomplete: findAutocomplete,
107-
config : algoliaConfig.instant,
108-
translations : algoliaConfig.translations,
109-
})
110-
)
111-
.show();
105+
106+
const template = $('#instant_wrapper_template').html();
107+
const templateVars = {
108+
second_bar : algoliaConfig.instant.enabled,
109+
findAutocomplete: findAutocomplete,
110+
config : algoliaConfig.instant,
111+
translations : algoliaConfig.translations,
112+
};
113+
114+
const wrapperHtml = templateProcessor.process(template, templateVars);
115+
$('.algolia-instant-selector-results').html(wrapperHtml).show();
112116

113117
/**
114118
* Initialise instant search
@@ -332,17 +336,15 @@ define([
332336
container: '#algolia-stats',
333337
templates: {
334338
text: function (data) {
335-
var hoganTemplate = algoliaBundle.Hogan.compile(
336-
$('#instant-stats-template').html()
337-
);
338-
339339
data.first = data.page * data.hitsPerPage + 1;
340340
data.last = Math.min(
341341
data.page * data.hitsPerPage + data.hitsPerPage,
342342
data.nbHits
343343
);
344344
data.seconds = data.processingTimeMS / 1000;
345345
data.translations = window.algoliaConfig.translations;
346+
347+
// TODO: Revisit this injected jQuery logic
346348
const searchParams = new URLSearchParams(window.location.search);
347349
const searchQuery = searchParams.has('q') || '';
348350
if (searchQuery === '' && !algoliaConfig.isSearchPage) {
@@ -352,7 +354,9 @@ define([
352354
$('.algolia-instant-replaced-content').hide();
353355
$('.algolia-instant-selector-results').show();
354356
}
355-
return hoganTemplate.render(data);
357+
358+
const template = $('#instant-stats-template').html();
359+
return templateProcessor.process(template, data);
356360
},
357361
},
358362
},
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
define([], function () {
2+
const ENGINE_TYPE_HOGAN = 'hogan';
3+
const ENGINE_TYPE_MUSTACHE = 'mustache';
4+
5+
const trackingAdapter = {
6+
processAndMeasure: function(template, data, tag = '') {
7+
const start = performance.now();
8+
const result = this.process(template, data);
9+
const end = performance.now();
10+
const prefix = tag ? `${tag}: ` : '';
11+
console.log(
12+
`${prefix}Template execution time with "${this.engineType}": %s ms`,
13+
end - start
14+
);
15+
return result;
16+
}
17+
};
18+
19+
return {
20+
ENGINE_TYPE_HOGAN,
21+
ENGINE_TYPE_MUSTACHE,
22+
23+
getSelectedEngineType: () => ENGINE_TYPE_MUSTACHE, // override via mixin
24+
25+
// Retrieve the engine before calling process() if not able to use promises
26+
getSelectedEngineAdapter: async function() {
27+
return this.getEnhancedEngineAdapter(this.getSelectedEngineType());
28+
},
29+
30+
// Convenience method
31+
processTemplate: async function (template, data, measure = false) {
32+
const adapter = await this.getSelectedEngineAdapter();
33+
return (measure)
34+
? adapter.processAndMeasure(template, data)
35+
: adapter.process(template, data);
36+
},
37+
38+
getEnhancedEngineAdapter: async function (type) {
39+
const adapter = await this.getEngineAdapter(type);
40+
return {
41+
engineType: this.getSelectedEngineType(),
42+
...trackingAdapter,
43+
...adapter
44+
};
45+
},
46+
47+
getEngineAdapter: async function (type) {
48+
switch (type) {
49+
case ENGINE_TYPE_HOGAN:
50+
return this.getHoganAdapter();
51+
case ENGINE_TYPE_MUSTACHE:
52+
return this.getMustacheAdapter();
53+
default:
54+
throw new Error(`Unknown template engine: ${type}`);
55+
}
56+
},
57+
58+
getHoganAdapter: async function () {
59+
const Hogan = await this.getAdapterEngine('algoliaHoganLib');
60+
return {
61+
process: (template, data) => {
62+
return Hogan.compile(template).render(data);
63+
},
64+
};
65+
},
66+
67+
getMustacheAdapter: async function () {
68+
const Mustache = await this.getAdapterEngine('algoliaMustacheLib');
69+
return {
70+
process: (template, data) => {
71+
return Mustache.render(template, data);
72+
},
73+
};
74+
},
75+
76+
getAdapterEngine: async function (lib) {
77+
try {
78+
return await new Promise((resolve, reject) => {
79+
require([lib], resolve, reject);
80+
});
81+
} catch (err) {
82+
console.error(`Failed to load module ${lib} for template engine:`, err);
83+
throw err;
84+
}
85+
},
86+
};
87+
});

view/frontend/web/js/lib/hogan.min.js

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)