mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2025-05-02 06:26:22 -04:00
chore(dev): app boilerplate
Electron, React, Vite app boilerplate - license header - pre-commit and commit-msg hooks - storybook - fix windows tests; - fix linux build - CI setup - persistent store with electron-store and safeStorage - localization with react-intl Refs: - https://github.com/haveno-dex/haveno-ui/projects/1#card-81001746 - https://github.com/haveno-dex/haveno-ui/projects/1#card-81001745 Authored-by: schowdhuri Reviewed-by: localredhead
This commit is contained in:
parent
3a379a7c55
commit
a9893aa853
81 changed files with 16560 additions and 0 deletions
117
scripts/license.js
Normal file
117
scripts/license.js
Normal file
|
@ -0,0 +1,117 @@
|
|||
// =============================================================================
|
||||
// Copyright 2022 Haveno
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
const glob = require("glob");
|
||||
const fsPromise = require("fs/promises");
|
||||
|
||||
const DIVIDER = "=".repeat(77);
|
||||
|
||||
/**
|
||||
* Returns the list of source files which require a license header
|
||||
* @param {number} year - Copyright year
|
||||
* @param {string} owner - Copyright owner
|
||||
* @returns {string}
|
||||
*/
|
||||
const fnLicense = (year, owner) =>
|
||||
`// ${DIVIDER}
|
||||
Copyright ${year} ${owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
${DIVIDER}`
|
||||
.replace(/\n/g, "\n// ")
|
||||
.replace(/ +\n/g, "\n");
|
||||
|
||||
async function main() {
|
||||
console.log("Checking copyright headers...");
|
||||
const licenseHeader = fnLicense(new Date().getFullYear(), "Haveno");
|
||||
const files = await getFiles([
|
||||
"{packages,scripts,tests,types,.storybook}/**/*.{js,jsx,ts,tsx}",
|
||||
"*.{js,ts,mjs}",
|
||||
]);
|
||||
await Promise.all(
|
||||
files.map(async (file) => {
|
||||
let contents = (await fsPromise.readFile(file)).toString("utf-8");
|
||||
if (contents.startsWith(licenseHeader)) {
|
||||
// license exists
|
||||
return;
|
||||
}
|
||||
if (contents.startsWith("#!")) {
|
||||
// script; skip
|
||||
return;
|
||||
}
|
||||
const lines = contents.split("\n");
|
||||
const index = lines.findIndex((line) =>
|
||||
/\/\/ {2}Copyright (\d{4}) (.+)/.test(line)
|
||||
);
|
||||
if (index === 1) {
|
||||
// if the copyright is on line #2
|
||||
// remove the header
|
||||
while (lines[0].startsWith("//")) {
|
||||
lines.shift();
|
||||
}
|
||||
console.log("updating the license header in", file);
|
||||
contents = `${licenseHeader}\n${lines.join("\n")}`;
|
||||
} else {
|
||||
console.log("adding license header to", file);
|
||||
contents = `${licenseHeader}\n\n${contents}`;
|
||||
}
|
||||
await fsPromise.writeFile(file, contents);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of source files which require a license header
|
||||
* @param {Array<string>} patterns - glob patterns
|
||||
* @return {Promise<Array<string>>}
|
||||
*/
|
||||
async function getFiles(patterns) {
|
||||
const files = new Set();
|
||||
await Promise.all(
|
||||
patterns.map(
|
||||
(pattern) =>
|
||||
new Promise((resolve, reject) => {
|
||||
glob(
|
||||
pattern,
|
||||
{
|
||||
dot: true,
|
||||
ignore: ["**/dist/**/*"],
|
||||
},
|
||||
(err, paths) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
paths.map((path) => files.add(path));
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
return [...files];
|
||||
}
|
||||
|
||||
main();
|
69
scripts/update-electron-vendors.js
Normal file
69
scripts/update-electron-vendors.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
// =============================================================================
|
||||
// Copyright 2022 Haveno
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
const { writeFile } = require("fs/promises");
|
||||
const { execSync } = require("child_process");
|
||||
const electron = require("electron");
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
* Returns versions of electron vendors
|
||||
* The performance of this feature is very poor and can be improved
|
||||
* @see https://github.com/electron/electron/issues/28006
|
||||
*
|
||||
* @returns {NodeJS.ProcessVersions}
|
||||
*/
|
||||
function getVendors() {
|
||||
const output = execSync(`${electron} -p "JSON.stringify(process.versions)"`, {
|
||||
env: { ELECTRON_RUN_AS_NODE: "1" },
|
||||
encoding: "utf-8",
|
||||
});
|
||||
|
||||
return JSON.parse(output);
|
||||
}
|
||||
|
||||
function updateVendors() {
|
||||
const electronRelease = getVendors();
|
||||
|
||||
const nodeMajorVersion = electronRelease.node.split(".")[0];
|
||||
const chromeMajorVersion = electronRelease.v8
|
||||
.split(".")
|
||||
.splice(0, 2)
|
||||
.join("");
|
||||
|
||||
const browserslistrcPath = path.resolve(process.cwd(), ".browserslistrc");
|
||||
|
||||
return Promise.all([
|
||||
writeFile(
|
||||
"./.electron-vendors.cache.json",
|
||||
JSON.stringify(
|
||||
{
|
||||
chrome: chromeMajorVersion,
|
||||
node: nodeMajorVersion,
|
||||
},
|
||||
null,
|
||||
2
|
||||
) + "\n"
|
||||
),
|
||||
|
||||
writeFile(browserslistrcPath, `Chrome ${chromeMajorVersion}\n`, "utf8"),
|
||||
]);
|
||||
}
|
||||
|
||||
updateVendors().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
123
scripts/watch.js
Normal file
123
scripts/watch.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const { createServer, build, createLogger } = require("vite");
|
||||
const electronPath = require("electron");
|
||||
const { spawn } = require("child_process");
|
||||
|
||||
/** @type 'production' | 'development'' */
|
||||
const mode = (process.env.MODE = process.env.MODE || "development");
|
||||
|
||||
/** @type {import('vite').LogLevel} */
|
||||
const LOG_LEVEL = "info";
|
||||
|
||||
/** @type {import('vite').InlineConfig} */
|
||||
const sharedConfig = {
|
||||
mode,
|
||||
build: {
|
||||
watch: {},
|
||||
},
|
||||
logLevel: LOG_LEVEL,
|
||||
};
|
||||
|
||||
/** Messages on stderr that match any of the contained patterns will be stripped from output */
|
||||
const stderrFilterPatterns = [
|
||||
// warning about devtools extension
|
||||
// https://github.com/cawa-93/vite-electron-builder/issues/492
|
||||
// https://github.com/MarshallOfSound/electron-devtools-installer/issues/143
|
||||
/ExtensionLoadWarning/,
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {{name: string; configFile: string; writeBundle: import('rollup').OutputPlugin['writeBundle'] }} param0
|
||||
*/
|
||||
const getWatcher = ({ name, configFile, writeBundle }) => {
|
||||
return build({
|
||||
...sharedConfig,
|
||||
configFile,
|
||||
plugins: [{ name, writeBundle }],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start or restart App when source files are changed
|
||||
* @param {{config: {server: import('vite').ResolvedServerOptions}}} ResolvedServerOptions
|
||||
*/
|
||||
const setupMainPackageWatcher = ({ config: { server } }) => {
|
||||
// Create VITE_DEV_SERVER_URL environment variable to pass it to the main process.
|
||||
{
|
||||
const protocol = server.https ? "https:" : "http:";
|
||||
const host = server.host || "localhost";
|
||||
const port = server.port; // Vite searches for and occupies the first free port: 3000, 3001, 3002 and so on
|
||||
const path = "/";
|
||||
process.env.VITE_DEV_SERVER_URL = `${protocol}//${host}:${port}${path}`;
|
||||
}
|
||||
|
||||
const logger = createLogger(LOG_LEVEL, {
|
||||
prefix: "[main]",
|
||||
});
|
||||
|
||||
/** @type {ChildProcessWithoutNullStreams | null} */
|
||||
let spawnProcess = null;
|
||||
|
||||
return getWatcher({
|
||||
name: "reload-app-on-main-package-change",
|
||||
configFile: "packages/main/vite.config.js",
|
||||
writeBundle() {
|
||||
if (spawnProcess !== null) {
|
||||
spawnProcess.off("exit", process.exit);
|
||||
spawnProcess.kill("SIGINT");
|
||||
spawnProcess = null;
|
||||
}
|
||||
|
||||
spawnProcess = spawn(String(electronPath), ["."]);
|
||||
|
||||
spawnProcess.stdout.on(
|
||||
"data",
|
||||
(d) =>
|
||||
d.toString().trim() && logger.warn(d.toString(), { timestamp: true })
|
||||
);
|
||||
spawnProcess.stderr.on("data", (d) => {
|
||||
const data = d.toString().trim();
|
||||
if (!data) return;
|
||||
const mayIgnore = stderrFilterPatterns.some((r) => r.test(data));
|
||||
if (mayIgnore) return;
|
||||
logger.error(data, { timestamp: true });
|
||||
});
|
||||
|
||||
// Stops the watch script when the application has been quit
|
||||
spawnProcess.on("exit", process.exit);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Start or restart App when source files are changed
|
||||
* @param {{ws: import('vite').WebSocketServer}} WebSocketServer
|
||||
*/
|
||||
const setupPreloadPackageWatcher = ({ ws }) =>
|
||||
getWatcher({
|
||||
name: "reload-page-on-preload-package-change",
|
||||
configFile: "packages/preload/vite.config.js",
|
||||
writeBundle() {
|
||||
ws.send({
|
||||
type: "full-reload",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const viteDevServer = await createServer({
|
||||
...sharedConfig,
|
||||
configFile: "packages/renderer/vite.config.js",
|
||||
});
|
||||
|
||||
await viteDevServer.listen();
|
||||
|
||||
await setupPreloadPackageWatcher(viteDevServer);
|
||||
await setupMainPackageWatcher(viteDevServer);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
Loading…
Add table
Add a link
Reference in a new issue