refactor(desktop): add render thread build and add welcome window

pull/100/head
moonrailgun 2 years ago
parent 9f6d10cb28
commit c303ded91f

@ -1,18 +0,0 @@
import webWebpackConfig from '../../../web/build/webpack.config';
import type { Configuration } from 'webpack';
import webpackPaths from './webpack.paths';
export function getWebTailchatWebpackConfig(): Configuration {
return {
...webWebpackConfig,
plugins: webWebpackConfig.plugins?.filter(
(p) => !['GenerateSW'].includes(p.constructor.name)
),
output: {
path: webpackPaths.distRendererPath,
filename: '[name].[contenthash].js',
publicPath: '/',
},
target: ['web', 'electron-renderer'],
};
}

@ -3,11 +3,12 @@
*/
import webpack from 'webpack';
import TsconfigPathsPlugins from 'tsconfig-paths-webpack-plugin';
import webpackPaths from './webpack.paths';
import { dependencies as externals } from '../../release/app/package.json';
const configuration: webpack.Configuration = {
externals: [...Object.keys(externals || {}), 'electron-screenshots'],
externals: [...Object.keys(externals || {})],
stats: 'errors-only',
@ -21,6 +22,9 @@ const configuration: webpack.Configuration = {
options: {
// Remove this line to enable type checking in webpack builds
transpileOnly: true,
compilerOptions: {
module: 'esnext',
},
},
},
},
@ -41,22 +45,11 @@ const configuration: webpack.Configuration = {
resolve: {
extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'],
modules: [webpackPaths.srcPath, 'node_modules'],
fallback: {
crypto: require.resolve('crypto-browserify'),
http: require.resolve('stream-http'),
https: require.resolve('https-browserify'),
path: require.resolve('path-browserify'),
stream: require.resolve('stream-browserify'),
url: require.resolve('url/'),
fs: false,
},
// There is no need to add aliases here, the paths in tsconfig get mirrored
plugins: [new TsconfigPathsPlugins()],
},
plugins: [
new webpack.DefinePlugin({
'process.env.FE_URL': JSON.stringify(process.env.FE_URL),
'process.env.SERVICE_URL': JSON.stringify(process.env.SERVICE_URL),
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
}),

@ -1,3 +0,0 @@
/* eslint import/no-unresolved: off, import/no-self-import: off */
module.exports = require('./webpack.config.renderer.dev').default;

@ -15,15 +15,8 @@ import deleteSourceMaps from '../scripts/delete-source-maps';
checkNodeEnv('production');
deleteSourceMaps();
const devtoolsConfig =
process.env.DEBUG_PROD === 'true'
? {
devtool: 'source-map',
}
: {};
const configuration: webpack.Configuration = {
...devtoolsConfig,
devtool: 'source-map',
mode: 'production',
@ -37,6 +30,9 @@ const configuration: webpack.Configuration = {
output: {
path: webpackPaths.distMainPath,
filename: '[name].js',
library: {
type: 'umd',
},
},
optimization: {
@ -50,6 +46,7 @@ const configuration: webpack.Configuration = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
analyzerPort: 8888,
}),
/**
@ -66,6 +63,10 @@ const configuration: webpack.Configuration = {
DEBUG_PROD: false,
START_MINIMIZED: false,
}),
new webpack.DefinePlugin({
'process.type': '"browser"',
}),
],
/**

@ -24,6 +24,9 @@ const configuration: webpack.Configuration = {
output: {
path: webpackPaths.dllPath,
filename: 'preload.js',
library: {
type: 'umd',
},
},
plugins: [

@ -0,0 +1,77 @@
/**
* Builds the DLL for development electron renderer process
*/
import webpack from 'webpack';
import path from 'path';
import { merge } from 'webpack-merge';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import { dependencies } from '../../package.json';
import checkNodeEnv from '../scripts/check-node-env';
checkNodeEnv('development');
const dist = webpackPaths.dllPath;
const configuration: webpack.Configuration = {
context: webpackPaths.rootPath,
devtool: 'eval',
mode: 'development',
target: 'electron-renderer',
externals: ['fsevents', 'crypto-browserify'],
/**
* Use `module` from `webpack.config.renderer.dev.js`
*/
module: require('./webpack.config.renderer.dev').default.module,
entry: {
renderer: Object.keys(dependencies || {}),
},
output: {
path: dist,
filename: '[name].dev.dll.js',
library: {
name: 'renderer',
type: 'var',
},
},
plugins: [
new webpack.DllPlugin({
path: path.join(dist, '[name].json'),
name: '[name]',
}),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
options: {
context: webpackPaths.srcPath,
output: {
path: webpackPaths.dllPath,
},
},
}),
],
};
export default merge(baseConfig, configuration);

@ -1,21 +1,174 @@
import 'webpack-dev-server';
import type { Configuration } from 'webpack';
import { spawn } from 'child_process';
import { getWebTailchatWebpackConfig } from './utils';
import path from 'path';
import fs from 'fs';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import chalk from 'chalk';
import { merge } from 'webpack-merge';
import { execSync, spawn } from 'child_process';
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import checkNodeEnv from '../scripts/check-node-env';
require('dotenv').config();
// When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's
// at the dev webpack config is not accidentally run in a production environment
if (process.env.NODE_ENV === 'production') {
checkNodeEnv('development');
}
const port = process.env.PORT || 1212;
const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json');
const skipDLLs =
module.parent?.filename.includes('webpack.config.renderer.dev.dll') ||
module.parent?.filename.includes('webpack.config.eslint');
const webWebpackConfig = getWebTailchatWebpackConfig();
/**
* Warn if the DLL is not built
*/
if (
!skipDLLs &&
!(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest))
) {
console.log(
chalk.black.bgYellow.bold(
'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"'
)
);
execSync('npm run postinstall');
}
const configuration: webpack.Configuration = {
devtool: 'inline-source-map',
mode: 'development',
target: ['web', 'electron-renderer'],
const configuration: Configuration = {
...webWebpackConfig,
entry: [
`webpack-dev-server/client?http://localhost:${port}/dist`,
'webpack/hot/only-dev-server',
webWebpackConfig.entry?.['app'],
path.join(webpackPaths.srcRendererPath, 'index.tsx'),
],
output: {
path: webpackPaths.distRendererPath,
publicPath: '/',
filename: 'renderer.dev.js',
library: {
type: 'umd',
},
},
module: {
rules: [
{
test: /\.s?(c|a)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
},
},
'sass-loader',
],
include: /\.module\.s?(c|a)ss$/,
},
{
test: /\.s?css$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /\.module\.s?(c|a)ss$/,
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
// Images
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
// SVG
{
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
'file-loader',
],
},
],
},
plugins: [
...(skipDLLs
? []
: [
new webpack.DllReferencePlugin({
context: webpackPaths.dllPath,
manifest: require(manifest),
sourceType: 'var',
}),
]),
new webpack.NoEmitOnErrorsPlugin(),
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*
* By default, use 'development' as NODE_ENV. This can be overriden with
* 'staging', for example, by changing the ENV variables in the npm scripts
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'development',
}),
new webpack.LoaderOptionsPlugin({
debug: true,
}),
new ReactRefreshWebpackPlugin(),
new HtmlWebpackPlugin({
filename: path.join('index.html'),
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
},
isBrowser: false,
env: process.env.NODE_ENV,
isDevelopment: process.env.NODE_ENV !== 'production',
nodeModules: webpackPaths.appNodeModulesPath,
}),
],
node: {
__dirname: false,
__filename: false,
},
devServer: {
port,
compress: true,
@ -37,7 +190,13 @@ const configuration: Configuration = {
.on('error', (spawnError) => console.error(spawnError));
console.log('Starting Main Process...');
spawn('npm', ['run', 'start:main'], {
let args = ['run', 'start:main'];
if (process.env.MAIN_ARGS) {
args = args.concat(
['--', ...process.env.MAIN_ARGS.matchAll(/"[^"]+"|[^\s"]+/g)].flat()
);
}
spawn('npm', args, {
shell: true,
stdio: 'inherit',
})
@ -51,4 +210,4 @@ const configuration: Configuration = {
},
};
export default configuration;
export default merge(baseConfig, configuration);

@ -1,11 +1,141 @@
import type { Configuration } from 'webpack';
import { getWebTailchatWebpackConfig } from './utils';
/**
* Build config for electron renderer process
*/
const webWebpackConfig = getWebTailchatWebpackConfig();
import path from 'path';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import baseConfig from './webpack.config.base';
import webpackPaths from './webpack.paths';
import checkNodeEnv from '../scripts/check-node-env';
import deleteSourceMaps from '../scripts/delete-source-maps';
checkNodeEnv('production');
deleteSourceMaps();
const configuration: webpack.Configuration = {
devtool: 'source-map',
const configuration: Configuration = {
...webWebpackConfig,
mode: 'production',
target: ['web', 'electron-renderer'],
entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')],
output: {
path: webpackPaths.distRendererPath,
publicPath: './',
filename: 'renderer.js',
library: {
type: 'umd',
},
},
module: {
rules: [
{
test: /\.s?(a|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true,
importLoaders: 1,
},
},
'sass-loader',
],
include: /\.module\.s?(c|a)ss$/,
},
{
test: /\.s?(a|c)ss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
exclude: /\.module\.s?(c|a)ss$/,
},
// Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
// Images
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
// SVG
{
test: /\.svg$/,
use: [
{
loader: '@svgr/webpack',
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
'file-loader',
],
},
],
},
optimization: {
minimize: true,
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
},
plugins: [
/**
* Create global constants which can be configured at compile time.
*
* Useful for allowing different behaviour between development builds and
* release builds
*
* NODE_ENV should be production so that modules do not perform certain
* development checks
*/
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: false,
}),
new MiniCssExtractPlugin({
filename: 'style.css',
}),
new BundleAnalyzerPlugin({
analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled',
analyzerPort: 8889,
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.join(webpackPaths.srcRendererPath, 'index.ejs'),
minify: {
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
},
isBrowser: false,
isDevelopment: false,
}),
new webpack.DefinePlugin({
'process.type': '"renderer"',
}),
],
};
export default configuration;
export default merge(baseConfig, configuration);

@ -7,7 +7,6 @@ const dllPath = path.join(__dirname, '../dll');
const srcPath = path.join(rootPath, 'src');
const srcMainPath = path.join(srcPath, 'main');
const srcRendererPath = path.join(srcPath, 'renderer');
const srcPublicPath = path.join(rootPath, '../app/public');
const releasePath = path.join(rootPath, 'release');
const appPath = path.join(releasePath, 'app');
@ -18,7 +17,6 @@ const srcNodeModulesPath = path.join(srcPath, 'node_modules');
const distPath = path.join(appPath, 'dist');
const distMainPath = path.join(distPath, 'main');
const distRendererPath = path.join(distPath, 'renderer');
const distPublicPath = path.join(distRendererPath, 'public');
const buildPath = path.join(releasePath, 'build');
@ -37,6 +35,4 @@ export default {
distMainPath,
distRendererPath,
buildPath,
srcPublicPath,
distPublicPath,
};

@ -38,14 +38,13 @@
"build": "concurrently \"yarn build:main\" \"yarn build:renderer\"",
"build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
"build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps",
"postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts",
"lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx",
"package": "cross-env DEBUG_PROD=true yarn package:nodebug --config.asar=false",
"package:all": "yarn package:nodebug -mwl",
"package:nodebug": "ts-node ./.erb/scripts/clean.js dist && yarn build && electron-builder build --publish never",
"rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
"dev": "cross-env FE_URL=http://127.0.0.1:11011 SERVICE_URL=http://127.0.0.1:11000 yarn start",
"dev:nightly": "cross-env FE_URL=http://nightly.paw.msgbyte.com SERVICE_URL=https://tailchat-nightly.moonrailgun.com/ yarn start",
"dev": "yarn start",
"start": "ts-node ./.erb/scripts/check-port-in-use.js && yarn start:renderer",
"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only .",
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
@ -117,7 +116,6 @@
"electron-debug": "^3.2.0",
"electron-is": "^3.0.0",
"electron-log": "^4.4.7",
"electron-screenshots": "^0.5.15",
"electron-serve": "^1.1.0",
"electron-updater": "^5.0.1",
"electron-window-state": "^5.0.3",
@ -126,7 +124,6 @@
"lodash": "^4.17.21",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-router-dom": "^6.3.0",
"source-ref-loader": "^1.0.7"
},
"devDependencies": {
@ -205,6 +202,7 @@
"ts-jest": "27.1.4",
"ts-loader": "^9.3.0",
"ts-node": "^10.7.0",
"tsconfig-paths-webpack-plugin": "^4.0.1",
"typescript": "^4.6.4",
"url": "^0.11.0",
"url-loader": "^4.1.1",

@ -14,5 +14,7 @@
"postinstall": "npm run electron-rebuild && npm run link-modules",
"link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts"
},
"dependencies": {}
"dependencies": {
"electron-screenshots": "^0.5.23"
}
}

@ -2,3 +2,111 @@
# yarn lockfile v1
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
electron-screenshots@^0.5.23:
version "0.5.23"
resolved "https://registry.npmmirror.com/electron-screenshots/-/electron-screenshots-0.5.23.tgz#4d0b8ff8dee31033faf8b8680f3ff93d88d5df47"
integrity sha512-mcBDauRdKyuUOPX64inJwbBsbmFbmszDB0qlcc5ofO1q/SugiAvagVrajcK9jl9DWJwO4tVFDgqXJDHG6U//yA==
dependencies:
debug "^4.3.4"
fs-extra "^11.1.1"
node-screenshots "^0.1.4"
react-screenshots "^0.5.22"
fs-extra@^11.1.1:
version "11.1.1"
resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.11"
resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
ms@2.1.2:
version "2.1.2"
resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
node-screenshots-darwin-arm64@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-darwin-arm64/-/node-screenshots-darwin-arm64-0.1.4.tgz#434e181156c235b7e41682de164732d2fbd8499c"
integrity sha512-PN9hy1Dd+vvRU6sol/sNBu1+XZ0VoUkZ1nWClmSjwLlwGYe2L5xNBnG1OTiiZeNCueBlyf/0k0vI5hognH/LVA==
node-screenshots-darwin-universal@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-darwin-universal/-/node-screenshots-darwin-universal-0.1.4.tgz#93a9ce4b707f2e15114b75c67c89da7a030caa35"
integrity sha512-xYZrTyVI+8gWXr3mmhcvqUyv8lwWLruhNgE8ClhX+1y6rP8LKoZ5QohBuTPEtIo0oC0y0EETbBnHW/5IkRlijg==
node-screenshots-darwin-x64@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-darwin-x64/-/node-screenshots-darwin-x64-0.1.4.tgz#5cff721d174d0b3b2f430c331012ad27ca852284"
integrity sha512-JDWSC7pmph7RN7SnJeXwwzKHk1anMk3cqskgT47h1t4Hu3tN1a0sKfKagglRaI9Y2IoDfBTLSZxNNwyCZag5iQ==
node-screenshots-linux-x64-gnu@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-linux-x64-gnu/-/node-screenshots-linux-x64-gnu-0.1.4.tgz#77cc54ddfff941f34db61ad0aba0e3603e2e2937"
integrity sha512-oj39sWl9Xe8wGmHeUoAwLSN+0186XJrmVojOSEovBLCY2teUSHNPOq8D52z67mPv7S4bNHilj5b52jz9nl31/Q==
node-screenshots-linux-x64-musl@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-linux-x64-musl/-/node-screenshots-linux-x64-musl-0.1.4.tgz#cc558db789d44a8fda7274b82f34e2ffb77c8b83"
integrity sha512-eHRC6BobZPRbyj01VIiaK84kg4plSGBSPYYSo4ObFzrFmD3dRaUgTfsACoi8th0XiNd25w6/FyAIKKGU5M8IPg==
node-screenshots-win32-arm64-msvc@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-win32-arm64-msvc/-/node-screenshots-win32-arm64-msvc-0.1.4.tgz#a61c6d1f86761b24fdd379b8cd6249e2a2bda056"
integrity sha512-BgwLbAQwvnv+T0W47Dq9Pd7/IKTMRCie3ECW6aLG3jqsPhKMqXac8lyrJbaYR88lxlKWraWxREkb1sx6gQaUlA==
node-screenshots-win32-ia32-msvc@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-win32-ia32-msvc/-/node-screenshots-win32-ia32-msvc-0.1.4.tgz#17809fd941fc822dcdffaa9312f95782f4f275b1"
integrity sha512-afZqWWbfZ3nChI8eeZ93J7bn5096Zq+NRutvqNZhBYLAGZd+hCWqcDumTgJ74oUMVi49Cn06isXxj+MB3RtUDQ==
node-screenshots-win32-x64-msvc@0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots-win32-x64-msvc/-/node-screenshots-win32-x64-msvc-0.1.4.tgz#325df877896dd0533e63c90f0d8436e2c11a43e5"
integrity sha512-08mfx/6veDKrdx0KDVMqnYjZq0U4LIbezIKBIgI06Bj+S8CrgXBvTQTEu+lsL/PZMK+J9yimI2Bp77h2AqhaiQ==
node-screenshots@^0.1.4:
version "0.1.4"
resolved "https://registry.npmmirror.com/node-screenshots/-/node-screenshots-0.1.4.tgz#ec6c7626aaea9afc2bd78ad379dd9feeb13cd6c8"
integrity sha512-QmbgiI0VkV3wu+Dn7Kn107/VnujdFgT3juDdaRv2GyOviVghP3+QD46IVU/IlXmzgxVFTjIiVBRrI6yovDnXiQ==
optionalDependencies:
node-screenshots-darwin-arm64 "0.1.4"
node-screenshots-darwin-universal "0.1.4"
node-screenshots-darwin-x64 "0.1.4"
node-screenshots-linux-x64-gnu "0.1.4"
node-screenshots-linux-x64-musl "0.1.4"
node-screenshots-win32-arm64-msvc "0.1.4"
node-screenshots-win32-ia32-msvc "0.1.4"
node-screenshots-win32-x64-msvc "0.1.4"
react-screenshots@^0.5.22:
version "0.5.22"
resolved "https://registry.npmmirror.com/react-screenshots/-/react-screenshots-0.5.22.tgz#2d974189d2d2df74388a4a19482fd1c956641837"
integrity sha512-aooIlb1k6161BTqhhyADlMrlF0n1UdudjuhyvXaCQfwURXZNuUerMxFuOfwNCgSbPAHlxdHCWtYQ6iQT+RaF+w==
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

@ -13,7 +13,7 @@ import { app, BrowserWindow, shell, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { getMainWindowUrl } from './util';
import { resolveHtmlPath } from './util';
import windowStateKeeper from 'electron-window-state';
import is from 'electron-is';
import { initScreenshots } from './screenshots';
@ -73,8 +73,54 @@ const installExtensions = async () => {
.catch(console.log);
};
const webPreferences: Electron.WebPreferences = {
nodeIntegration: false,
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
};
let welcomeWindow: BrowserWindow | null = null;
let mainWindow: BrowserWindow | null = null;
const createWindow = async () => {
const createWelcomeWindow = async () => {
// 创建一个新的浏览器窗口
welcomeWindow = new BrowserWindow({
width: 800,
height: 600,
frame: false,
webPreferences,
});
// 加载欢迎窗口的HTML文件
welcomeWindow.loadURL(resolveHtmlPath('index.html'));
// 监听从渲染进程发送的选择用户事件
// welcomeWindow.webContents.on('selectUser', (event, user) => {
// selectedUser = user;
// welcomeWindow.close(); // 关闭欢迎窗口
// createMainWindow(); // 创建主窗口
// });
welcomeWindow.webContents.on('ipc-message', (e, channel, data) => {
if (channel === 'close') {
welcomeWindow?.close();
} else if (channel === 'selectServer') {
console.log(data);
const url = data.url;
createMainWindow(url).then(() => {
welcomeWindow?.close();
});
}
});
welcomeWindow.on('closed', () => {
welcomeWindow = null;
});
};
const createMainWindow = async (url: string) => {
try {
log.info('Create window');
@ -92,7 +138,7 @@ const createWindow = async () => {
defaultWidth: 1200,
defaultHeight: 800,
});
log.info('load window state with:', mainWindow);
log.info('load window state with:', mainWindowState);
const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
@ -104,32 +150,10 @@ const createWindow = async () => {
height: mainWindowState.height,
width: mainWindowState.width,
icon: getAssetPath('icon.png'),
webPreferences: {
nodeIntegration: false,
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
});
// 方案一: 通过文件协议加载界面
// const url = resolveHtmlPath('index.html');
// log.info('loadUrl:', url);
// mainWindow.loadURL(url);
// 方案二: 通过本地起一个http代理服务然后electron访问http服务
// log.info('Starting Local Http Server');
// const url = await getMainWindowUrl();
// log.info('Local Server started, entry:', url);
// 方案三: 直接访问远程服务
log.info('Start with remote server', {
FE_URL: process.env.FE_URL,
SERVICE_URL: process.env.SERVICE_URL,
webPreferences,
});
const url = process.env.FE_URL || process.env.SERVICE_URL;
mainWindow.loadURL(url as string);
mainWindow.loadURL(url);
/**
*
@ -209,14 +233,14 @@ app.on('window-all-closed', () => {
app
.whenReady()
.then(() => {
createWindow();
createWelcomeWindow();
initScreenshots();
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
if (welcomeWindow === null && mainWindow === null) {
createWelcomeWindow();
}
});
})

@ -5,7 +5,11 @@ import {
webFrame,
} from 'electron';
export type Channels = 'ipc-example' | 'webview-message';
export type Channels =
| 'ipc-example'
| 'webview-message'
| 'close'
| 'selectServer';
contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {

@ -1,40 +1,16 @@
import log from 'electron-log';
import { URL } from 'url';
import path from 'path';
import is from 'electron-is';
import { startLocalServer } from './lib/http';
import getPort, { makeRange } from 'get-port';
import log from 'electron-log';
export let resolveHtmlPath: (htmlFileName: string) => string;
if (process.env.NODE_ENV === 'development') {
const port = process.env.PORT || 1212;
resolveHtmlPath = (htmlFileName: string) => {
export function resolveHtmlPath(htmlFileName: string) {
if (process.env.NODE_ENV === 'development') {
const port = process.env.PORT || 1212;
const url = new URL(`http://localhost:${port}`);
url.pathname = htmlFileName;
return url.href;
};
} else {
resolveHtmlPath = (htmlFileName: string) => {
return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
};
}
/**
*
*/
export async function getMainWindowUrl() {
if (is.dev()) {
const port = process.env.PORT || 1212;
return `http://localhost:${port}/index.html`;
} else {
const port = await getPort({
port: makeRange(11000, 20000), // 使用高位端口
});
await startLocalServer(path.resolve(__dirname, '../renderer/'), port);
return `http://localhost:${port}/index.html`;
}
return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
}
export function getDefaultLoggerPath(): string {

@ -42,16 +42,8 @@ li {
list-style: none;
}
a {
text-decoration: none;
height: fit-content;
width: fit-content;
margin: 10px;
}
a:hover {
opacity: 1;
text-decoration: none;
button + button {
margin-left: 10px;
}
.Hello {

@ -1,4 +1,3 @@
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
import icon from '../../assets/icon.svg';
import './App.css';
@ -6,45 +5,44 @@ const Hello = () => {
return (
<div>
<div className="Hello">
<img width="200px" alt="icon" src={icon} />
<img width="60px" alt="icon" src={icon} />
<h1>Tailchat</h1>
</div>
<div>
<button
type="button"
onClick={() => {
window.electron.ipcRenderer.sendMessage('selectServer', {
url: 'https://nightly.paw.msgbyte.com/',
});
}}
>
Nightly
</button>
</div>
<h1>electron-react-boilerplate</h1>
<div className="Hello">
<a
href="https://electron-react-boilerplate.js.org/"
target="_blank"
rel="noreferrer"
<button
type="button"
onClick={() => {
window.open('https://tailchat.msgbyte.com/');
}}
>
<button type="button">
<span role="img" aria-label="books">
📚
</span>
Read our docs
</button>
</a>
<a
href="https://github.com/sponsors/electron-react-boilerplate"
target="_blank"
rel="noreferrer"
Learn More
</button>
<button
type="button"
onClick={() => {
window.electron.ipcRenderer.sendMessage('close');
}}
>
<button type="button">
<span role="img" aria-label="books">
🙏
</span>
Donate
</button>
</a>
Exit
</button>
</div>
</div>
);
};
export default function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Hello />} />
</Routes>
</Router>
);
return <Hello />;
}

@ -9,6 +9,6 @@
<title>Tailchat</title>
</head>
<body>
<div id="tailchat"></div>
<div id="root"></div>
</body>
</html>

@ -1,15 +1,13 @@
import '../../../web/src/index';
import { createRoot } from 'react-dom/client';
import App from './App';
// import { createRoot } from 'react-dom/client';
// import App from './App';
const container = document.getElementById('root') as HTMLElement;
const root = createRoot(container);
root.render(<App />);
// const container = document.getElementById('root')!;
// const root = createRoot(container);
// root.render(<App />);
// // calling IPC exposed from preload script
// window.electron.ipcRenderer.once('ipc-example', (arg) => {
// // eslint-disable-next-line no-console
// console.log(arg);
// });
// window.electron.ipcRenderer.sendMessage('ipc-example', ['ping']);
// calling IPC exposed from preload script
window.electron.ipcRenderer.once('ipc-example', (arg) => {
// eslint-disable-next-line no-console
console.log(arg);
});
window.electron.ipcRenderer.sendMessage('ipc-example', ['ping']);

@ -4,7 +4,7 @@ declare global {
interface Window {
electron: {
ipcRenderer: {
sendMessage(channel: Channels, args: unknown[]): void;
sendMessage(channel: Channels, ...args: unknown[]): void;
on(
channel: string,
func: (...args: unknown[]) => void

@ -1132,7 +1132,7 @@
core-js-pure "^3.20.2"
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.18.3"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4"
integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==
@ -4833,16 +4833,6 @@ electron-rebuild@^3.2.7:
tar "^6.0.5"
yargs "^17.0.1"
electron-screenshots@^0.5.15:
version "0.5.15"
resolved "https://registry.npmmirror.com/electron-screenshots/-/electron-screenshots-0.5.15.tgz#3800127da5442a3421ec18aa5df38553da75e618"
integrity sha512-93iFLCaLWnMCWzHXahk0rUkmbAebJEO3+AlntMwBrxURqZ4m7Hm/d8Z1Em92NMQtPeX44B+96gWknLOiLCzYOQ==
dependencies:
debug "^4.3.3"
fs-extra "^10.1.0"
node-screenshots "^0.1.1"
react-screenshots "^0.5.15"
electron-serve@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/electron-serve/-/electron-serve-1.1.0.tgz#507f56c8512c501880d3a9bec792fa92512af378"
@ -4978,6 +4968,14 @@ enhanced-resolve@^5.0.0, enhanced-resolve@^5.9.3:
graceful-fs "^4.2.4"
tapable "^2.2.0"
enhanced-resolve@^5.7.0:
version "5.15.0"
resolved "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"
entities@^2.0.0:
version "2.2.0"
resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
@ -5940,7 +5938,7 @@ fresh@0.5.2:
resolved "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
fs-extra@^10.0.0, fs-extra@^10.1.0:
fs-extra@^10.0.0:
version "10.1.0"
resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
@ -6350,13 +6348,6 @@ hex-color-regex@^1.1.0:
resolved "https://registry.npmmirror.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
history@^5.2.0:
version "5.3.0"
resolved "https://registry.npmmirror.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
dependencies:
"@babel/runtime" "^7.7.6"
hmac-drbg@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@ -8338,54 +8329,6 @@ node-releases@^2.0.8:
resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f"
integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==
node-screenshots-darwin-arm64@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-darwin-arm64/-/node-screenshots-darwin-arm64-0.1.1.tgz#d581cfb26b9ac7168a9568055c02f76c97831854"
integrity sha512-ECseBNybDcl5W8hMNo35gLqob7DJIcGQAYrCMvP7wrthQT6WLlynrkJCfPWHXjHM821huvoFfgVr00od0GTZRA==
node-screenshots-darwin-x64@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-darwin-x64/-/node-screenshots-darwin-x64-0.1.1.tgz#fb4bc3d890c8a6ef2377d2e0e893945b8892cce6"
integrity sha512-Ah8z6V8xQhmLyem7UnTWyOAGONJVklSLDnggUIXpIxZ9ecsbD0083bl2K+Cx/fLzP8akKRJ4s6domssgCKgJRg==
node-screenshots-linux-x64-gnu@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-linux-x64-gnu/-/node-screenshots-linux-x64-gnu-0.1.1.tgz#2b5d58eaba5a4b8f17c8d7531b86c583e815bd1f"
integrity sha512-K/cd3ZdN1wO/6gTImOkougROrPkbI/6Inn152x3ZiQgxbZ4a7n75fq+wRRonSh7YzGPdBvvSPGRwDtXK9Da8Ew==
node-screenshots-linux-x64-musl@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-linux-x64-musl/-/node-screenshots-linux-x64-musl-0.1.1.tgz#3bf37e1b499f046a122a283d08289231c3ec648c"
integrity sha512-Ag++DSXrOkf1fvjaHjlTHJzKhpCV66L4/9zTQJgeLfZkJIlgegdmH/35kXvOzKPUcjzAb+GDeDOkbO6/VgfIEA==
node-screenshots-win32-arm64-msvc@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-win32-arm64-msvc/-/node-screenshots-win32-arm64-msvc-0.1.1.tgz#7206ac99d243769173bd6593fbd56520e08c2e2e"
integrity sha512-hB5Cm0s0SoaN6RmmRzoBN9A7PGnVqGSfx2qnOclG351N4YRQf9uU0pgDcZMVzPfi6mzHlx/VRsJOwtQgXVKOFg==
node-screenshots-win32-ia32-msvc@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-win32-ia32-msvc/-/node-screenshots-win32-ia32-msvc-0.1.1.tgz#fac73f6b79f4381f41a8ab8696b993950096bbb1"
integrity sha512-4nRBAlkNrKvJ7AIQC2lBZykju9lzX/VGYhffVcMpPvgY5d/S67ir2aME/KsXTDFbWclzxU8grlvL9Tx14s8q/w==
node-screenshots-win32-x64-msvc@0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots-win32-x64-msvc/-/node-screenshots-win32-x64-msvc-0.1.1.tgz#7e5a7a1339c7fe4fce9370e74eed38de92fa951b"
integrity sha512-yI1Yf4HZTE+mtLZKsM9gFfrf/MsCywAQ5o/Xmd0uovdtt3IYRxc/QUatxbUQyl7mWX/TRJlj4ihIET4/rFRY5Q==
node-screenshots@^0.1.1:
version "0.1.1"
resolved "https://registry.npmmirror.com/node-screenshots/-/node-screenshots-0.1.1.tgz#6556f0710fb00b79bed5474844e3ac24791f2dbf"
integrity sha512-XhteRLrlrpzMo1ZxaxkQ8URo6vqtqLRy3GVzVEWupYrZYUFgC7tBAC9kqemxXvugtS5ufYqqdyoLhHcWhKLvOQ==
optionalDependencies:
node-screenshots-darwin-arm64 "0.1.1"
node-screenshots-darwin-x64 "0.1.1"
node-screenshots-linux-x64-gnu "0.1.1"
node-screenshots-linux-x64-musl "0.1.1"
node-screenshots-win32-arm64-msvc "0.1.1"
node-screenshots-win32-ia32-msvc "0.1.1"
node-screenshots-win32-x64-msvc "0.1.1"
nopt@^5.0.0:
version "5.0.0"
resolved "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
@ -9408,26 +9351,6 @@ react-refresh@^0.13.0:
resolved "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.13.0.tgz#cbd01a4482a177a5da8d44c9755ebb1f26d5a1c1"
integrity sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==
react-router-dom@^6.3.0:
version "6.3.0"
resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==
dependencies:
history "^5.2.0"
react-router "6.3.0"
react-router@6.3.0:
version "6.3.0"
resolved "https://registry.npmmirror.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
dependencies:
history "^5.2.0"
react-screenshots@^0.5.15:
version "0.5.15"
resolved "https://registry.npmmirror.com/react-screenshots/-/react-screenshots-0.5.15.tgz#0599fbdfdcb6392ddea718be208ab82238fb8ee6"
integrity sha512-HbaVXzlM4l4Vl/NgJ25sD2C0hdOMeDTFBzLqLRBFA5GF0ds1+rU3NWkVOTpvnuydD3qC/saCOd79a+MxubGgYQ==
react-shallow-renderer@^16.15.0:
version "16.15.0"
resolved "https://registry.npmmirror.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457"
@ -10735,6 +10658,15 @@ ts-node@^10.7.0:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
tsconfig-paths-webpack-plugin@^4.0.1:
version "4.0.1"
resolved "https://registry.npmmirror.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.1.tgz#a24651d0f69668a1abad38d3c2489855c257460d"
integrity sha512-m5//KzLoKmqu2MVix+dgLKq70MnFi8YL8sdzQZ6DblmCdfuq/y3OqvJd5vMndg2KEVCOeNz8Es4WVZhYInteLw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.7.0"
tsconfig-paths "^4.1.2"
tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
@ -10745,6 +10677,15 @@ tsconfig-paths@^3.14.1:
minimist "^1.2.6"
strip-bom "^3.0.0"
tsconfig-paths@^4.1.2:
version "4.2.0"
resolved "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c"
integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==
dependencies:
json5 "^2.2.2"
minimist "^1.2.6"
strip-bom "^3.0.0"
tslib@^1.8.1:
version "1.14.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"

Loading…
Cancel
Save