diff --git a/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php b/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php index d709cec522590e83fddbb19cf245a256e325a7d5..7045c25efcd51d7b0feacbe4fd87c60bbe5b0adf 100644 --- a/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php +++ b/typo3/sysext/backend/Classes/Form/Element/AbstractFormElement.php @@ -334,9 +334,12 @@ abstract class AbstractFormElement extends AbstractNode if ($javaScriptEvaluation instanceof JavaScriptModuleInstruction) { if ($javaScriptEvaluation->shallLoadRequireJs()) { // just use the module name and export-name + // @deprecated will be removed in TYPO3 v13.0 $resultArray['javaScriptModules'][] = JavaScriptModuleInstruction::forRequireJS( $javaScriptEvaluation->getName(), - $javaScriptEvaluation->getExportName() + $javaScriptEvaluation->getExportName(), + // silence deprecation error, has already been triggered by the original JavaScriptModuleInstruction instance + true )->invoke('registerCustomEvaluation', $name); } else { // just use the module name and export-name diff --git a/typo3/sysext/core/Classes/Controller/RequireJsController.php b/typo3/sysext/core/Classes/Controller/RequireJsController.php index 40c41c9bd3777fe18739a9b4646723b0f72ac88b..c6d626b109291b52b59663d3a3d3348ce2d4352f 100644 --- a/typo3/sysext/core/Classes/Controller/RequireJsController.php +++ b/typo3/sysext/core/Classes/Controller/RequireJsController.php @@ -25,6 +25,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; /** * Handling requirejs client requests. + * + * @deprecated will be removed in TYPO3 v13.0. */ class RequireJsController { diff --git a/typo3/sysext/core/Classes/Page/JavaScriptModuleInstruction.php b/typo3/sysext/core/Classes/Page/JavaScriptModuleInstruction.php index 409c067d6273617c35541fe0f40e698620f51847..ed4cf4cd8b257554cee8883efe54667395f171c0 100644 --- a/typo3/sysext/core/Classes/Page/JavaScriptModuleInstruction.php +++ b/typo3/sysext/core/Classes/Page/JavaScriptModuleInstruction.php @@ -23,6 +23,7 @@ class JavaScriptModuleInstruction implements \JsonSerializable { /** * Indicates a requireJS module shall be loaded. + * @deprecated will be removed in TYPO3 v13.0 */ public const FLAG_LOAD_REQUIRE_JS = 1; @@ -61,11 +62,15 @@ class JavaScriptModuleInstruction implements \JsonSerializable * @param string $name RequireJS module name * @param string|null $exportName (optional) name used internally to export the module * @return self + * @deprecated will be removed in TYPO3 v13.0. Use JavaScriptModuleInstruction::create() instead. */ - public static function forRequireJS(string $name, string $exportName = null): self + public static function forRequireJS(string $name, string $exportName = null, bool $internalCall = false): self { $target = GeneralUtility::makeInstance(static::class, $name, self::FLAG_LOAD_REQUIRE_JS); $target->exportName = $exportName; + if (!$internalCall) { + trigger_error('JavaScriptModuleInstruction::forRequireJS() is deprecated in favor of native ES6 modules, use JavaScriptModuleInstruction::create() instead. Support for RequireJS module loading will be removed in TYPO3 v13.0.', E_USER_DEPRECATED); + } return $target; } @@ -183,6 +188,9 @@ class JavaScriptModuleInstruction implements \JsonSerializable return $this; } + /** + * @deprecated will be removed in TYPO3 v13.0 + */ public function shallLoadRequireJs(): bool { return ($this->flags & self::FLAG_LOAD_REQUIRE_JS) === self::FLAG_LOAD_REQUIRE_JS; diff --git a/typo3/sysext/core/Classes/Page/PageRenderer.php b/typo3/sysext/core/Classes/Page/PageRenderer.php index 7d851b1c087eef8f00b764e20e9b47d071aade4a..dbf0512f5f5e362e9b4b21dc9aa3f5ab05bcf91a 100644 --- a/typo3/sysext/core/Classes/Page/PageRenderer.php +++ b/typo3/sysext/core/Classes/Page/PageRenderer.php @@ -1578,9 +1578,13 @@ class PageRenderer implements SingletonInterface * * @param string $mainModuleName Must be in the form of "TYPO3/CMS/PackageName/ModuleName" e.g. "TYPO3/CMS/Backend/FormEngine" * @param string $callBackFunction loaded right after the requireJS loading, must be wrapped in function() {} + * @deprecated will be removed in TYPO3 v13.0. Use loadJavaScriptModule() instead, available since TYPO3 v12.0. */ - public function loadRequireJsModule($mainModuleName, $callBackFunction = null) + public function loadRequireJsModule($mainModuleName, $callBackFunction = null, bool $internal = false) { + if (!$internal) { + trigger_error('PageRenderer->loadRequireJsModule is deprecated in favor of native ES6 modules, use loadJavaScriptModule() instead. Support for RequireJS module loading will be removed in TYPO3 v13.0.', E_USER_DEPRECATED); + } $inlineCodeKey = $mainModuleName; // make sure requireJS is initialized $this->loadRequireJs(); @@ -1593,7 +1597,7 @@ class PageRenderer implements SingletonInterface } if ($callBackFunction === null && $this->getApplicationType() === 'BE') { $this->javaScriptRenderer->addJavaScriptModuleInstruction( - JavaScriptModuleInstruction::forRequireJS($mainModuleName) + JavaScriptModuleInstruction::forRequireJS($mainModuleName, null, true) ); return; } diff --git a/typo3/sysext/core/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/core/Configuration/Backend/AjaxRoutes.php index 60a3b8a1d8a4a57067f737c2fa4818f302b74524..f75a7dd3424a63ce72a1d57e43ef0919130066ab 100644 --- a/typo3/sysext/core/Configuration/Backend/AjaxRoutes.php +++ b/typo3/sysext/core/Configuration/Backend/AjaxRoutes.php @@ -7,6 +7,7 @@ use TYPO3\CMS\Core\Controller\RequireJsController; */ return [ // dynamically load requirejs module definitions + // @deprecated will be removed in TYPO3 v13.0. 'core_requirejs' => [ 'path' => '/core/requirejs', 'access' => 'public', diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-97057-DeprecateRequireJSSupport.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-97057-DeprecateRequireJSSupport.rst new file mode 100644 index 0000000000000000000000000000000000000000..3748b36b43a6497919cbd301922015c0b2dfe071 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/12.0/Deprecation-97057-DeprecateRequireJSSupport.rst @@ -0,0 +1,75 @@ +.. include:: /Includes.rst.txt + +.. _deprecation-97057-1664653704: + +================================================= +Deprecation: #97057 - Deprecate RequireJS support +================================================= + +See :issue:`97057` + +Description +=========== + +The RequireJS project has been discontinued_ and was therefore +replaced by native ECMAScript v6/v11 modules in TYPO3 in :issue:`96510`. + +The infrastructure for configuration and loading of RequireJS +modules is now deprecated and will be removed in TYPO3 v13. + + +Impact +====== + +Registering modules via :php:`'requireJsModules'` will still work. +These modules will be loaded after modules registered via :php:`'javaScriptModules'`. Extensions that +use :php:`'requireJsModules` will work as before but trigger a PHP :php:`E_USER_DEPRECATED` error. + + +Affected installations +====================== + +Installations that register custom JavaScript modules for the TYPO3 backend. + + +Migration +========= + +Migrate your JavaScript from the AMD module format to native ES6 modules and register your configuration in :php:`Configuration/JavaScriptModules.php`, also see :issue:`96510` for more information: + +.. code-block:: php + + # Configuration/JavaScriptModules.php + <?php + + return [ + 'dependencies' => ['core', 'backend'], + 'imports' => [ + '@vendor/my-extension/' => 'EXT:my_extension/Resources/Public/JavaScript/', + ], + ]; + +Then use :php:`TYPO3\CMS\Core\Page\PageRenderer::loadJavaScriptModules()` instead of :php:`TYPO3\CMS\Core\Page\PageRenderer::loadRequireJsModule()` to load the ES6 module: + +.. code-block:: php + + // via PageRenderer + $this->packageRenderer->loadJavaScriptModule('@vendor/my-extension/example.js'); + + +In Fluid templates `includeJavaScriptModules` is to be used instead of `includeRequireJsModules`: + +In Fluid template the `includeJavaScriptModules` property of the +:html:`<f:be.pageRenderer>` ViewHelper may be used: + +.. code-block:: xml + + <f:be.pageRenderer + includeJavaScriptModules="{ + 0: '@vendor/my-extension/example.js' + }" + /> + +.. _discontinued: https://github.com/requirejs/requirejs/issues/1816 + +.. index:: Backend, JavaScript, NotScanned, ext:backend diff --git a/typo3/sysext/core/Tests/Functional/Page/JavaScriptRendererTest.php b/typo3/sysext/core/Tests/Functional/Page/JavaScriptRendererTest.php index 716abb281e9159a4cafb041442f9ad0f13dadf78..0aba10395ebd7c019da43ae0da7e5d89f6e34c4e 100644 --- a/typo3/sysext/core/Tests/Functional/Page/JavaScriptRendererTest.php +++ b/typo3/sysext/core/Tests/Functional/Page/JavaScriptRendererTest.php @@ -32,15 +32,15 @@ class JavaScriptRendererTest extends FunctionalTestCase { $subject = JavaScriptRenderer::create('anything.js'); $subject->addJavaScriptModuleInstruction( - JavaScriptModuleInstruction::forRequireJS('TYPO3/CMS/Test*/') + JavaScriptModuleInstruction::create('@typo3/test/module.js') ->invoke('test*/', 'arg*/') ); $subject->addGlobalAssignment(['section*/' => ['key*/' => 'value*/']]); self::assertSame( '<script src="anything.js" async="async">' . '/* [{"type":"globalAssignment","payload":{"section*\/":{"key*\/":"value*\/"}}},' - . '{"type":"javaScriptModuleInstruction","payload":{"name":"TYPO3\/CMS\/Test*\/","exportName":null,' - . '"flags":1,"items":[{"type":"invoke","method":"test*\/","args":["arg*\/"]}]}}] */</script>', + . '{"type":"javaScriptModuleInstruction","payload":{"name":"@typo3\/test\/module.js","exportName":null,' + . '"flags":2,"items":[{"type":"invoke","method":"test*\/","args":["arg*\/"]}]}}] */</script>', trim($subject->render()) ); } diff --git a/typo3/sysext/dashboard/Classes/Controller/DashboardController.php b/typo3/sysext/dashboard/Classes/Controller/DashboardController.php index da34c372a8a2f4ed513134b5c01b698a471d5d91..2ba53029af924030ab76d64efe1cda9af5bd5198 100644 --- a/typo3/sysext/dashboard/Classes/Controller/DashboardController.php +++ b/typo3/sysext/dashboard/Classes/Controller/DashboardController.php @@ -168,10 +168,12 @@ class DashboardController } foreach ($this->dashboardInitializationService->getRequireJsModules() as $requireJsModule) { if (is_array($requireJsModule)) { - $this->pageRenderer->loadRequireJsModule($requireJsModule[0], $requireJsModule[1]); + // Deprecation message is triggered by DashboardInitializationService::defineResourcesOfWidgets, and therefore silenced here. + $this->pageRenderer->loadRequireJsModule($requireJsModule[0], $requireJsModule[1], true); } else { + // Deprecation message is triggered by DashboardInitializationService::defineResourcesOfWidgets, and therefore silenced here. $javaScriptRenderer->addJavaScriptModuleInstruction( - JavaScriptModuleInstruction::forRequireJS($requireJsModule) + JavaScriptModuleInstruction::forRequireJS($requireJsModule, null, true) ); } } diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Menus/ActionMenuViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Menus/ActionMenuViewHelper.php index 84127af2c7ac7d793340e9ba87b8678f2344e536..7101cfd06e0d8a8ab4fed442c367f9ffae912b8a 100644 --- a/typo3/sysext/fluid/Classes/ViewHelpers/Be/Menus/ActionMenuViewHelper.php +++ b/typo3/sysext/fluid/Classes/ViewHelpers/Be/Menus/ActionMenuViewHelper.php @@ -17,9 +17,8 @@ declare(strict_types=1); namespace TYPO3\CMS\Fluid\ViewHelpers\Be\Menus; -use TYPO3\CMS\Core\Page\JavaScriptModuleInstruction; -use TYPO3\CMS\Core\Page\JavaScriptRenderer; use TYPO3\CMS\Core\Page\PageRenderer; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3Fluid\Fluid\Core\Compiler\TemplateCompiler; use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode; use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper; @@ -79,8 +78,8 @@ final class ActionMenuViewHelper extends AbstractTagBasedViewHelper 'data-action-navigate' => '$value', ]); $this->tag->setContent($options); - return $this->loadRequireJsModule('TYPO3/CMS/Backend/GlobalEventHandler') - . '<div class="docheader-funcmenu">' . $this->tag->render() . '</div>'; + $this->getPageRenderer()->loadJavaScriptModule('@typo3/backend/global-event-handler.js'); + return '<div class="docheader-funcmenu">' . $this->tag->render() . '</div>'; } /** @@ -95,17 +94,8 @@ final class ActionMenuViewHelper extends AbstractTagBasedViewHelper return null; } - /** - * Renders `<script src="JavaScriptItemHandler.js">...</script>` for loading - * corresponding module. Using `JavaScriptRenderer` makes this independent - * from `PageRenderer` and its current application state. - */ - protected function loadRequireJsModule(string $name): string + protected static function getPageRenderer(): PageRenderer { - $javaScriptRenderer = JavaScriptRenderer::create(); - $javaScriptRenderer->addJavaScriptModuleInstruction( - JavaScriptModuleInstruction::forRequireJS($name) - ); - return $javaScriptRenderer->render(); + return GeneralUtility::makeInstance(PageRenderer::class); } } diff --git a/typo3/sysext/form/Classes/Controller/FormEditorController.php b/typo3/sysext/form/Classes/Controller/FormEditorController.php index 6cf23319e112e356202eb229ffdf462512bdc412..463732f84c49cf86d854d83d6ae8b4a642408dea 100644 --- a/typo3/sysext/form/Classes/Controller/FormEditorController.php +++ b/typo3/sysext/form/Classes/Controller/FormEditorController.php @@ -108,7 +108,7 @@ class FormEditorController extends AbstractBackendController $this->prototypeConfiguration['formEditor']['dynamicJavaScriptModules']['additionalViewModelModules'] ?? [] ); $additionalViewModelRequireJsModules = array_map( - static fn (string $name) => JavaScriptModuleInstruction::forRequireJS($name), + static fn (string $name) => JavaScriptModuleInstruction::forRequireJS($name, null, true), $this->prototypeConfiguration['formEditor']['dynamicRequireJsModules']['additionalViewModelModules'] ?? [] ); if (count($additionalViewModelRequireJsModules) > 0) { diff --git a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php index 3aa246a757bb85620ea0022bc4e3f69dd870edcb..6f2e4cc63f7087f4d4e41f599c660851aa4461ee 100644 --- a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php +++ b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php @@ -152,8 +152,12 @@ class SetupModuleController $event = new AddJavaScriptModulesEvent(); /** @var AddJavaScriptModulesEvent $event */ $event = $this->eventDispatcher->dispatch($event); + foreach ($event->getJavaScriptModules() as $specifier) { + $this->pageRenderer->loadJavaScriptModule($specifier); + } foreach ($event->getModules() as $moduleName) { - $this->pageRenderer->loadRequireJsModule($moduleName); + // The deprecation is added in AddJavaScriptModulesEvent::addModule, and therefore silenced here. + $this->pageRenderer->loadRequireJsModule($moduleName, null, true); } } diff --git a/typo3/sysext/setup/Classes/Event/AddJavaScriptModulesEvent.php b/typo3/sysext/setup/Classes/Event/AddJavaScriptModulesEvent.php index 63ba207f9ed5599507046ab252e1e73dcaacdc70..440d8c2145c11f5a4668d941473f43da1f946e5e 100644 --- a/typo3/sysext/setup/Classes/Event/AddJavaScriptModulesEvent.php +++ b/typo3/sysext/setup/Classes/Event/AddJavaScriptModulesEvent.php @@ -22,19 +22,47 @@ namespace TYPO3\CMS\Setup\Event; */ final class AddJavaScriptModulesEvent { + /** + * @var string[] + */ + private array $javaScriptModules = []; + /** * @var string[] */ private array $modules = []; + /** + * @param string $specifier Bare module identifier like @my/package/filename.js + */ + public function addJavaScriptModule(string $specifier): void + { + if (in_array($specifier, $this->javaScriptModules, true)) { + return; + } + $this->javaScriptModules[] = $specifier; + } + + /** + * @deprecated will be removed in TYPO3 v13.0. Use addJavaScriptModule() instead, available since TYPO3 v12.0. + */ public function addModule(string $moduleName): void { + trigger_error('AddJavaScriptModulesEvent->addModule is deprecated in favor of native ES6 modules and will be removed in TYPO3 v13.0. Use an ES6 module via addJavaScriptModule instead.', E_USER_DEPRECATED); if (in_array($moduleName, $this->modules, true)) { return; } $this->modules[] = $moduleName; } + /** + * @return string[] + */ + public function getJavaScriptModules(): array + { + return $this->javaScriptModules; + } + /** * @return string[] */