<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>magento2 Archives - gj</title>
	<atom:link href="https://blog.gaiterjones.com/tag/magento2/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.gaiterjones.com/tag/magento2/</link>
	<description>gaiterjones</description>
	<lastBuildDate>Wed, 10 Feb 2021 10:03:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8</generator>
	<item>
		<title>How to Improve Magento 2 ElasticSearch Catalog Search Results and Relevance</title>
		<link>https://blog.gaiterjones.com/how-to-improve-magento-2-elasticsearch-catalog-search-results-and-relevance/</link>
					<comments>https://blog.gaiterjones.com/how-to-improve-magento-2-elasticsearch-catalog-search-results-and-relevance/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Thu, 20 Aug 2020 17:15:25 +0000</pubDate>
				<category><![CDATA[ElasticSearch]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[elasticsearch]]></category>
		<category><![CDATA[magento2]]></category>
		<guid isPermaLink="false">https://blog.gaiterjones.com/?p=2275</guid>

					<description><![CDATA[TL;DR Migrating the Magento 2 catalog search engine to Smile ElasticSuite will resolve pretty much all the issues you might be experiencing with Magento 2 native ElasticSearch catalog search so...<a class="more-link" href="https://blog.gaiterjones.com/how-to-improve-magento-2-elasticsearch-catalog-search-results-and-relevance/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<h1>TL;DR</h1>
<p>Migrating the Magento 2 catalog search engine to <a href="https://github.com/Smile-SA/elasticsuite">Smile ElasticSuite</a> will resolve pretty much all the issues you might be experiencing with Magento 2 native ElasticSearch catalog search so go ahead and <a href="#elasticsuite">Jump to the ElasticSuite installation.</a></p>
<p>If you are new to ElasticSearch or want to find out how to customise ElasticSearch in Magento 2 read on!</p>
<h1>Magento Catalog Search</h1>
<p>Up until version 2.3 the default catalog search engine for Magento used the MySql Magento database. Using MySql for search was adequate but it lacked the features and scalability of enterprise search solutions. In version 2.3 Magento built in support for ElasticSearch as the catalog search engine and announced in 2019 that MySql search would be deprecated. As of version 2.4 in July 2020 the MySql catalog search engine was removed completely from Magento 2.</p>
<figure id="blog-es_5" aria-describedby="caption-blog-es-5" style="width: 600px" class="wp-caption aligncenter"><img fetchpriority="high" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_5.png" alt="" width="393" height="280" class="aligncenter size-full wp-image-2301" /><figcaption id="caption-blog-es-5" class="wp-caption-text"><br />
MySql catalog search deprecation notice<br /></figcaption></figure>
<p>Native support for ElasticSearch was good news for Merchants, Elasticsearch is a java based open-source, RESTful, distributed search and analytics engine built on Apache Lucene. Since its release in 2010, Elasticsearch has quickly become the most popular search engine.</p>
<p>It&#8217;s worth mentioning that ElasticSearch in Magento 2 is not just used for user full text search queries, the catalog search engine is responsible for returning all catalog queries including category products and filtered navigation product lists.</p>
<p>For customers ElasticSearch should provide faster and more <strong>relevant</strong> search experiences &#8211; the problem for merchants is that out of the box Magento 2 ElasticSearch just doesn&#8217;t do this &#8211; catalog search results and relevance have a tendency to be extremely poor. The built in search struggles to provide accurate and relevant results for simple queries such as SKUs.</p>
<p>Whilst MySql catalog search had some admin options to refine search results, there are no options available to customise catalog search with ElasticSearch. ElasticSearch is a great search engine but the native Magento 2 catalog full text search implementation is very disappointing.</p>
<p>Let&#8217;s look at ways to customise ElasticSearch catalog search in Magento using your own module to improve some areas of search relevance.</p>
<h1>Simple SKU Search</h1>
<p>Poor search results or search relevance with native Magento ElasticSearch is very apparent when searching for SKUs. Let&#8217;s look at a simple SKU search for one of the sample products provided in the Magento 2 sample data.</p>
<figure id="blog-es_1" aria-describedby="caption-blog-es-1" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_1.jpg" alt="" width="454" height="318" class="aligncenter wp-image-2281" /><figcaption id="caption-blog-es-1" class="wp-caption-text"><br />
SKU Search for Magento 2 sample product<br /></figcaption></figure>
<p>Article MH03 is a range of Hoodies. Searching for &#8216;MH03&#8217; correctly returns all 16 products. But what if you want to search for MH03-XL?</p>
<figure id="blog-es_2-2" aria-describedby="caption-blog-es-2-2" style="width: 600px" class="wp-caption aligncenter"><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_2-2.jpg" alt="" width="446" height="253" class="aligncenter wp-image-2283" /><figcaption id="caption-blog-es-2-2" class="wp-caption-text"><br />
Refined SKU Search for Magento 2 sample data<br /></figcaption></figure>
<p>Here we see that 112 items are returned when in fact only the first 3 were 100% matches for the search term. Native search really struggles with search terms containing special characters such as the hyphen commonly used in SKUs resulting in extremely poor search results. To look at why we are seeing so many results returned we need to look at the relevance score of the search results.</p>
<h1>Customise Elastic Search</h1>
<p>To capture the data returned by an ElasticSearch frontend full text search query we need to create a debug plugin for <code>Magento\Elasticsearch\SearchAdapter\ResponseFactory</code> that will let us analyse the search data and log it.</p>
<p><code>&lt;type name="Magento\Elasticsearch\SearchAdapter\ResponseFactory"&gt;</code><br />
<code>&lt;plugin disabled="false" sortOrder="2" name="gaiterjones_elasticsearch_queryresultsdebug" type="Gaiterjones\Elasticsearch\Plugin\QueryResultsDebug"/&gt;</code><br />
<code>&lt;/type&gt;</code></p>
<div style="padding-bottom: 20px;">
<span class="collapseomatic collapse" id="id680b5b0a1fe3d"  tabindex="0" title="beforeCreate plugin for SearchAdapterResponseFactory"    >beforeCreate plugin for SearchAdapterResponseFactory</span><div id="target-id680b5b0a1fe3d" class="collapseomatic_content ">
[code language=&#8221;php&#8221;]
    public function beforeCreate(\Magento\Elasticsearch\SearchAdapter\ResponseFactory $subject, $result)<br />
    {<br />
       if($this-&gt;debug)<br />
       {<br />
           if(!is_array($result) || empty($result)) {return false;}</p>
<p>           $scores=array();</p>
<p>           foreach ($result[&#8216;documents&#8217;] as $rawDocument) {<br />
               $this-&gt;logger-&gt;debug(&#8216;ELASTIC_SEARCH_QUERY_RESULTS_DEBUG&#8217;,$rawDocument);<br />
               array_push($scores,$rawDocument[&#8216;_score&#8217;]);<br />
           }</p>
<p>           if (count($result[&#8216;documents&#8217;]) &gt; 0)<br />
           {<br />
              $_debug=array(<br />
                   &#8216;results&#8217; =&gt; count($result[&#8216;documents&#8217;]),<br />
                   &#8216;scores&#8217; =&gt; $scores,<br />
                   &#8216;min_relevance_score&#8217; =&gt; $this-&gt;configuration-&gt;getMinScore(),<br />
                   &#8216;min_score&#8217; =&gt; min($scores),<br />
                   &#8216;max_score&#8217; =&gt; max($scores)<br />
               );</p>
<p>               $this-&gt;logger-&gt;debug(&#8216;ELASTIC_SEARCH_QUERY_RESULTS_DEBUG&#8217;,$_debug);<br />
           }<br />
       }<br />
    }<br />
[/code]
</div>
</p></div>
<p>The plugin dumps the search data to the debug log in <code>var/log</code>, this allows us to look more closely at the ElasticSearch results for the MH03-XL SKU full text search :</p>
<pre>Array
(
    [results] =&gt; 112
    [scores] =&gt; Array
        (
            [0] =&gt; 40.57959
            [1] =&gt; 40.57959
            [2] =&gt; 40.57959
            [3] =&gt; 29.099976
            [4] =&gt; 12.694372
            SNIP...
            [108] =&gt; 8.300152
            [109] =&gt; 8.300152
            [110] =&gt; 7.9659967
            [111] =&gt; 7.9659967
        )

    [min_relevance_score] =&gt; 1
    [min_score] =&gt; 7.9659967
    [max_score] =&gt; 40.57959
)
</pre>
<p>The debug shows the ElasticSearch rawdocument score  for the 112 search results, you can see that the score value for the search ranges from 7.9 to 40.5 with the most relevant results having a higher score. If we were to define a minimum relevance score of 40 the search results would be much more accurate.</p>
<p>We can do this with another plugin :</p>
<p><code>&lt;type name="Magento\Elasticsearch\Elasticsearch5\SearchAdapter\Mapper"&gt;</code><br />
<code>&lt;plugin disabled="false" sortOrder="1" name="gaiterjones_elasticsearch_searchadapter_mapperplugin" type="Gaiterjones\Elasticsearch\Plugin\Elasticsearch5\SearchAdapter\MapperPlugin"/&gt;</code><br />
<code>&lt;/type&gt;</code></p>
<div style="padding-bottom: 20px;">
<span class="collapseomatic collapse" id="id680b5b0a1fea7"  tabindex="0" title="aroundBuildQuery plugin for SearchAdapterMapperPlugin"    >aroundBuildQuery plugin for SearchAdapterMapperPlugin</span><div id="target-id680b5b0a1fea7" class="collapseomatic_content ">
[code language=&#8221;php&#8221;]
    public function aroundBuildQuery(<br />
        Mapper $subject,<br />
        callable $proceed,<br />
        RequestInterface $request<br />
    ) {<br />
        $searchQuery = $proceed($request);</p>
<p>        if ($request-&gt;getName() === &#8216;quick_search_container&#8217;) {<br />
            $searchQuery[&#8216;body&#8217;][&#8216;min_score&#8217;] = $this-&gt;configuration-&gt;getMinScore();<br />
        }</p>
<p>        return $searchQuery;<br />
    }<br />
[/code]
</div>
</p></div>
<p>Here we set a <code>min_score</code> value for the search query. Setting this to <em>40</em> would return just three results for the MH03-XL SKU search.</p>
<figure id="blog-es_3" aria-describedby="caption-blog-es-3" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_3.jpg" alt="" width="600" height="315" class="aligncenter size-full wp-image-2285" /><figcaption id="caption-blog-es-3" class="wp-caption-text"><br />
SKU Search for Magento 2 sample products with min_score value<br /></figcaption></figure>
<p>This looks much better, we can improve the relevance of the search results by filtering out results that have a low ElasticSearch score. The tricky part here is deciding what the minimum score value should be &#8211; it can be difficult to find a value that works well for different search queries.</p>
<p>Another useful ElasticSearch customisation is changing the ngram values when indexing the catalog. The <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html">ngram tokenizer</a> helps break search terms up into smaller words. We can change the ngram value with another plugin</p>
<p><code>&lt;type name="Magento\Elasticsearch\Model\Adapter\Index\Builder"&gt;</code><br />
<code>&lt;plugin disabled="false" sortOrder="3" name="gaiterjones_elasticsearch_indexbuilder" type="Gaiterjones\Elasticsearch\Plugin\IndexBuilder"&gt;&lt;/plugin&gt;</code><br />
<code>&lt;/type&gt;</code></p>
<div style="padding-bottom: 20px;">
<span class="collapseomatic collapse" id="id680b5b0a1ff13"  tabindex="0" title="plugin afterBuild method for IndexBuilder"    >plugin afterBuild method for IndexBuilder</span><div id="target-id680b5b0a1ff13" class="collapseomatic_content ">
[code language=&#8221;php&#8221;]
    public function afterBuild(\Magento\Elasticsearch\Model\Adapter\Index\Builder $subject, $result)<br />
    {<br />
        $likeToken = $this-&gt;getLikeTokenizer();<br />
        $result[&#8216;analysis&#8217;][&#8216;tokenizer&#8217;] = $likeToken;<br />
        $result[&#8216;analysis&#8217;][&#8216;filter&#8217;][&#8216;trigrams_filter&#8217;] = [<br />
            &#8216;type&#8217; =&gt; &#8216;ngram&#8217;,<br />
            &#8216;min_gram&#8217; =&gt; 3,<br />
            &#8216;max_gram&#8217; =&gt; 3<br />
        ];<br />
        $result[&#8216;analysis&#8217;][&#8216;analyzer&#8217;][&#8216;my_analyzer&#8217;] = [<br />
            &#8216;type&#8217; =&gt; &#8216;custom&#8217;,<br />
            &#8216;tokenizer&#8217; =&gt; &#8216;standard&#8217;,<br />
            &#8216;filter&#8217; =&gt; [<br />
                &#8216;lowercase&#8217;, &#8216;trigrams_filter&#8217;<br />
            ]
        ];<br />
        return $result;<br />
    }</p>
<p>    protected function getLikeTokenizer()<br />
    {<br />
        $tokenizer = [<br />
            &#8216;default_tokenizer&#8217; =&gt; [<br />
                &#8216;type&#8217; =&gt; &#8216;ngram&#8217;<br />
            ],<br />
        ];<br />
        return $tokenizer;<br />
    }<br />
[/code]
</div>
</p></div>
<p>In this case we are increasing the ngram value to <em>3</em>. This will take effect at the next catalog search full text reindex.</p>
<p>To test these customisation values for yourself you can download the full module here <a href="https://github.com/gaiterjones/Magento2_Gaiterjones_Elasticsearch">https://github.com/gaiterjones/Magento2_Gaiterjones_Elasticsearch</a></p>
<p>The module adds a configuration value to <em>Stores -> Configuration -> Catalog -> Search</em> where you can set the minimum score value for Elastic Search results.</p>
<figure id="blog-es_4" aria-describedby="caption-blog-es-4" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_4.jpg" alt="" width="600" height="155" class="aligncenter size-full wp-image-2287" /><figcaption id="caption-blog-es-4" class="wp-caption-text"><br />
Configure search minimum score value in admin<br /></figcaption></figure>
<p>It&#8217;s a real shame that ElasticSearch customisation options such as these are not built into Magento 2 by default to help Merchants improve the search experience. ElasticSearch is new to me, and will be to a lot of merchants and Magento devs upgrading to Magento 2.4. It&#8217;s a very complex system to understand and although we can tweak some values as shown to improve results this is not a great solution to the problem.</p>
<p>If like me you are still not happy with the native Magento 2 ElasticSearch catalog search results the absolute best solution I have found is to migrate to <a href="https://github.com/Smile-SA/elasticsuite" rel="noopener noreferrer" target="_blank">Smile ElasticSuite</a></p>
<p>Simply put, installing the Smile ElasticSuite modules and changing catalog search to ElasticSuite will <strong>immediately</strong> give you almost perfect search results. ElasticSuite is very simple to install and works out of the box improving search results and search relevance.</p>
<h1 id="elasticsuite">Install Smile ElasticSuite</h1>
<p>Here are the steps required to install ElasticSuite.</p>
<p><em>Note that ElasticSuite includes it&#8217;s own custom layered navigation, if you are already using third party layered navigation modules you will need to disable these first before installing elasticsuite.</em></p>
<p>You will need to choose the correct ElasticSuite version for the version of Magento 2 you are using. Here are the options for Magento 2.3.x and 2.4</p>
<ul style="list-style-type:none;">
<li>Magento 2.3.3 -> 2.3.5</li>
<li>
<ul style="list-style-type:none;">
<li>ElasticSuite 2.8.x : <code>composer require smile/elasticsuite ~2.8.0</code></li>
</ul>
</li>
<li>Magento 2.3.5 +</li>
<li>
<ul style="list-style-type:none;">
<li>ElasticSuite 2.9.x : <code>composer require smile/elasticsuite ~2.9.0</code></li>
</ul>
</li>
<li>Magento 2.4.0</li>
<li>
<ul style="list-style-type:none;">
<li>ElasticSuite 2.10.x : <code>composer require smile/elasticsuite ~2.10.0</code></li>
</ul>
</li>
</ul>
<ul>
<p>After installing the modules run <code>setup:upgrade</code> and then configure your ElasticSearch server hostname.</p>
<li><code>bin/magento s:up</code></li>
<li><code>bin/magento config:set -l smile_elasticsuite_core_base_settings/es_client/servers elasticsearch_server_hostname:9200</code></li>
<li><code>bin/magento s:up</code></li>
<li><code>bin/magento index:reindex</code></li>
</ul>
<p>To change your catalog search engine to ElasticSuite navigate to <em>Stores -> Configuration -> Catalog -> Search</em> and select ElasticSuite as the new catalog search engine.</p>
<figure id="blog-es_6-2" aria-describedby="caption-blog-es-6-2" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_6-2.jpg" alt="Configure ElasticSuite as Catalog Search Engine" width="600" height="219" class="size-full wp-image-2304" /><figcaption id="caption-blog-es-6-2" class="wp-caption-text">Configure ElasticSuite as Catalog Search Engine</figcaption></figure>
<p>Refresh caches and the ElasticSuite catalog search engine should now be setup and working &#8211; <em>congratulations</em> &#8211; Magento 2 full text catalog search just got a whole lot better!</p>
<p>if you see the following error in the frontend, simply run the indexer again.</p>
<pre>Exception #0 (LogicException): catalog_product index does not exist yet. Make sure everything is reindexed.</pre>
<p>ElasticSuite has some great features :</p>
<ul>
<li>A new search input form with automatic and relevant search suggestions in a dropdown list</li>
<li>Layered navigation with price sliders and advanced filters</li>
<li>Automatic redirect to product when search returns a single matching product</li>
<li>Automatic spell checked search terms</li>
<li>Smart virtual product categories</li>
<li>Search analysis in admin</li>
</ul>
<p>You will notice straight away when searching for SKUs that ElasticSuite returns more relevant results than native search. </p>
<figure id="attachment_2341" aria-describedby="caption-attachment-2341" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_8.jpg" alt="ElasticSuite sample product SKU search" width="600" height="257" class="size-full wp-image-2341" /><figcaption id="caption-attachment-2341" class="wp-caption-text">ElasticSuite sample product SKU search</figcaption></figure>
<p>Using the SKU search example you can search for all or part of the SKU with or without the hyphen and accurate search results will be returned. Notice below the search for MH03 XL without the hyphen returns the correct results</p>
<figure id="attachment_2343" aria-describedby="caption-attachment-2343" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_9.jpg" alt="ElasticSuite sample product SKU search" width="600" height="332" class="size-full wp-image-2343" /><figcaption id="caption-attachment-2343" class="wp-caption-text">ElasticSuite sample product SKU search</figcaption></figure>
<p>The redirect to product feature when a single matching product is found in search is really useful taking the customer directly to the relevant product.</p>
<p>The search analysis in admin is a great feature allowing you to see how search is being utilised by your customers and which search terms lead to conversions.</p>
<figure id="attachment_2321" aria-describedby="caption-attachment-2321" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/08/blog-es_7.jpg" alt="ElasticSuite search analysis" width="600" height="723" class="size-full wp-image-2321" /><figcaption id="caption-attachment-2321" class="wp-caption-text">ElasticSuite search analysis</figcaption></figure>
<p>For more information on ElasticSuite features and configuration consult the <a href="https://github.com/Smile-SA/elasticsuite/wiki">ElasticSuite Wiki</a> or visit the <a href="https://elasticsuite.io/" rel="noopener noreferrer" target="_blank">website</a>.</p>
<p>Many thanks to the <a href="https://elasticsuite.io/en/#page5" rel="noopener noreferrer" target="_blank">Smile team</a> for making this module freely available to the Magento 2 community.</p>
<h2>Acknowledgements</h2>
<ul>
<li><a target="_blank" href="https://elasticsuite.io/en/" rel="noopener noreferrer">Smile ElasticSuite</a></li>
<li>Moore Digital <a target="_blank" href="https://github.com/mooore-digital/magento2-module-elasticsearch-relevance" rel="noopener noreferrer">Magento 2 Elasticsearch Relevance</a></li>
<li>Sandip &#8211; <a target="_blank" href="https://magento.stackexchange.com/a/307365/7863" rel="noopener noreferrer">ngram plugin</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/how-to-improve-magento-2-elasticsearch-catalog-search-results-and-relevance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Magento 2 Javascript Bundling with Magepack</title>
		<link>https://blog.gaiterjones.com/magento-2-javascript-bundling-with-magepack/</link>
					<comments>https://blog.gaiterjones.com/magento-2-javascript-bundling-with-magepack/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 03 May 2020 19:51:28 +0000</pubDate>
				<category><![CDATA[Javascript Bundling]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[bundling]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[lighthouse]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[magepack]]></category>
		<category><![CDATA[pagespeed]]></category>
		<guid isPermaLink="false">https://blog.gaiterjones.com/?p=2171</guid>

					<description><![CDATA[Magento 2 PageSpeed (Lighthouse) performance audit results for mobile and desktop are notoriously bad. Imagine you have worked for months on a new Magento 2 eCommerce store, followed best practices...<a class="more-link" href="https://blog.gaiterjones.com/magento-2-javascript-bundling-with-magepack/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Magento 2 PageSpeed (<a href="https://developers.google.com/web/tools/lighthouse">Lighthouse</a>) performance audit results for mobile and desktop are notoriously bad. Imagine you have worked for months on a new Magento 2 eCommerce store, followed best practices for setup and optimisation, the store seems to be running fine but the first time you run a Lighthouse report you see a performance score like this:<img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_1.jpg" alt="" width="250" height="250" class="aligncenter size-full wp-image-2172" />There are a lot of factors that can affect the Lighthouse performance results for any website but for Magento 2 a big performance killer is the sheer amount of external resources required to render a page whether it be a product page, cms page or category page. Some of these render blocking resources such as Javascript or CSS can cause significant delays in page loading and affect performance. You will see this type of performance problem identified in Lighthouse as &#8220;Eliminate render-blocking resources&#8221;.</p>
<p>Magento 2 uses the RequireJs <span>javascript module system to load Javascript source code <em>required</em> for each Magento 2 page. If you have a lot of custom features with modules implementing additional Magento 2 Javascript<em> mixins </em>the number of Javascript resources in addition to the core javascript code required by Magento will increase and adversely affect page loading performance. As an example, here is the network console log from a really simple product page from my development site, you can see that there are 194 requests for Javascript resources!</span></p>
<figure id="attachment_2196" aria-describedby="caption-attachment-2196" style="width: 473px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_8.png" alt="Simple Magento 2 product page loads 194 Javascript files" width="473" height="361" class="wp-image-2196" /><figcaption id="caption-attachment-2196" class="wp-caption-text">Simple Magento 2 product page loads 194 Javascript files</figcaption></figure>
<p>There are various ways to try and reduce the performance impact of loading lots of Javascript including using http2 which is great at handling small file requests quickly or minifying the Javascript source to reduce it&#8217;s size but the most effective way of optimising Javascript loading is to use bundling.</p>
<p style="text-align: center;"><em>Javascript bundling is a technique that combines or bundles multiple files in order to reduce the number of HTTP requests that are required to load a page.<br />
</em></p>
<p>Magento 2 has a built in javascript bundler that is extremely ineffective! Users report it creating a <a href="https://github.com/magento/magento2/issues/4506">huge multi megabyte javascript</a> file that decreases performance instead of improving it. You will actually see the recommendation <em>not</em> to use the built in Magento 2 bundling referenced in Lighthouse reports &#8211; &#8220;Disable Magento&#8217;s built-in <a rel="noopener noreferrer" target="_blank" href="https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/themes/js-bundling.html">JavaScript bundling and minification</a>, and consider using <a rel="noopener noreferrer" target="_blank" href="https://github.com/magento/baler/">baler</a> instead.&#8221;</p>
<p><a href="https://github.com/magento/baler/">Baler</a> mentioned here is an AMD (Asynchronous Module Definition) module bundler / preloader for Magento 2 stores. You will find a lot of Magento 2 js bundling guides that recommend using Baler but for the average developer (like me) or Magento 2 merchant the bundling process with Baler can be quite complex and daunting. There is however a new Magento 2 js bundler available that is much easier to use.</p>
<h1>MageSuite Magepack</h1>
<p>The <a href="https://github.com/magesuite/magepack">Magepack</a> from MageSuite is a &#8220;<em>Next generation Magento 2 advanced JavaScript bundler</em>&#8221; it&#8217;s pretty easy to implement and as of version 2.0 the results it achieves are very impressive.</p>
<ul>
<li>Up to 91 points mobile score in Google Lighthouse.</li>
<li>Up to 98% reduction in JavaScript file requests.</li>
<li>Up to 44% reduction in transferred JavaScript size.</li>
<li>Up to 75% reduction in total load time.</li>
<li>Works with Magento&#8217;s JavaScript minification and merging enabled.</li>
<li>Uses custom solution (inspired by Baler)</li>
</ul>
<p><span>I installed Magepack on my Magento 2 development site in May 2020 and achieved a 100 desktop performance score with PageSpeed  &#8211;</span></p>
<p><a href="https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fmagento2.gaiterjones.com%2Fen%2Faffirm-water-bottle.html&amp;tab=desktop"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_2.jpg" alt="" width="600" height="209" class="aligncenter wp-image-2175 size-full" /></a>This is a simple product page, using the default Luma theme and I am also using Nginx as a container proxy running the PageSpeed module, so you probably won&#8217;t achieve this kind of result on a real world product page but you will see a <strong>huge</strong> improvement. Check the results yourself <a href="https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fmagento2.gaiterjones.com%2Fen%2Faffirm-water-bottle.html&amp;tab=desktop">here</a>.</p>
<p>Let&#8217;s look at how to setup and install MagePack for Magento 2.3.x / 2.4.x.</p>
<h2>Setup and install Magepack for Magento 2.3.x and 2.4.x</h2>
<p>MagePack consists of a NodeJS bundler app and a Magento 2 module. The bundler app runs on Node JS v10 or higher. I&#8217;m running MagePack in my Docker Magento 2 php container, it&#8217;s running Ubuntu server 20.04LTS and I&#8217;ve tested Magepack with Magento 2.3.3, 2.3.5 and 2.4.1. To install Node JS simply run</p>
<pre class="brush: bash; title: ; notranslate">
curl -sL https://deb.nodesource.com/setup_10.x | bash -
apt-get install -y nodejs
</pre>
<p>Ubuntu will probably need some more dependencies before MagePack will install</p>
<pre class="brush: bash; title: ; notranslate">apt-get install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget</pre>
<p>Finally to install the NodeJS MagePack app itself run<br />
<code>npm install -g magepack  --unsafe-perm=true --allow-root</code></p>
<figure id="attachment_2180" aria-describedby="caption-attachment-2180" style="width: 626px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-magepack-screenshot.jpg" alt="Installing Magepack NodeJS app and dependencies" width="626" height="300" class="wp-image-2180" /><figcaption id="caption-attachment-2180" class="wp-caption-text">Installing Magepack NodeJS app and dependencies</figcaption></figure>
<p>You will see that Magepack pulls down Chromium &#8211; it needs a web browser to analyse your Magento 2 site, most of the dependencies installed earlier are required for Chromium.</p>
<p>With Magepack installed, we now need to install the <a href="https://github.com/magesuite/magepack-magento">Magepack Magento 2 module</a></p>
<p><code>composer require creativestyle/magesuite-magepack</code></p>
<p>Next, depending on the version of Magento 2 you are running you might need to install some patches.</p>
<ul>
<li>For Magento 2.3.3 and earlier 7 patches are required</li>
<li>For Magento 2.3.4 and 2.3.5 1 patch is required</li>
<li><strong>For Magento 2.4.1 no patches are required (tested November 2020)</strong></li>
</ul>
<p>The most painless way of patching Magento 2 is to use <a href="https://github.com/cweagans/composer-patches">Cweagans/Composer-Patches</a></p>
<p><code>composer require cweagans/composer-patches</code></p>
<p>You will find all the patches you need here : https://github.com/integer-net/magento2-requirejs-bundling</p>
<p>In your Magento 2 installation folder create a <em>patches</em> folder copy the patches into it and edit your Magento 2 composer.json file to include the following composer extra patches config.</p>
<p>If you see the error <code>Evaluation failed: ReferenceError: BASE_URL is not defined</code> running magepack generate with 2.3.5+ or 2.4.x check your CSP configuration, or try disabling the CSP module temporarily &#8211; errors reported by CSP may create a magepack error.</p>
<span class="collapseomatic collapse" id="id680b5b0a22a34"  tabindex="0" title="2.3.3 composer extra patches config"    >2.3.3 composer extra patches config</span><div id="target-id680b5b0a22a34" class="collapseomatic_content ">
[text]
    &quot;extra&quot;: {<br />
            &quot;magento-force&quot;: &quot;override&quot;,<br />
            &quot;composer-exit-on-patch-failure&quot;: true,<br />
            &quot;patches&quot;: {<br />
                &quot;magento/magento2-base&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-base.diff&quot;,<br />
                    &quot;Refactor JavaScript mixins module https://github.com/magento/magento2/pull/25587&quot;: &quot;patches/composer/M233/github-pr-25587-base.diff&quot;<br />
                },<br />
                &quot;magento/module-braintree&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-braintree.diff&quot;<br />
                },<br />
                &quot;magento/module-catalog&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-catalog.diff&quot;<br />
                },<br />
                &quot;magento/module-customer&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-customer.diff&quot;<br />
                },<br />
                &quot;magento/module-msrp&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-msrp.diff&quot;<br />
                },<br />
                &quot;magento/module-paypal&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-paypal.diff&quot;<br />
                },<br />
                &quot;magento/module-theme&quot;: {<br />
                    &quot;[Performance] Fix missing shims and phtml files with mage-init directives (https://github.com/magento/magento2/commit/db43c11c6830465b764ede32abb7262258e5f574)&quot;: &quot;patches/composer/M233/github-pr-4721-theme.diff&quot;,<br />
                    &quot;fix_baler_jquery_cookie&quot;: &quot;https://gist.github.com/tdgroot/f95c398c565d9bbb83e0a650cdf67617/raw/69ee2d001ff509d25d1875743e417d914e20fd85/fix_baler_jquery_cookie.patch&quot;<br />
                }<br />
            }<br />
        },<br />
[/text]
</div>
<span class="collapseomatic collapse" id="id680b5b0a22a68"  tabindex="0" title="2.3.4, 2.3.5 composer extra patches config"    >2.3.4, 2.3.5 composer extra patches config</span><div id="target-id680b5b0a22a68" class="collapseomatic_content ">
[text]
    &quot;extra&quot;: {<br />
            &quot;magento-force&quot;: &quot;override&quot;,<br />
            &quot;composer-exit-on-patch-failure&quot;: true,<br />
            &quot;patches&quot;: {<br />
                &quot;magento/magento2-base&quot;: {<br />
                    &quot;Refactor JavaScript mixins module https://github.com/magento/magento2/pull/25587&quot;: &quot;patches/composer/M234/github-pr-25587-base.diff&quot;<br />
                }<br />
            }<br />
        },<br />
[/text]
</div>
<p>Now run <code>composer update</code> Magento 2 will be patched and we are good to go.</p>
<h2>Let’s get ready to bundle</h2>
<p>Magepack needs to analyse pages from your Magento 2 store to determine the Javascript files your store is using and how they can be bundled. It saves this information in a configuration file called <em>magepack.config.js</em>. The magepack config file is generated by analysing three different type of pages from your Magento 2 store, a cms page i.e. the home page, a category page and a product page. This is done using the <code>magepack generate</code> command and supplying three store urls.</p>
<div>
<pre class="brush: bash; title: ; notranslate">
magepack generate --cms-url=&quot;http://magento2.gaiterjones.com/&quot; --category-url=&quot;http://magento2.gaiterjones.com/en/buy-x-get-y.html&quot; --product-url=&quot;http://magento2.gaiterjones.com/en/affirm-water-bottle.html&quot;
</pre>
<p>Run this command in the root folder of your Magento 2 installation to create the magepack.config.js file. It&#8217;s worth noting that you could run this generate command from any system, and just copy the generated config file to your Magento 2 server.</p>
<p>If you take a look at magepack.config.js you will see it contains references to all the javascript required to load Magento pages. Below is an example from a product page.</p>
<span class="collapseomatic collapse" id="id680b5b0a22a91"  tabindex="0" title="example product section from magepack.config.js"    >example product section from magepack.config.js</span><div id="target-id680b5b0a22a91" class="collapseomatic_content ">
[code language=&#8221;javascript&#8221;]
    name: &#8216;product&#8217;,<br />
    modules: {<br />
      &#8216;Magento_Catalog/js/price-utils&#8217;: &#8216;Magento_Catalog/js/price-utils&#8217;,<br />
      &#8216;Magento_Catalog/js/price-box&#8217;: &#8216;Magento_Catalog/js/price-box&#8217;,<br />
      &#8216;Magento_Wishlist/js/add-to-wishlist&#8217;: &#8216;Magento_Wishlist/js/add-to-wishlist&#8217;,<br />
      &#8216;Magento_Cookie/js/require-cookie&#8217;: &#8216;Magento_Cookie/js/require-cookie&#8217;,<br />
      &#8216;Magento_Swatches/js/configurable-customer-data&#8217;: &#8216;Magento_Swatches/js/configurable-customer-data&#8217;,<br />
      &#8216;Magento_Review/js/error-placement&#8217;: &#8216;Magento_Review/js/error-placement&#8217;,<br />
      &#8216;Magento_Review/js/process-reviews&#8217;: &#8216;Magento_Review/js/process-reviews&#8217;,<br />
      &#8216;Elgentos_LargeConfigProducts/js/swatch-renderer-mixin&#8217;: &#8216;Elgentos_LargeConfigProducts/js/swatch-renderer-mixin&#8217;,<br />
      &#8216;text!Magento_Theme/templates/breadcrumbs.html&#8217;: &#8216;Magento_Theme/templates/breadcrumbs.html&#8217;,<br />
      &#8216;magnifier/magnifier&#8217;: &#8216;magnifier/magnifier&#8217;,<br />
      &#8216;magnifier/magnify&#8217;: &#8216;magnifier/magnify&#8217;,<br />
      &#8216;Magento_Catalog/js/gallery&#8217;: &#8216;Magento_Catalog/js/gallery&#8217;,<br />
      &#8216;Magento_ProductVideo/js/load-player&#8217;: &#8216;Magento_ProductVideo/js/load-player&#8217;,<br />
      &#8216;Magento_ProductVideo/js/fotorama-add-video-events&#8217;: &#8216;Magento_ProductVideo/js/fotorama-add-video-events&#8217;,<br />
      &#8216;Magento_Theme/js/model/breadcrumb-list&#8217;: &#8216;Magento_Theme/js/model/breadcrumb-list&#8217;,<br />
      &#8216;Magento_Theme/js/view/breadcrumbs&#8217;: &#8216;Magento_Theme/js/view/breadcrumbs&#8217;,<br />
      &#8216;Magento_Theme/js/view/add-home-breadcrumb&#8217;: &#8216;Magento_Theme/js/view/add-home-breadcrumb&#8217;,<br />
      &#8216;Magento_Catalog/js/product/breadcrumbs&#8217;: &#8216;Magento_Catalog/js/product/breadcrumbs&#8217;,<br />
      &#8216;jquery/jquery.parsequery&#8217;: &#8216;jquery/jquery.parsequery&#8217;,<br />
      &#8216;Magento_ConfigurableProduct/js/options-updater&#8217;: &#8216;Magento_ConfigurableProduct/js/options-updater&#8217;,<br />
      &#8216;Magento_Review/js/validate-review&#8217;: &#8216;Magento_Review/js/validate-review&#8217;,<br />
      &#8216;Magento_Swatches/js/swatch-renderer&#8217;: &#8216;Magento_Swatches/js/swatch-renderer&#8217;,<br />
      &#8216;Magento_Catalog/product/view/validation&#8217;: &#8216;Magento_Catalog/product/view/validation&#8217;,<br />
      &#8216;Magento_Catalog/js/product/view/product-ids&#8217;: &#8216;Magento_Catalog/js/product/view/product-ids&#8217;,<br />
      &#8216;Magento_Catalog/js/product/view/product-ids-resolver&#8217;: &#8216;Magento_Catalog/js/product/view/product-ids-resolver&#8217;,<br />
      &#8216;Magento_Catalog/js/catalog-add-to-cart&#8217;: &#8216;Magento_Catalog/js/catalog-add-to-cart&#8217;,<br />
      &#8216;Magento_Catalog/js/validate-product&#8217;: &#8216;Magento_Catalog/js/validate-product&#8217;,<br />
      &#8216;Magento_Catalog/js/product/view/provider&#8217;: &#8216;Magento_Catalog/js/product/view/provider&#8217;,<br />
      &#8216;text!mage/gallery/gallery.html&#8217;: &#8216;mage/gallery/gallery.html&#8217;,<br />
      &#8216;text!Magento_InstantPurchase/template/confirmation.html&#8217;: &#8216;Magento_InstantPurchase/template/confirmation.html&#8217;,<br />
      &#8216;Magento_InstantPurchase/js/view/instant-purchase&#8217;: &#8216;Magento_InstantPurchase/js/view/instant-purchase&#8217;,<br />
      &#8216;Magento_Review/js/view/review&#8217;: &#8216;Magento_Review/js/view/review&#8217;,<br />
      &#8216;fotorama/fotorama&#8217;: &#8216;fotorama/fotorama&#8217;,<br />
      &#8216;mage/gallery/gallery&#8217;: &#8216;mage/gallery/gallery&#8217;,<br />
      &#8216;text!Magento_InstantPurchase/template/instant-purchase.html&#8217;: &#8216;Magento_InstantPurchase/template/instant-purchase.html&#8217;<br />
    }<br />
  },<br />
[/code]
</div>
<p>All that remains now is for us to create the bundle files and deploy them for all our store views and themes. This is simply done with the <code>magepack bundle</code> command which you can execute from the Magento installation root folder. If you are running in development mode, deploy frontend static files first.</p>
<p><code>magepack bundle</code></p>
<figure id="attachment_2194" aria-describedby="caption-attachment-2194" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_5.jpg" alt="Magepacl bundle command" width="600" height="231" class="wp-image-2194 size-full" /><figcaption id="caption-attachment-2194" class="wp-caption-text">Magepack bundle command</figcaption></figure>
<p>Finally enable Magepack Javascript bundling in admin :</p>
<p style="text-align: center;"><strong>Stores &#8211; Configuration &#8211; Advanced &#8211; Developer &#8211; Javascript Settings</strong></p>
<figure id="attachment_2193" aria-describedby="caption-attachment-2193" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_4.jpg" alt="Enable Magepack bundling in admin" width="600" height="201" class="wp-image-2193 size-full" /><figcaption id="caption-attachment-2193" class="wp-caption-text">Enable Magepack bundling in admin</figcaption></figure>
<p>If you are in production mode these options will be hidden in admin. To enable Magepack Javascript bundling from the command line use</p>
<p><code>bin/magento config:set dev/js/enable_magepack_js_bundling 1</code></p>
<p>Note that you should also enable the other Javascript optimisation options here including minfy javascript files and move js code to the bottom of the page &#8211; but <strong>don&#8217;t</strong> enable the default bundling!</p>
<p>MagePack Javascript bundling should now be enabled. To check it&#8217;s working go to a Magento 2 product page and look at the source code, do a search for &#8220;bundle&#8221; and you should see the magepack javascript bundles</p>
<p><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_6.jpg" alt="" width="1003" height="158" class="aligncenter wp-image-2195" /></p>
<p>Now refresh the page and have a look at your network log</p>
<figure id="attachment_2197" aria-describedby="caption-attachment-2197" style="width: 447px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_9.png" alt="After bundling there are only 7 js requests on the product page" width="447" height="269" class="wp-image-2197" /><figcaption id="caption-attachment-2197" class="wp-caption-text">After bundling there are only 7 js requests on the product page</figcaption></figure>
<p>Instead of loading 194 Javascript files, the product page now loads 7, Magepack has bundled all the Javascript into two main bundle files.</p>
<p>I guess it&#8217;s now time to look at the PageSpeed Lighthouse performance reports for your optimised Magento 2 pages. If you are using the Chrome browser simply run a Lighthouse report from the DevTools page. You can also use Googles PageSpeed insights tool at <a href="https://developers.google.com/speed/pagespeed/insights/">https://developers.google.com/speed/pagespeed/insights/</a></p>
<p>This is the improvement I saw in a live production Magento 2 site</p>
<figure id="attachment_2224" aria-describedby="caption-attachment-2224" style="width: 800px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2020/05/blog-pagespeed_12.jpg" alt="Performance results before and after bundling" width="800" height="350" class="wp-image-2224 size-full" /><figcaption id="caption-attachment-2224" class="wp-caption-text">Performance results before and after bundling</figcaption></figure>
<p>If you don’t see a big improvement remember there are a lot of other factors taken into Lighthouse performance reports. Work through the report and try to find out where you can make further improvements.</p>
<h2>Deployment in production</h2>
<p>Whenever you flush your sites static files you will need to remember to run <code>magepack bundle</code> again. In production mode you should add this to your deployment process</p>
<pre class="brush: bash; title: ; notranslate">
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy en_GB --area adminhtml
bin/magento setup:static-content:deploy en_GB --area frontend --theme MY/Theme -f
magepack bundle
bin/magento cache:clean
</pre>
<p><strong>Top Tip</strong> &#8211; if for any reason you want to generate the magepack.config.js bundle config again remember to disable the Magepack module first!</p>
<h2>Testing and Troubleshooting</h2>
<p>You should test your store thoroughly to make sure there are no Javascript problems caused by the bundling process. Magepack cannot always 100% bundle all the Javascript required by some pages. Check your web browser console for errors. If you find some features of your store are not working, try and identify if the code was included in the magepack.config.js file. Try removing the code from the bundle and test again.</p>
<h2>Selective Bundling</h2>
<p>If you do not want to bundle at checkout, or any other specific pages take a look at the isEnabled method in the Block\BundlesLoader class. This method determines whether the magepack module is enabled and if bundling should be activated. Simply detect any page here i.e. checkout pages and return false to disable bundling at checkout.</p>
<pre class="brush: php; title: ; notranslate">

        \Magento\Framework\App\Request\Http $request,
        ....
        $this-&gt;request = $request;
        ....
public function isEnabled()
{
        if ($this-&gt;request-&gt;getFullActionName() == 'checkout_index_index') {

            // disable for checkout
            //
            return false;
        }

...


</pre>
<h2>Magepack for Magento Cloud</h2>
<p>You need to have magepack.config in repo, add this to magento.app.yaml:</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;\n================================== Install and configure Magepack - Start ===============================&quot;
unset NPM_CONFIG_PREFIX
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.35.1/install.sh | bash
export NVM_DIR=&quot;$HOME/.nvm&quot;
&#x5B; -s &quot;$NVM_DIR/nvm.sh&quot;  ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;
nvm install --lts=dubnium
npm install -g magepack
echo &quot;\n================================== create bundle ===============================&quot;
magepack bundle
echo &quot;\n================================== Install and configure Magepack - END =================================&quot;
</pre>
<p><em>Thanks to Solteq for this information.</em></p>
<p>Magepack is pretty new with updates being made regularly, be sure to check out the projects GitHub page for new issues.</p>
<h3>References</h3>
<p><a href="https://github.com/magesuite/magepack">https://github.com/magesuite/magepack</a><br />
<a href="https://github.com/magesuite/magepack-magento">https://github.com/magesuite/magepack-magento</a><br />
<a href="https://www.integer-net.com/magento-2-javascript-bundling-integer-net-2/">https://www.integer-net.com/magento-2-javascript-bundling-integer-net-2/</a><br />
<a href="https://gist.github.com/tdgroot/f95c398c565d9bbb83e0a650cdf67617">https://gist.github.com/tdgroot/f95c398c565d9bbb83e0a650cdf67617</a><br />
<a href="https://github.com/integer-net/magento2-requirejs-bundling">https://github.com/integer-net/magento2-requirejs-bundling</a><br />
<a href="https://developers.google.com/speed/pagespeed/module">https://developers.google.com/speed/pagespeed/module</a></p>
<p><a href="https://blog.gaiterjones.com/magento-google-pagespeed-jscsshtmlminify-optimisation/">PageSpeed optimisation in Magento 1</a></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento-2-javascript-bundling-with-magepack/feed/</wfw:commentRss>
			<slash:comments>37</slash:comments>
		
		
			</item>
		<item>
		<title>Magento 2.2.X Development and Upgrades</title>
		<link>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/</link>
					<comments>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Thu, 03 May 2018 08:55:14 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1883</guid>

					<description><![CDATA[Today (2nd May 2018) Magento released Magento CE 2.2.4. Recently the Magento Devs have been pretty busy pushing out 2.2.x updates and Magento 2 is maturing nicely. I am still...<a class="more-link" href="https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Today (2nd May 2018) Magento released Magento CE 2.2.4. Recently the Magento Devs have been pretty busy pushing out 2.2.x updates and Magento 2 is maturing nicely. I am still getting to grips with Magento 2 and don&#8217;t expect to release a live site for at least another year so it makes sense to develop with the latest version of Magento. My <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">Magento 2.2.x development environment</a> is built on Docker and installing new Magento 2 dev shops is a breeze:</p>
<ol>
<li>git clone https://github.com/gaiterjones/docker-magento2-2</li>
<li>cd docker-magento2-2/magento</li>
<li>edit .env</li>
<li>docker-compose build</li>
<li>docker-compose up -d</li>
<li>http://magento2.dev.com</li>
</ol>
<p>Upgrading Magento is always a scary experience &#8211; Magento 2 is even more terrifying so I recommend you get used to doing updates with your dev systems. If you are manually upgrading from a previous 2.x version, you can use composer within the docker container:</p>
<ol>
<li>Take a backup</li>
<li>Enter maintenance mode</li>
<li>edit compose.json
<ol>
<li>change version</li>
</ol>
</li>
<li>flush redis
<ol>
<li><span>redis-cli flushall in the redis containers</span></li>
</ol>
</li>
<li>composer update</li>
<li><span>rm -rf var/cache/* var/page_cache/* var/generation/* var/di/*</span></li>
<li><span>chmod +x bin/magento</span></li>
<li><span>php bin/magento cache:flush</span></li>
<li><span>php bin/magento setup:upgrade</span></li>
<li><span>php bin/magento indexer:reindex</span></li>
</ol>
<p>If the upgrade breaks any sample data reinstall with php -f bin/magento sampledata:deploy</p>
<p>I regularly update my Magento 2 docker containers with each version update check them out at <a href="https://github.com/gaiterjones/docker-magento2-2">https://github.com/gaiterjones/docker-magento2-2</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Magento 2 theme blank SASS parent and child setup and installation</title>
		<link>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/</link>
					<comments>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Mon, 03 Jul 2017 13:04:59 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Frontend Development]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[less]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[sass]]></category>
		<category><![CDATA[theme blank sass]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1712</guid>

					<description><![CDATA[With CE 1.9 Magento introduced the SASS stylesheet language to aid frontend development. With Magento 2.x for reasons best known to the developers they switched from SASS to LESS. At the...<a class="more-link" href="https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>With CE 1.9 Magento introduced the <a href="http://sass-lang.com/">SASS</a> stylesheet language to aid frontend development. With Magento 2.x for <a href="https://magento.stackexchange.com/questions/26439/sass-in-1-9-less-in-2-why">reasons best known to the developers</a> they switched from SASS to LESS. At the end of the day both LESS and SASS are compiled into good old CSS but if your stylesheet language of preference is SASS or you are new to Magento and are looking for a good starting block to build a new theme from then it is well worth taking a look at <em>SnowDogApps </em><a href="https://github.com/SnowdogApps/magento2-theme-blank-sass">theme blank sass project</a>.</p>
<p>The <a href="https://community.magento.com/t5/Less-to-Sass-Community-Project/bd-p/less-to-sass">Less to Sass Community Project</a> is officially supported by Magento and Theme Blank SASS is the result of this project &#8211; a (production ready) Magento 2 blank theme converted to SASS.</p>
<p>Together with the accompanying <a href="https://github.com/SnowdogApps/magento2-frontools">Fronttools pack</a> you get the development tools and extendable SASS based blank theme you need to get you started building your own custom theme.</p>
<h1>Why use theme blank SASS ?</h1>
<ul>
<li>If you are coming from Magento 1.9 then you already are familiar with SASS</li>
<li>Magento 2.x may possibly move to SASS in the future</li>
<li>LUMA is not designed to be extended as a blank theme</li>
<li>Essential development tools such as browsersync are included</li>
</ul>
<h1>How to install theme blank SASS parent theme and Fronttools</h1>
<p>You can be up and running with theme blank SASS and fronttools in a few minutes. Here is a step by step theme blank sass and frontools installation guide tested on my <a href="https://github.com/gaiterjones/docker-magento2">Magento 2.x docker containers.</a></p>
<p>I am installing the parent theme and fronttools directly into my docker Magento 2 php-apache container with a bash script :</p>
<p><code>curl -o- http://gaiterjones.com/dropbox/magento2/theme-blank-sass/install-theme-blank-sass.sh | bash</code><br />
&nbsp;<br />
<span class="collapseomatic collapse" id="id680b5b0a29cc5"  tabindex="0" title="script to install theme-blank-sass and fronttools"    >script to install theme-blank-sass and fronttools</span><div id="target-id680b5b0a29cc5" class="collapseomatic_content ">
[bash]
#!/bin/bash<br />
# GAITERJONES<br />
# blog.gaiterjones.com<br />
# script to install theme-blank-sass and fronttools<br />
# for docker service https://github.com/gaiterjones/docker-magento2<br />
#<br />
set -e<br />
# variables<br />
RED=&#8217;&#92;&#48;33[0;31m&#8217;<br />
NC=&#8217;&#92;&#48;33[0m&#8217;</p>
<p># CHANGE THIS<br />
MAGENTO_DIR=&#8217;/var/www/dev/magento2&#8242;<br />
NVM_HOME=&#8217;/var/www&#8217;</p>
<p># start<br />
printf &quot;${RED}Installing theme-blank-sass into Magento Root: ${MAGENTO_DIR}&#8230;\n\n${NC}&quot;<br />
cd ${MAGENTO_DIR}<br />
composer require snowdog/theme-blank-sass<br />
composer require snowdog/frontools<br />
${MAGENTO_DIR}/bin/magento setup:upgrade<br />
${MAGENTO_DIR}/bin/magento cache:clean</p>
<p>printf &quot;${RED}Installing nvm&#8230;\n${NC}&quot;<br />
cd /tmp<br />
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash<br />
export NVM_DIR=${NVM_HOME}/.nvm<br />
 [ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;<br />
nvm install &#8211;lts<br />
nvm use &#8211;lts<br />
printf &quot;${RED}Installing gulp&#8230;\n${NC}&quot;<br />
npm install -g gulp-cli</p>
<p>printf &quot;${RED}Installing frontools&#8230;\n${NC}&quot;<br />
cd ${MAGENTO_DIR}/vendor/snowdog/frontools<br />
npm install<br />
gulp setup<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/browser-sync.json<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/themes-blank-sass-parent.json<br />
curl -o &quot;${MAGENTO_DIR}/vendor/snowdog/theme-blank-sass/web/images/logo.svg&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/logo-theme-blank-sass.svg</p>
<p>printf &quot;${RED}Generating theme-blank-sass styles&#8230;\n${NC}&quot;<br />
gulp styles</p>
<p>printf &quot;${RED}Configuring Snowdog/blank theme.\n${NC}&quot;<br />
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list &#8211;format=csv \<br />
  | grep &#8216;Snowdog/blank&#8217; | cut -d, -f1)&quot; \<br />
  ; test -n &quot;${THEME_ID}&quot; \<br />
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;<br />
${MAGENTO_DIR}/bin/magento cache:clean</p>
<p># done<br />
printf &quot;${RED}Installation complete.\n\n${NC}&quot;<br />
[/bash]
</div>
<p>Here are the script commands broken down into some more detail :</p>
<p>Set the install environment variables</p>
<pre class="brush: bash; title: ; notranslate">
cd ${MAGENTO_DIR}
MAGENTO_DIR='/var/www/dev/magento2'
NVM_HOME='/var/www'
</pre>
<p><em>MAGENTO_DIR</em> is the path to the magento root and <em>NVM_HOME</em> the path to the NVM installation home folder &#8211; this is the home folder for the user that installs NVM</p>
<p>Install the theme and tools with composer, upgrade Magento and refresh caches.</p>
<pre class="brush: bash; title: ; notranslate">
composer require snowdog/theme-blank-sassinstall theme blank sass
composer require snowdog/frontoolsinstall fronttools

${MAGENTO_DIR}/bin/magento setup:upgradeupdate Magento
${MAGENTO_DIR}/bin/magento cache:cleanrefresh caches
</pre>
<p>Install NVM and gulp-cli</p>
<pre class="brush: bash; title: ; notranslate">
cd /tmp
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
export NVM_DIR=${NVM_HOME}/.nvm
 &#x5B; -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;
nvm install --lts
nvm use --lts
npm install -g gulp-cli
</pre>
<p>Install frontools.</p>
<pre class="brush: bash; title: ; notranslate">
cd ${MAGENTO_DIR}/vendor/snowdog/frontools
npm install
</pre>
<p>You run the fronttools setup with <em>gulp setup</em>, this will copy the project sample configuration files to ${MAGENTO_DIR}/dev/tools/frontools/config/.  You must edit <em>themes.json</em>, for the parent theme.</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;blank&quot;: {
    &quot;src&quot;: &quot;vendor/snowdog/theme-blank-sass&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Snowdog/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;],
    &quot;ignore&quot;: &#x5B;&quot;.test&quot;]
  }
}

</pre>
<p>The script is copying my themes and browser-sync json configuration files via curl.</p>
<pre class="brush: bash; title: ; notranslate">
gulp setup
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/browser-sync.json
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/themes-blank-sass-parent.json
gulp styles
</pre>
<p>Next I compile the SASS to CSS and install it using</p>
<pre class="brush: bash; title: ; notranslate">
gulp styles
</pre>
<p>Finally I am using <a href="https://github.com/netz98/n98-magerun2">n98-magerun2</a> to enable the new theme, and refresh the Magento caches.</p>
<pre class="brush: bash; title: ; notranslate">
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list --format=csv \
  | grep 'Snowdog/blank' | cut -d, -f1)&quot; \
  ; test -n &quot;${THEME_ID}&quot; \
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;
${MAGENTO_DIR}/bin/magento cache:clean
</pre>
<p><img loading="lazy" decoding="async" src="http://gaiterjones.com/dropbox/magento2/theme-blank-sass/logo-theme-blank-sass.svg" width="248" height="73" class="aligncenter size-large" /><br />
Theme blank SASS parent theme is now installed. You can watch the install process below.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento-sass-blank-parent.gif" alt="magento 2 theme blank sass install video" class="aligncenter" /></p>
<p>We used the <em>gulp setup</em>, and <em>gulp styles </em>tasks above &#8211; other useful tasks include</p>
<ul>
<li>gulp clean
<ul>
<li><span>Removes </span><code>/pub/static</code><span> directory content.</span></li>
</ul>
</li>
<li>gulp dev
<ul>
<li><span>Runs </span><a href="https://www.browsersync.io/">browserSync</a><span> and </span><code>inheritance</code><span>, </span><code>babel</code><span>, </span><code>styles</code><span>, </span><code>watch</code><span> tasks.</span></li>
</ul>
</li>
</ul>
<p>See the fronttools project page for a full list of gulp tasks or use the gulp default task.</p>
<h1>How to install a theme blank SASS child theme</h1>
<p>Usual Magento best practice dictates that instead of editing the parent them we extend it with a child theme. You extend <code>Snowdog/blank</code> the same way as <a href="http://devdocs.magento.com/guides/v2.0/frontend-dev-guide/themes/theme-inherit.html">any other theme</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;theme xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;urn:magento:framework:Config/etc/theme.xsd&quot;&gt;
    &lt;title&gt;Gaiterjones/blank&lt;/title&gt;
    &lt;parent&gt;Snowdog/blank&lt;/parent&gt;
    &lt;media&gt;
        &lt;preview_image&gt;media/preview.jpg&lt;/preview_image&gt;
    &lt;/media&gt;
&lt;/theme&gt;
</pre>
<p>I tested this with my Docker environment and used the following script to extend theme blank SASS with my <code>Gaiterjones/blank</code> child theme.</p>
<p><code>curl -o- http://gaiterjones.com/dropbox/magento2/theme-blank-sass/child/install-child-theme-blank-sass.sh | bash</code></p>
<span class="collapseomatic collapse" id="id680b5b0a29d33"  tabindex="0" title="script to install theme-blank-sass child theme"    >script to install theme-blank-sass child theme</span><div id="target-id680b5b0a29d33" class="collapseomatic_content ">
[bash]
#!/bin/bash<br />
# GAITERJONES<br />
# blog.gaiterjones.com<br />
# script to install example theme-blank-sass child theme<br />
#<br />
set -e<br />
# variables<br />
RED=&#8217;&#92;&#48;33[0;31m&#8217;<br />
NC=&#8217;&#92;&#48;33[0m&#8217;</p>
<p># CHANGE THIS<br />
MAGENTO_DIR=&#8217;/var/www/dev/magento2&#8242;<br />
NVM_HOME=&#8217;/var/www&#8217;</p>
<p># start<br />
printf &quot;${RED}Installing theme-blank-sass child theme into Magento Root: ${MAGENTO_DIR}&#8230;\n\n${NC}&quot;<br />
n98-magerun2.phar maintenance:enable<br />
cd ${MAGENTO_DIR}/app/design/frontend<br />
curl https://pe.terjon.es/dropbox/magento2/theme-blank-sass/child/gaiterjones-blank-child-theme-blank-sass.tar | tar x<br />
${MAGENTO_DIR}/bin/magento setup:upgrade<br />
cd ${MAGENTO_DIR}/vendor/snowdog/frontools</p>
<p>printf &quot;${RED}Configuring Gaiterjones/blank theme.\n${NC}&quot;<br />
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list &#8211;format=csv \<br />
  | grep &#8216;Gaiterjones/blank&#8217; | cut -d, -f1)&quot; \<br />
  ; test -n &quot;${THEME_ID}&quot; \<br />
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;</p>
<p>printf &quot;${RED}Installing new themes.json config&#8230;\n${NC}&quot;<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; https://gaiterjones.com/dropbox/magento2/theme-blank-sass/child/themes-blank-sass-parent-child.json<br />
printf &quot;${RED}Generating theme-blank-sass styles&#8230;\n${NC}&quot;<br />
export NVM_DIR=${NVM_HOME}/.nvm<br />
 [ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;<br />
gulp styles<br />
${MAGENTO_DIR}/bin/magento cache:clean<br />
n98-magerun2.phar maintenance:disable<br />
# done<br />
printf &quot;${RED}Installation complete.\n\n${NC}&quot;</p>
[/bash]
</div>
<p>The script extracts the <code>Gaiterjones/blank</code> child theme source files to <em>app/design/frontend/Gaiterjones/blank </em>and updates Magento. We need to also update the fronttools <em>themes.json </em>config file to let fronttools know where our child theme lives</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;blank&quot;: {
    &quot;src&quot;: &quot;vendor/snowdog/theme-blank-sass&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Snowdog/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;],
    &quot;ignore&quot;: &#x5B;&quot;.test&quot;]
  },
  &quot;gaiterjones-blank&quot;: {
    &quot;src&quot;: &quot;app/design/frontend/Gaiterjones/blank&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Gaiterjones/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;localeOverwrites&quot;: true,
    &quot;parent&quot;: &quot;blank&quot;,
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;]
  }  
}

</pre>
<p>Next I am activating the theme with n98-magerun2 and then I simply need to refresh the caches and run <em>gulp styles </em> again to create the CSS for our child theme.</p>
<pre class="brush: bash; title: ; notranslate">
gulp styles
${MAGENTO_DIR}/bin/magento cache:clean
</pre>
<p>Fronttools compiles and installs the CSS for our child theme which is now installed and ready to view.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento-sass-blank-child.gif" alt="magento 2 theme blank sass child theme install video" class="aligncenter" /></p>
<p>You can see theme blank SASS in action on my <a href="http://magento2.gaiterjones.com" target="_blank">development site</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Magento CE v2.4.x Development Deployment with PHP7.4, Apache2.4, REDIS, VARNISH, RabbitMQ, Scaleable</title>
		<link>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/</link>
					<comments>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 25 Jun 2017 13:31:05 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1694</guid>

					<description><![CDATA[Installing Magento 2 in a development environment can be time consuming. This is my Magento 2 development deployment for Docker which can be used to quickly create a new Magento...<a class="more-link" href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Installing Magento 2 in a development environment can be time consuming. This is my Magento 2 development deployment for Docker which can be used to quickly create a new Magento 2 Open Source (formerly known as CE) environment, or switch between persistent development environment volumes.</p>
<h2>Features</h2>
<ul>
<li>PHP 7.4 and Apache 2.4 built on the latest PHUSION docker images</li>
<li>2 Redis servers for Session and System (including FPC)</li>
<li>MYSQL 8</li>
<li>PhpMyAdmin</li>
<li>Varnish 6 for FPC</li>
<li>RabbitMQ</li>
<li>Management container and Scale Manager for <a href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/">scaled service dynamic load balancing</a></li>
<li>composer, n98-magerun2, PHP Redis Admin, XDEBUG</li>
<li><b>Magento 2.4.2 (Feb 2021)</b></li>
</ul>
<h2>Requirements</h2>
<ul>
<li>Host server with min 2GB RAM</li>
<li>Docker Engine</li>
<li>Docker Compose 3.1</li>
</ul>
<h2>Base Images / Source for 2.4 deployment</h2>
<ul>
<li><a href="https://hub.docker.com/r/gaiterjones/magento2/">gaiterjones/magento2</a> for 2.4
<ul>
<li><a href="https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/magento240-build">https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/magento240-build</a></li>
<li>PHUSION
<ul>
<li><a href="https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/phusion1100-apache2-php7-4-build">https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/phusion1001-apache2-php7-4-build</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Deployment</h2>
<p>Here are the steps to deploy this Magento 2.4 development environment:</p>
<ul>
<li>Clone the source file repository from, GitHub
<ul>
<li>2.4
<ul>
<li>git clone https://github.com/gaiterjones/docker-magento2</li>
</ul>
</li>
</ul>
</li>
<li>Change into the Magento 2 directory
<ul>
<li>cd magento2</li>
</ul>
</li>
<li>Edit the .env file and set the working environment for your deployment :
<ul>
<li>APPDOMAIN=dev.com
<ul>
<li>the domain name for the magento installation</li>
</ul>
</li>
<li>SMTP=XXX
<ul>
<li>the smtp gateway for your deployment, required for Magento email.</li>
</ul>
</li>
<li>MAGENTO_URL=http://magento2.dev.com
<ul>
<li>the Magento URL for your deployment</li>
</ul>
</li>
<li>MAGENTO_REPO_USERNAME/PASSWORD
<ul>
<li>your Magento repo authentication details required for Magento installation</li>
</ul>
</li>
<li>CONTAINERDATA=/home/docker/data/
<ul>
<li>Used for persistent container data</li>
</ul>
</li>
</ul>
</li>
<li>Edit docker-compose.yml
<ul>
<li>You can remove the Manager and Memcache service here if you do not want to deploy the scale manager.</li>
<li>for mysql persistent data uncomment the following from the mysql image
<ul>
<li><strong>#</strong>&#8211; &#8220;${CONTAINERDATA}/${PROJECT_NAME}/mysql/dev1:/var/lib/mysql&#8221;</li>
</ul>
</li>
<li>If you are using Nginx as a container reverse proxy change the ports and networks for the varnish service accordingly.</li>
</ul>
</li>
<li>Generate a Varnish Secret
<ul>
<li>You can create a new <a href="https://varnish-cache.org/docs/trunk/users-guide/run_security.html"><em>varnish secret</em></a> by running <em>newsecret.sh</em> in the varnish folder.</li>
</ul>
</li>
<li>BUILD
<ul>
<li><span>docker-compose build</span></li>
</ul>
</li>
<li>START
<ul>
<li><span>docker-compose up -d</span>
<ul>
<li>Allow 60 seconds after starting for composer to initialise</li>
</ul>
</li>
</ul>
</li>
<li>Install Magento Sample Data (optional)
<ul>
<li><span>docker exec -it magento2_php-apache_1 install-sampledata</span>
<ul>
<li><span>ignore error </span><em>Can&#8217;t run this operation: deployment configuration is absent.</em></li>
</ul>
</li>
</ul>
</li>
<li>Install Magento
<ul>
<li><span>docker exec -it magento2_php-apache_1 install-magento</span></li>
</ul>
</li>
</ul>
<h2>Script install</h2>
<p>For a quick test, spin up a Type 2 <a href="https://www.packet.net/">packet.net</a> server running Ubuntu LTS 20.04, install Docker CE and docker compose and then run</p>
<p><code>docker exec -it --user magento magento2_php-apache_1 su root -c "curl -o- https://gaiterjones.com/dropbox/magento2/docker/install.sh | bash"</code></p>
<p>&nbsp;</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento240.gif" alt="magento 2 docker containers install video" class="aligncenter" /></p>
<h2>Testing</h2>
<ul>
<li>frontend
<ul>
<li style="list-style-type: none;">
<ul>
<li><em><strong>http://magento2.dev.com</strong></em></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style: none;"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/Image.png" alt="" width="500" height="311" class="aligncenter wp-image-1695" /></li>
</ul>
</li>
<li>backend
<ul>
<li style="list-style-type: none;">
<ul>
<li><em><strong>http://magento2.dev.com/admin/</strong></em>
<ul>
<li>login using the credentials you set in .env</li>
</ul>
</li>
<li>Configure Varnish FPC
<ul>
<li><span>Stores-&gt; Configuration -&gt; Advanced -&gt; Full Page Cache</span></li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li style="list-style: none;"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/Image-1.png" alt="" width="500" height="401" class="aligncenter wp-image-1696" /></li>
<li>Test from containers with curl (optional)
<ul>
<li><em>curl -I -H &#8220;host: magento2.dev.com&#8221; magento2_php-apache_1:80</em></li>
<li><em>curl -H &#8220;host: magento2.dev.com&#8221; magento2_php-apache_1:80/healthcheck.php</em></li>
</ul>
</li>
<li>n98-magerun2
<ul>
<li><span>docker exec -it &#8211;user magento magento2_php-apache_1 /usr/local/bin/n98-magerun2.phar</span></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Persistent volumes</h2>
<p>Your development deployment data will be lost when you restart the php-apache or sql containers. If you want data to persist after installation perform the following steps:</p>
<ul>
<li>Tar the Magento source files in the php-apache container
<ul>
<li>docker exec -it &#8211;user magento magento2_php-apache_1 tar -cvf /home/data/magento2.tar /var/www/dev</li>
<li>The tar file will be saved to the docker container data folder specified in .env</li>
</ul>
</li>
<li>Stop the containers
<ul>
<li>docker-compose down -v</li>
</ul>
</li>
<li>Untar to host
<ul>
<li>tar -xvf magento2.tar</li>
</ul>
</li>
<li>Move the /var/www/dev folder to your persistent data folder i.e. /home/docker/data/magento2/dev1</li>
<li>Uncomment the data volume in docker-compose.yml
<ul>
<li>#- &#8220;${CONTAINERDATA}/${PROJECT_NAME}/dev1:/var/www/dev&#8221;</li>
</ul>
</li>
<li>Restart containers, Magento data is now persistent.</li>
</ul>
<h2>Scaling php-apache</h2>
<p>You can scale the php-apache Magento service with</p>
<p><em>docker-compose scale php-apache=X</em></p>
<p>See <a href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/">this post for more information</a>.</p>
<h2>manager container</h2>
<p>In production I prefer to use a management container for all Magento admin and cli commands. The manager container can be used as the main administration container for your production environment. You should move all cron jobs to the manager and you can also move web administration to the manager container. This will free up the php-apache container just to be used to serve frontend web requests and allows you to use the scale function. You will also notice that separating cron tasks into a separate container reduces the memory requirement of the php-apache container significantly.</p>
<p>To start an admin bash session in the management container use<br />
<span></span></p>
<div><code>docker exec -i-t --user magento magento2_php-apache_1 /bin/bash</code></div>
<h2>References</h2>
<ul>
<li><a href="https://github.com/fballiano"><span>Fabrizio Balliano</span></a></li>
<li><a href="https://github.com/alexcheng1982">Alex Cheng</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Mono Host Magento 2 Service Scaling and Dynamic Load Balancing with VARNISH</title>
		<link>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/</link>
					<comments>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 18 Jun 2017 16:30:30 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[Scaled Services]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[scale]]></category>
		<category><![CDATA[varnish]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1674</guid>

					<description><![CDATA[As I started building Docker service container images for Magento 2 CE development I got interested in the concept of dynamic service load balancing on a single host. Having already...<a class="more-link" href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>As I started building <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">Docker service container images for Magento 2</a> CE development I got interested in the concept of dynamic service load balancing on a single host. Having already created a <a href="https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/">dynamic load balancer using NGINX</a> I wanted to do the same for Magento 2 using <strong>Varnish</strong>.</p>
<p>My Magento 2 service container images include REDIS services for the Magento session and system cache and a Varnish service for the full page cache. Varnish is an HTTP accelerator designed for content-heavy dynamic web sites and is the recommended full page cache system for Magento 2.</p>
<figure id="attachment_1690" aria-describedby="caption-attachment-1690" style="width: 1280px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/magento2-docker-network.png" alt="" width="1280" height="1024" class="size-full wp-image-1690" /><figcaption id="caption-attachment-1690" class="wp-caption-text">Magento 2 Docker Network</figcaption></figure>
<p>Varnish is configured via the Varnish Configuration Language (VCL) config file. By configuring multiple backend servers in VCL and grouping them into a director we can create a Varnish <a href="https://varnish-cache.org/docs/trunk/users-guide/vcl-backends.html">load balancer</a>.</p>
<span class="collapseomatic collapse" id="id680b5b0a2f251"  tabindex="0" title="Varnish Magento 2 load balancing VCL"    >Varnish Magento 2 load balancing VCL</span><div id="target-id680b5b0a2f251" class="collapseomatic_content ">
<pre>[text]
backend magento2_php_apache_1 {
.host = &quot;x.x.x.2&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_2 {
.host = &quot;x.x.x.8&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_3 {
.host = &quot;x.x.x.10&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_4 {
.host = &quot;x.x.x.11&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_5 {
.host = &quot;x.x.x.9&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
sub vcl_init {
new cluster1 = directors.round_robin();
cluster1.add_backend(magento2_php_apache_1);
cluster1.add_backend(magento2_php_apache_2);
cluster1.add_backend(magento2_php_apache_3);
cluster1.add_backend(magento2_php_apache_4);
cluster1.add_backend(magento2_php_apache_5);
}
[/text]</pre>
</div>
<h2>Scale Manager</h2>
<p>I use a service container called <em>php-apache</em> to run the Magento core code. Docker compose allows you to scale containers on a single host, so for example with the command</p>
<p><em>docker-compose scale php-apache=5</em></p>
<p>I can quickly scale the Magento2 php-apache service up to 5 containers, that is 5 instances of the php-apache service running the Magento2 core php code and apache web server.</p>
<p>The scale manager service monitors docker processes and detects when the php-apache service is scaled up or down. When a change is detected it dynamically creates the VCL configuration required to tell Varnish about the changes and applies these to the Varnish server.</p>
<figure id="attachment_1676" aria-describedby="caption-attachment-1676" style="width: 500px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/magento2-scale-demo.jpg" alt="" width="500" height="487" class="size-full wp-image-1676" /><figcaption id="caption-attachment-1676" class="wp-caption-text">Magento 2 Scale Demo</figcaption></figure>
<h2>Magento 2 Scale Demo</h2>
<p>In the video below I start with one running instance of the Magento 2 service, I then scale the service up to 5 and using the scale demo page (which is not cached by Varnish) on my <a href="http://magento2.gaiterjones.com/">Magento 2 dev site</a> to analyse the scale manager output data and display the running Magento 2 service containers.</p>
<p>As I refresh the page the Magento 2 container rendering the page is highlighted in yellow. you can see how Varnish round robins between the 5 available containers. Finally I scale the service back down and manually update the Varnish server config via the command line php script on the manager.</p>
<p>Another way to see the round robin connection distribution from varnish is to load up a <em>phpinfo()</em> page, you will see the SERVER_ADDR variable changing with each container that processes the request.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-magento2-scaledemox2.gif" alt="docker scale service dynamic load balancing with nginx demo video" class="aligncenter" /></p>
<p>Would you actually run 5 Magento 2 php-apache services? Good question! For true resilience and load balancing you would need multiple hosts and a Docker swarm. Multiple service containers on a single host do at least provide a simple level of redundancy and host server load balancing, I would definitely consider using it in production especially with a multi core server.</p>
<p>Many thanks to <a href="https://github.com/fballiano/docker-magento2">Fabrizio Balliano</a> for the inspiration and assistance.</p>
<p>See <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">this post</a> for instructions on how to deploy this Magento 2 development environment.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
