FrakenApp #1: Part 6, Webpack!
For the last couple of weeks, I tried to get React to work with Phone Home App, and I would come face to face with Webpack! Getting Webpack and React to work in the browser isn't such a big deal, but add Electron to the mix... So I decided to get Webpack to work with Electron and do React later.
Webpack and Electron
The problem I had with Webpack is that, by default, it wants to stuff everything into a single bundle file. Electron needs at least three files: the main process's JavaScript file, the renderer's JavaScript file, and an HTML file.
2 exports
I figured out how split the export into two parts. Each one would have a different target telling Webpack what I was trying to build, 'electron-main'
and 'electron-renderer'
.
HtmlWebpackPlugin
I renamed index.html
to index.ejs
, took out the script tag pointing to renderer.js
, and let the HtmlWebpackPlugin wepback plugin create the HTML file.
webpack.config.js
Here is my webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const commonConfig = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.tsx$/,
loader: 'ts-loader'
}
]
},
resolve: {
extensions: ['.js', '.ts', '.json']
}
};
module.exports = [
// 1. The Main bundle
Object.assign(
{
target: 'electron-main',
entry: {main: './main.ts'}
},
commonConfig),
// 2. The Renderer bundle
Object.assign(
{
target: 'electron-renderer',
entry: {renderer: './renderer.ts'},
plugins: [
// 3. The HTML file
// (I converted the old html file to ejs
// so Webpack would build here)
new HtmlWebpackPlugin(
{
filename: `index.html`,
template: './index.ejs'
})
]
},
commonConfig)
];
index.ejs
index.ejs
is the HTML of the old index.html
with all the script
tags removed. Webpack will add the link to the renderer script.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Phone Home App</title>
</head>
<body>
<h1>Phone Home App</h1>
<br />
<input type="text" id="messageText" name="messageText" value="" />
<input type="button" id="phoneHome" value="Phone Home" />
<br />
<h2>Incoming Calls</h2>
<div id="received-data-content"></div>
</body>
</html>
More Dev Dependencies
In the process, I added a whole mess of Dev Dependencies. Since Webpack adds any dependency to the bundle, Dev Dependencies are best. For example, jQuery
will be added to renderer.js
, so it doesn't need to be in node-modules
.
You can add each like this in npm
:
npm install some-package --save-dev
or in yarn
:
yarn add some-package -D
Here are all the dependencies:
@types/electron
@types/jquery
@types/node
babel-core
babel-loader
babel-preset-es2015-node
babel-preset-react
cross-env
electron
electron-is-dev
html-webpack-plugin
jquery
net
node-loader
standard
standard-loader
ts-loader
ts-node
typescript
webpack
webpack-cli
Launching
Before launching the client, you will need to launch a server, either simple-tcp-repeater or simple-tcp-repeater-net before you launch the client.
npm or yarn
I edited the scripts section of package.json
to build with Webpack.
"scripts": {
"build": "webpack --config webpack.config.js --mode=development",
"client": "electron ./dist/main.js",
"start": "npm run build && npm run client"
},
build
builds without launching, client
launches without building, and start
does both.
You can launch the app with npm
like this:
npm run start
or with yarn
:
yarn start
vscode
I updated VSCode's launch.json
and added a tasks.json
to
.vscode/launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit:
// https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Client: Debug Main Process",
"type": "node",
"request": "launch",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"runtimeArgs": [
"--remote-debugging-port=9222"
],
"cwd": "${workspaceRoot}",
"program": "${workspaceRoot}/dist/main.js",
"timeout": 20000,
"sourceMaps": true,
"preLaunchTask": "build"
},
{
"name": "Client: Attach to Render Process",
"type": "chrome",
"request": "attach",
"port": 9222,
"webRoot": "${workspaceRoot}/dist/index.html"
}
],
"compounds": [
{
"name": "Client",
"configurations": [
"Client: Debug Main Process",
"Client: Attach to Render Process"
]
}
]
}
.vscode/tasks.json
In launch.json
, there is the line "preLaunchTask": "build"
, this refers to a new file, tasks.json
, which essentially points to build
from package.json
. This task is executing npm run build
.
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"command": "npm",
"tasks": [
{
"label": "build",
"type": "shell",
"args": [
"run",
"build"
],
"problemMatcher": []
}
]
}
Failed Experiments
I have to confess; this is a result of several failed experiments. Since this blog is more of a record of my explorations than a purely technical blog, I should summarize my more extensive experiments.
Directly To React.
I tried to graph some React directly into Phone Home App. Since many React samples use Webpack, I ended up with a hybrid app with only the React part bundled. This approach worked OK as long as I didn't have to communicate between the bundled and unbundled components.
Add Webpack, then React
Then I tried to add Webpack to Phone Home App. First, I tried to reverse engineer Electron React Boilerplate, but that was too far from the current state of the Phone Home App and I wanted to see more of the guts. I did a similar experiment with Electron Forge. These projects taught me quite a bit and showed me that I needed to read more about Webpack.
Forget React, just Webpack
I gave up trying to get Webpack and React working in one step. I was getting resolve 'fs' errors. I solved this by setting the target
to 'electron-renderer'
.
At this point, I watched the PluralSite course Webpack Fundamentals like a TV show and then started to dig in deeper into Webpack.
After finishing the Webpack Fundamentals course, I searched for electron-renderer
and Wepback
. I ran across Scott Logic's Setting up a TypeScript Electron app in WebPack, which I used as a basis of my transformations.
Finish Line
After this long tech journey, I conquered! I am starting to understand how these parts fit together.
Progress in the FrakenApp #1
What I have
- Still using .NET Core, though I didn't touch it this time.
- The app now uses TypeScript.
- Now using Webpack (new requirement)
What's still missing
- No Oracle.
- Not using strict TypeScript.
- Using JQuery, not React.js.
- Not building the Electron App; I'm running it from VS Code.
- Didn't test it on the Mac this cycle
The Code
The code is available on my GitHub as Frakenapp-01 or the Release for this article