<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[The WebDevCodeZone]]></title><description><![CDATA[I'm Wolfgang, a paramedic turned fullstack developer in 2018. I build online stores and love teaching coding to unlock creativity and to help thinking outside t]]></description><link>https://blog.kreminger.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 06 Sep 2026 15:13:29 GMT</lastBuildDate><atom:link href="https://blog.kreminger.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Set Up and Use Shopware's Admin Watcher with DDEV for Shopware < 6.7.3.0 and Vite]]></title><description><![CDATA[Starting with Shopware 6.7, the administration is built with Vite. Because of the new build tool, the structure and how hot module reloading works is different now.
I know that this guide is not bulletproof regarding update safety, because each Shopw...]]></description><link>https://blog.kreminger.dev/shopware-6-7-admin-watcher-ddev-vite-setup-guide</link><guid isPermaLink="true">https://blog.kreminger.dev/shopware-6-7-admin-watcher-ddev-vite-setup-guide</guid><category><![CDATA[shopware6]]></category><category><![CDATA[vite]]></category><category><![CDATA[ddev]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Wolfgang Kreminger]]></dc:creator><pubDate>Wed, 09 Jul 2025 10:51:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/cckf4TsHAuw/upload/f325ff06d07e7060843227361f56424c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Starting with Shopware 6.7, the administration is built with Vite. Because of the new build tool, the structure and how hot module reloading works is different now.</p>
<p>I know that this guide is not bulletproof regarding <strong>update safety</strong>, because each Shopware core update will overwrite the changes. But you have to keep in mind that it is also hard for Shopware to maintain different development environments. I'm pretty sure Shopware will add a fix if there is time left to implement it, because as you will see, there is not much to change to make it work with DDEV.</p>
<p>So let's jump right into it.</p>
<h2 id="heading-the-problem">The Problem</h2>
<p>There is an issue on GitHub titled <a target="_blank" href="https://github.com/shopware/shopware/issues/9393">Vite watch administration not loading plugin modules</a>, which outlines the problem developers face when using DDEV with Shopware 6.7's Vite-based administration. In short, each plugin (or extension) starts its own Vite dev server. However, because DDEV uses the ddev-router in the background, this setup does not work out of the box.</p>
<p>If you try to use the admin watcher without applying the necessary changes, you will encounter errors such as:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752131702931/6a57b42d-93b3-4ebe-8ea1-46b0c845554b.png" alt class="image--center mx-auto" /></p>
<p>Of course, the administration is still working but your plugins (or extensions) will not get injected.</p>
<p>The root cause is that DDEV cannot map or, more accurately, does not allow access to the ports used by the Vite dev servers. To resolve this, you need to apply the changes described in this guide.</p>
<h2 id="heading-changes-in-pluginsvitets">Changes in plugins.vite.ts</h2>
<p>On line 184, there is the extensionEntries config starting. Within the forEach loop change this</p>
<p>from</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/build/plugins.vite.ts</span>

<span class="hljs-keyword">if</span> (extension.isApp) {
    swPluginDevJsonData[extension.technicalName].html = <span class="hljs-string">`http://<span class="hljs-subst">${host}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/index.html`</span>;
}

<span class="hljs-keyword">if</span> (extension.isPlugin) {
    swPluginDevJsonData[extension.technicalName].js = <span class="hljs-string">`http://<span class="hljs-subst">${host}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/<span class="hljs-subst">${fileName}</span>`</span>;
    swPluginDevJsonData[extension.technicalName].hmrSrc = <span class="hljs-string">`http://<span class="hljs-subst">${host}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/@vite/client`</span>;
}
</code></pre>
<p>to</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/build/plugins.vite.ts</span>

<span class="hljs-keyword">const</span> realHost = process.env.DDEV_PRIMARY_URL
              ? <span class="hljs-string">`<span class="hljs-subst">${process.env.DDEV_PRIMARY_URL.replace(<span class="hljs-regexp">/:\d+$/</span>, <span class="hljs-string">''</span>)}</span>`</span>
              : <span class="hljs-string">`http://<span class="hljs-subst">${host}</span>`</span>;

<span class="hljs-keyword">if</span> (extension.isApp) {
    swPluginDevJsonData[extension.technicalName].html = <span class="hljs-string">`<span class="hljs-subst">${realHost}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/index.html`</span>;
}

<span class="hljs-keyword">if</span> (extension.isPlugin) {
    swPluginDevJsonData[extension.technicalName].js = <span class="hljs-string">`<span class="hljs-subst">${realHost}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/<span class="hljs-subst">${fileName}</span>`</span>;
    swPluginDevJsonData[extension.technicalName].hmrSrc = <span class="hljs-string">`<span class="hljs-subst">${realHost}</span>:<span class="hljs-subst">${availablePorts[index]}</span>/@vite/client`</span>;
}
</code></pre>
<p>Afterwards, change the server config for app and the plugin system.</p>
<p>Add <code>const host = '0.0.0.0';</code> within the loop <code>for (let i = 0; i &lt; extensionEntries.length; i++)</code> to make it accessible via the host machine.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/build/plugins.vite.ts</span>

<span class="hljs-comment">// Start dev servers</span>
 <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; extensionEntries.length; i++) {
    <span class="hljs-keyword">const</span> host = <span class="hljs-string">'0.0.0.0'</span>;
    <span class="hljs-comment">// ... rest of code</span>
}
</code></pre>
<p>Next, search for createServer and replace from</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/build/plugins.vite.ts</span>

server: {
    port,
    host,
    cors: <span class="hljs-literal">true</span>,
},
</code></pre>
<p>to</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/build/plugins.vite.ts</span>

server: {
    port,
    host,
    origin: process.env.DDEV_PRIMARY_URL
        ? <span class="hljs-string">`<span class="hljs-subst">${process.env.DDEV_PRIMARY_URL.replace(<span class="hljs-regexp">/:\d+$/</span>, <span class="hljs-string">''</span>)}</span>:`</span> + port
        : <span class="hljs-literal">undefined</span>,
    cors: {
        origin: <span class="hljs-regexp">/https?:\/\/([A-Za-z0-9\-\.]+)?(\.ddev\.site)(?::\d+)?$/</span>,
    },
},
</code></pre>
<h2 id="heading-changes-in-viteconfigmts">Changes in vite.config.mts</h2>
<p>Add the cors config to the server config which starts at line 65 and add it after the origin property.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// vendor/shopware/administration/Resources/app/administration/vite.config.mts</span>

cors: {
    origin: <span class="hljs-regexp">/https?:\/\/([A-Za-z0-9\-\.]+)?(\.ddev\.site)(?::\d+)?$/</span>,
},
</code></pre>
<h2 id="heading-changes-in-the-env-file">Changes in the .env file</h2>
<p>Add a entry for host like</p>
<pre><code class="lang-bash">HOST=0.0.0.0
</code></pre>
<h2 id="heading-changes-in-ddevconfigyaml">Changes in .ddev/config.yaml</h2>
<p>In order to expose all needed ports, there has to be an entry for each port. From my experience, it is sufficient to expose the ports 5173-5400. Each plugin will get its own dev server starting at port 5333. Because DDEV does not support port ranges natively in config.yaml, we have to define each port separately.</p>
<p>You can create the entries with this bash script:</p>
<pre><code class="lang-bash"><span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> $(seq 5173 5400); <span class="hljs-keyword">do</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"- name: webdev-dev-server-admin-port-<span class="hljs-variable">$i</span>"</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"  container_port: <span class="hljs-variable">$i</span>"</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"  http_port: <span class="hljs-subst">$(((i-1)</span>*10))"</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"  https_port: <span class="hljs-variable">$i</span>"</span>
<span class="hljs-keyword">done</span> &gt; /path/to/file/ports.txt
</code></pre>
<p>Next, take the contents of the generated <code>ports.txt</code> file and add them to your <code>./ddev/config.yaml</code> file. Look for the commented line containing <code>web_extra_exposed_ports</code>—this is where you should insert the port entries to keep the configuration organized.</p>
<p>Finally, restart your DDEV project with:</p>
<pre><code class="lang-bash">ddev restart
</code></pre>
<p>You should now be able to use the admin watcher by running</p>
<pre><code class="lang-bash">ddev <span class="hljs-built_in">exec</span> ./bin/watch-administration.sh
</code></pre>
<h2 id="heading-summary">Summary</h2>
<p>By following the steps above, you can successfully configure Shopware 6.7's Admin Watcher to work seamlessly with DDEV. The adjustments ensure that hot module reloading and plugin development work reliably in your local environment. While these changes may need to be reapplied after Shopware updates, they provide a practical solution for efficient development workflows with DDEV and Shopware 6.7 for extensions within the administration.</p>
<hr />
<p>Let me know if it worked for you, or if you found anything that could be improved.</p>
]]></content:encoded></item><item><title><![CDATA[Unlocking Shopware 6 Secrets: Master Building Administration Plugin Assets Without Wrecking the Core!]]></title><description><![CDATA[We are often phased with situations, where we actually have a hard time to figure out why certain things are suddenly broken just by running a simple command which is intended to be used to create for eg static build files.
So was I while talking wit...]]></description><link>https://blog.kreminger.dev/unlocking-shopware-6-secrets-master-building-administration-plugin-assets-without-wrecking-the-core</link><guid isPermaLink="true">https://blog.kreminger.dev/unlocking-shopware-6-secrets-master-building-administration-plugin-assets-without-wrecking-the-core</guid><category><![CDATA[shopware6]]></category><category><![CDATA[PHP]]></category><category><![CDATA[Symfony]]></category><dc:creator><![CDATA[Wolfgang Kreminger]]></dc:creator><pubDate>Mon, 18 Sep 2023 20:37:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694978747893/58bdc0ab-a098-425a-bfa3-17f480008411.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We are often phased with situations, where we actually have a hard time to figure out why certain things are suddenly broken just by running a simple command which is intended to be used to create for eg static build files.</p>
<p>So was I while talking with friends about a weird behavior which they encountered after running</p>
<pre><code class="lang-bash">./bin/build-administration.sh
</code></pre>
<p>This command - which I thought should get executed after a shopware update - seems not to be what I thought it would be. I mean, it did and does what it should on my side but broke the administration for them.</p>
<h2 id="heading-going-down-the-rabbit-hole">Going down the rabbit hole</h2>
<h3 id="heading-binbuild-administrationshhttpsgithubcomshopwarerecipesblobmainshopwareadministration64binbuild-administrationsh">./bin/<a target="_blank" href="https://github.com/shopware/recipes/blob/main/shopware/administration/6.4/bin/build-administration.sh">build-administration.sh</a></h3>
<p>This little shell script does actually nothing special. It just goes through all directories, npm clean installs all dependencies (and also all dev-dependencies) for the plugins which you have installed and activated and also the shopware administration core.</p>
<p>The key takeaway from here is, that the resolve process of installing the plugin dependencies happens through webpack which is configured with a webpack.config.js file in the <a target="_blank" href="https://github.com/shopware/administration/blob/trunk/Resources/app/administration/webpack.config.js">administration core</a> codebase.</p>
<p>But, running this command on production means a few things</p>
<ol>
<li><p>Downtime/not working administration as long as all npm packages get installed and the final build is finished</p>
</li>
<li><p>Your Plugin administration assets get build</p>
</li>
<li><p>The core administration files get build again as well although there should be no changes (as long as you didn't update anything manually which you should never do 😅)</p>
</li>
</ol>
<h3 id="heading-whats-wrong-with-using-it-in-production">What's wrong with using it in production?</h3>
<p>First, the official shopware docs do not mention node js as requirement, it is optional. You might have installed it for any reason (who did not build something in production because something else is broken, we know it right? 😅) but you don't have to.</p>
<p>Second, building the entire administration core Javascript/Typescript/Scss code can be time consuming especially if it is not needed nor intended that we do it at all. The <a target="_blank" href="https://github.com/shopware/administration/tree/v6.5.5.1">Shopware administration repo</a> has <a target="_blank" href="https://github.com/shopware/administration/tree/v6.5.5.1/Resources/public/static">all build</a> files already committed into the repository. You get the updated build files while updating shopware anyway for free.</p>
<p>Third, why should we risk a downtime although it might not be necessary at all?</p>
<h3 id="heading-how-should-it-be-done-then">How should it be done then?</h3>
<p>Good question, you can still stick to the ./<a target="_blank" href="https://github.com/shopware/recipes/blob/main/shopware/administration/6.4/bin/build-administration.sh">bin/build-administration.sh</a> shell script but, you should use it with a additional env variable. The right command would be</p>
<pre><code class="lang-bash">SHOPWARE_ADMIN_BUILD_ONLY_EXTENSIONS=<span class="hljs-string">'1'</span> ./bin/build-administration.sh
</code></pre>
<p>This env variable is used in the webpack.config.js file of the administration core. Once it is set, the administration core code doesn't get touched at all but only your installed and activated plugins will get build.</p>
<p>Another way of building the static files for the administration is mentioned in the next section.</p>
<h3 id="heading-is-there-a-easier-way-to-build-static-files-for-administration">Is there a easier way to build static files for administration?</h3>
<p>The easiest way to make sure all build files are in the plugin directory (no matter if self developed or installed from the shopware community store) is by using the build command which I mentioned above or by using the <a target="_blank" href="https://sw-cli.fos.gg/">shopware-cli</a> from FriendsOfShopware.</p>
<p>This cli tool makes sure, that only necessary files land in the build. This means, no dev dependencies, just the code which you need for production.</p>
<p>Once installed, you can simply run in your Shopware root</p>
<pre><code class="lang-bash">shopware-cli extension build custom/plugins/PLUGIN_NAME
</code></pre>
<p>This will install all necessary dependencies and bundle the files for the administration of the plugin.</p>
<h3 id="heading-but-how-does-it-work-with-plugins-which-i-install-from-the-store">But how does it work with plugins which I install from the store?</h3>
<p>This was the question which I asked myself. There are specific requirements for a plugin to be available in the store.</p>
<p>One of those requirements is, everything is bundled up into one zip file. I won't talk about each necessary file but one part of this zip file are the static build files, the bundled js and css files, which reside in <code>YourPlugin/src/Resources/public/administration</code>.</p>
<p>After installing and activating a new plugin from the shopware community store, a PHP service gets called which in fact does the same thing as</p>
<pre><code class="lang-bash">bin/console assets:install
</code></pre>
<p>to copy all the files and make them available to get called from the administration logic.</p>
<h3 id="heading-how-should-i-proceed-then-need-that-thing-on-production-shipped">How should I proceed then? Need that thing on production shipped 🚀</h3>
<p>It depends on the environment where you do all of the build steps.</p>
<p>Let's take a look about three of them because doing it on production servers should be the very last environment where you should do it. Consider it not recommended, but it will also work there.</p>
<h4 id="heading-development-environment">Development Environment</h4>
<p>If you simply want to do it with one plugin, you can run the command which you already saw above by using the shopware-cli</p>
<pre><code class="lang-bash">shopware-cli extension build custom/plugins/PLUGIN_NAME
</code></pre>
<p>If you want to build all static assets of all locally installed plugins, then you can use a little shell script</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> /plugins
<span class="hljs-keyword">for</span> dir <span class="hljs-keyword">in</span> */ ; <span class="hljs-keyword">do</span> \
    <span class="hljs-built_in">echo</span> <span class="hljs-string">"Running shopware-cli extension \ build for <span class="hljs-variable">${dir}</span>..."</span> \
    shopware-cli extension build <span class="hljs-string">"<span class="hljs-variable">${dir}</span>"</span> \
<span class="hljs-keyword">done</span>
</code></pre>
<p>You will recognize, that this is not the best way because the shopware-cli will fetch the shopware core code for each plugin. This command builds not only the administration code but also your storefront code</p>
<p>A better way to build all static assets for administration only will be to run the project build command in the root of your shopware instance.</p>
<pre><code class="lang-bash">shopware-cli project admin-build
</code></pre>
<p>This does essentially the same as ./<a target="_blank" href="https://github.com/shopware/recipes/blob/main/shopware/administration/6.4/bin/build-administration.sh">bin/build-administration.sh</a> except of leaving all of the shopware core asset builds untouched.</p>
<h4 id="heading-cicd">CI/CD</h4>
<p>The best idea of course is always to use a CI/CD for managing builds and deployments.</p>
<p>You can use the same commands as mentioned in the Development Environment section. It depends on which CI/CD Service you are using but the project admin-build command will need a entire shopware instance. To achive this, you can use a <a target="_blank" href="http://ghcr.io/friendsofshopware/platform-plugin-dev">docker container</a> from FriendsOfShopware.</p>
<h4 id="heading-production-not-recommended">Production (not recommended ☝🏻)</h4>
<p>If nothing else is possible anymore and the production version of your shopware store seems to be broken and you know it is because of new code which might not get loaded properly, then you can try to build the administration to make it full functioning again.</p>
<p>But you should only do it, if you are sure that it is related to a plugin which worked before. Also double check if the build files of the plugin are there where they should be.</p>
<p>If they are missing, then you can try to build them again with</p>
<pre><code class="lang-bash">SHOPWARE_ADMIN_BUILD_ONLY_EXTENSIONS=<span class="hljs-string">'1</span>
</code></pre>
<p>Or if you have the shopware-cli installed on production as well with</p>
<pre><code class="lang-bash">shopware-cli extension build custom/plugins/PLUGIN_NAME
</code></pre>
<p>If you are using the shopware-cli, then you have to execute another command afterwards to get the build files copied to</p>
<p><code>&lt;ShopwareRoot&gt;public/bundles/PLUGIN_NAME/administration</code></p>
<p>The command which you have to execute is</p>
<pre><code class="lang-bash">bin/console assets:install
</code></pre>
<p>After running it, you should find the static files of the plugin for the administration in the mentioned public/bundles directory.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Shopwares static file build system for the administration is a solid and well organized pipeline of tools to enable a easy to use process if used right. By enhancing this process with using the right environmental variables or the shopware-cli - which was build from one of Shopwares core development members - you can go even further which will reduce the build time on one hand and makes sure that you don't build files which already exist or even break them.</p>
<p>I use the shopware-cli in a CI/CD pipeline via github actions myself for our staging, testing and production environments for <a target="_blank" href="https://0815.at">0815.at</a> to build all static files (not just the administration static files) and to deploy them.</p>
<p>It is not only the best option performance wise, but also the safest way to not break working shopware production core code.</p>
]]></content:encoded></item></channel></rss>