patch: development environment

Add webpack dev server and hot module reloading to get live changes and reloads without reloading the whole electron app.

This patch also runs the development environment in development mode, which is much, much faster on builds and rebuilds.
This commit is contained in:
Zane Hitchcox 2021-04-21 09:43:39 -04:00
parent 33dd07c675
commit 1ee110bc95
8 changed files with 3060 additions and 16244 deletions

View File

@ -38,6 +38,7 @@ import * as exceptionReporter from './modules/exception-reporter';
import * as osDialog from './os/dialog';
import * as windowProgress from './os/window-progress';
import MainPage from './pages/main/MainPage';
import './css/main.css';
window.addEventListener(
'unhandledrejection',
@ -339,7 +340,7 @@ window.addEventListener('beforeunload', async (event) => {
}
});
async function main() {
export async function main() {
await ledsInit();
ReactDOM.render(
React.createElement(MainPage),
@ -356,5 +357,3 @@ async function main() {
},
);
}
main();

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Etcher</title>
<link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<main id="main"></main>
<script src="http://localhost:3030/gui.js"></script>
</body>
</html>

10
lib/gui/app/renderer.ts Normal file
View File

@ -0,0 +1,10 @@
// @ts-nocheck
import { main } from './app';
if (module.hot) {
module.hot.accept('./app', () => {
main();
});
}
main();

19170
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,10 +22,10 @@
"test-shared": "electron-mocha --recursive --reporter spec --require ts-node/register --require-main tests/gui/allow-renderer-process-reuse.ts --full-trace --no-sandbox tests/shared/**/*.ts",
"test": "npm run lint && npm run test-gui && npm run test-shared && npm run test-spectron && npm run sanity-checks",
"sanity-checks": "bash scripts/ci/ensure-all-file-extensions-in-gitattributes.sh",
"start": "./node_modules/.bin/ts-node scripts/start.ts",
"start": "./node_modules/.bin/electron .",
"postshrinkwrap": "ts-node ./scripts/clean-shrinkwrap.ts",
"webpack": "webpack",
"watch": "webpack --watch",
"watch": "webpack serve --no-optimization-minimize --config ./webpack.dev.config.ts",
"concourse-build-electron": "npm run webpack",
"concourse-test": "npx npm@6.14.8 test",
"concourse-test-electron": "npx npm@6.14.8 test"
@ -110,6 +110,7 @@
"sinon": "^9.0.2",
"spectron": "^14.0.0",
"string-replace-loader": "^3.0.1",
"style-loader": "^2.0.0",
"styled-components": "^5.1.0",
"sudo-prompt": "github:zvin/sudo-prompt#7cdede2f0da28fbcc2db48402d7d935f3a825c91",
"sys-class-rgb-led": "^3.0.0",
@ -117,8 +118,10 @@
"ts-node": "^9.1.1",
"tslib": "^2.0.0",
"typescript": "^4.2.2",
"url-loader": "^4.1.1",
"uuid": "^8.1.0",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0"
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^3.11.2"
}
}

View File

@ -1,16 +0,0 @@
import { watch } from 'fs/promises';
import { spawn } from 'child_process';
const startElectron = () =>
spawn('./node_modules/.bin/electron', ['.'], {
stdio: 'inherit',
});
(async () => {
const watcher = watch('./generated', { recursive: true });
let electronProcess = startElectron();
for await (const _event of watcher) {
electronProcess.kill();
electronProcess = startElectron();
}
})();

View File

@ -17,7 +17,6 @@
import * as CopyPlugin from 'copy-webpack-plugin';
import { readdirSync } from 'fs';
import * as _ from 'lodash';
import * as MiniCssExtractPlugin from 'mini-css-extract-plugin';
import * as os from 'os';
import outdent from 'outdent';
import * as path from 'path';
@ -120,7 +119,7 @@ function fetchWasm(...where: string[]) {
} catch {
}
function appPath() {
return Path.isAbsolute(__dirname) ?
return Path.isAbsolute(__dirname) ?
__dirname :
Path.join(
// With macOS universal builds, getAppPath() returns the path to an app.asar file containing an index.js file which will
@ -158,7 +157,12 @@ const commonConfig = {
rules: [
{
test: /\.css$/,
use: 'css-loader',
use: ['style-loader', 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: { name: renameNodeModules },
},
{
test: /\.svg$/,
@ -348,10 +352,18 @@ const guiConfig = {
__filename: true,
},
entry: {
gui: path.join(__dirname, 'lib', 'gui', 'app', 'app.ts'),
gui: path.join(__dirname, 'lib', 'gui', 'app', 'renderer.ts'),
},
plugins: [
...commonConfig.plugins,
new CopyPlugin({
patterns: [
{ from: 'lib/gui/app/index.html', to: 'index.html' },
// electron-builder doesn't bundle folders named "assets"
// See https://github.com/electron-userland/electron-builder/issues/4545
{ from: 'assets/icon.png', to: 'media/icon.png' },
],
}),
// Remove "Download the React DevTools for a better development experience" message
new BannerPlugin({
banner: '__REACT_DEVTOOLS_GLOBAL_HOOK__ = { isDisabled: true };',
@ -390,42 +402,4 @@ const childWriterConfig = {
},
};
const cssConfig = {
mode: 'production',
optimization: {
minimize: false,
},
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
loader: 'file-loader',
options: { name: renameNodeModules },
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: '[name].css' }),
new CopyPlugin({
patterns: [
{ from: 'lib/gui/app/index.html', to: 'index.html' },
// electron-builder doesn't bundle folders named "assets"
// See https://github.com/electron-userland/electron-builder/issues/4545
{ from: 'assets/icon.png', to: 'media/icon.png' },
],
}),
],
entry: {
index: path.join(__dirname, 'lib', 'gui', 'app', 'css', 'main.css'),
},
output: {
publicPath: '',
path: path.join(__dirname, 'generated'),
},
};
module.exports = [cssConfig, guiConfig, etcherConfig, childWriterConfig];
export default [guiConfig, etcherConfig, childWriterConfig];

22
webpack.dev.config.ts Normal file
View File

@ -0,0 +1,22 @@
import configs from './webpack.config';
import { WebpackOptionsNormalized } from 'webpack';
import * as fs from 'fs';
const [
guiConfig,
etcherConfig,
childWriterConfig,
] = (configs as unknown) as WebpackOptionsNormalized[];
configs.forEach((config) => {
config.mode = 'development';
});
guiConfig.devServer = {
hot: true,
port: 3030,
};
fs.copyFileSync('./lib/gui/app/index.dev.html', './generated/index.html');
export default [guiConfig, etcherConfig, childWriterConfig];