@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.
@@ -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, exec } from 'child_process';
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
- // import pjson from '../package.json' assert { type: 'json' }
18
- // console.log(`VIXONIC PACKAGER: Version ${pjson.version}`)
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
- if (options.target !== 'electron-renderer' && options.externals.length > 0) {
33
- throw new Error(`Can't use external dependencies if target is not electron-renderer.`);
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, '../', options.config);
153
+ const configPath = path.resolve(__dirname, options.config);
86
154
  try {
87
155
  const webpackConfig = (await import(configPath)).default(options);
88
- webpack(webpackConfig, function (err, stats) {
89
- if (err) {
90
- console.error('Build error:', err);
91
- if (err.details) {
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
- else {
100
- if (stats.hasErrors()) {
101
- const info = stats.toJson('errors-only');
102
- console.error(clc.red('Webpack errors:'));
103
- if (info.errors && info.errors.length) {
104
- info.errors.forEach((e) => {
105
- console.error(clc.red(typeof e === 'object' ? JSON.stringify(e, null, 2) : e));
106
- });
107
- }
108
- else {
109
- console.error(clc.red(JSON.stringify(info, null, 2)));
110
- }
111
- callback && callback(stats);
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.log(clc.green('Build OK.'));
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
- return `${x}@${JSON.parse(fs.readFileSync(path.resolve(options.src, '..', 'node_modules', x, 'package.json'), 'utf8')).version}`;
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 = externals.join(' ');
131
- console.log(clc.blue(`Installing externals ${externals}...`));
132
- exec(`npm install --prefix ./ --production ${externals}`, {
133
- cwd: options.build
134
- }, (err, _stdout) => {
135
- if (err)
136
- throw err;
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 && callback(null);
217
+ callback?.(null);
218
+ });
219
+ child.on('error', (err) => {
220
+ callback?.(err);
139
221
  });
140
222
  }
141
223
  else {
142
- callback && callback(null);
224
+ callback?.(null);
143
225
  }
144
226
  }
145
227
  function zip() {
146
228
  console.log(clc.blue('Archiving...'));
147
- let output = fs.createWriteStream(path.resolve(options.build, '../', 'build.zip'));
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(path.resolve(options.build), './');
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
- console.log('[VMP] ▸ starting dev-server & electron in watch mode…');
162
- const cfgPath = path.resolve(__dirname, '..', 'dist/webpack.config.js');
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
- console.log(`[VMP] ▸ dev-server listening on http://localhost:${options.port}`);
174
- const cmd = [
175
- 'npx', 'electron', electronPath,
176
- '--src', path.resolve(options.src),
177
- '--build', path.resolve(options.build),
178
- '--port', String(options.port),
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
- return require(path.resolve(options.confDefinition, 'index.ts')).configuration;
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
- fs.writeFileSync(path.resolve(options.src, 'parameters.d.ts'), configuration.declarationFileString);
213
- fs.writeFileSync(path.resolve(options.src, '..', 'configuration.json'), JSON.stringify(configuration, undefined, 2));
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 jsonPath = path.resolve(options.src, '../', 'configuration.json');
224
- const json = JSON.parse(fs.readFileSync(jsonPath, 'utf8')); // Leer y parsear el archivo JSON
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(options.src, 'test', 'parameters.json');
228
- const values = JSON.parse(fs.readFileSync(valuesPath, 'utf8')); // Leer y parsear otro archivo JSON
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.0",
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": "cp launcher.html dist/launcher.html",
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.5.1",
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",