Magento 2 – Type error: require is not a function for admin grid in custom page with custom tab

I am trying to load a grid to a tab on a custom page in Mangento 2 admin. The grid is rendered beautifully but js seems to be uninitialized after the ajax reload fetches it from controller. The grid is not responsive at all. Browser console displays “Type Error: require is not a function”, but I don’t understand how to initialize js for the grid after ajax.

My code (skipping boilerplate e.g. registration.php, composer.json, etc/module.xml, etc/adminhtml/routes.xml):

/Vendor/Module/Controller/Adminhtml/Offers/Edit.php

<?php
  namespace VendorModuleControllerAdminhtmlOffers;

  class Edit extends MagentoBackendAppAction{
    
    protected $resultPageFactory;

    public function __construct(
        MagentoBackendAppActionContext $context,
        MagentoFrameworkViewResultPageFactory $resultPageFactory
    ) {
         parent::__construct($context);
         $this->resultPageFactory = $resultPageFactory;
    }

    public function execute()
    {
         return  $resultPage = $this->resultPageFactory->create();
    }
  }
?>

/Vendor/Module/view/adminhtml/layouts/module_offers_edit.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>
        <title>
            Angebot
        </title>
    </head>
    <body>
        <referenceContainer name="left">
            <block class="VendorModuleBlockAdminhtmlOfferEditTabs"
                name="vendor_module_offer.edit.tabs"/>
        </referenceContainer>
        <referenceContainer name="content">
            <block class="VendorModuleBlockAdminhtmlOfferEdit"
                name="vendor_module_offer.edit"/>
        </referenceContainer>
    </body>
</page>

/Vendor/Module/Block/Adminhtml/Offer/Edit.php

<?php
namespace VendorModuleBlockAdminhtmlOffer;

use MagentoBackendBlockWidgetFormContainer;

class Edit extends Container{

    protected $_coreRegistry = null;

    public function __construct(
        MagentoBackendBlockWidgetContext $context,
        MagentoFrameworkRegistry $registry,
        array $data = []
    ) {
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }
    protected function _construct()
    {
        $this->_objectId = 'module_offer_id';
        $this->_blockGroup = 'Vendor_Module';
        $this->_controller = 'adminhtml_offer';
        parent::_construct();
        $this->buttonList->remove('save');
    }

    public function getHeaderText()
    {
        return __('Offer');
    }

    protected function _isAllowedAction($resourceId)
    {
        return $this->_authorization->isAllowed($resourceId);
    }

}

/Vendor/Module/Block/Adminhtml/Offer/Edit/Tabs.php

<?php
   namespace VendorModuleBlockAdminhtmlOfferEdit;

   use MagentoBackendBlockWidgetTabs as WidgetTabs;

   class Tabs extends WidgetTabs{

    protected function _construct()
    {
        parent::_construct();
        $this->setId('offer_edit_tabs');
        $this->setDestElementId('edit_form');
        $this->setTitle(__('Angebot'));
    }

    protected function _beforeToHtml()
    {
        $this->addTab(
            'Produkte',
            [
                'label' => __('Products'),
                'url' => $this->getUrl('module/*/products', ['_current' => true]),
                'class' => 'ajax'
            ]
        );
        return parent::_beforeToHtml();
    }
}

This is all just setup for the tabs to display on the page with path .../admin/module/offers/edit/ID. Now, to fill the tab with products I load the grid with this:

/Vendor/Module/Controller/Adminhtml/Offers/Products.php

<?php
  namespace VendorModuleControllerAdminhtmlOffers;

  class Products extends MagentoBackendAppAction{
    protected $resultPageFactory;

    public function __construct(
        MagentoBackendAppActionContext $context,
        MagentoFrameworkViewResultPageFactory $resultPageFactory
    ) {
         parent::__construct($context);
         $this->resultPageFactory = $resultPageFactory;
    }

    public function execute()
    {
         return  $resultPage = $this->resultPageFactory->create();
    }
  }
?>

/Vendor/Module/view/adminhtml/layout/module_offers_products.xml

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd">
    <container name="root" label="Root">
        <block class="VendorModuleBlockAdminhtmlOfferEditTabViewProducts" name="offer.edit.tab.product"/>
    </container>
</layout>

/Vendor/Module/Block/Adminhtml/Offer/Edit/Tab/View/Products.php

<?php
namespace VendorModuleBlockAdminhtmlOfferEditTabView;

use MagentoCustomerControllerRegistryConstants;

class Products extends MagentoBackendBlockWidgetGridExtended
{

    protected $_coreRegistry = null;

    protected $_collectionFactory;

    public function __construct(
        MagentoBackendBlockTemplateContext $context,
        MagentoBackendHelperData $backendHelper,
        VendorModuleModelOfferItemFactory $collectionFactory,
        MagentoFrameworkRegistry $coreRegistry,
        PsrLogLoggerInterface $logger,
        array $data = []
    ) {
         $this->_logger = $logger;
        $this->_coreRegistry = $coreRegistry;
        $this->_collectionFactory = $collectionFactory;
        parent::__construct($context, $backendHelper, $data);
    }

    protected function _construct()
    {
        parent::_construct();
        $this->setId('offer_view_products_grid');
        $this->setDefaultSort('offer_item_stock_id', 'desc');
        $this->setSortable(true);
        $this->setPagerVisibility(true);
        $this->setFilterVisibility(true);
    }

    protected function _preparePage()
    {
        $this->getCollection()->setPageSize(5)->setCurPage(1);
    }

    protected function _prepareCollection()
    {
        $collection = $this->_collectionFactory->create()->getCollection();
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    protected function _prepareMassaction()
    {
        $this->setMassactionIdField('offer_item_stock_id');
        $this->getMassactionBlock()->setFormFieldName('stock_ids');
        $this->getMassactionBlock()->addItem(
            'customize',
            [
                'label' => __('Anpassen (ToDo)'),
                'url' => $this->getUrl('test/test/test')
            ]
        );
        return $this;
    }
     protected function _prepareColumns()
    {
        $this->addColumn(
            'offer_item_stock_id',
            ['header' => __('Stock ID'), 'index' => 'offer_item_stock_id', 'type' => 'number', 'width' => '50px']
        );
        return parent::_prepareColumns();
    }

    public function getHeadersVisibility()
    {
        return $this->getCollection()->getSize() >= 0;
    }

    public function getRowUrl($row)
    {
        return $this->getUrl('test/test/test');
    }
}

So my question is how to initialize js for the grid after ajax load.