electron-incremental-update 2.0.0-beta.7 → 2.0.0-beta.9

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/vite.js CHANGED
@@ -1,5 +1,5 @@
1
- import path2, { join, resolve, basename, dirname } from 'node:path';
2
- import fs, { rmSync, renameSync, writeFileSync, readFileSync, existsSync, cpSync, mkdirSync } from 'node:fs';
1
+ import path5 from 'node:path';
2
+ import fs3 from 'node:fs';
3
3
  import { createLogger, normalizePath, mergeConfig, createFilter } from 'vite';
4
4
  import ElectronSimple from 'vite-plugin-electron/simple';
5
5
  import { startup } from 'vite-plugin-electron';
@@ -9,14 +9,14 @@ import { isCI } from 'ci-info';
9
9
  export { isCI } from 'ci-info';
10
10
  import Asar from '@electron/asar';
11
11
  import { build } from 'esbuild';
12
- import { spawn } from 'node:child_process';
12
+ import cp from 'node:child_process';
13
13
  import * as babel from '@babel/core';
14
14
  import MagicString from 'magic-string';
15
- import { brotliCompress } from 'node:zlib';
16
- import { createSign, createPrivateKey, createHash, createCipheriv } from 'node:crypto';
15
+ import zlib from 'node:zlib';
16
+ import crypto from 'node:crypto';
17
17
  import { generate } from 'selfsigned';
18
18
 
19
- // src/vite.ts
19
+ // src/vite/index.ts
20
20
 
21
21
  // src/utils/version.ts
22
22
  function parseVersion(version) {
@@ -64,7 +64,7 @@ var bytecodeId = `${id}-bytecode`;
64
64
  var log = createLogger("info", { prefix: `[${id}]` });
65
65
  var bytecodeLog = createLogger("info", { prefix: `[${bytecodeId}]` });
66
66
 
67
- // src/build-plugins/bytecode/code.ts
67
+ // src/vite/bytecode/code.ts
68
68
  var bytecodeGeneratorScript = "const vm = require('vm')\nconst v8 = require('v8')\nconst wrap = require('module').wrap\nv8.setFlagsFromString('--no-lazy')\nv8.setFlagsFromString('--no-flush-bytecode')\nlet code = ''\nprocess.stdin.setEncoding('utf-8')\nprocess.stdin.on('readable', () => {\n const data = process.stdin.read()\n if (data !== null) {\n code += data\n }\n})\nprocess.stdin.on('end', () => {\n try {\n if (typeof code !== 'string') {\n throw new Error('javascript code must be string.')\n }\n const script = new vm.Script(wrap(code), { produceCachedData: true })\n const bytecodeBuffer = script.createCachedData()\n process.stdout.write(bytecodeBuffer)\n } catch (error) {\n console.error(error)\n }\n})\n";
69
69
  var bytecodeModuleLoaderCode = '"use strict";\nconst fs = require("fs");\nconst path = require("path");\nconst vm = require("vm");\nconst v8 = require("v8");\nconst Module = require("module");\nv8.setFlagsFromString("--no-lazy");\nv8.setFlagsFromString("--no-flush-bytecode");\nconst FLAG_HASH_OFFSET = 12;\nconst SOURCE_HASH_OFFSET = 8;\nlet dummyBytecode;\nfunction setFlagHashHeader(bytecodeBuffer) {\n if (!dummyBytecode) {\n const script = new vm.Script("", {\n produceCachedData: true\n });\n dummyBytecode = script.createCachedData();\n }\n dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);\n};\nfunction getSourceHashHeader(bytecodeBuffer) {\n return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);\n};\nfunction buffer2Number(buffer) {\n let ret = 0;\n ret |= buffer[3] << 24;\n ret |= buffer[2] << 16;\n ret |= buffer[1] << 8;\n ret |= buffer[0];\n return ret;\n};\nModule._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {\n const bytecodeBuffer = fs.readFileSync(filename);\n if (!Buffer.isBuffer(bytecodeBuffer)) {\n throw new Error("BytecodeBuffer must be a buffer object.");\n }\n setFlagHashHeader(bytecodeBuffer);\n const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));\n let dummyCode = "";\n if (length > 1) {\n dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";\n }\n const script = new vm.Script(dummyCode, {\n filename: filename,\n lineOffset: 0,\n displayErrors: true,\n cachedData: bytecodeBuffer\n });\n if (script.cachedDataRejected) {\n throw new Error("Invalid or incompatible cached data (cachedDataRejected)");\n }\n const require = function (id) {\n return module.require(id);\n };\n require.resolve = function (request, options) {\n return Module._resolveFilename(request, module, false, options);\n };\n if (process.mainModule) {\n require.main = process.mainModule;\n }\n require.extensions = Module._extensions;\n require.cache = Module._cache;\n const compiledWrapper = script.runInThisContext({\n filename: filename,\n lineOffset: 0,\n columnOffset: 0,\n displayErrors: true\n });\n const dirname = path.dirname(filename);\n const args = [module.exports, require, module, filename, dirname, process, global];\n return compiledWrapper.apply(module.exports, args);\n};\n';
70
70
  var electronModulePath = getPackageInfoSync("electron")?.rootPath;
@@ -76,13 +76,13 @@ function getElectronPath() {
76
76
  if (!electronModulePath) {
77
77
  throw new Error("Electron is not installed");
78
78
  }
79
- const pathFile = path2.join(electronModulePath, "path.txt");
79
+ const pathFile = path5.join(electronModulePath, "path.txt");
80
80
  let executablePath;
81
- if (fs.existsSync(pathFile)) {
82
- executablePath = fs.readFileSync(pathFile, "utf-8");
81
+ if (fs3.existsSync(pathFile)) {
82
+ executablePath = fs3.readFileSync(pathFile, "utf-8");
83
83
  }
84
84
  if (executablePath) {
85
- electronExecPath = path2.join(electronModulePath, "dist", executablePath);
85
+ electronExecPath = path5.join(electronModulePath, "dist", executablePath);
86
86
  process.env.ELECTRON_EXEC_PATH = electronExecPath;
87
87
  } else {
88
88
  throw new Error("Electron executable file is not existed");
@@ -91,14 +91,14 @@ function getElectronPath() {
91
91
  return electronExecPath;
92
92
  }
93
93
  function getBytecodeCompilerPath() {
94
- const scriptPath = path2.join(electronModulePath, "bytenode.cjs");
95
- if (!fs.existsSync(scriptPath)) {
96
- fs.writeFileSync(scriptPath, bytecodeGeneratorScript);
94
+ const scriptPath = path5.join(electronModulePath, "bytenode.cjs");
95
+ if (!fs3.existsSync(scriptPath)) {
96
+ fs3.writeFileSync(scriptPath, bytecodeGeneratorScript);
97
97
  }
98
98
  return scriptPath;
99
99
  }
100
100
  function toRelativePath(filename, importer) {
101
- const relPath = path2.posix.relative(path2.dirname(importer), filename);
101
+ const relPath = path5.posix.relative(path5.dirname(importer), filename);
102
102
  return relPath.startsWith(".") ? relPath : `./${relPath}`;
103
103
  }
104
104
  function compileToBytecode(code) {
@@ -106,8 +106,8 @@ function compileToBytecode(code) {
106
106
  const logErr = (...args) => bytecodeLog.error(args.join(" "), { timestamp: true });
107
107
  const electronPath = getElectronPath();
108
108
  const bytecodePath = getBytecodeCompilerPath();
109
- return new Promise((resolve2, reject) => {
110
- const proc = spawn(electronPath, [bytecodePath], {
109
+ return new Promise((resolve, reject) => {
110
+ const proc = cp.spawn(electronPath, [bytecodePath], {
111
111
  env: { ELECTRON_RUN_AS_NODE: "1" },
112
112
  stdio: ["pipe", "pipe", "pipe", "ipc"]
113
113
  });
@@ -118,7 +118,7 @@ function compileToBytecode(code) {
118
118
  if (proc.stdout) {
119
119
  proc.stdout.on("data", (chunk) => data = Buffer.concat([data, chunk]));
120
120
  proc.stdout.on("error", (err) => logErr(err));
121
- proc.stdout.on("end", () => resolve2(data));
121
+ proc.stdout.on("end", () => resolve(data));
122
122
  }
123
123
  if (proc.stderr) {
124
124
  proc.stderr.on("data", (chunk) => logErr("Error: ", chunk.toString()));
@@ -126,40 +126,80 @@ function compileToBytecode(code) {
126
126
  }
127
127
  proc.addListener("error", (err) => logErr(err));
128
128
  proc.on("error", (err) => reject(err));
129
- proc.on("exit", () => resolve2(data));
129
+ proc.on("exit", () => resolve(data));
130
130
  });
131
131
  }
132
- function convertArrowToFunction(code) {
132
+ function convertArrowFunctionAndTemplate(code) {
133
133
  const result = babel.transform(code, {
134
- plugins: ["@babel/plugin-transform-arrow-functions"]
134
+ plugins: ["@babel/plugin-transform-arrow-functions", "@babel/plugin-transform-template-literals"]
135
135
  });
136
136
  return {
137
137
  code: result?.code || code,
138
138
  map: result?.map
139
139
  };
140
140
  }
141
- function escapeRegExpString(str) {
142
- return str.replace(/\\/g, "\\\\").replace(/[|{}()[\]^$+*?.]/g, "\\$&");
141
+ var decodeFn = ";function _0xstr_(a,b){return String.fromCharCode.apply(0,a.map(function(x){return x-b}))};";
142
+ function obfuscateString(input, offset = ~~(Math.random() * 16) + 1) {
143
+ const hexArray = input.split("").map((c) => "0x" + (c.charCodeAt(0) + offset).toString(16));
144
+ return `_0xstr_([${hexArray.join(",")}],${offset})`;
143
145
  }
144
- function convertString(code, strings, sourcemap) {
145
- let s = null;
146
- for (const str of strings.filter(Boolean)) {
147
- const regex = new RegExp(`["']${escapeRegExpString(str)}["']`, "g");
148
- s ||= new MagicString(code).replace(regex, (match) => obfuscateString(match.slice(1, -1)));
146
+ function convertLiteral(code, sourcemap, offset) {
147
+ const s = new MagicString(code);
148
+ let hasTransformed = false;
149
+ const ast = babel.parse(code, { ast: true });
150
+ if (!ast) {
151
+ throw new Error("cannot parse code");
152
+ }
153
+ babel.traverse(ast, {
154
+ StringLiteral(path6) {
155
+ const parent = path6.parent;
156
+ const node = path6.node;
157
+ if (parent.type === "CallExpression") {
158
+ if (parent.callee.type === "Identifier" && parent.callee.name === "require") {
159
+ return;
160
+ }
161
+ if (parent.callee.type === "Import") {
162
+ return;
163
+ }
164
+ }
165
+ if (parent.type.startsWith("Export")) {
166
+ return;
167
+ }
168
+ if (parent.type.startsWith("Import")) {
169
+ return;
170
+ }
171
+ if (parent.type === "ObjectProperty" && parent.key === node) {
172
+ const result2 = `[${obfuscateString(node.value, offset)}]`;
173
+ const start2 = node.start;
174
+ const end2 = node.end;
175
+ if (start2 && end2) {
176
+ s.overwrite(start2, end2, result2);
177
+ hasTransformed = true;
178
+ }
179
+ return;
180
+ }
181
+ if (!node.value.trim()) {
182
+ return;
183
+ }
184
+ const result = obfuscateString(node.value, offset);
185
+ const start = node.start;
186
+ const end = node.end;
187
+ if (start && end) {
188
+ s.overwrite(start, end, result);
189
+ hasTransformed = true;
190
+ }
191
+ }
192
+ });
193
+ if (hasTransformed) {
194
+ s.append("\n").append(decodeFn);
149
195
  }
150
- return s ? {
196
+ return {
151
197
  code: s.toString(),
152
- map: sourcemap ? s.generateMap({ hires: "boundary" }) : null
153
- } : { code };
154
- }
155
- var decodeFn = "function(a,b){return String.fromCharCode.apply(0,a.map(function(x){return x-b}))}";
156
- function obfuscateString(input) {
157
- const offset = Math.random() << 4 | 0;
158
- const hexArray = input.split("").map((c) => "0x" + (c.charCodeAt(0) + offset).toString(16));
159
- return `(${decodeFn})(${JSON.stringify(hexArray)},${offset})`;
198
+ map: sourcemap ? s.generateMap({ hires: true }) : void 0
199
+ };
160
200
  }
161
201
 
162
- // src/build-plugins/utils.ts
202
+ // src/vite/utils.ts
163
203
  function readableSize(size) {
164
204
  const units = ["B", "KB", "MB", "GB"];
165
205
  let i = 0;
@@ -170,7 +210,7 @@ function readableSize(size) {
170
210
  return `${size.toFixed(2)} ${units[i]}`;
171
211
  }
172
212
 
173
- // src/build-plugins/build.ts
213
+ // src/vite/build.ts
174
214
  async function buildAsar({
175
215
  version,
176
216
  asarOutputPath,
@@ -179,11 +219,11 @@ async function buildAsar({
179
219
  rendererDistPath,
180
220
  generateGzipFile
181
221
  }) {
182
- renameSync(rendererDistPath, join(electronDistPath, "renderer"));
183
- writeFileSync(join(electronDistPath, "version"), version);
222
+ fs3.renameSync(rendererDistPath, path5.join(electronDistPath, "renderer"));
223
+ fs3.writeFileSync(path5.join(electronDistPath, "version"), version);
184
224
  await Asar.createPackage(electronDistPath, asarOutputPath);
185
- const buf = await generateGzipFile(readFileSync(asarOutputPath));
186
- writeFileSync(gzipPath, buf);
225
+ const buf = await generateGzipFile(fs3.readFileSync(asarOutputPath));
226
+ fs3.writeFileSync(gzipPath, buf);
187
227
  log.info(`build update asar to '${gzipPath}' [${readableSize(buf.length)}]`, { timestamp: true });
188
228
  return buf;
189
229
  }
@@ -206,9 +246,9 @@ async function buildVersion({
206
246
  signature: "",
207
247
  version
208
248
  };
209
- if (existsSync(versionPath)) {
249
+ if (fs3.existsSync(versionPath)) {
210
250
  try {
211
- const oldVersionJson = JSON.parse(readFileSync(versionPath, "utf-8"));
251
+ const oldVersionJson = JSON.parse(fs3.readFileSync(versionPath, "utf-8"));
212
252
  if (isUpdateJSON(oldVersionJson)) {
213
253
  _json = oldVersionJson;
214
254
  } else {
@@ -222,7 +262,7 @@ async function buildVersion({
222
262
  if (!isUpdateJSON(_json)) {
223
263
  throw new Error("invalid version info");
224
264
  }
225
- writeFileSync(versionPath, JSON.stringify(_json, null, 2));
265
+ fs3.writeFileSync(versionPath, JSON.stringify(_json, null, 2));
226
266
  log.info(`build version info to '${versionPath}'`, { timestamp: true });
227
267
  }
228
268
  async function buildEntry({
@@ -232,7 +272,7 @@ async function buildEntry({
232
272
  entryOutputDirPath,
233
273
  nativeModuleEntryMap,
234
274
  overrideEsbuildOptions
235
- }, define, protectedStrings) {
275
+ }, define, bytecodeOptions) {
236
276
  const option = mergeConfig(
237
277
  {
238
278
  entryPoints: {
@@ -257,30 +297,27 @@ async function buildEntry({
257
297
  overrideEsbuildOptions ?? {}
258
298
  );
259
299
  const { metafile } = await build(option);
260
- if (protectedStrings === void 0) {
300
+ if (!bytecodeOptions?.enable) {
261
301
  return;
262
302
  }
263
- const filePaths = Object.keys(metafile?.outputs ?? []);
303
+ const filePaths = Object.keys(metafile?.outputs ?? []).filter((filePath) => filePath.endsWith("js"));
264
304
  for (const filePath of filePaths) {
265
- let code = readFileSync(filePath, "utf-8");
266
- const fileName = basename(filePath);
305
+ let code = fs3.readFileSync(filePath, "utf-8");
306
+ const fileName = path5.basename(filePath);
267
307
  const isEntry = fileName.endsWith("entry.js");
268
- if (isEntry) {
269
- code = code.replace(
270
- /(`-----BEGIN CERTIFICATE-----[\s\S]*-----END CERTIFICATE-----\n`)/,
271
- (_, cert) => `"${cert.slice(1, -1).replace(/\n/g, "\\n")}"`
272
- );
308
+ let transformedCode = convertLiteral(convertArrowFunctionAndTemplate(code).code).code;
309
+ if (bytecodeOptions.beforeCompile) {
310
+ const result = await bytecodeOptions.beforeCompile(transformedCode, filePath);
311
+ if (result) {
312
+ transformedCode = result;
313
+ }
273
314
  }
274
- const transformedCode = convertString(
275
- convertArrowToFunction(code).code,
276
- [...protectedStrings, ...isEntry ? getCert(code) : []]
277
- ).code;
278
315
  const buffer = await compileToBytecode(transformedCode);
279
- writeFileSync(`${filePath}c`, buffer);
280
- writeFileSync(
316
+ fs3.writeFileSync(
281
317
  filePath,
282
318
  `${isEntry ? bytecodeModuleLoaderCode : useStrict}${isEntry ? "" : "module.exports = "}require("./${fileName}c")`
283
319
  );
320
+ fs3.writeFileSync(`${filePath}c`, buffer);
284
321
  bytecodeLog.info(
285
322
  `${filePath} [${(buffer.byteLength / 1e3).toFixed(2)} kB]`,
286
323
  { timestamp: true }
@@ -288,49 +325,45 @@ async function buildEntry({
288
325
  }
289
326
  bytecodeLog.info(`${filePaths.length} file${filePaths.length > 1 ? "s" : ""} compiled into bytecode`, { timestamp: true });
290
327
  }
291
- function getCert(code) {
292
- const cert = code.match(/-----BEGIN CERTIFICATE-----[\s\S]*-----END CERTIFICATE-----\\n/)?.[0];
293
- return cert ? [cert] : [];
294
- }
295
328
  async function defaultZipFile(buffer) {
296
- return new Promise((resolve2, reject) => {
297
- brotliCompress(buffer, (err, buffer2) => {
329
+ return new Promise((resolve, reject) => {
330
+ zlib.brotliCompress(buffer, (err, buffer2) => {
298
331
  if (err) {
299
332
  reject(err);
300
333
  } else {
301
- resolve2(buffer2);
334
+ resolve(buffer2);
302
335
  }
303
336
  });
304
337
  });
305
338
  }
306
339
  function hashBuffer(data, length) {
307
- const hash = createHash("SHA256").update(data).digest("binary");
340
+ const hash = crypto.createHash("SHA256").update(data).digest("binary");
308
341
  return Buffer.from(hash).subarray(0, length);
309
342
  }
310
343
  function aesEncrypt(plainText, key, iv) {
311
- const cipher = createCipheriv("aes-256-cbc", key, iv);
344
+ const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
312
345
  return cipher.update(plainText, "utf8", "base64url") + cipher.final("base64url");
313
346
  }
314
347
  function defaultSignature(buffer, privateKey, cert, version) {
315
- const sig = createSign("RSA-SHA256").update(buffer).sign(createPrivateKey(privateKey), "base64");
348
+ const sig = crypto.createSign("RSA-SHA256").update(buffer).sign(crypto.createPrivateKey(privateKey), "base64");
316
349
  return aesEncrypt(`${sig}%${version}`, hashBuffer(cert, 32), hashBuffer(buffer, 16));
317
350
  }
318
351
  function generateKeyPair(keyLength, subject, days, privateKeyPath, certPath) {
319
- const privateKeyDir = dirname(privateKeyPath);
320
- if (!existsSync(privateKeyDir)) {
321
- mkdirSync(privateKeyDir, { recursive: true });
352
+ const privateKeyDir = path5.dirname(privateKeyPath);
353
+ if (!fs3.existsSync(privateKeyDir)) {
354
+ fs3.mkdirSync(privateKeyDir, { recursive: true });
322
355
  }
323
- const certDir = dirname(certPath);
324
- if (!existsSync(certDir)) {
325
- mkdirSync(certDir, { recursive: true });
356
+ const certDir = path5.dirname(certPath);
357
+ if (!fs3.existsSync(certDir)) {
358
+ fs3.mkdirSync(certDir, { recursive: true });
326
359
  }
327
360
  const { cert, private: privateKey } = generate(subject, {
328
361
  keySize: keyLength,
329
362
  algorithm: "sha256",
330
363
  days
331
364
  });
332
- writeFileSync(privateKeyPath, privateKey.replace(/\r\n?/g, "\n"));
333
- writeFileSync(certPath, cert.replace(/\r\n?/g, "\n"));
365
+ fs3.writeFileSync(privateKeyPath, privateKey.replace(/\r\n?/g, "\n"));
366
+ fs3.writeFileSync(certPath, cert.replace(/\r\n?/g, "\n"));
334
367
  }
335
368
  function parseKeys({
336
369
  keyLength,
@@ -339,29 +372,29 @@ function parseKeys({
339
372
  subject,
340
373
  days
341
374
  }) {
342
- const keysDir = dirname(privateKeyPath);
375
+ const keysDir = path5.dirname(privateKeyPath);
343
376
  let privateKey = process.env.UPDATER_PK;
344
377
  let cert = process.env.UPDATER_CERT;
345
378
  if (privateKey && cert) {
346
379
  log.info("use UPDATER_PK and UPDATER_CERT from environment variables", { timestamp: true });
347
380
  return { privateKey, cert };
348
381
  }
349
- if (!existsSync(keysDir)) {
350
- mkdirSync(keysDir);
382
+ if (!fs3.existsSync(keysDir)) {
383
+ fs3.mkdirSync(keysDir);
351
384
  }
352
- if (!existsSync(privateKeyPath) || !existsSync(certPath)) {
385
+ if (!fs3.existsSync(privateKeyPath) || !fs3.existsSync(certPath)) {
353
386
  log.info("no key pair found, generate new key pair", { timestamp: true });
354
387
  generateKeyPair(keyLength, parseSubjects(subject), days, privateKeyPath, certPath);
355
388
  }
356
- privateKey = readFileSync(privateKeyPath, "utf-8");
357
- cert = readFileSync(certPath, "utf-8");
389
+ privateKey = fs3.readFileSync(privateKeyPath, "utf-8");
390
+ cert = fs3.readFileSync(certPath, "utf-8");
358
391
  return { privateKey, cert };
359
392
  }
360
393
  function parseSubjects(subject) {
361
394
  return Object.entries(subject).filter(([_, value]) => !!value).map(([name, value]) => ({ name, value }));
362
395
  }
363
396
 
364
- // src/build-plugins/option.ts
397
+ // src/vite/option.ts
365
398
  function parseOptions(pkg, sourcemap = false, minify = false, options = {}) {
366
399
  const {
367
400
  minimumVersion = "0.0.0",
@@ -433,15 +466,16 @@ function parseOptions(pkg, sourcemap = false, minify = false, options = {}) {
433
466
  };
434
467
  return { buildAsarOption, buildEntryOption, buildVersionOption, postBuild, cert };
435
468
  }
436
- function bytecodePlugin(enable, env, options = {}) {
469
+ function bytecodePlugin(env, options) {
470
+ const {
471
+ enable,
472
+ preload = false,
473
+ beforeCompile
474
+ } = options;
437
475
  if (!enable) {
438
476
  return null;
439
477
  }
440
- const {
441
- protectedStrings = [],
442
- enablePreload = false
443
- } = options;
444
- if (!enablePreload && env === "preload") {
478
+ if (!preload && env === "preload") {
445
479
  bytecodeLog.warn('bytecodePlugin is skiped in preload. To enable in preload, please manually set the "enablePreload" option to true and set `sandbox: false` when creating the window', { timestamp: true });
446
480
  return null;
447
481
  }
@@ -457,10 +491,9 @@ function bytecodePlugin(enable, env, options = {}) {
457
491
  config = resolvedConfig;
458
492
  },
459
493
  transform(code, id2) {
460
- if (protectedStrings.length === 0 || !filter(id2)) {
461
- return;
494
+ if (!filter(id2)) {
495
+ return convertLiteral(code, !!config.build.sourcemap);
462
496
  }
463
- return convertString(code, protectedStrings, !!config.build.sourcemap);
464
497
  },
465
498
  generateBundle(options2) {
466
499
  if (options2.format !== "es" && bytecodeRequired) {
@@ -482,7 +515,7 @@ function bytecodePlugin(enable, env, options = {}) {
482
515
  }
483
516
  if (chunk.type === "chunk") {
484
517
  bytecodeRequired = true;
485
- return convertArrowToFunction(code);
518
+ return convertArrowFunctionAndTemplate(code);
486
519
  }
487
520
  return null;
488
521
  },
@@ -497,7 +530,7 @@ function bytecodePlugin(enable, env, options = {}) {
497
530
  (chunk) => chunk.type === "chunk" && chunk.fileName !== bytecodeModuleLoader
498
531
  );
499
532
  const bytecodeChunks = chunks.map((chunk) => chunk.fileName);
500
- const nonEntryChunks = chunks.filter((chunk) => !chunk.isEntry).map((chunk) => path2.basename(chunk.fileName));
533
+ const nonEntryChunks = chunks.filter((chunk) => !chunk.isEntry).map((chunk) => path5.basename(chunk.fileName));
501
534
  const pattern = nonEntryChunks.map((chunk) => `(${chunk})`).join("|");
502
535
  const bytecodeRE = pattern ? new RegExp(`require\\(\\S*(?=(${pattern})\\S*\\))`, "g") : null;
503
536
  const getBytecodeLoaderBlock = (chunkFileName) => {
@@ -508,6 +541,12 @@ function bytecodePlugin(enable, env, options = {}) {
508
541
  const chunk = output[name];
509
542
  if (chunk.type === "chunk") {
510
543
  let _code = chunk.code;
544
+ if (beforeCompile) {
545
+ const cbResult = await beforeCompile(_code, chunk.fileName);
546
+ if (cbResult) {
547
+ _code = cbResult;
548
+ }
549
+ }
511
550
  if (bytecodeRE && _code.match(bytecodeRE)) {
512
551
  let match;
513
552
  const s = new MagicString(_code);
@@ -520,20 +559,20 @@ function bytecodePlugin(enable, env, options = {}) {
520
559
  }
521
560
  _code = s.toString();
522
561
  }
523
- const chunkFilePath = path2.resolve(outDir, name);
562
+ const chunkFilePath = path5.resolve(outDir, name);
524
563
  if (bytecodeChunks.includes(name)) {
525
564
  const bytecodeBuffer = await compileToBytecode(_code);
526
- fs.writeFileSync(path2.resolve(outDir, name + "c"), bytecodeBuffer);
565
+ fs3.writeFileSync(chunkFilePath + "c", bytecodeBuffer);
527
566
  if (chunk.isEntry) {
528
567
  const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
529
- const bytecodeModuleBlock = `require("./${path2.basename(name) + "c"}");`;
568
+ const bytecodeModuleBlock = `require("./${path5.basename(name) + "c"}");`;
530
569
  const code = `${useStrict}
531
570
  ${bytecodeLoaderBlock}
532
571
  module.exports=${bytecodeModuleBlock}
533
572
  `;
534
- fs.writeFileSync(chunkFilePath, code);
573
+ fs3.writeFileSync(chunkFilePath, code);
535
574
  } else {
536
- fs.unlinkSync(chunkFilePath);
575
+ fs3.unlinkSync(chunkFilePath);
537
576
  }
538
577
  bytecodeFiles.push({ name: name + "c", size: bytecodeBuffer.length });
539
578
  } else {
@@ -560,14 +599,14 @@ module.exports=${bytecodeModuleBlock}
560
599
  _code = hasBytecodeMoudle ? _code.replace(useStrict, `${useStrict}
561
600
  ${bytecodeLoaderBlock}`) : _code;
562
601
  }
563
- fs.writeFileSync(chunkFilePath, _code);
602
+ fs3.writeFileSync(chunkFilePath, _code);
564
603
  }
565
604
  }
566
605
  })
567
606
  );
568
607
  },
569
608
  closeBundle() {
570
- const outDir = `${normalizePath(path2.relative(config.root, path2.resolve(config.root, config.build.outDir)))}/`;
609
+ const outDir = `${normalizePath(path5.relative(config.root, path5.resolve(config.root, config.build.outDir)))}/`;
571
610
  bytecodeFiles.forEach((file) => {
572
611
  bytecodeLog.info(
573
612
  `${outDir}${file.name} [${readableSize(file.size)}]`,
@@ -589,9 +628,9 @@ function debugStartup(args) {
589
628
  function getMainFilePath(options) {
590
629
  let mainFilePath;
591
630
  if (typeof options === "string") {
592
- mainFilePath = basename(options);
631
+ mainFilePath = path5.basename(options);
593
632
  } else if (Array.isArray(options)) {
594
- mainFilePath = basename(options[0]);
633
+ mainFilePath = path5.basename(options[0]);
595
634
  } else {
596
635
  const name = options?.index ?? options?.main;
597
636
  if (!name) {
@@ -631,21 +670,18 @@ async function electronWithUpdater(options) {
631
670
  return void 0;
632
671
  }
633
672
  const _options = parseOptions(pkg, sourcemap, minify, updater);
634
- const bytecodeOptions = typeof bytecode === "object" ? bytecode : bytecode === true ? { protectedStrings: [] } : void 0;
635
- if (bytecodeOptions) {
636
- minify = false;
637
- }
673
+ const bytecodeOptions = typeof bytecode === "object" ? bytecode : bytecode === true ? { enable: true } : void 0;
638
674
  try {
639
- rmSync(_options.buildAsarOption.electronDistPath, { recursive: true, force: true });
640
- rmSync(_options.buildEntryOption.entryOutputDirPath, { recursive: true, force: true });
675
+ fs3.rmSync(_options.buildAsarOption.electronDistPath, { recursive: true, force: true });
676
+ fs3.rmSync(_options.buildEntryOption.entryOutputDirPath, { recursive: true, force: true });
641
677
  } catch {
642
678
  }
643
679
  log.info(`remove old files`, { timestamp: true });
644
680
  const { buildAsarOption, buildEntryOption, buildVersionOption, postBuild, cert } = _options;
645
681
  const { entryOutputDirPath, nativeModuleEntryMap, appEntryPath } = buildEntryOption;
646
682
  sourcemap ??= isBuild || !!process.env.VSCODE_DEBUG;
647
- const _appPath = normalizePath(join(entryOutputDirPath, "entry.js"));
648
- if (resolve(normalizePath(pkg.main)) !== resolve(_appPath)) {
683
+ const _appPath = normalizePath(path5.join(entryOutputDirPath, "entry.js"));
684
+ if (path5.resolve(normalizePath(pkg.main)) !== path5.resolve(_appPath)) {
649
685
  throw new Error(`wrong "main" field in package.json: "${pkg.main}", it should be "${_appPath}"`);
650
686
  }
651
687
  const define = {
@@ -661,20 +697,20 @@ async function electronWithUpdater(options) {
661
697
  await buildEntry(
662
698
  buildEntryOption,
663
699
  define,
664
- isBuild ? bytecodeOptions?.protectedStrings : void 0
700
+ bytecodeOptions
665
701
  );
666
702
  log.info(`vite build entry to '${entryOutputDirPath}'`, { timestamp: true });
667
703
  };
668
704
  const _postBuild = postBuild ? async () => await postBuild({
669
705
  getPathFromEntryOutputDir(...paths) {
670
- return join(entryOutputDirPath, ...paths);
706
+ return path5.join(entryOutputDirPath, ...paths);
671
707
  },
672
708
  copyToEntryOutputDir({ from, to, skipIfExist = true }) {
673
- if (existsSync(from)) {
674
- const target = join(entryOutputDirPath, to ?? basename(from));
675
- if (!skipIfExist || !existsSync(target)) {
709
+ if (fs3.existsSync(from)) {
710
+ const target = path5.join(entryOutputDirPath, to ?? path5.basename(from));
711
+ if (!skipIfExist || !fs3.existsSync(target)) {
676
712
  try {
677
- cpSync(from, target);
713
+ fs3.cpSync(from, target);
678
714
  } catch (error) {
679
715
  log.warn(`copy failed: ${error}`);
680
716
  }
@@ -685,7 +721,7 @@ async function electronWithUpdater(options) {
685
721
  };
686
722
  let isInit = false;
687
723
  const rollupOptions = {
688
- external: (src) => src.startsWith("node:") || Object.keys("dependencies" in pkg ? pkg.dependencies : {}).includes(src),
724
+ external: (src) => src.startsWith("node:") || Object.keys("dependencies" in pkg ? pkg.dependencies : {}).includes(src) || src === "original-fs",
689
725
  treeshake: true
690
726
  };
691
727
  const electronPluginOptions = {
@@ -707,7 +743,7 @@ async function electronWithUpdater(options) {
707
743
  {
708
744
  plugins: [
709
745
  !isBuild && useNotBundle ? notBundle() : void 0,
710
- bytecodeOptions && bytecodePlugin(!!bytecode, "main", bytecodeOptions)
746
+ bytecodeOptions && bytecodePlugin("main", bytecodeOptions)
711
747
  ],
712
748
  build: {
713
749
  sourcemap,
@@ -726,7 +762,7 @@ async function electronWithUpdater(options) {
726
762
  vite: mergeConfig(
727
763
  {
728
764
  plugins: [
729
- bytecodeOptions && bytecodePlugin(!!bytecode, "preload", bytecodeOptions),
765
+ bytecodeOptions && bytecodePlugin("preload", bytecodeOptions),
730
766
  {
731
767
  name: `${id}-build`,
732
768
  enforce: "post",
@@ -772,7 +808,10 @@ async function electronWithUpdater(options) {
772
808
  }
773
809
  let extraHmrPlugin;
774
810
  if (nativeModuleEntryMap) {
775
- const files = [...Object.values(nativeModuleEntryMap), appEntryPath].map((file) => resolve(normalizePath(file)));
811
+ const files = [
812
+ ...Object.values(nativeModuleEntryMap),
813
+ appEntryPath
814
+ ].map((file) => path5.resolve(normalizePath(file)));
776
815
  extraHmrPlugin = {
777
816
  name: `${id}-dev`,
778
817
  apply() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "electron-incremental-update",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.7",
4
+ "version": "2.0.0-beta.9",
5
5
  "description": "electron incremental update tools, powered by vite",
6
6
  "author": "subframe7536",
7
7
  "license": "MIT",
@@ -45,6 +45,7 @@
45
45
  "build": "tsup && esno fix-module.cjs",
46
46
  "release": "pnpm test && pnpm run build && bumpp --all && npm publish",
47
47
  "test": "vitest --run",
48
+ "test:dev": "vitest",
48
49
  "format": "eslint . --fix"
49
50
  },
50
51
  "publishConfig": {
@@ -53,27 +54,28 @@
53
54
  },
54
55
  "peerDependencies": {
55
56
  "@electron/asar": "*",
56
- "esbuild": "*",
57
- "magic-string": "*"
57
+ "esbuild": "*"
58
58
  },
59
59
  "dependencies": {
60
- "@babel/core": "^7.24.7",
60
+ "@babel/core": "^7.24.9",
61
61
  "@babel/plugin-transform-arrow-functions": "^7.24.7",
62
+ "@babel/plugin-transform-template-literals": "^7.24.7",
62
63
  "@subframe7536/type-utils": "^0.1.6",
63
64
  "ci-info": "^4.0.0",
64
65
  "local-pkg": "^0.5.0",
66
+ "magic-string": "^0.30.10",
65
67
  "selfsigned": "^2.4.1",
66
68
  "vite-plugin-electron": "^0.28.7"
67
69
  },
68
70
  "devDependencies": {
69
- "@subframe7536/eslint-config": "^0.7.2",
71
+ "@subframe7536/eslint-config": "^0.7.3",
70
72
  "@types/babel__core": "^7.20.5",
71
73
  "@types/node": "^20.14.11",
72
74
  "bumpp": "^9.4.1",
73
75
  "electron": "28.2.10",
74
76
  "eslint": "^9.7.0",
75
77
  "esno": "^4.7.0",
76
- "tsup": "^8.1.0",
78
+ "tsup": "^8.2.1",
77
79
  "typescript": "^5.5.3",
78
80
  "vite": "^5.3.4",
79
81
  "vite-plugin-electron": "^0.28.7",