diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index 91ad003c5fef60b552a50ec6823b388153c4a365..0000000000000000000000000000000000000000
--- a/.babelrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-	"presets": [
-		"react"
-	]
-}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 698d5d9ea79bbcc57e826db422ab662e6695be5f..6efebe21156b2fc9148ecd6853e668f98e812095 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 .sync-config.cson
 .electron-gyp
 .npmrc
+.idea
 
 .DS_Store
 
@@ -14,4 +15,4 @@ npm-debug.log
 
 Jitsi Meet*
 
-build/
\ No newline at end of file
+build/
diff --git a/app/features/app/components/App.js b/app/features/app/components/App.js
new file mode 100644
index 0000000000000000000000000000000000000000..2afd5020d2588bba32526490a2ed892f0eedfa0d
--- /dev/null
+++ b/app/features/app/components/App.js
@@ -0,0 +1,32 @@
+import React, { Component } from 'react';
+
+import { Conference } from '../../conference';
+import config from '../../config';
+
+/**
+ * Main component encapsulating the entire application.
+ */
+export default class App extends Component {
+    /**
+     * Initializes a new {@code App} instance.
+     *
+     * @inheritdoc
+     */
+    constructor() {
+        super();
+
+        document.title = config.appName;
+    }
+
+    /**
+     * Implements React's {@link Component#render()}.
+     *
+     * @inheritdoc
+     * @returns {ReactElement}
+     */
+    render() {
+        return (
+            <Conference />
+        );
+    }
+}
diff --git a/app/features/app/components/index.js b/app/features/app/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..c866729a65868adac6c4cf7e3664a8d74640be89
--- /dev/null
+++ b/app/features/app/components/index.js
@@ -0,0 +1 @@
+export { default as App } from './App';
diff --git a/app/features/app/index.js b/app/features/app/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..07635cbbc8e7a20c52efe5c76088af24735709d8
--- /dev/null
+++ b/app/features/app/index.js
@@ -0,0 +1 @@
+export * from './components';
diff --git a/windows/jitsi-meet/src/index.js b/app/features/conference/components/Conference.js
similarity index 68%
rename from windows/jitsi-meet/src/index.js
rename to app/features/conference/components/Conference.js
index b7d7e3602a6f8daeb2f1e69c5e36fddfc3f0947c..e77ece9d5c08329ef835440ef558da934140d24e 100644
--- a/windows/jitsi-meet/src/index.js
+++ b/app/features/conference/components/Conference.js
@@ -1,5 +1,4 @@
-import React from 'react';
-import { render } from 'react-dom';
+import { Component } from 'react';
 
 import {
     RemoteControl,
@@ -8,43 +7,43 @@ import {
     setupWiFiStats
 } from 'jitsi-meet-electron-utils';
 
-import { jitsiMeetDomain } from '../../../config.js';
+import config from '../../config';
 
 /**
  * Jitsi Meet Window Component
  */
-class JitsiMeetWindow extends React.Component {
-
-    /**
-     * Render function of component
-     * @return {ScriptElement}
-     */
-    render() {
-        return null;
-    }
-
+export default class Conference extends Component {
     /**
      * Attach the script
      */
     componentDidMount() {
-
         const script = document.createElement('script');
 
         script.async = true;
         script.onload = this._onScriptLoad;
         script.onerror = console.error;
-        script.src = `https://${jitsiMeetDomain}/external_api.js`;
+        script.src = `https://${config.defaultDomain}/external_api.js`;
 
         document.head.appendChild(script);
     }
 
+
+    /**
+     * Render function of component.
+     *
+     * @return {ReactElement}
+     */
+    render() {
+        return null;
+    }
+
     /**
      * When the script is loaded attach utils from jitsi-meet-electron-utils
      */
     _onScriptLoad() {
         const JitsiMeetExternalAPI = window.JitsiMeetExternalAPI;
 
-        const api = new JitsiMeetExternalAPI(jitsiMeetDomain);
+        const api = new JitsiMeetExternalAPI(config.defaultDomain);
         const iframe = api.getIFrame();
 
         setupScreenSharingForWindow(iframe);
@@ -53,5 +52,3 @@ class JitsiMeetWindow extends React.Component {
         setupWiFiStats(iframe);
     }
 }
-
-render(<JitsiMeetWindow />, document.getElementById('app'));
diff --git a/app/features/conference/components/index.js b/app/features/conference/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ee56f548438ba1c9a8c1167b02942eeaffb1ca5
--- /dev/null
+++ b/app/features/conference/components/index.js
@@ -0,0 +1 @@
+export { default as Conference } from './Conference';
diff --git a/app/features/conference/index.js b/app/features/conference/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..07635cbbc8e7a20c52efe5c76088af24735709d8
--- /dev/null
+++ b/app/features/conference/index.js
@@ -0,0 +1 @@
+export * from './components';
diff --git a/app/features/config/index.js b/app/features/config/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..22d380639a7d9cb926e200ce225d4be3c0ee0c37
--- /dev/null
+++ b/app/features/config/index.js
@@ -0,0 +1,12 @@
+
+export default {
+    /**
+     * Application name.
+     */
+    appName: 'Jitsi Meet',
+
+    /**
+     * The domain of the Jitsi Meet deployment that will be used.
+     */
+    defaultDomain: 'meet.jit.si'
+};
diff --git a/templates/index.html b/app/index.html
similarity index 82%
rename from templates/index.html
rename to app/index.html
index 48f1288fdee4056f01640885009631ccc0416c54..befc6f95c48f67fea715501bd8a3eb7c15cd9c74 100644
--- a/templates/index.html
+++ b/app/index.html
@@ -1,7 +1,6 @@
 <!DOCTYPE html>
 <html>
 <head>
-    <title><%= htmlWebpackPlugin.options.title %></title>
     <style>
         body, html {
             margin: 0;
diff --git a/app/index.js b/app/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..968cd0f0a67004afac9edd4bb747e94bd23ad747
--- /dev/null
+++ b/app/index.js
@@ -0,0 +1,9 @@
+import React from 'react';
+import { render } from 'react-dom';
+
+import { App } from './features/app';
+
+/**
+ * Render the main / root application.
+ */
+render(<App />, document.getElementById('app'));
diff --git a/config.js b/config.js
deleted file mode 100644
index 73d54c3cb689eb8805f46066abacad6e43cf8a66..0000000000000000000000000000000000000000
--- a/config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
-    /**
-     * The domain of the Jitsi Meet deployment that will be used.
-     */
-    jitsiMeetDomain: 'meet.jit.si'
-};
diff --git a/webpack.config.js b/webpack.config.js
index 4d6ac55ddb93e2e938c4368dce8b912822eec626..1d2bea9844fe47bc258c1fc3c6c6015177a40392 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -15,6 +15,15 @@ const commonConfig = {
             {
                 exclude: /(node_modules)/,
                 loader: 'babel-loader',
+                options: {
+                    presets: [
+                        [
+                            require.resolve('babel-preset-env'),
+                            { modules: false }
+                        ],
+                        require.resolve('babel-preset-react')
+                    ]
+                },
                 test: /\.js$/
             },
             {
@@ -41,11 +50,10 @@ module.exports = [
     commonConfig),
     Object.assign({
         target: 'electron-renderer',
-        entry: { renderer: './windows/jitsi-meet/src/index.js' },
+        entry: { renderer: './app/index.js' },
         plugins: [
             new HtmlWebpackPlugin({
-                title: 'Jitsi Meet',
-                template: path.resolve('./templates/index.html')
+                template: './app/index.html'
             })
         ]
     },