@vixoniccom/module-packager 2.12.0-dev.0 → 2.12.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/electron.js +58 -0
- package/dist/launcher.html +96 -0
- package/dist/main.js +194 -104
- package/dist/webpack.config.js +158 -0
- package/package.json +5 -6
package/dist/electron.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { app, BrowserWindow } from 'electron';
|
|
3
|
+
import remoteMain from '@electron/remote/main/index.js';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import commandLineArgs from 'command-line-args';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const optionDefinitions = [
|
|
10
|
+
{ name: 'externals', type: String, defaultValue: [], multiple: true },
|
|
11
|
+
{ name: 'src', type: String, defaultValue: path.join(__dirname, 'src') },
|
|
12
|
+
{ name: 'build', type: String, defaultValue: path.join(__dirname, 'build') },
|
|
13
|
+
{ name: 'config', type: String, defaultValue: './webpack.config.js' },
|
|
14
|
+
{ name: 'port', type: Number, defaultValue: 8080 },
|
|
15
|
+
{ name: 'mode', type: String, defaultValue: 'build' }
|
|
16
|
+
];
|
|
17
|
+
const options = commandLineArgs(optionDefinitions);
|
|
18
|
+
if (options.mode === 'watch') {
|
|
19
|
+
(await import('electron-debug')).default({ showDevTools: true });
|
|
20
|
+
}
|
|
21
|
+
remoteMain.initialize();
|
|
22
|
+
let mainWindow = null;
|
|
23
|
+
function createWindow() {
|
|
24
|
+
mainWindow = new BrowserWindow({
|
|
25
|
+
show: false,
|
|
26
|
+
x: 100,
|
|
27
|
+
y: 100,
|
|
28
|
+
width: 1024,
|
|
29
|
+
height: 768,
|
|
30
|
+
webPreferences: {
|
|
31
|
+
nodeIntegrationInSubFrames: true,
|
|
32
|
+
allowRunningInsecureContent: true,
|
|
33
|
+
nodeIntegration: true,
|
|
34
|
+
contextIsolation: false,
|
|
35
|
+
webSecurity: false,
|
|
36
|
+
webviewTag: true
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
remoteMain.enable(mainWindow.webContents);
|
|
40
|
+
const launcherPath = path.join(__dirname, 'launcher.html');
|
|
41
|
+
const launcherURL = `file://${launcherPath}`;
|
|
42
|
+
mainWindow.loadURL(launcherURL);
|
|
43
|
+
// mainWindow.webContents.openDevTools({ mode: 'detach' })
|
|
44
|
+
mainWindow.webContents.once('did-finish-load', () => {
|
|
45
|
+
mainWindow?.show();
|
|
46
|
+
mainWindow?.webContents.send('init', options);
|
|
47
|
+
});
|
|
48
|
+
mainWindow.on('closed', () => (mainWindow = null));
|
|
49
|
+
}
|
|
50
|
+
app.whenReady().then(() => {
|
|
51
|
+
createWindow();
|
|
52
|
+
app.on('activate', () => {
|
|
53
|
+
if (BrowserWindow.getAllWindows().length === 0) {
|
|
54
|
+
createWindow();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
app.on('window-all-closed', () => app.quit());
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" xml:lang="en" style="width: 100%; height: 100%; margin: 0; padding: 0;">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<title></title>
|
|
7
|
+
</head>
|
|
8
|
+
|
|
9
|
+
<body style="width: 100%; height: 100%; margin: 0; padding: 0;">
|
|
10
|
+
<!-- Remover el webview del HTML -->
|
|
11
|
+
<div id="webview-container" style="width: 100%; height: 100%;"></div>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
const path = require('path')
|
|
15
|
+
let ModuleController;
|
|
16
|
+
try {
|
|
17
|
+
const moduleControllerModule = require('@vixoniccom/module-controller');
|
|
18
|
+
ModuleController = moduleControllerModule.default;
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error('[WEBVIEW] NO se pudo cargar ModuleController', err);
|
|
21
|
+
}
|
|
22
|
+
const { ipcRenderer } = require('electron')
|
|
23
|
+
const remote = require('@electron/remote')
|
|
24
|
+
|
|
25
|
+
ipcRenderer.on('init', (event, options) => {
|
|
26
|
+
// Crear el webview dinámicamente
|
|
27
|
+
const webview = document.createElement('webview')
|
|
28
|
+
webview.id = 'webview'
|
|
29
|
+
webview.style.width = '100%'
|
|
30
|
+
webview.style.height = '100%'
|
|
31
|
+
webview.setAttribute('partition', 'persist:webview')
|
|
32
|
+
|
|
33
|
+
webview.setAttribute('nodeintegration', '')
|
|
34
|
+
webview.setAttribute('webpreferences', 'webSecurity=false, allowRunningInsecureContent=true, nodeIntegration=yes, contextIsolation=no')
|
|
35
|
+
|
|
36
|
+
const win = remote.getCurrentWindow()
|
|
37
|
+
|
|
38
|
+
webview.addEventListener('did-finish-load', () => {
|
|
39
|
+
win.show()
|
|
40
|
+
win.focus()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const resolvedSrc = options.mode === 'watch'
|
|
44
|
+
? `http://localhost:${options.port}/index.html`
|
|
45
|
+
: `file://${path.join(options.build, 'index.html')}`
|
|
46
|
+
|
|
47
|
+
webview.src = resolvedSrc
|
|
48
|
+
|
|
49
|
+
// Añadir el webview al DOM después de configurarlo
|
|
50
|
+
document.getElementById('webview-container').appendChild(webview)
|
|
51
|
+
|
|
52
|
+
function getData() {
|
|
53
|
+
const data = {}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
data.parameters = require(path.join(options.src, 'test', 'parameters.json')).parameters
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log('No parameters:', err.message)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let escaped = path.join(options.mode === 'watch' ? options.src : options.build, 'test', 'downloads')
|
|
62
|
+
|
|
63
|
+
// Add file:// to watch because in this mode the app will be in a localhost hosted environment.
|
|
64
|
+
if (options.mode === 'watch') escaped = `file://${escaped}`
|
|
65
|
+
escaped = escaped.replace(/\\/g, '/')
|
|
66
|
+
|
|
67
|
+
data.downloadsPath = escaped
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
data.services = require(path.join(options.src, 'test','services.json')).services
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.log('No services:', err.message)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return data
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getSchema() {
|
|
80
|
+
try {
|
|
81
|
+
return require(path.join(options.src, '../configuration.json')).schema
|
|
82
|
+
} catch (err) {
|
|
83
|
+
console.log('No schema:', err.message)
|
|
84
|
+
return {}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const data = getData()
|
|
89
|
+
const schema = getSchema()
|
|
90
|
+
|
|
91
|
+
ModuleController.init(win, webview, data, schema, options.mode === 'watch')
|
|
92
|
+
})
|
|
93
|
+
</script>
|
|
94
|
+
</body>
|
|
95
|
+
|
|
96
|
+
</html>
|
package/dist/main.js
CHANGED
|
@@ -4,18 +4,26 @@ import commandLineArgs from 'command-line-args';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import webpack from 'webpack';
|
|
6
6
|
import WebpackDevServer from 'webpack-dev-server';
|
|
7
|
-
import { spawn
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import archiver from 'archiver';
|
|
11
11
|
import clc from 'cli-color';
|
|
12
12
|
import { Configuration } from '@vixoniccom/modules';
|
|
13
13
|
import tsNode from 'ts-node';
|
|
14
|
+
import { createRequire } from 'module';
|
|
15
|
+
import which from 'which';
|
|
14
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
17
|
const __dirname = path.dirname(__filename);
|
|
16
18
|
const electronPath = path.join(__dirname, 'electron.js');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
let npxPath;
|
|
20
|
+
try {
|
|
21
|
+
npxPath = which.sync('npx');
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.log(error);
|
|
25
|
+
console.error('Error: npx is not installed or not found in PATH.');
|
|
26
|
+
}
|
|
19
27
|
const optionDefinitions = [
|
|
20
28
|
{ name: 'externals', type: String, defaultValue: [], multiple: true },
|
|
21
29
|
{ name: 'target', type: String, defaultValue: 'web' },
|
|
@@ -29,9 +37,92 @@ const optionDefinitions = [
|
|
|
29
37
|
{ name: 'tsOverride', type: Boolean }
|
|
30
38
|
];
|
|
31
39
|
const options = commandLineArgs(optionDefinitions);
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
// Validación de entrada mejorada
|
|
41
|
+
function validateOptions(options) {
|
|
42
|
+
if (options.target !== 'electron-renderer' && options.externals.length > 0) {
|
|
43
|
+
throw new Error(`Can't use external dependencies if target is not electron-renderer.`);
|
|
44
|
+
}
|
|
45
|
+
// Validar puerto
|
|
46
|
+
if (options.port < 1 || options.port > 65535) {
|
|
47
|
+
throw new Error('Port must be between 1 and 65535');
|
|
48
|
+
}
|
|
49
|
+
// Validar modo
|
|
50
|
+
const validModes = ['build', 'watch', 'run', 'generate-configuration', 'validate-configuration'];
|
|
51
|
+
if (!validModes.includes(options.mode)) {
|
|
52
|
+
throw new Error(`Invalid mode. Must be one of: ${validModes.join(', ')}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Función para sanitizar rutas
|
|
56
|
+
function sanitizePath(inputPath) {
|
|
57
|
+
// Prevenir path traversal
|
|
58
|
+
if (inputPath.includes('..') || inputPath.includes('~')) {
|
|
59
|
+
throw new Error('Invalid path: path traversal detected');
|
|
60
|
+
}
|
|
61
|
+
return path.resolve(inputPath);
|
|
62
|
+
}
|
|
63
|
+
// Función centralizada para crear argumentos de Electron
|
|
64
|
+
function createElectronArgs(mode) {
|
|
65
|
+
return [
|
|
66
|
+
electronPath,
|
|
67
|
+
'--src', sanitizePath(options.src),
|
|
68
|
+
'--build', sanitizePath(options.build),
|
|
69
|
+
'--port', String(options.port),
|
|
70
|
+
'--mode', mode,
|
|
71
|
+
'--config', options.config,
|
|
72
|
+
...options.externals.flatMap((pkg) => ['--externals', pkg])
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
// Función centralizada para manejar procesos Electron
|
|
76
|
+
function spawnElectronProcess(mode) {
|
|
77
|
+
const args = createElectronArgs(mode);
|
|
78
|
+
const nodeEnv = mode === 'run' ? 'production' : 'development';
|
|
79
|
+
const child = spawn(npxPath, ['electron', ...args], {
|
|
80
|
+
cwd: __dirname,
|
|
81
|
+
env: {
|
|
82
|
+
...process.env,
|
|
83
|
+
NODE_ENV: nodeEnv,
|
|
84
|
+
ELECTRON_DISABLE_SECURITY_WARNINGS: 'true',
|
|
85
|
+
NODE_NO_WARNINGS: '1'
|
|
86
|
+
},
|
|
87
|
+
stdio: ['inherit', 'pipe', 'pipe']
|
|
88
|
+
});
|
|
89
|
+
// Manejo centralizado de logs
|
|
90
|
+
setupChildProcessLogging(child);
|
|
91
|
+
return child;
|
|
34
92
|
}
|
|
93
|
+
// Función para manejar logging de procesos hijo
|
|
94
|
+
function setupChildProcessLogging(child) {
|
|
95
|
+
child.stdout?.on('data', (data) => {
|
|
96
|
+
const output = data.toString();
|
|
97
|
+
if (!shouldFilterLog(output)) {
|
|
98
|
+
process.stdout.write(output);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
child.stderr?.on('data', (data) => {
|
|
102
|
+
const output = data.toString();
|
|
103
|
+
if (!shouldFilterLog(output)) {
|
|
104
|
+
process.stderr.write(output);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Función centralizada para compilar webpack
|
|
109
|
+
async function compileWebpack() {
|
|
110
|
+
// CORREGIDO: Usar __dirname para el webpack.config.js del module-packager
|
|
111
|
+
const cfgPath = path.resolve(__dirname, 'webpack.config.js');
|
|
112
|
+
const webpackConfigFactory = (await import(cfgPath)).default;
|
|
113
|
+
const compiler = webpack(webpackConfigFactory(options));
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
compiler.run((err, stats) => {
|
|
116
|
+
if (err)
|
|
117
|
+
return reject(err);
|
|
118
|
+
if (stats?.hasErrors()) {
|
|
119
|
+
return reject(new Error(stats.toString({ all: false, errors: true, colors: true })));
|
|
120
|
+
}
|
|
121
|
+
compiler.close(closeErr => (closeErr ? reject(closeErr) : resolve()));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
validateOptions(options);
|
|
35
126
|
if (options.mode === 'build') {
|
|
36
127
|
pack(() => {
|
|
37
128
|
if (options.target === 'electron-renderer') {
|
|
@@ -45,75 +136,58 @@ if (options.mode === 'build') {
|
|
|
45
136
|
});
|
|
46
137
|
}
|
|
47
138
|
else if (options.mode === 'watch') {
|
|
48
|
-
console.log('[DEBUG] Entrando a watch()');
|
|
49
139
|
watch();
|
|
50
140
|
}
|
|
51
141
|
else if (options.mode === 'run') {
|
|
52
142
|
run();
|
|
53
143
|
}
|
|
54
144
|
else if (options.mode === 'generate-configuration') {
|
|
55
|
-
generateConfiguration();
|
|
145
|
+
await generateConfiguration();
|
|
56
146
|
}
|
|
57
147
|
else if (options.mode === 'validate-configuration') {
|
|
58
148
|
validateConfiguration();
|
|
59
149
|
}
|
|
60
|
-
function runElectron() {
|
|
61
|
-
const electronProcess = spawn('npx', [
|
|
62
|
-
'electron',
|
|
63
|
-
electronPath,
|
|
64
|
-
'--src', path.resolve(options.src),
|
|
65
|
-
'--build', path.resolve(options.build),
|
|
66
|
-
'--port', `${options.port}`,
|
|
67
|
-
'--mode', options.mode,
|
|
68
|
-
'--config', options.config,
|
|
69
|
-
'--externals', options.externals.join(',')
|
|
70
|
-
], {
|
|
71
|
-
cwd: __dirname,
|
|
72
|
-
env: { ...process.env, NODE_ENV: 'development' },
|
|
73
|
-
stdio: 'inherit'
|
|
74
|
-
});
|
|
75
|
-
electronProcess.on('close', (code) => {
|
|
76
|
-
console.log(`Electron process exited with code ${code}`);
|
|
77
|
-
if (code !== 0) {
|
|
78
|
-
console.error('Electron process exited with an error.');
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
150
|
async function pack(callback) {
|
|
83
151
|
console.log(clc.blue('Building module...'));
|
|
84
152
|
validateConfiguration();
|
|
85
|
-
const configPath = path.resolve(__dirname,
|
|
153
|
+
const configPath = path.resolve(__dirname, options.config);
|
|
86
154
|
try {
|
|
87
155
|
const webpackConfig = (await import(configPath)).default(options);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
console.error('Details:', err.details);
|
|
93
|
-
}
|
|
94
|
-
if (err.errors) {
|
|
95
|
-
console.error('TS Errors:', JSON.stringify(err.errors, null, 2));
|
|
96
|
-
}
|
|
97
|
-
throw err;
|
|
156
|
+
function handleWebpackError(err) {
|
|
157
|
+
console.error('Build error:', err);
|
|
158
|
+
if (err.details) {
|
|
159
|
+
console.error('Details:', err.details);
|
|
98
160
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
161
|
+
if (err.errors) {
|
|
162
|
+
console.error('TS Errors:', JSON.stringify(err.errors, null, 2));
|
|
163
|
+
}
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
function handleWebpackStats(stats, callback) {
|
|
167
|
+
if (stats.hasErrors()) {
|
|
168
|
+
const info = stats.toJson('errors-only');
|
|
169
|
+
console.error(clc.red('Webpack errors:'));
|
|
170
|
+
if (info.errors?.length) {
|
|
171
|
+
info.errors.forEach((e) => {
|
|
172
|
+
console.error(clc.red(typeof e === 'object' ? JSON.stringify(e, null, 2) : e));
|
|
173
|
+
});
|
|
112
174
|
}
|
|
113
175
|
else {
|
|
114
|
-
console.
|
|
115
|
-
callback && callback(null);
|
|
176
|
+
console.error(clc.red(JSON.stringify(info, null, 2)));
|
|
116
177
|
}
|
|
178
|
+
callback?.(stats);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
console.log(clc.green('Build OK.'));
|
|
182
|
+
callback?.(null);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
webpack(webpackConfig, function (err, stats) {
|
|
186
|
+
if (err) {
|
|
187
|
+
handleWebpackError(err);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
handleWebpackStats(stats, callback);
|
|
117
191
|
}
|
|
118
192
|
});
|
|
119
193
|
}
|
|
@@ -124,30 +198,42 @@ async function pack(callback) {
|
|
|
124
198
|
}
|
|
125
199
|
function installExternals(callback) {
|
|
126
200
|
let externals = options.externals.map((x) => {
|
|
127
|
-
|
|
201
|
+
// Validar nombre del paquete
|
|
202
|
+
if (!/^[@a-z0-9-_./]+$/i.test(x)) {
|
|
203
|
+
throw new Error(`Invalid package name: ${x}`);
|
|
204
|
+
}
|
|
205
|
+
const packageJsonPath = sanitizePath(path.resolve(options.src, '..', 'node_modules', x, 'package.json'));
|
|
206
|
+
return `${x}@${JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).version}`;
|
|
128
207
|
});
|
|
129
208
|
if (externals.length) {
|
|
130
|
-
externals
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
209
|
+
console.log(clc.blue(`Installing externals ${externals.join(', ')}...`));
|
|
210
|
+
const npmPath = which.sync('npm');
|
|
211
|
+
const child = spawn(npmPath, ['install', '--prefix', './', '--production', ...externals], { cwd: sanitizePath(options.build), stdio: 'inherit' });
|
|
212
|
+
child.on('exit', (code) => {
|
|
213
|
+
if (code !== 0) {
|
|
214
|
+
return callback?.(new Error(`npm install failed with code ${code}`));
|
|
215
|
+
}
|
|
137
216
|
console.log(clc.green('Externals installed.'));
|
|
138
|
-
callback
|
|
217
|
+
callback?.(null);
|
|
218
|
+
});
|
|
219
|
+
child.on('error', (err) => {
|
|
220
|
+
callback?.(err);
|
|
139
221
|
});
|
|
140
222
|
}
|
|
141
223
|
else {
|
|
142
|
-
callback
|
|
224
|
+
callback?.(null);
|
|
143
225
|
}
|
|
144
226
|
}
|
|
145
227
|
function zip() {
|
|
146
228
|
console.log(clc.blue('Archiving...'));
|
|
147
|
-
|
|
229
|
+
console.log(clc.blue('Cleaning build...'));
|
|
230
|
+
const buildPath = sanitizePath(options.build);
|
|
231
|
+
const zipPath = path.resolve(buildPath, '../', 'build.zip');
|
|
232
|
+
console.log("[DEBUG] Cleaning build folder", zipPath);
|
|
233
|
+
let output = fs.createWriteStream(zipPath);
|
|
148
234
|
let archive = archiver('zip');
|
|
149
235
|
archive.pipe(output);
|
|
150
|
-
archive.directory(
|
|
236
|
+
archive.directory(buildPath, './');
|
|
151
237
|
archive.finalize();
|
|
152
238
|
output.on('close', function () {
|
|
153
239
|
console.log(clc.green('Generated build.zip.'));
|
|
@@ -158,10 +244,9 @@ function zip() {
|
|
|
158
244
|
clc.move(-2, 0);
|
|
159
245
|
}
|
|
160
246
|
async function watch() {
|
|
161
|
-
|
|
162
|
-
const cfgPath = path.resolve(__dirname, '
|
|
247
|
+
// CORREGIDO: Usar __dirname para el webpack.config.js del module-packager
|
|
248
|
+
const cfgPath = path.resolve(__dirname, 'webpack.config.js');
|
|
163
249
|
const webpackConfigFactory = (await import(cfgPath)).default;
|
|
164
|
-
console.log('[VMP] ▸ webpack config loaded from', cfgPath);
|
|
165
250
|
const compiler = webpack(webpackConfigFactory(options));
|
|
166
251
|
const server = new WebpackDevServer({
|
|
167
252
|
static: false,
|
|
@@ -170,32 +255,15 @@ async function watch() {
|
|
|
170
255
|
historyApiFallback: true
|
|
171
256
|
}, compiler);
|
|
172
257
|
await server.start();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
'--mode', 'watch',
|
|
180
|
-
'--config', options.config,
|
|
181
|
-
'--externals', options.externals.join(',')
|
|
182
|
-
].join(' ');
|
|
183
|
-
console.log(`[VMP] ▸ ${cmd}`);
|
|
184
|
-
const child = exec(cmd, { cwd: __dirname, env: { ...process.env, NODE_ENV: 'development' } });
|
|
185
|
-
child.stdout?.pipe(process.stdout);
|
|
186
|
-
child.stderr?.pipe(process.stderr);
|
|
187
|
-
}
|
|
188
|
-
function run() {
|
|
189
|
-
pack((err) => {
|
|
190
|
-
if (err) {
|
|
191
|
-
throw err;
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
runElectron();
|
|
195
|
-
}
|
|
196
|
-
});
|
|
258
|
+
spawnElectronProcess('watch');
|
|
259
|
+
}
|
|
260
|
+
async function run() {
|
|
261
|
+
await new Promise((resolve) => pack((err) => (err ? console.log(err) : resolve())));
|
|
262
|
+
await compileWebpack();
|
|
263
|
+
spawnElectronProcess('run');
|
|
197
264
|
}
|
|
198
|
-
function loadConfiguration() {
|
|
265
|
+
async function loadConfiguration() {
|
|
266
|
+
const require = createRequire(import.meta.url);
|
|
199
267
|
tsNode.register({
|
|
200
268
|
compilerOptions: {
|
|
201
269
|
moduleResolution: 'node',
|
|
@@ -204,13 +272,15 @@ function loadConfiguration() {
|
|
|
204
272
|
checkJs: false
|
|
205
273
|
}
|
|
206
274
|
});
|
|
207
|
-
|
|
275
|
+
const configPath = sanitizePath(path.resolve(options.confDefinition, 'index.ts'));
|
|
276
|
+
return require(configPath).configuration;
|
|
208
277
|
}
|
|
209
|
-
function generateConfiguration() {
|
|
278
|
+
async function generateConfiguration() {
|
|
210
279
|
try {
|
|
211
|
-
let configuration = loadConfiguration();
|
|
212
|
-
|
|
213
|
-
fs.writeFileSync(path.resolve(
|
|
280
|
+
let configuration = await loadConfiguration();
|
|
281
|
+
const srcPath = sanitizePath(options.src);
|
|
282
|
+
fs.writeFileSync(path.resolve(srcPath, 'parameters.d.ts'), configuration.declarationFileString);
|
|
283
|
+
fs.writeFileSync(path.resolve(srcPath, '..', 'configuration.json'), JSON.stringify(configuration, undefined, 2));
|
|
214
284
|
console.log(clc.green(`Configuration generated`));
|
|
215
285
|
}
|
|
216
286
|
catch (e) {
|
|
@@ -220,12 +290,13 @@ function generateConfiguration() {
|
|
|
220
290
|
}
|
|
221
291
|
function validateConfiguration() {
|
|
222
292
|
try {
|
|
223
|
-
const
|
|
224
|
-
const
|
|
293
|
+
const srcPath = sanitizePath(options.src);
|
|
294
|
+
const jsonPath = path.resolve(srcPath, '../', 'configuration.json');
|
|
295
|
+
const json = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
|
|
225
296
|
const conf = Configuration.fromJSON(json);
|
|
226
297
|
if (conf.durationFormula) {
|
|
227
|
-
const valuesPath = path.resolve(
|
|
228
|
-
const values = JSON.parse(fs.readFileSync(valuesPath, 'utf8'));
|
|
298
|
+
const valuesPath = path.resolve(srcPath, 'test', 'parameters.json');
|
|
299
|
+
const values = JSON.parse(fs.readFileSync(valuesPath, 'utf8'));
|
|
229
300
|
console.log('Validate duration');
|
|
230
301
|
console.log('Duration on undefined:', conf.getDuration({}), 'seconds');
|
|
231
302
|
console.log('Duration:', conf.getDuration(values.parameters), 'seconds');
|
|
@@ -237,3 +308,22 @@ function validateConfiguration() {
|
|
|
237
308
|
throw e;
|
|
238
309
|
}
|
|
239
310
|
}
|
|
311
|
+
function shouldFilterLog(output) {
|
|
312
|
+
const filtersToRemove = [
|
|
313
|
+
"'session.getAllExtensions' is deprecated",
|
|
314
|
+
"DeprecationWarning: Compilation.assets will be frozen",
|
|
315
|
+
"BREAKING CHANGE: No more changes should happen to Compilation.assets",
|
|
316
|
+
"[DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning",
|
|
317
|
+
"Compilation.assets will be frozen in future",
|
|
318
|
+
"Request Autofill.enable failed",
|
|
319
|
+
"Request Autofill.setAddresses failed",
|
|
320
|
+
"Uncaught (in promise) SyntaxError",
|
|
321
|
+
"wasn't found",
|
|
322
|
+
"asset main.js",
|
|
323
|
+
"runtime modules",
|
|
324
|
+
"orphan modules",
|
|
325
|
+
"cacheable modules",
|
|
326
|
+
"webpack compiled successfully"
|
|
327
|
+
];
|
|
328
|
+
return filtersToRemove.some(filter => output.includes(filter));
|
|
329
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
4
|
+
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
|
|
5
|
+
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
6
|
+
import TerserPlugin from 'terser-webpack-plugin';
|
|
7
|
+
import webpack from 'webpack';
|
|
8
|
+
export default (env = {}, argv = {}) => {
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const options = {
|
|
11
|
+
src: env.src ?? './src',
|
|
12
|
+
build: env.build ?? './build',
|
|
13
|
+
port: env.port ?? 8080,
|
|
14
|
+
mode: argv.mode ?? 'production',
|
|
15
|
+
};
|
|
16
|
+
const isDev = options.mode === 'development' ||
|
|
17
|
+
argv.watch === true ||
|
|
18
|
+
process.env.NODE_ENV === 'development';
|
|
19
|
+
const buildPath = path.resolve(options.build);
|
|
20
|
+
const controllerHtmlPath = path.resolve(options.src, 'index.html');
|
|
21
|
+
const controllerStaticPath = path.resolve(path.dirname(controllerHtmlPath), '../static');
|
|
22
|
+
const controllerFontsPath = path.resolve(path.dirname(controllerHtmlPath), '../fonts');
|
|
23
|
+
const controllerTestPath = path.resolve(options.src, 'test');
|
|
24
|
+
return {
|
|
25
|
+
mode: isDev ? 'development' : 'production',
|
|
26
|
+
target: options.target ?? 'electron-renderer',
|
|
27
|
+
entry: isDev ? [
|
|
28
|
+
`webpack-dev-server/client?http://localhost:${options.port}/`,
|
|
29
|
+
'webpack/hot/dev-server',
|
|
30
|
+
path.resolve(options.src, 'main.ts')
|
|
31
|
+
] : path.resolve(options.src, 'main.ts'),
|
|
32
|
+
output: {
|
|
33
|
+
path: buildPath,
|
|
34
|
+
filename: '[name].js',
|
|
35
|
+
publicPath: isDev ? '/' : './'
|
|
36
|
+
},
|
|
37
|
+
performance: {
|
|
38
|
+
maxAssetSize: 2000000, //2MB
|
|
39
|
+
maxEntrypointSize: 2000000,
|
|
40
|
+
hints: isDev ? false : 'warning'
|
|
41
|
+
},
|
|
42
|
+
externals: {
|
|
43
|
+
electron: 'commonjs electron',
|
|
44
|
+
'@vixoniccom/module-controller': 'commonjs @vixoniccom/module-controller',
|
|
45
|
+
webpack: 'commonjs webpack',
|
|
46
|
+
'terser-webpack-plugin': 'commonjs terser-webpack-plugin',
|
|
47
|
+
esbuild: 'commonjs esbuild',
|
|
48
|
+
'@swc/core': 'commonjs @swc/core',
|
|
49
|
+
'@swc/wasm': 'commonjs @swc/wasm'
|
|
50
|
+
},
|
|
51
|
+
resolve: {
|
|
52
|
+
extensions: ['.tsx', '.ts', '.js', '.jsx', '.mjs'],
|
|
53
|
+
mainFields: ['module', 'browser', 'main'],
|
|
54
|
+
fullySpecified: false,
|
|
55
|
+
fallback: {
|
|
56
|
+
process: require.resolve('process/browser.js'),
|
|
57
|
+
global: require.resolve('global')
|
|
58
|
+
},
|
|
59
|
+
modules: ['node_modules', 'src', 'static']
|
|
60
|
+
},
|
|
61
|
+
module: {
|
|
62
|
+
rules: [
|
|
63
|
+
{
|
|
64
|
+
test: /\.(ts|tsx|js|jsx)$/,
|
|
65
|
+
exclude: /node_modules/,
|
|
66
|
+
use: {
|
|
67
|
+
loader: 'ts-loader',
|
|
68
|
+
options: {
|
|
69
|
+
transpileOnly: true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
test: /\.s[ac]ss$/,
|
|
75
|
+
use: ['style-loader', 'css-loader', 'sass-loader']
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
test: /\.css$/,
|
|
79
|
+
use: ['style-loader', 'css-loader'],
|
|
80
|
+
exclude: /node_modules/
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|mp4)$/,
|
|
84
|
+
type: 'asset/resource',
|
|
85
|
+
generator: {
|
|
86
|
+
filename: '[name][ext]'
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
test: /\.html$/,
|
|
91
|
+
use: {
|
|
92
|
+
loader: 'html-loader',
|
|
93
|
+
options: {
|
|
94
|
+
sources: false,
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
plugins: [
|
|
101
|
+
new webpack.DefinePlugin({
|
|
102
|
+
global: 'globalThis'
|
|
103
|
+
}),
|
|
104
|
+
new webpack.ProvidePlugin({
|
|
105
|
+
process: 'process/browser.js'
|
|
106
|
+
}),
|
|
107
|
+
new CleanWebpackPlugin(),
|
|
108
|
+
new HtmlWebpackPlugin({
|
|
109
|
+
template: controllerHtmlPath,
|
|
110
|
+
filename: 'index.html',
|
|
111
|
+
inject: 'body',
|
|
112
|
+
chunks: ['main']
|
|
113
|
+
}),
|
|
114
|
+
new CopyWebpackPlugin({
|
|
115
|
+
patterns: [
|
|
116
|
+
{ from: controllerStaticPath, to: 'static', noErrorOnMissing: true },
|
|
117
|
+
{ from: controllerFontsPath, to: 'fonts', noErrorOnMissing: true },
|
|
118
|
+
{ from: controllerTestPath, to: 'test', noErrorOnMissing: true }
|
|
119
|
+
]
|
|
120
|
+
})
|
|
121
|
+
],
|
|
122
|
+
optimization: {
|
|
123
|
+
minimize: !isDev,
|
|
124
|
+
minimizer: [
|
|
125
|
+
new TerserPlugin({
|
|
126
|
+
minify: TerserPlugin.terserMinify,
|
|
127
|
+
terserOptions: {
|
|
128
|
+
ecma: 2020,
|
|
129
|
+
compress: true,
|
|
130
|
+
mangle: true,
|
|
131
|
+
format: { comments: false }
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
devtool: isDev ? 'source-map' : false,
|
|
137
|
+
devServer: isDev ? {
|
|
138
|
+
static: [
|
|
139
|
+
{
|
|
140
|
+
directory: path.resolve(options.src, 'test'),
|
|
141
|
+
publicPath: '/test',
|
|
142
|
+
watch: true,
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
open: false,
|
|
146
|
+
client: {
|
|
147
|
+
overlay: true
|
|
148
|
+
},
|
|
149
|
+
port: options.port || 8080,
|
|
150
|
+
hot: true,
|
|
151
|
+
historyApiFallback: true,
|
|
152
|
+
devMiddleware: {
|
|
153
|
+
publicPath: '/',
|
|
154
|
+
writeToDisk: false
|
|
155
|
+
}
|
|
156
|
+
} : undefined
|
|
157
|
+
};
|
|
158
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vixoniccom/module-packager",
|
|
3
|
-
"version": "2.12.0-dev.
|
|
3
|
+
"version": "2.12.0-dev.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"bin": {
|
|
@@ -15,11 +15,8 @@
|
|
|
15
15
|
"clean": "rimraf dist",
|
|
16
16
|
"build:main": "tsc -p tsconfig.json --outDir dist",
|
|
17
17
|
"build:renderer": "webpack --config webpack.config.js --env src=./ --env build=./dist/build --mode production",
|
|
18
|
-
"copy:launcher": "
|
|
18
|
+
"copy:launcher": "cpy launcher.html dist",
|
|
19
19
|
"build": "npm run clean && npm-run-all -p build:renderer build:main && npm run copy:launcher",
|
|
20
|
-
"watch:renderer": "webpack --config webpack.config.js --env src=./ --env build=./dist/build --mode=development --watch",
|
|
21
|
-
"watch:main": "tsc -p tsconfig.json --outDir dist --watch",
|
|
22
|
-
"dev:watch": "npm run clean && npm-run-all -p watch:renderer watch:main",
|
|
23
20
|
"prerelease-dev": "standard-version --prerelease dev",
|
|
24
21
|
"prerelease-rc": "standard-version --prerelease rc",
|
|
25
22
|
"prerelease-test": "standard-version --prerelease test",
|
|
@@ -35,6 +32,7 @@
|
|
|
35
32
|
"cli-color": "^1.2.0",
|
|
36
33
|
"command-line-args": "^3.0.1",
|
|
37
34
|
"copy-webpack-plugin": "^13.0.0",
|
|
35
|
+
"cpy-cli": "^5.0.0",
|
|
38
36
|
"css-loader": "^7.1.2",
|
|
39
37
|
"electron": "^36.1.0",
|
|
40
38
|
"electron-debug": "^3.2.0",
|
|
@@ -43,7 +41,8 @@
|
|
|
43
41
|
"html-webpack-plugin": "^4.5.2",
|
|
44
42
|
"lodash": "^4.17.21",
|
|
45
43
|
"process": "^0.11.10",
|
|
46
|
-
"raw-loader": "^0.
|
|
44
|
+
"raw-loader": "^4.0.2",
|
|
45
|
+
"rimraf": "^6.0.1",
|
|
47
46
|
"style-loader": "^4.0.0",
|
|
48
47
|
"ts-loader": "^9.5.0",
|
|
49
48
|
"ts-node": "^10.9.1",
|