mirror of
https://github.com/frappe/books.git
synced 2024-11-09 15:20:56 +00:00
build: create app protocol
- add a build script (wip not yet packaged)
This commit is contained in:
parent
dde007dd09
commit
8df735d76f
79
build/scripts/build.mjs
Normal file
79
build/scripts/build.mjs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
import esbuild from 'esbuild';
|
||||||
|
import { $ } from 'execa';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import * as vite from 'vite';
|
||||||
|
import { getMainProcessCommonConfig } from './helpers.mjs';
|
||||||
|
|
||||||
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const root = path.join(dirname, '..', '..');
|
||||||
|
|
||||||
|
const $$ = $({ stdio: 'inherit' });
|
||||||
|
await $$`rm -rf ${path.join(root, 'dist_electron', 'build')}`;
|
||||||
|
|
||||||
|
await buildMainProcessSource();
|
||||||
|
await buildRendererProcessSource();
|
||||||
|
|
||||||
|
async function buildMainProcessSource() {
|
||||||
|
const commonConfig = getMainProcessCommonConfig(root);
|
||||||
|
const result = await esbuild.build({
|
||||||
|
...commonConfig,
|
||||||
|
outfile: path.join(root, 'dist_electron', 'build', 'main.js'),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.errors.length) {
|
||||||
|
console.error('app build failed due to main process source build');
|
||||||
|
result.errors.forEach((err) => console.error(err));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildRendererProcessSource() {
|
||||||
|
const base = 'app://';
|
||||||
|
const outDir = path.join(root, 'dist_electron', 'build', 'src');
|
||||||
|
await vite.build({
|
||||||
|
base: `/${base}`,
|
||||||
|
root: path.join(root, 'src'),
|
||||||
|
build: { outDir },
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
vue: 'vue/dist/vue.esm-bundler.js',
|
||||||
|
fyo: path.join(root, 'fyo'),
|
||||||
|
src: path.join(root, 'src'),
|
||||||
|
schemas: path.join(root, 'schemas'),
|
||||||
|
backend: path.join(root, 'backend'),
|
||||||
|
models: path.join(root, 'models'),
|
||||||
|
utils: path.join(root, 'utils'),
|
||||||
|
regional: path.join(root, 'regional'),
|
||||||
|
reports: path.join(root, 'reports'),
|
||||||
|
dummy: path.join(root, 'dummy'),
|
||||||
|
fixtures: path.join(root, 'fixtures'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
removeBaseLeadingSlash(outDir, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes leading slash from all renderer files
|
||||||
|
* electron uses a custom registered protocol to load the
|
||||||
|
* files: "app://"
|
||||||
|
*
|
||||||
|
* @param {string} dir
|
||||||
|
* @param {string} base
|
||||||
|
*/
|
||||||
|
function removeBaseLeadingSlash(dir, base) {
|
||||||
|
for (const file of fs.readdirSync(dir)) {
|
||||||
|
const filePath = path.join(dir, file);
|
||||||
|
if (fs.lstatSync(filePath).isDirectory()) {
|
||||||
|
removeBaseLeadingSlash(filePath, base);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contents = fs.readFileSync(filePath).toString('utf-8');
|
||||||
|
fs.writeFileSync(filePath, contents.replaceAll('/' + base, base));
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ import esbuild from 'esbuild';
|
|||||||
import { $ } from 'execa';
|
import { $ } from 'execa';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { excludeVendorFromSourceMap } from './plugins.mjs';
|
import { getMainProcessCommonConfig } from './helpers.mjs';
|
||||||
|
|
||||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
||||||
process.env['NODE_ENV'] = 'development';
|
process.env['NODE_ENV'] = 'development';
|
||||||
@ -45,16 +45,8 @@ if (!process.argv.includes('--no-renderer')) {
|
|||||||
* to [re]build the main process code
|
* to [re]build the main process code
|
||||||
*/
|
*/
|
||||||
const ctx = await esbuild.context({
|
const ctx = await esbuild.context({
|
||||||
entryPoints: [path.join(root, 'main.ts')],
|
...getMainProcessCommonConfig(root),
|
||||||
bundle: true,
|
outfile: path.join(root, 'dist_electron', 'dev', 'main.js'),
|
||||||
sourcemap: true,
|
|
||||||
sourcesContent: false,
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node16',
|
|
||||||
outfile: path.join(root, 'dist', 'dev', 'main.js'),
|
|
||||||
external: ['knex', 'electron', 'better-sqlite3'],
|
|
||||||
plugins: [excludeVendorFromSourceMap],
|
|
||||||
write: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,7 +127,7 @@ async function handleResult(result) {
|
|||||||
function runElectron() {
|
function runElectron() {
|
||||||
const electronProcess = $$`npx electron --inspect=5858 ${path.join(
|
const electronProcess = $$`npx electron --inspect=5858 ${path.join(
|
||||||
root,
|
root,
|
||||||
'dist',
|
'dist_electron',
|
||||||
'dev',
|
'dev',
|
||||||
'main.js'
|
'main.js'
|
||||||
)}`;
|
)}`;
|
||||||
|
51
build/scripts/helpers.mjs
Normal file
51
build/scripts/helpers.mjs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common ESBuild config used for building main process source
|
||||||
|
* code for both dev and production.
|
||||||
|
*
|
||||||
|
* @param {string} root
|
||||||
|
* @returns {import('esbuild').BuildOptions}
|
||||||
|
*/
|
||||||
|
export function getMainProcessCommonConfig(root) {
|
||||||
|
return {
|
||||||
|
entryPoints: [path.join(root, 'main.ts')],
|
||||||
|
bundle: true,
|
||||||
|
sourcemap: true,
|
||||||
|
sourcesContent: false,
|
||||||
|
platform: 'node',
|
||||||
|
target: 'node16',
|
||||||
|
external: ['knex', 'electron', 'better-sqlite3'],
|
||||||
|
plugins: [excludeVendorFromSourceMap],
|
||||||
|
write: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ESBuild plugin used to prevent source maps from being generated for
|
||||||
|
* packages inside node_modules, only first-party code source maps
|
||||||
|
* are to be included.
|
||||||
|
*
|
||||||
|
* Note, this is used only for the main process source code.
|
||||||
|
*
|
||||||
|
* source: https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409
|
||||||
|
* @type {import('esbuild').Plugin}
|
||||||
|
*/
|
||||||
|
export const excludeVendorFromSourceMap = {
|
||||||
|
name: 'excludeVendorFromSourceMap',
|
||||||
|
setup(build) {
|
||||||
|
build.onLoad({ filter: /node_modules/ }, (args) => {
|
||||||
|
if (args.path.endsWith('.json')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
contents:
|
||||||
|
fs.readFileSync(args.path, 'utf8') +
|
||||||
|
'\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==',
|
||||||
|
loader: 'default',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
@ -1,23 +0,0 @@
|
|||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* source: https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409
|
|
||||||
* @type {import('esbuild').Plugin}
|
|
||||||
*/
|
|
||||||
export const excludeVendorFromSourceMap = {
|
|
||||||
name: 'excludeVendorFromSourceMap',
|
|
||||||
setup(build) {
|
|
||||||
build.onLoad({ filter: /node_modules/ }, (args) => {
|
|
||||||
if (args.path.endsWith('.json')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
contents:
|
|
||||||
fs.readFileSync(args.path, 'utf8') +
|
|
||||||
'\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==',
|
|
||||||
loader: 'default',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
61
main.ts
61
main.ts
@ -8,9 +8,12 @@ import {
|
|||||||
BrowserWindow,
|
BrowserWindow,
|
||||||
BrowserWindowConstructorOptions,
|
BrowserWindowConstructorOptions,
|
||||||
protocol,
|
protocol,
|
||||||
|
ProtocolRequest,
|
||||||
|
ProtocolResponse,
|
||||||
} from 'electron';
|
} from 'electron';
|
||||||
import Store from 'electron-store';
|
import Store from 'electron-store';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import registerAppLifecycleListeners from './main/registerAppLifecycleListeners';
|
import registerAppLifecycleListeners from './main/registerAppLifecycleListeners';
|
||||||
import registerAutoUpdaterListeners from './main/registerAutoUpdaterListeners';
|
import registerAutoUpdaterListeners from './main/registerAutoUpdaterListeners';
|
||||||
@ -122,15 +125,20 @@ export class Main {
|
|||||||
this.mainWindow = new BrowserWindow(options);
|
this.mainWindow = new BrowserWindow(options);
|
||||||
|
|
||||||
if (this.isDevelopment) {
|
if (this.isDevelopment) {
|
||||||
this.loadDevServerURL();
|
this.setViteServerURL();
|
||||||
} else {
|
} else {
|
||||||
this.loadAppUrl();
|
this.registerAppProtocol();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mainWindow!.loadURL(this.winURL);
|
||||||
|
if (this.isDevelopment && !this.isTest) {
|
||||||
|
this.mainWindow!.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setMainWindowListeners();
|
this.setMainWindowListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDevServerURL() {
|
setViteServerURL() {
|
||||||
let port = 6969;
|
let port = 6969;
|
||||||
let host = '0.0.0.0';
|
let host = '0.0.0.0';
|
||||||
|
|
||||||
@ -141,18 +149,13 @@ export class Main {
|
|||||||
|
|
||||||
// Load the url of the dev server if in development mode
|
// Load the url of the dev server if in development mode
|
||||||
this.winURL = `http://${host}:${port}/`;
|
this.winURL = `http://${host}:${port}/`;
|
||||||
this.mainWindow!.loadURL(this.winURL);
|
|
||||||
|
|
||||||
if (this.isDevelopment && !this.isTest) {
|
|
||||||
this.mainWindow!.webContents.openDevTools();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAppUrl() {
|
registerAppProtocol() {
|
||||||
// createProtocol('app');
|
protocol.registerBufferProtocol('app', bufferProtocolCallback);
|
||||||
// Load the index.html when not in development
|
|
||||||
// this.winURL = 'app://./index.html';
|
// Use the registered protocol url to load the files.
|
||||||
// this.mainWindow!.loadURL(this.winURL);
|
this.winURL = 'app://./index.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
setMainWindowListeners() {
|
setMainWindowListeners() {
|
||||||
@ -170,4 +173,36 @@ export class Main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback used to register the custom app protocol,
|
||||||
|
* during prod, files are read and served by using this
|
||||||
|
* protocol.
|
||||||
|
*/
|
||||||
|
function bufferProtocolCallback(
|
||||||
|
request: ProtocolRequest,
|
||||||
|
callback: (response: ProtocolResponse) => void
|
||||||
|
) {
|
||||||
|
const { pathname, host } = new URL(request.url);
|
||||||
|
const filePath = path.join(
|
||||||
|
__dirname,
|
||||||
|
'src',
|
||||||
|
decodeURI(host),
|
||||||
|
decodeURI(pathname)
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.readFile(filePath, (_, data) => {
|
||||||
|
const extension = path.extname(filePath).toLowerCase();
|
||||||
|
const mimeType =
|
||||||
|
{
|
||||||
|
'.js': 'text/javascript',
|
||||||
|
'.css': 'text/css',
|
||||||
|
'.html': 'text/html',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.json': 'application/json',
|
||||||
|
}[extension] ?? '';
|
||||||
|
|
||||||
|
callback({ mimeType, data });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default new Main();
|
export default new Main();
|
||||||
|
@ -29,7 +29,7 @@ async function getPrintTemplatePaths(): Promise<{
|
|||||||
const files = await fs.readdir(root);
|
const files = await fs.readdir(root);
|
||||||
return { files, root };
|
return { files, root };
|
||||||
} catch {
|
} catch {
|
||||||
root = path.join(__dirname, `../templates`);
|
root = path.join(__dirname, '..', '..', `templates`);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -8,15 +8,13 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node build/scripts/dev.mjs",
|
"dev": "node build/scripts/dev.mjs",
|
||||||
|
"build": "node build/scripts/build.mjs",
|
||||||
"dev:main": "node build/scripts/dev.mjs --no-renderer",
|
"dev:main": "node build/scripts/dev.mjs --no-renderer",
|
||||||
"dev:renderer": "yarn vite",
|
"dev:renderer": "yarn vite",
|
||||||
"build": "vue-cli-service build",
|
|
||||||
"lint": "vue-cli-service lint",
|
"lint": "vue-cli-service lint",
|
||||||
"release": "scripts/publish-mac-arm.sh",
|
"release": "scripts/publish-mac-arm.sh",
|
||||||
"postinstall": "electron-rebuild",
|
"postinstall": "electron-rebuild",
|
||||||
"postuninstall": "electron-rebuild",
|
"postuninstall": "electron-rebuild",
|
||||||
"electron:build": "vue-cli-service electron:build",
|
|
||||||
"electron:serve": "vue-cli-service electron:serve",
|
|
||||||
"script:translate": "scripts/runner.sh scripts/generateTranslations.ts",
|
"script:translate": "scripts/runner.sh scripts/generateTranslations.ts",
|
||||||
"script:profile": "scripts/profile.sh",
|
"script:profile": "scripts/profile.sh",
|
||||||
"test": "scripts/test.sh"
|
"test": "scripts/test.sh"
|
||||||
@ -73,6 +71,7 @@
|
|||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-vue": "^7.0.0",
|
"eslint-plugin-vue": "^7.0.0",
|
||||||
"execa": "^7.1.1",
|
"execa": "^7.1.1",
|
||||||
|
"fs-extra": "^11.1.1",
|
||||||
"lint-staged": "^11.2.6",
|
"lint-staged": "^11.2.6",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"prettier": "^2.4.1",
|
"prettier": "^2.4.1",
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
|
||||||
<title>Frappe Books</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>
|
|
||||||
<strong>We're sorry but Frappe Books doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
|
||||||
</noscript>
|
|
||||||
<!-- built files will replace body.innerHTML -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -2,11 +2,15 @@ import vue from '@vitejs/plugin-vue';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a work in progress vite config. Currently only dev works.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
/**
|
||||||
|
* This vite config file is used only for dev mode, i.e.
|
||||||
|
* to create a serve build modules of the source code
|
||||||
|
* which will be rendered by electron.
|
||||||
|
*
|
||||||
|
* For building the project, vite is used programmatically
|
||||||
|
* see build/scripts/build.mjs for this.
|
||||||
|
*/
|
||||||
export default () => {
|
export default () => {
|
||||||
let port = 6969;
|
let port = 6969;
|
||||||
let host = '0.0.0.0';
|
let host = '0.0.0.0';
|
||||||
|
@ -6534,6 +6534,15 @@ fs-extra@^10.1.0:
|
|||||||
jsonfile "^6.0.1"
|
jsonfile "^6.0.1"
|
||||||
universalify "^2.0.0"
|
universalify "^2.0.0"
|
||||||
|
|
||||||
|
fs-extra@^11.1.1:
|
||||||
|
version "11.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.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"
|
||||||
|
|
||||||
fs-extra@^7.0.1:
|
fs-extra@^7.0.1:
|
||||||
version "7.0.1"
|
version "7.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
|
||||||
|
Loading…
Reference in New Issue
Block a user