From b2ca1b064bd42d61ae0e159bf773e147c07f8cf4 Mon Sep 17 00:00:00 2001 From: Thomas Date: Thu, 11 Feb 2021 17:22:40 +0100 Subject: [PATCH] Add script tag support (#16) * added script tag support * added use_contao_template_variables option * huge documentation update --- README.md | 47 ++++-- docs/configuration.md | 65 +++++---- docs/setup_bundle.md | 19 +-- docs/setup_entries.md | 5 + docs/setup_project.md | 107 +++++++------- src/DependencyInjection/Configuration.php | 6 +- src/EventListener/GeneratePageListener.php | 14 +- .../ReplaceDynamicScriptTagsListener.php | 44 +++++- src/Resources/contao/config/runonce.php | 115 --------------- .../DependencyInjection/ConfigurationTest.php | 4 +- .../GeneratePageListenerTest.php | 43 +++--- .../ReplaceDynamicScriptTagsListenerTest.php | 135 ++++++++++++++++-- 12 files changed, 348 insertions(+), 256 deletions(-) create mode 100644 docs/setup_entries.md delete mode 100644 src/Resources/contao/config/runonce.php diff --git a/README.md b/README.md index a8a68aa..346b3b0 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,16 @@ ![CI](https://github.com/heimrichhannot/contao-encore-bundle/workflows/CI/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/heimrichhannot/contao-encore-bundle/badge.svg?branch=master)](https://coveralls.io/github/heimrichhannot/contao-encore-bundle?branch=master) -This bundle brings deep integration for symfony encore into contao. On the one hand, your can prepare your bundles to define own webpack entries, which added with just one command to your webpack entries. On the other hand, this bundle allows you to add encore entries only on the pages you need them for optimizing your website performance. +Use the power and simplicity of symfony webpack encore in contao. This bundle let you decide on layout and page level, which encore entries should be loaded. If you want more, you can prepare your bundles define their own encore entries, so never need to manually add or remove encore entries again. ## Features - use symfony encore ([symfony/webpack-encore](https://github.com/symfony/webpack-encore) and [symfony/webpack-encore-bundle](https://github.com/symfony/webpack-encore-bundle)) to enhance your contao assets workflow - conditionally load your assets only if necessary (entrypoints can be activated in the backend in layout and page setting or added via service from your bundle code (e.g. in a frontend module)) - prepare your bundles to add encore entries when install them and strip assets from the contao global asset arrays -## Setup + +## Setup + ### Prerequisites @@ -21,6 +23,7 @@ This bundle brings deep integration for symfony encore into contao. On the one h * In order to add the node dependencies required by composer bundles, you probably want to add them to your project's node dependencies when running webpack in the project's scope. You can use [Foxy](docs/introductions/bundles_with_webpack.md) for this task. + ### Prepare your project and bundle Setup your project for encore bundle: @@ -30,18 +33,23 @@ Setup your project for encore bundle: [Bundle setup](docs/setup_bundle.md) +### Run Encore +1. Clear your cache + + php vendor/bin/contao-console cache:clear -### Run Encore +1. Run encore prepare command -1. Clear your cache (`vendor/bin/contao-console cache:clear`) + php vendor/bin/contao-console encore:prepare -1. Run the Contao command `vendor/bin/contao-console encore:prepare`. This generates a file called `encore.bundles.js` in your project root. -This file contains entries for all contao encore compatible bundles that are added by calling `encoreBundles.addEntries();` in your `webpack.config.js`. +1. Run encore to generate the assets + + `yarn encore dev` - > IMPORTANT: You have to call this command every time you want your bundle webpack entries to be updated, e.g. if you added new entries to your yml configuration or added a new encore-bundle compatible bundle. +1. Activate encore entries in the contao backend -1. Now run `yarn encore dev --watch` to generate the assets. For production assets (deployment), run `yarn encore production`. +Now run `yarn encore dev --watch` to generate the assets. For production assets (deployment), run `yarn encore production`. * If you have a large set of entries and the generation takes very long, you can use the command line parameter `--entries` in order to limit the generation to certain entries: `yarn encore dev --entries="entry1,entry2,entry3"` (the entry names can be taken from the generated file `encore.bundles.js`). * You can also explicitly skip certain entries for generation by using the command line parameter `--skip-entries`: `yarn encore dev --skip-entries="entry1,entry2,entry3"`. @@ -49,7 +57,6 @@ This file contains entries for all contao encore compatible bundles that are add 1. If the generation succeeded without errors, you can now active encore entries. See Usage -> Activate encore entries for how to do that. - ## Usage ### Activate encore entries @@ -62,6 +69,28 @@ This file contains entries for all contao encore compatible bundles that are add * Pay attention that you check entries as active (if you want them to be loaded)! * If you want an already added entry to be not loaded on an specific page, select it as entry and don't check "active". +### Prepare command + + php vendor/bin/contao-console encore:prepare + +The prepare command must be executed after every change to the encore entries configuration, e.g. after a composer update or changes to that configurations in your own code. + +This generates a file called `encore.bundles.js` in your project root. +This file contains entries for all contao encore compatible bundles that are added by calling `encoreBundles.addEntries();` in your `webpack.config.js`. + +### Run encore + +Run encore to generate/compile your assets. + + yarn encore dev + yarn encore dev --watch + yarn encore prod + +This bundle adds to additional options to the encore command: + +* `entries`: Limit generation to passed entries. Useful if you have a large amount of entries and compilation needs time, but you're working on a specific entries. Example: `yarn encore dev --entries="entry1,entry2,entry3"` +* `skip-entries`: Skip given entries for generation. Example: `yarn encore dev --skip-entries="entry1,entry2,entry3"` + ## Documentation [Project setup](docs/setup_project.md) - Prepare your contao project for use with encore and encore bundle diff --git a/docs/configuration.md b/docs/configuration.md index 62bbfca..31c4a41 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,49 +6,52 @@ The complete bundle configuration: # Default configuration for extension with alias: "huh_encore" huh_encore: - # Add javascript files which should be registered as encore entries. - js_entries: + # Use contao template variables in fe_page (stylesheets, head, mootools) for inserting assets instead of the custom template variables of this bundle. Recommended: true. Default: false (due bc reasons). Will be default true in next major version. + use_contao_template_variables: false - # Prototype - - + # Add javascript files which should be registered as encore entries. + js_entries: - # Will be shown in contao backend and will be used as alias/identifier in the database. - name: ~ # Required + # Prototype + - - # Path to the Javascript file. - file: ~ # Required + # Will be shown in contao backend and will be used as alias/identifier in the database. + name: ~ # Required - # Set to true, if entry requires css. - requires_css: ~ + # Path to the Javascript file. + file: ~ # Required - # Set to true, if entry should added to the encoreHeadScripts section in your page layout instead to the bottom (CSS will always be added to the head). - head: ~ - templates: + # Set to true, if entry requires css. + requires_css: ~ - # Register import templates to customize how assets are imported into your templates. - imports: + # Set to true, if entry should added to the encoreHeadScripts section in your page layout instead to the bottom (CSS will always be added to the head). + head: ~ + templates: - # Prototype - - + # Register import templates to customize how assets are imported into your templates. + imports: - # Unique template alias. Example: default_css - name: ~ # Required + # Prototype + - - # Full references twig template path. Example: @HeimrichHannotContaoEncore/encore_css_imports.html.twig - template: ~ # Required + # Unique template alias. Example: default_css + name: ~ # Required - # A list of keys that should be stripped from the global contao arrays. Here you can add assets, that you serve with webpack, so they won't be loaded twice or on the wrong page. IMPORTANT: The strings defined here must match the array keys in Contao's global arrays - unset_global_keys: + # Full references twig template path. Example: @HeimrichHannotContaoEncore/encore_css_imports.html.twig + template: ~ # Required - # Assets will be stripped from $GLOBALS['TL_JAVASCRIPT'] - js: [] + # A list of keys that should be stripped from the global contao arrays. Here you can add assets, that you serve with webpack, so they won't be loaded twice or on the wrong page. IMPORTANT: The strings defined here must match the array keys in Contao's global arrays + unset_global_keys: - # Assets will be stripped from $GLOBALS['TL_JQUERY'] - jquery: [] + # Assets will be stripped from $GLOBALS['TL_JAVASCRIPT'] + js: [] - # Assets will be stripped from $GLOBALS['TL_USER_CSS'] and $GLOBALS['TL_CSS'] - css: [] + # Assets will be stripped from $GLOBALS['TL_JQUERY'] + jquery: [] - # Remove jQuery from global array, if addJQuery is enabled in layout section. - unset_jquery: false + # Assets will be stripped from $GLOBALS['TL_USER_CSS'] and $GLOBALS['TL_CSS'] + css: [] + + # Remove jQuery from global array, if addJQuery is enabled in layout section. + unset_jquery: false ``` \ No newline at end of file diff --git a/docs/setup_bundle.md b/docs/setup_bundle.md index bd43bd8..171109d 100644 --- a/docs/setup_bundle.md +++ b/docs/setup_bundle.md @@ -7,8 +7,14 @@ With encore bundle you can prepare your bundles to automatically create encore e ```yaml huh_encore: js_entries: - - { name: contao-my-project-bundle, requires_css: true, head: false, file: "vendor/acme/contao-my-project-bundle/src/Resources/public/js/my-project-bundle.js" } - - { name: special-feature, requires_css: true, head: false, file: "vendor/acme/contao-my-project-bundle/src/Resources/public/js/awesome-but-rare-used-feature.js" } + - name: contao-my-project-bundle + requires_css: true + head: false + file: "vendor/acme/contao-my-project-bundle/src/Resources/public/js/my-project-bundle.js" + - name: special-feature + requires_css: true + head: false + file: "vendor/acme/contao-my-project-bundle/src/Resources/public/js/awesome-but-rare-used-feature.js" unset_global_keys: js: - contao-my-project-bundle @@ -51,12 +57,7 @@ With encore bundle you can prepare your bundles to automatically create encore e > If you want encore bundle to be an optional dependency, please consider the [developers documentation](developers.md). -1. You probably want to have your bundle's node dependencies added automatically to the project's node_modules directory when installed. You can simply use [Foxy](https://github.com/fxpio/foxy) for this task. To keep it simple: besides having foxy installed in your project, you need to set `"foxy": true` in the `extra` section of your bundle's `composer.json` and add an ordinary `package.json` as usual for node modules. See [heimrichhannot/contao-list-bundle](https://github.com/heimrichhannot/contao-list-bundle) for an example. +1. Optional: You probably want to have your bundle's node dependencies added automatically to the project's node_modules directory when installed. You can simply use [Foxy](https://github.com/fxpio/foxy) for this task. To keep it simple: besides having foxy installed in your project, you need to set `"foxy": true` in the `extra` section of your bundle's `composer.json` and add an ordinary `package.json` as usual for node modules. See [heimrichhannot/contao-list-bundle](https://github.com/heimrichhannot/contao-list-bundle) for an example. -1. Optional: Add encore entries automatically from code (for example in frontend module): +1. Optional: If your bundle need an encore entry to be loaded to work (e.g. if it's needed for a frontend module or widget), you can load entries from you code. See [developers documentation](developers.md) for how to do that. -```php -if ($this->container->has('huh.encore.asset.frontend')) { - $this->container->get('huh.encore.asset.frontend')->addActiveEntrypoint('contao-slick-bundle'); -} -``` \ No newline at end of file diff --git a/docs/setup_entries.md b/docs/setup_entries.md new file mode 100644 index 0000000..b29a547 --- /dev/null +++ b/docs/setup_entries.md @@ -0,0 +1,5 @@ +# Setup entries + +This guide tells you how to add encore entries from you code. + +1. Create javascript file per entry, like \ No newline at end of file diff --git a/docs/setup_project.md b/docs/setup_project.md index 3dac5b9..c26455b 100644 --- a/docs/setup_project.md +++ b/docs/setup_project.md @@ -10,7 +10,7 @@ Setup your project for encore bundle. 1. Update your database -1. Create your webpack/encore config file (`webpack.config.js`) in your project root. +1. Update/Create your webpack config file (`webpack.config.js`) in your project root. 1. Require the generated `encore.bundles.js` (this file is generated with the encore:prepare command, see [Run Encore](../README.md#run-encore)) @@ -19,59 +19,60 @@ Setup your project for encore bundle. ``` 1. Call `encoreBundles.addEntries()` - - Example: - - ```javascript - let Encore = require('@symfony/webpack-encore'), - encoreBundles = require('./encore.bundles'); - - Encore - .setOutputPath('web/build/') - .setPublicPath('/build') - .cleanupOutputBeforeBuild() - .enableVersioning() - - // css - .enableSassLoader() - .enablePostCssLoader() - - // js - .enableSourceMaps(!Encore.isProduction()) - - .splitEntryChunks() - .enableSingleRuntimeChunk() - ; - - // this function adds entries for all contao encore compatible bundles automatically - // -> the source of that is the file "encore.bundles.js" in your project root which is - // generated automatically using the contao command "vendor/bin/contao-console encore:prepare" - // -> you can pass an array to the function if you want to skip certain entries - encoreBundles.addEntries(); - - // support dynamic chunks - let config = Encore.getWebpackConfig(); - - config.output.chunkFilename = '[name].bundle.js'; - - // support symlinks - config.resolve.symlinks = false; + + Example: + + ```javascript + // webpack.config.js + + let Encore = require('@symfony/webpack-encore'), + encoreBundles = require('./encore.bundles'); + + Encore + .setOutputPath('web/build/') + .setPublicPath('/build') + .cleanupOutputBeforeBuild() + .enableVersioning() + + // css + .enableSassLoader() + .enablePostCssLoader() + + // js + .enableSourceMaps(!Encore.isProduction()) - module.exports = config; - ``` + .splitEntryChunks() + .enableSingleRuntimeChunk() + ; + + // this function adds entries for all contao encore compatible bundles automatically + // -> the source of that is the file "encore.bundles.js" in your project root which is + // generated automatically using the contao command "vendor/bin/contao-console encore:prepare" + // -> you can pass an array to the function if you want to skip certain entries + encoreBundles.addEntries(); + + // support dynamic chunks + let config = Encore.getWebpackConfig(); + + // support symlinks + config.resolve.symlinks = false; + + module.exports = config; + ``` - We recommend adding corejs polyfill (former babel polyfill) into your setup, see [Javascript setup section](setup_javascript.md) for more informations. + > We recommend adding corejs polyfill (former babel polyfill) into your setup, see [Javascript setup section](setup_javascript.md) for more informations. -1. Update your `fe_page` template or use the bundled `fe_page_encore_bundle` template. Following changes to your template are necessary: - 1. Add the following in `` region: +1. Set `huh_encore.use_contao_template_variables` to true - ```php - encoreStylesheets; ?> - encoreHeadScripts; ?> - ``` - - 1. Add the following into the footer region: - - ```php - encoreScripts; ?> - ````` \ No newline at end of file +```yaml +# config/config.yml (Contao >= 4.9) +# app/config/config.yml (Contao 4.4) +huh_encore: + use_contao_template_variables: true + +``` + +> This option was added to use the default contao fe_page template variables instead of custom variables from this bundle. The old implementation is considered deprecated and will be removed in a future version. If you still want or need to use it, see `src/Resources/contao/templates/fe_page_encore_bundle.html5` for usage. + +1. Optional: Add entries. + You can now add entries from your project, if you maintain your assets in your project code. The easiest way would be to just add them in your webpack.config.js. But you can also add them from configuration, see [Bundle Setup](setup_bundle.md) for more information. \ No newline at end of file diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 21296c5..224eb05 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -1,7 +1,7 @@ children() + ->booleanNode('use_contao_template_variables') + ->defaultFalse() + ->info('Use contao template variables in fe_page (stylesheets, head, mootools) for inserting assets instead of the custom template variables of this bundle. Recommended: true. Default: false (due bc reasons). Will be default true in next major version.') + ->end() ->arrayNode('js_entries') ->info('Add javascript files which should be registered as encore entries.') ->arrayPrototype() diff --git a/src/EventListener/GeneratePageListener.php b/src/EventListener/GeneratePageListener.php index 828189b..08eabf2 100644 --- a/src/EventListener/GeneratePageListener.php +++ b/src/EventListener/GeneratePageListener.php @@ -60,7 +60,9 @@ public function __invoke(PageModel $pageModel, LayoutModel $layout, PageRegular if (!$layout->addEncore) { return; } - $this->addEncore($pageModel, $layout, $pageRegular); + if (!isset($this->bundleConfig['use_contao_template_variables']) || true !== $this->bundleConfig['use_contao_template_variables']) { + $this->createEncoreScriptTags($pageRegular); + } } /** @@ -80,6 +82,9 @@ public function onGeneratePage(PageModel $pageModel, LayoutModel $layout, PageRe * @throws \Twig\Error\RuntimeError * @throws \Twig\Error\SyntaxError * @throws \Exception + * + * @deprecated This method is not used anymore and will be removed in next major release + * @codeCoverageIgnore */ public function addEncore(PageModel $page, LayoutModel $layout, PageRegular $pageRegular, ?string $encoreField = 'encoreEntries', bool $includeInline = false): void { @@ -112,4 +117,11 @@ public function cleanGlobalArrays(LayoutModel $layout) EntryHelper::cleanGlobalArrays($this->bundleConfig); } + + protected function createEncoreScriptTags(PageRegular $pageRegular) + { + $pageRegular->Template->encoreStylesheets = '[[HUH_ENCORE_CSS]]'; + $pageRegular->Template->encoreScripts = '[[HUH_ENCORE_JS]]'; + $pageRegular->Template->encoreHeadScripts = '[[HUH_ENCORE_HEAD_JS]]'; + } } diff --git a/src/EventListener/ReplaceDynamicScriptTagsListener.php b/src/EventListener/ReplaceDynamicScriptTagsListener.php index 993f811..1074c41 100644 --- a/src/EventListener/ReplaceDynamicScriptTagsListener.php +++ b/src/EventListener/ReplaceDynamicScriptTagsListener.php @@ -8,6 +8,9 @@ namespace HeimrichHannot\EncoreBundle\EventListener; +use Contao\LayoutModel; +use Contao\PageModel; +use HeimrichHannot\EncoreBundle\Asset\TemplateAsset; use HeimrichHannot\EncoreBundle\Helper\EntryHelper; use HeimrichHannot\UtilsBundle\Container\ContainerUtil; use HeimrichHannot\UtilsBundle\Model\ModelUtil; @@ -29,15 +32,20 @@ class ReplaceDynamicScriptTagsListener * @var ModelUtil */ protected $modelUtil; + /** + * @var TemplateAsset + */ + protected $templateAsset; /** * ReplaceDynamicScriptTagsListener constructor. */ - public function __construct(array $bundleConfig, ContainerUtil $containerUtil, ModelUtil $modelUtil) + public function __construct(array $bundleConfig, ContainerUtil $containerUtil, ModelUtil $modelUtil, TemplateAsset $templateAsset) { $this->bundleConfig = $bundleConfig; $this->containerUtil = $containerUtil; $this->modelUtil = $modelUtil; + $this->templateAsset = $templateAsset; } public function __invoke(string $buffer): string @@ -47,16 +55,46 @@ public function __invoke(string $buffer): string } global $objPage; - $objLayout = $this->modelUtil->findModelInstanceByPk('tl_layout', $objPage->layoutId); - if (!$objLayout || !$objLayout->addEncore) { + $layout = $this->modelUtil->findModelInstanceByPk('tl_layout', $objPage->layoutId); + if (!$layout || !$layout->addEncore) { return $buffer; } + if (!isset($this->bundleConfig['use_contao_template_variables']) || true !== $this->bundleConfig['use_contao_template_variables']) { + $buffer = $this->replaceEncoreTags($buffer, $objPage, $layout); + } else { + $buffer = $this->replaceContaoTags($buffer, $objPage, $layout); + } + $this->cleanGlobalArrays(); return $buffer; } + protected function replaceEncoreTags(string $buffer, PageModel $page, LayoutModel $layout): string + { + $templateAssets = $this->templateAsset->createInstance($page, $layout, 'encoreEntries'); + + $replace = []; + $replace['[[HUH_ENCORE_CSS]]'] = trim($templateAssets->linkTags()); + $replace['[[HUH_ENCORE_JS]]'] = trim($templateAssets->scriptTags()); + $replace['[[HUH_ENCORE_HEAD_JS]]'] = trim($templateAssets->headScriptTags()); + + return str_replace(array_keys($replace), $replace, $buffer); + } + + protected function replaceContaoTags(string $buffer, PageModel $page, LayoutModel $layout): string + { + $templateAssets = $this->templateAsset->createInstance($page, $layout, 'encoreEntries'); + + $replace = []; + $replace['[[TL_CSS]]'] = '[[TL_CSS]]'.trim($templateAssets->linkTags()); + $replace['[[TL_BODY]]'] = trim($templateAssets->scriptTags()).'[[TL_BODY]]'; + $replace['[[TL_HEAD]]'] = '[[TL_HEAD]]'.trim($templateAssets->headScriptTags()); + + return str_replace(array_keys($replace), $replace, $buffer); + } + /** * @codeCoverageIgnore */ diff --git a/src/Resources/contao/config/runonce.php b/src/Resources/contao/config/runonce.php deleted file mode 100644 index 883eadd..0000000 --- a/src/Resources/contao/config/runonce.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @license http://www.gnu.org/licences/lgpl-3.0.html LGPL - */ - -use Contao\Controller; -use Contao\Database; -use Contao\LayoutModel; -use Contao\PageModel; -use Contao\System; -use Symfony\Component\DependencyInjection\ContainerInterface; - -class EncoreBundleMigration -{ - /** - * @var ContainerInterface - */ - protected $container; - /** - * @var Database - */ - protected $database; - - public function __construct() { - $this->container = System::getContainer(); - $this->database = $this->container->get('contao.framework')->createInstance(Database::class); - } - - public function run() - { - // Don't run on fresh install - if (!$this->database->tableExists('tl_page')) - { - return; - } - $this->migrationTo090(); - } - - protected function migrationTo090() - { - // tl_page.addEncore was deleted on version 0.9.0 - if (!$this->database->fieldExists('addEncore', 'tl_page')) - { - return; - } - - Controller::loadDataContainer('tl_layout'); - - $encoreFields = ['addEncore','addEncoreBabelPolyfill','encoreBabelPolyfillEntryName','encoreStylesheetsImportsTemplate','encoreScriptsImportsTemplate']; - - foreach ($encoreFields as $field) - { - if (!$this->database->fieldExists($field, 'tl_layout')) - { - if (isset($GLOBALS['TL_DCA']['tl_layout']['fields'][$field]['sql'])) - { - $this->database->execute("ALTER TABLE tl_layout ADD ".$field . " " . $GLOBALS['TL_DCA']['tl_layout']['fields'][$field]['sql']); - } - } - } - - - $pagesWithLayout = PageModel::findByIncludeLayout("1"); - $processedLayouts = []; - - foreach ($pagesWithLayout as $page) - { - if (in_array($page->layout, $processedLayouts)) - { - continue; - } - - $layout = LayoutModel::findByPk($page->layout); - if (!$layout) - { - continue; - } - - if (!"root" === $page->type) - { - $rootPage = PageModel::findByPk($page->rootId); - if (!$rootPage) - { - continue; - } - } - else { - $rootPage = $page; - } - - if ($rootPage->addEncore) - { - reset($encoreFields); - $updateString = implode('=?, ', $encoreFields).'=?'; - $values = []; - foreach ($encoreFields as $field) - { - $values[] = $rootPage->{$field}; - } - - $result = $this->database->prepare('UPDATE tl_layout SET '.$updateString)->execute($values); - $processedLayouts[] = $layout->id; - } - } - } -} - -$migration = new EncoreBundleMigration(); -$migration->run(); \ No newline at end of file diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php index 210fd4e..29ef861 100644 --- a/tests/DependencyInjection/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -1,7 +1,7 @@ getConfigTreeBuilder(); $this->assertInstanceOf(TreeBuilder::class, $treeBuilder); - $this->assertCount(5, $treeBuilder->getRootNode()->getChildNodeDefinitions()); + $this->assertCount(6, $treeBuilder->getRootNode()->getChildNodeDefinitions()); $tree = $treeBuilder->buildTree(); $this->assertSame('huh_encore', $tree->getName()); diff --git a/tests/EventListener/GeneratePageListenerTest.php b/tests/EventListener/GeneratePageListenerTest.php index ceecb64..2aa9674 100644 --- a/tests/EventListener/GeneratePageListenerTest.php +++ b/tests/EventListener/GeneratePageListenerTest.php @@ -79,8 +79,8 @@ public function createTestInstance(array $parameters = [], $hookListenerMock = n public function testInvoke() { - $hookListener = $this->createTestInstance([], $this->getMockBuilder(GeneratePageListener::class)->setMethods(['addEncore', 'cleanGlobalArrays'])); - $hookListener->expects($this->never())->method('addEncore')->willReturn(true); + $hookListener = $this->createTestInstance([], $this->getMockBuilder(GeneratePageListener::class)->setMethods(['createEncoreScriptTags'])); + $hookListener->expects($this->never())->method('createEncoreScriptTags')->willReturn(true); $pageModel = $this->mockClassWithProperties(PageModel::class, []); $layoutModel = $this->mockModelObject(LayoutModel::class, ['addEncore' => '']); @@ -88,8 +88,17 @@ public function testInvoke() $hookListener->__invoke($pageModel, $layoutModel, $pageRegular); unset($hookListener); - $hookListener = $this->createTestInstance([], $this->getMockBuilder(GeneratePageListener::class)->setMethods(['addEncore'])); - $hookListener->expects($this->once())->method('addEncore')->willReturn(true); + $hookListener = $this->createTestInstance([], $this->getMockBuilder(GeneratePageListener::class)->setMethods(['createEncoreScriptTags'])); + $hookListener->expects($this->once())->method('createEncoreScriptTags')->willReturn(true); + + $pageModel = $this->mockClassWithProperties(PageModel::class, []); + $layoutModel = $this->mockClassWithProperties(LayoutModel::class, ['addEncore' => '1']); + $pageRegular = $this->createMock(PageRegular::class); + $hookListener->__invoke($pageModel, $layoutModel, $pageRegular); + unset($hookListener); + + $hookListener = $this->createTestInstance(['bundleConfig' => ['use_contao_template_variables' => true]], $this->getMockBuilder(GeneratePageListener::class)->setMethods(['createEncoreScriptTags'])); + $hookListener->expects($this->never())->method('createEncoreScriptTags')->willReturn(true); $pageModel = $this->mockClassWithProperties(PageModel::class, []); $layoutModel = $this->mockClassWithProperties(LayoutModel::class, ['addEncore' => '1']); @@ -97,25 +106,19 @@ public function testInvoke() $hookListener->__invoke($pageModel, $layoutModel, $pageRegular); } - public function testAddEncore() + public function testCreateEncoreScriptTags() { - /** @var TemplateAsset|MockObject $templateAsset */ - $templateAsset = $this->createMock(TemplateAsset::class); - $templateAsset->expects($this->exactly(2))->method('createInstance')->willReturnSelf(); - $templateAsset->method('linkTags')->willReturn(''); - $templateAsset->method('inlineCssLinkTag')->willReturn('a.custom{color:blue;}'); - $templateAsset->method('scriptTags')->willReturn(''); - $templateAsset->method('headScriptTags')->willReturn(''); - $pageModel = $this->mockModelObject(PageModel::class); - $layoutModel = $this->mockModelObject(LayoutModel::class, []); + /** @var GeneratePageListener $instance */ + $instance = $this->createTestInstance(); + + $pageModel = $this->mockClassWithProperties(PageModel::class, []); + $layoutModel = $this->mockModelObject(LayoutModel::class, ['addEncore' => '1']); $pageRegular = $this->mockClassWithProperties(PageRegular::class, ['Template' => new \stdClass()]); - $listener = $this->createTestInstance(['templateAsset' => $templateAsset]); - $listener->addEncore($pageModel, $layoutModel, $pageRegular); - $this->assertSame('', $pageRegular->Template->encoreStylesheets); - $this->assertFalse(isset($pageRegular->Template->encoreStylesheetsInline)); + $instance->__invoke($pageModel, $layoutModel, $pageRegular); - $listener->addEncore($pageModel, $layoutModel, $pageRegular, null, true); - $this->assertSame('a.custom{color:blue;}', $pageRegular->Template->encoreStylesheetsInline); + $this->assertSame('[[HUH_ENCORE_CSS]]', $pageRegular->Template->encoreStylesheets); + $this->assertSame('[[HUH_ENCORE_JS]]', $pageRegular->Template->encoreScripts); + $this->assertSame('[[HUH_ENCORE_HEAD_JS]]', $pageRegular->Template->encoreHeadScripts); } } diff --git a/tests/EventListener/ReplaceDynamicScriptTagsListenerTest.php b/tests/EventListener/ReplaceDynamicScriptTagsListenerTest.php index c0e47ba..50eb3e9 100644 --- a/tests/EventListener/ReplaceDynamicScriptTagsListenerTest.php +++ b/tests/EventListener/ReplaceDynamicScriptTagsListenerTest.php @@ -11,28 +11,59 @@ use Contao\LayoutModel; use Contao\PageModel; use Contao\TestCase\ContaoTestCase; +use HeimrichHannot\EncoreBundle\Asset\TemplateAsset; use HeimrichHannot\EncoreBundle\EventListener\ReplaceDynamicScriptTagsListener; use HeimrichHannot\UtilsBundle\Container\ContainerUtil; use HeimrichHannot\UtilsBundle\Model\ModelUtil; +use PHPUnit\Framework\MockObject\MockBuilder; use PHPUnit\Framework\MockObject\MockObject; class ReplaceDynamicScriptTagsListenerTest extends ContaoTestCase { + /** + * @return ReplaceDynamicScriptTagsListener|MockObject + */ + public function getTestInstance(array $parameter = [], ?MockBuilder $mockBuilder = null) + { + $parameter['bundleConfig'] = $parameter['bundleConfig'] ?? []; + $parameter['containerUtil'] = $parameter['containerUtil'] ?? $this->createMock(ContainerUtil::class); + $parameter['modelUtil'] = $parameter['modelUtil'] ?? $this->createMock(ModelUtil::class); + $parameter['templateAsset'] = $parameter['templateAsset'] ?? $this->createMock(TemplateAsset::class); + + if ($mockBuilder) { + $instance = $mockBuilder->setConstructorArgs([ + $parameter['bundleConfig'], + $parameter['containerUtil'], + $parameter['modelUtil'], + $parameter['templateAsset'], + ])->getMock(); + } else { + $instance = new ReplaceDynamicScriptTagsListener( + $parameter['bundleConfig'], + $parameter['containerUtil'], + $parameter['modelUtil'], + $parameter['templateAsset'] + ); + } + + return $instance; + } + public function testInvoke() { /** @var ContainerUtil|MockObject $containerUtilMock */ $containerUtilMock = $this->createMock(ContainerUtil::class); $containerUtilMock->expects($this->once())->method('isFrontend')->willReturn(false); - $modelUtilMock = $this->createMock(ModelUtil::class); - /** @var ReplaceDynamicScriptTagsListener|MockObject $instance */ - $instance = $this->getMockBuilder(ReplaceDynamicScriptTagsListener::class) - ->setConstructorArgs([[], $containerUtilMock, $modelUtilMock]) - ->setMethods(['cleanGlobalArrays']) - ->getMock() - ; + $mockBilder = $this->getMockBuilder(ReplaceDynamicScriptTagsListener::class) + ->setMethods(['cleanGlobalArrays', 'replaceEncoreTags']); + $instance = $this->getTestInstance([ + 'containerUtil' => $containerUtilMock, + ], $mockBilder); + $instance->expects($this->never())->method('cleanGlobalArrays')->willReturn(false); + $instance->expects($this->never())->method('replaceEncoreTags')->willReturn(false); $instance->__invoke('test'); /** @var ContainerUtil|MockObject $containerUtilMock */ @@ -48,11 +79,12 @@ public function testInvoke() ); /** @var ReplaceDynamicScriptTagsListener|MockObject $instance */ - $instance = $this->getMockBuilder(ReplaceDynamicScriptTagsListener::class) - ->setConstructorArgs([[], $containerUtilMock, $modelUtilMock]) - ->setMethods(['cleanGlobalArrays']) - ->getMock() - ; + $mockBilder = $this->getMockBuilder(ReplaceDynamicScriptTagsListener::class) + ->setMethods(['cleanGlobalArrays', 'replaceEncoreTags']); + $instance = $this->getTestInstance([ + 'containerUtil' => $containerUtilMock, + 'modelUtil' => $modelUtilMock, + ], $mockBilder); $GLOBALS['objPage'] = $this->mockClassWithProperties(PageModel::class, ['layoutId' => 1]); @@ -61,4 +93,83 @@ public function testInvoke() $instance->__invoke('test'); $instance->__invoke('test'); } + + public function testReplaceEncoreTags() + { + /** @var ContainerUtil|MockObject $containerUtilMock */ + $containerUtilMock = $this->createMock(ContainerUtil::class); + $containerUtilMock->method('isFrontend')->willReturn(true); + + $modelUtilMock = $this->createMock(ModelUtil::class); + $modelUtilMock->method('findModelInstanceByPk')->willReturn( + $this->mockClassWithProperties(LayoutModel::class, ['addEncore' => '1']) + ); + + $templateAssetMock = $this->createMock(TemplateAsset::class); + $templateAssetMock->method('createInstance')->willReturnSelf(); + $templateAssetMock->method('linkTags')->willReturn(''); + $templateAssetMock->method('scriptTags')->willReturn('