WIP attempt to wire up electron-forge

I wasn't able to get this fully working, IIRC; the challenge was getting
the webpack build for web stuff to happen reliably.
This commit is contained in:
Max Goodhart
2023-04-14 23:33:57 -07:00
committed by sayhiben
parent 00e07549d6
commit cf73dcf604
19 changed files with 4987 additions and 1180 deletions

4
.gitignore vendored
View File

@@ -3,6 +3,8 @@ coverage
dist dist
node_modules node_modules
reports reports
.webpack
out/
# Individual files # Individual files
junit.xml junit.xml

77
forge.config.js Normal file
View File

@@ -0,0 +1,77 @@
module.exports = {
packagerConfig: { extraResource: './dist/web' },
rebuildConfig: {},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {},
},
{
name: '@electron-forge/maker-zip',
platforms: ['darwin'],
},
{
name: '@electron-forge/maker-deb',
config: {},
},
{
name: '@electron-forge/maker-rpm',
config: {},
},
],
plugins: [
{
name: '@electron-forge/plugin-webpack',
config: {
mainConfig: './webpack.main.config.js',
renderer: {
config: './webpack.renderer.config.js',
entryPoints: [
{
name: 'background',
html: './src/renderer/background.html',
js: './src/renderer/background.js',
preload: {
js: './src/renderer/layerPreload.js',
},
},
{
name: 'overlay',
html: './src/renderer/overlay.html',
js: './src/renderer/overlay.js',
preload: {
js: './src/renderer/layerPreload.js',
},
},
{
name: 'playHLS',
html: './src/renderer/playHLS.html',
js: './src/renderer/playHLS.js',
},
{
name: 'media',
preload: {
js: './src/renderer/mediaPreload.js',
},
},
],
},
},
},
],
hooks: {
// HACK: monkeypatch in extra webpack config to build control site
generateAssets: (forgeConfig) => {
const { configGenerator } = forgeConfig.pluginInterface.plugins[0]
const origGetRendererConfig = configGenerator.getRendererConfig
configGenerator.getRendererConfig = async (entryPoints) => {
const config = await origGetRendererConfig.call(
configGenerator,
entryPoints,
)
config.push(require('./webpack.web.config'))
return config
}
},
},
}

5816
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,19 +2,22 @@
"name": "streamwall", "name": "streamwall",
"version": "0.0.1", "version": "0.0.1",
"description": "View streams in a grid", "description": "View streams in a grid",
"main": "src/index.js", "main": "./.webpack/main",
"scripts": { "scripts": {
"build": "webpack", "build": "webpack",
"prune": "rm -rf dist", "prune": "rm -rf dist",
"start": "npm run build -- --stats=errors-only && electron dist", "start": "electron-forge start",
"start-local": "npm run build -- --stats=errors-only && electron dist --control.address=http://localhost:4444 --control.username=streamwall --control.password=local-dev", "start-local": "npm run build -- --stats=errors-only && electron dist --control.address=http://localhost:4444 --control.username=streamwall --control.password=local-dev",
"start-dev": "npm run build -- --stats=verbose && electron dist --enable-logging --control.address=http://localhost:4444 --control.username=streamwall --control.password=local-dev", "start-dev": "npm run build -- --stats=verbose && electron dist --enable-logging --control.address=http://localhost:4444 --control.username=streamwall --control.password=local-dev",
"test": "jest", "test": "jest",
"test:ci": "jest --ci --reporters=default --reporters=jest-junit --testPathIgnorePatterns=src/node/server.test.js --coverage" "test:ci": "jest --ci --reporters=default --reporters=jest-junit --testPathIgnorePatterns=src/node/server.test.js --coverage",
"package": "electron-forge package",
"make": "electron-forge make"
}, },
"author": "Max Goodhart <c@chromakode.com>", "author": "Max Goodhart <c@chromakode.com>",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@electron-forge/plugin-webpack": "^6.1.1",
"@iarna/toml": "^2.2.5", "@iarna/toml": "^2.2.5",
"@repeaterjs/repeater": "^3.0.6", "@repeaterjs/repeater": "^3.0.6",
"@sentry/electron": "^5.3.0", "@sentry/electron": "^5.3.0",
@@ -27,6 +30,7 @@
"hls.js": "^1.5.14", "hls.js": "^1.5.14",
"jsondiffpatch": "^0.6.0", "jsondiffpatch": "^0.6.0",
"koa": "^2.15.3", "koa": "^2.15.3",
"electron-squirrel-startup": "^1.0.0",
"koa-basic-auth": "^4.0.0", "koa-basic-auth": "^4.0.0",
"koa-easy-ws": "^2.1.0", "koa-easy-ws": "^2.1.0",
"koa-route": "^4.0.1", "koa-route": "^4.0.1",
@@ -55,12 +59,18 @@
"@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx": "^7.25.2",
"@babel/preset-env": "^7.25.3", "@babel/preset-env": "^7.25.3",
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@electron-forge/cli": "^6.1.1",
"@electron-forge/maker-deb": "^6.1.1",
"@electron-forge/maker-rpm": "^6.1.1",
"@electron-forge/maker-squirrel": "^6.1.1",
"@electron-forge/maker-zip": "^6.1.1",
"babel-jest": "^29.7.0", "babel-jest": "^29.7.0",
"babel-loader": "^9.1.3", "babel-loader": "^9.1.3",
"babel-plugin-styled-components": "^2.1.4", "babel-plugin-styled-components": "^2.1.4",
"bufferutil": "^4.0.8", "bufferutil": "^4.0.8",
"copy-webpack-plugin": "^12.0.2", "copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"electron": "^24.1.2",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0", "jest": "^29.7.0",

View File

@@ -68,7 +68,7 @@ export default class StreamWindow extends EventEmitter {
const backgroundView = new BrowserView({ const backgroundView = new BrowserView({
webPreferences: { webPreferences: {
contextIsolation: true, contextIsolation: true,
preload: path.join(app.getAppPath(), 'layerPreload.js'), preload: BACKGROUND_PRELOAD_WEBPACK_ENTRY,
}, },
}) })
win.addBrowserView(backgroundView) win.addBrowserView(backgroundView)
@@ -79,13 +79,13 @@ export default class StreamWindow extends EventEmitter {
height, height,
useContentSize: true, useContentSize: true,
}) })
backgroundView.webContents.loadFile('background.html') backgroundView.webContents.loadURL(BACKGROUND_WEBPACK_ENTRY)
this.backgroundView = backgroundView this.backgroundView = backgroundView
const overlayView = new BrowserView({ const overlayView = new BrowserView({
webPreferences: { webPreferences: {
contextIsolation: true, contextIsolation: true,
preload: path.join(app.getAppPath(), 'layerPreload.js'), preload: OVERLAY_PRELOAD_WEBPACK_ENTRY,
}, },
}) })
win.addBrowserView(overlayView) win.addBrowserView(overlayView)
@@ -95,7 +95,7 @@ export default class StreamWindow extends EventEmitter {
width, width,
height, height,
}) })
overlayView.webContents.loadFile('overlay.html') overlayView.webContents.loadURL(OVERLAY_WEBPACK_ENTRY)
this.overlayView = overlayView this.overlayView = overlayView
this.viewActions = { this.viewActions = {
@@ -148,7 +148,7 @@ export default class StreamWindow extends EventEmitter {
const { backgroundColor } = this.config const { backgroundColor } = this.config
const view = new BrowserView({ const view = new BrowserView({
webPreferences: { webPreferences: {
preload: path.join(app.getAppPath(), 'mediaPreload.js'), preload: MEDIA_PRELOAD_WEBPACK_ENTRY,
nodeIntegration: false, nodeIntegration: false,
enableRemoteModule: false, enableRemoteModule: false,
contextIsolation: true, contextIsolation: true,

View File

@@ -381,7 +381,7 @@ async function main(argv) {
if (argv.control.address) { if (argv.control.address) {
console.debug('Initializing web server...') console.debug('Initializing web server...')
const webDistPath = path.join(app.getAppPath(), 'web') const webDistPath = path.join(app.getAppPath(), './web')
await initWebServer({ await initWebServer({
certDir: argv.cert.dir, certDir: argv.cert.dir,
certProduction: argv.cert.production, certProduction: argv.cert.production,

49
webpack.base.config.js Normal file
View File

@@ -0,0 +1,49 @@
module.exports = ({ babel }) => ({
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: babel,
},
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
{
test: /\.svg$/,
loader: '@svgr/webpack',
options: {
replaceAttrValues: {
'#333': 'currentColor',
'#555': '{props.color}',
},
},
},
],
},
resolve: {
extensions: ['.jsx', '.js'],
alias: {
react: 'preact/compat',
'react-dom': 'preact/compat',
},
},
stats: {
colors: true,
modules: true,
reasons: true,
errorDetails: true,
warnings: true,
}
})

View File

@@ -1,130 +0,0 @@
const path = require('path')
const CopyPlugin = require('copy-webpack-plugin')
const baseConfig = ({ babel }) => ({
mode: 'development',
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: babel,
},
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
{
test: /\.svg$/,
loader: '@svgr/webpack',
options: {
replaceAttrValues: {
'#333': 'currentColor',
'#555': '{props.color}',
},
},
},
],
},
resolve: {
extensions: ['.jsx', '.js'],
alias: {
react: 'preact/compat',
'react-dom': 'preact/compat',
},
},
})
const nodeConfig = {
...baseConfig({
babel: {
presets: [
[
'@babel/preset-env',
{
modules: 'commonjs',
targets: { node: true },
},
],
],
},
}),
target: 'electron-main',
entry: {
index: './src/node/index.js',
},
externals: {
consolidate: 'commonjs consolidate',
fsevents: 'commonjs fsevents',
},
}
const browserConfig = {
...baseConfig({
babel: {
presets: [['@babel/preset-env', { targets: { electron: '11' } }]],
},
}),
devtool: 'cheap-source-map',
target: 'electron-renderer',
entry: {
background: './src/browser/background.js',
overlay: './src/browser/overlay.js',
layerPreload: './src/browser/layerPreload.js',
mediaPreload: './src/browser/mediaPreload.js',
playHLS: './src/browser/playHLS.js',
},
plugins: [
new CopyPlugin({
patterns: [{ from: 'src/browser/*.html', to: '[name].html' }],
}),
],
}
const webConfig = {
...baseConfig({
babel: {
presets: [
[
'@babel/preset-env',
{
modules: 'commonjs',
targets: '> 0.25%, not dead',
},
],
],
},
}),
devtool: 'cheap-source-map',
target: 'web',
entry: {
control: './src/web/entrypoint.js',
},
output: {
path: path.resolve(__dirname, 'dist/web'),
},
plugins: [
new CopyPlugin({
patterns: [{ from: 'src/web/*.ejs', to: '[name].ejs' }],
}),
],
stats: {
colors: true,
modules: true,
reasons: true,
errorDetails: true,
warnings: true,
}
}
module.exports = [nodeConfig, browserConfig, webConfig]

22
webpack.main.config.js Normal file
View File

@@ -0,0 +1,22 @@
const baseConfig = require('./webpack.base.config')
module.exports = {
...baseConfig({
babel: {
presets: [
[
'@babel/preset-env',
{
modules: 'commonjs',
targets: { node: true },
},
],
],
},
}),
entry: './src/node/main.js',
externals: {
consolidate: 'commonjs consolidate',
fsevents: 'commonjs fsevents',
},
}

View File

@@ -0,0 +1,9 @@
const baseConfig = require('./webpack.base.config')
module.exports = {
...baseConfig({
babel: {
presets: [['@babel/preset-env', { targets: { electron: '24' } }]],
},
}),
}

32
webpack.web.config.js Normal file
View File

@@ -0,0 +1,32 @@
const path = require('path')
const CopyPlugin = require('copy-webpack-plugin')
const baseConfig = require('./webpack.base.config')
module.exports = {
...baseConfig({
babel: {
presets: [
[
'@babel/preset-env',
{
modules: 'commonjs',
targets: '> 0.25%, not dead',
},
],
],
},
}),
devtool: 'cheap-source-map',
target: 'web',
entry: {
control: './src/web/entrypoint.js',
},
output: {
path: path.resolve(__dirname, '.webpack/main/web'),
},
plugins: [
new CopyPlugin({
patterns: [{ from: 'src/web/*.ejs', to: '[name].ejs' }],
}),
],
}