Magento2: Basic Frontend Module
We will do simple module which will write Hello world to frontend.  Copy source code under app/code/MichalMachovic/Helloworld. Activate the module, then you can see Hello world! on [YOUR_SITE]/helloworld/index/index.
Structure
Block
 |
 --Helloworld.php
Controller
 |
 Index
   |
   --Index.php
etc
 |
 module.xml
 frontend
    |
    --routes.xml
view
 |
 layout
  |
  --helloworld_index_index.xml
  |
  templates
  |
  --helloworld.phtml
registration.phpregistration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'MichalMachovic_Helloworld',
    __DIR__
);etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="MichalMachovic_Helloworld" setup_version="1.0.0.1"></module>
</config>etc/routes.xml
Lets take url http://localhost/magento2/sites/m2test/helloworld/index/index. In Magento 2, each individual module can claim a front name. The front name is the first segment of the URL — in our case that’s helloworld. When a module claims a front name, that is its way of saying: 
 Hello Magento systems code — if you see any URLs that start with /helloworld, I have controllers for them
 
All frontend routes are going under
 
<router id="standard"> 
 So following piece of code means: If there is url that starts with helloworld, module MichalMachovic_Helloworld will process it.
//etc/frontend/routes.xml
<?xml version="1.0"?>
 
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="helloworld" frontName="helloworld">
            <module name="MichalMachovic_Helloworld" />
        </route>
    </router>
</config>Controller/Index/Index.php
Magento 2 uses a traditional PHP transform the URL into a controller class name approach to controller naming. Let’s take another look at our URL
/helloworld/index/index
To come up with a controller class name, Magento 2 will look at the second and third URL segments (index, and index above, respectively). That is 
- The class name starts with MichalMachovic\Helloworld since we configured 
MichalMachovic_Helloworldto claim thehelloworldfront name. - Then we append Controller, because we’re defining a controller (
MichalMachovic\HelloWorld\Controller) - Then Magento appends the second URL segment (
index) with an upper casing (MichalMachovic\HelloWorld\Controller\Index) - Then Magento appends the third URL segment (
index) with an upper casing (MichalMachovic\HelloWorld\Controller\Index\Index)
That gives us a final controller name of ichalMachovic\Helloworld\Controller\Index\Index.php. Each frontend controller extendsMagento\Framework\App\Action\Action.
In Magento 2, if you want a controller to render an HTML page, you need to have the controller’s execute method return apageobject. 
<?php
 
namespace MichalMachovic\Helloworld\Controller\Index;
use Magento\Framework\App\Action\Context;
 
class Index extends \Magento\Framework\App\Action\Action
{
    protected $_resultPageFactory;
 
    public function __construct(Context $context, \Magento\Framework\View\Result\PageFactory $resultPageFactory)
    {
        $this->_resultPageFactory = $resultPageFactory;
        parent::__construct($context);
    }
 
    public function execute()
    {
        $resultPage = $this->_resultPageFactory->create();
        return $resultPage;
    }
}Block/Helloworld.php
<?php
namespace MichalMachovic\Helloworld\Block;
 
class Helloworld extends \Magento\Framework\View\Element\Template
{
    public function getHelloWorldTxt()
    {
        return 'Hello world!';
    }
    protected function _prepareLayout()
    {
      $this->setMessage('Hello');  //we can get this then in template
      $this->setName($this->getRequest()->getParam('name'));  //get parameter name
    }
}view/frontend/layout/helloworld_index_index.xml
If we create file helloworld_index_index.xml, we are telling Magento: If the handle helloworld_index_index is issue, use the layout instructions in this file. So something like: Magento, please create a block object using the class MichalMachovic\Helloworld\Block\Helloworld. This block should render with the template in the helloworld.phtml file, and let’s give the block a globally unique name of helloworld.  A block’s name should be a globally unique string, and can be used by other code to get a reference to our block object.
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd" layout="1column">
    <body>
        <referenceContainer name="content">
            <block class="MichalMachovic\Helloworld\Block\Helloworld" name="helloworld" template="helloworld.phtml" />
        </referenceContainer>
    </body>
</page>view/frontend/templates/helloworld.phtml
<h1><?php echo $this->getHelloWorldTxt(); ?></h1>
<?php echo $this->escapeHtml($this->getMessage()); ?>
<?php echo $this->escapeHtml($this->getName()); ?>