Question

I'm currently setting up the pipeline deployment process for a new store, Magento Commerce 2.2.5 with B2B module and sample data. I don't think the fact it's Commerce vs Open Source, has the sample data installed, or has the B2B module installed makes any difference.

There are 3 environments involved - local dev, remote dev and remote UAT. Both dev environments are running in developer mode and UAT is running in production mode. Locally everything is working fine, but after deploy dev just shows this exception on front and backend, no pages render:

1 exception(s):
Exception #0 (Magento\Framework\Exception\ValidatorException): Invalid template file: '/some/path/deployer/shared/vendor/magento/module-theme/view/frontend/templates/page/js/require_js.phtml' in module: '' block's name: 'require.js'

Exception #0 (Magento\Framework\Exception\ValidatorException): Invalid template file: '/some/path/deployer/shared/vendor/magento/module-theme/view/frontend/templates/page/js/require_js.phtml' in module: '' block's name: 'require.js'
#0 /some/path/deployer/shared/vendor/magento/framework/View/Element/Template.php(300): Magento\Framework\View\Element\Template->fetchView('/chroot/home/m2...')
#1 /some/path/deployer/shared/vendor/magento/framework/View/Element/AbstractBlock.php(667): Magento\Framework\View\Element\Template->_toHtml()
#2 /some/path/deployer/shared/vendor/magento/framework/View/Result/Page.php(248): Magento\Framework\View\Element\AbstractBlock->toHtml()
#3 /some/path/deployer/shared/vendor/magento/framework/View/Result/Layout.php(170): Magento\Framework\View\Result\Page->render(Object(Magento\Framework\App\Response\Http\Interceptor))
#4 /some/path/deployer/shared/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\View\Result\Layout->renderResult(Object(Magento\Framework\App\Response\Http\Interceptor))
#5 /some/path/deployer/shared/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\View\Result\Page\Interceptor->___callParent('renderResult', Array)
#6 /some/path/deployer/shared/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\View\Result\Page\Interceptor->Magento\Framework\Interception\{closure}(Object(Magento\Framework\App\Response\Http\Interceptor))
#7 /some/path/deployer/releases/11/generated/code/Magento/Framework/View/Result/Page/Interceptor.php(26): Magento\Framework\View\Result\Page\Interceptor->___callPlugins('renderResult', Array, Array)
#8 /some/path/deployer/shared/vendor/magento/framework/App/Http.php(139): Magento\Framework\View\Result\Page\Interceptor->renderResult(Object(Magento\Framework\App\Response\Http\Interceptor))
#9 /some/path/deployer/shared/vendor/magento/framework/App/Bootstrap.php(256): Magento\Framework\App\Http->launch()
#10 /some/path/deployer/releases/11/pub/index.php(37): Magento\Framework\App\Bootstrap->run(Object(Magento\Framework\App\Http\Interceptor))
#11 {main}

As you can probably guess from the paths I'm using deployer.org for deployments. I don't believe there to be any issues around the deployment setup, permissions and ownership etc, so to keep the initial question simple I won't include any details on that here. On UAT (running in production mode) the pages render, but none of the requireJS assets load with a 404 response because the path is wrong - it attempts to load directly at web root rather than from inside the static directory, i.e. http://some.site.com/mage/dataPost.js and not http://some.site.comstatic/version1530277872/mage/dataPost.js.

I suspect that both issues are related and it's probably worth pointing out that the file /some/path/deployer/shared/vendor/magento/module-theme/view/frontend/templates/page/js/require_js.phtml is present, and is exactly the same as in my local dev environment where everything is working correctly.

To me this seems all related to requireJS and it's interesting that the invalid template file exception shows no module. It's a completely clean install with no custom modules, only core code (the B2B module is core code not a third party). I know there are quite a few other questions with invalid template file errors, but these all seem related to third party/custom modules where there is an issue with the configuration.

Any thoughts or advice on a potential resolution much appreciated.

Was it helpful?

Solution

So it turns out that this is due to the vendor directory being defined as shared in the deployer config. As with other similar tools like capistrano, rocketeer etc, deployer symlinks to a shared parent directory of the current release. The end result of this is that Magento sees the vendor directory as being outside the Magento root directory. When loading templates checks are made in Magento\Framework\View\Element\Template\File\Validator::isValid() (vendor/magento/framework/View/Element/Template/File/Validator.php) and most relevant this section of the if statement:

...
&& $this->getRootDirectory()->isFile($this->getRootDirectory()->getRelativePath($filename))
...

Here a check is made to make sure that the template file is under the root directory of the Magento install. Because the vendor directory is symlinked this check fails and the exception above is thrown. So it's not relevant to requireJS, that was just the first template which failed the check. The solution is not to have the vendor directory defined as shared in the deployer config which does mean that every composer module has to be downloaded for every deploy which isn't ideal but, but it does fix the issue without the need to override any core behaviour.

For anyone who comes to this in the future, there is an issue open on github here, and a pull request to allow symliked templates outside of the Magento root.

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top