diff --git a/bin/electron-bytecode.js b/bin/electron-bytecode.js new file mode 100644 index 0000000..9af3153 --- /dev/null +++ b/bin/electron-bytecode.js @@ -0,0 +1,32 @@ +const vm = require('vm') +const v8 = require('v8') +const wrap = require('module').wrap + +v8.setFlagsFromString('--no-lazy') +v8.setFlagsFromString('--no-flush-bytecode') + +let code = '' + +process.stdin.setEncoding('utf-8') + +process.stdin.on('readable', () => { + const data = process.stdin.read() + if (data !== null) { + code += data + } +}) + +process.stdin.on('end', () => { + try { + if (typeof code !== 'string') { + throw new Error(`javascript code must be string. ${typeof code} was given.`) + } + + const script = new vm.Script(wrap(code), { produceCachedData: true }) + const bytecodeBuffer = script.createCachedData() + + process.stdout.write(bytecodeBuffer) + } catch (error) { + console.error(error) + } +}) diff --git a/package.json b/package.json index 5d18679..877fb03 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,8 @@ "vite": "^3.0.9" }, "dependencies": { + "@babel/core": "^7.19.1", + "@babel/plugin-transform-arrow-functions": "^7.18.6", "cac": "^6.7.12", "esbuild": "^0.14.54", "picocolors": "^1.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f81be7..94e784b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,6 +1,8 @@ lockfileVersion: 5.4 specifiers: + '@babel/core': ^7.19.1 + '@babel/plugin-transform-arrow-functions': ^7.18.6 '@microsoft/api-extractor': ^7.29.5 '@rollup/plugin-node-resolve': ^13.3.0 '@rollup/plugin-typescript': ^8.4.0 @@ -23,6 +25,8 @@ specifiers: vite: ^3.0.9 dependencies: + '@babel/core': 7.19.1 + '@babel/plugin-transform-arrow-functions': 7.18.6_@babel+core@7.19.1 cac: 6.7.12 esbuild: 0.14.54 picocolors: 1.0.0 @@ -48,6 +52,222 @@ devDependencies: packages: + /@ampproject/remapping/2.2.0: + resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/trace-mapping': 0.3.15 + dev: false + + /@babel/code-frame/7.18.6: + resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.18.6 + dev: false + + /@babel/compat-data/7.19.1: + resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/core/7.19.1: + resolution: {integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.0 + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.0 + '@babel/helper-compilation-targets': 7.19.1_@babel+core@7.19.1 + '@babel/helper-module-transforms': 7.19.0 + '@babel/helpers': 7.19.0 + '@babel/parser': 7.19.1 + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + convert-source-map: 1.8.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/generator/7.19.0: + resolution: {integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + '@jridgewell/gen-mapping': 0.3.2 + jsesc: 2.5.2 + dev: false + + /@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1: + resolution: {integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.19.1 + '@babel/core': 7.19.1 + '@babel/helper-validator-option': 7.18.6 + browserslist: 4.21.4 + semver: 6.3.0 + dev: false + + /@babel/helper-environment-visitor/7.18.9: + resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-function-name/7.19.0: + resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.18.10 + '@babel/types': 7.19.0 + dev: false + + /@babel/helper-hoist-variables/7.18.6: + resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + dev: false + + /@babel/helper-module-imports/7.18.6: + resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + dev: false + + /@babel/helper-module-transforms/7.19.0: + resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-module-imports': 7.18.6 + '@babel/helper-simple-access': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/helper-validator-identifier': 7.19.1 + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/helper-plugin-utils/7.19.0: + resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-simple-access/7.18.6: + resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + dev: false + + /@babel/helper-split-export-declaration/7.18.6: + resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.19.0 + dev: false + + /@babel/helper-string-parser/7.18.10: + resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-identifier/7.19.1: + resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-validator-option/7.18.6: + resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helpers/7.19.0: + resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.1 + '@babel/types': 7.19.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/highlight/7.18.6: + resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.19.1 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: false + + /@babel/parser/7.19.1: + resolution: {integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.19.0 + dev: false + + /@babel/plugin-transform-arrow-functions/7.18.6_@babel+core@7.19.1: + resolution: {integrity: sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.19.1 + '@babel/helper-plugin-utils': 7.19.0 + dev: false + + /@babel/template/7.18.10: + resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/parser': 7.19.1 + '@babel/types': 7.19.0 + dev: false + + /@babel/traverse/7.19.1: + resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.19.0 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.19.1 + '@babel/types': 7.19.0 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/types/7.19.0: + resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.18.10 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + dev: false + /@esbuild/linux-loong64/0.14.54: resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} @@ -92,6 +312,44 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@jridgewell/gen-mapping/0.1.1: + resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: false + + /@jridgewell/gen-mapping/0.3.2: + resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/trace-mapping': 0.3.15 + dev: false + + /@jridgewell/resolve-uri/3.1.0: + resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/set-array/1.1.2: + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + dev: false + + /@jridgewell/sourcemap-codec/1.4.14: + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + dev: false + + /@jridgewell/trace-mapping/0.3.15: + resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: false + /@microsoft/api-extractor-model/7.23.3: resolution: {integrity: sha512-HpsWzG6jrWHrTlIg53kmp/IVQPBHUZc+8dunnr9VXrmDjVBehaXxp9A6jhTQ/bd7W1m5TYfAvwCmseC1+9FCuA==} dependencies: @@ -426,6 +684,13 @@ packages: engines: {node: '>=12'} dev: true + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + /ansi-styles/4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -476,6 +741,17 @@ packages: fill-range: 7.0.1 dev: true + /browserslist/4.21.4: + resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001402 + electron-to-chromium: 1.4.254 + node-releases: 2.0.6 + update-browserslist-db: 1.0.9_browserslist@4.21.4 + dev: false + /builtin-modules/3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -491,6 +767,19 @@ packages: engines: {node: '>=6'} dev: true + /caniuse-lite/1.0.30001402: + resolution: {integrity: sha512-Mx4MlhXO5NwuvXGgVb+hg65HZ+bhUYsz8QtDGDo2QmaJS2GBX47Xfi2koL86lc8K+l+htXeTEB/Aeqvezoo6Ew==} + dev: false + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: false + /chalk/4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -527,6 +816,12 @@ packages: string-width: 5.1.2 dev: true + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + /color-convert/2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -534,6 +829,10 @@ packages: color-name: 1.1.4 dev: true + /color-name/1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true @@ -562,6 +861,12 @@ packages: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} dev: true + /convert-source-map/1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + dev: false + /cross-spawn/7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -581,7 +886,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /deep-is/0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -610,6 +914,10 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true + /electron-to-chromium/1.4.254: + resolution: {integrity: sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q==} + dev: false + /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true @@ -806,6 +1114,16 @@ packages: esbuild-windows-64: 0.14.54 esbuild-windows-arm64: 0.14.54 + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: false + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + /escape-string-regexp/4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1083,6 +1401,11 @@ packages: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true + /gensync/1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: false + /get-stream/6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -1113,6 +1436,11 @@ packages: path-is-absolute: 1.0.1 dev: true + /globals/11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: false + /globals/13.17.0: resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} engines: {node: '>=8'} @@ -1140,6 +1468,11 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true + /has-flag/3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + dev: false + /has-flag/4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1253,6 +1586,10 @@ packages: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: true + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + /js-yaml/4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -1260,6 +1597,12 @@ packages: argparse: 2.0.1 dev: true + /jsesc/2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: false + /json-schema-traverse/0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true @@ -1268,6 +1611,12 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json5/2.2.1: + resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} + engines: {node: '>=6'} + hasBin: true + dev: false + /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -1412,7 +1761,6 @@ packages: /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} @@ -1424,6 +1772,10 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-releases/2.0.6: + resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + dev: false + /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -1663,6 +2015,15 @@ packages: tslib: 2.4.0 dev: true + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: false + /semver/7.3.7: resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} engines: {node: '>=10'} @@ -1785,6 +2146,13 @@ packages: engines: {node: '>=8'} dev: true + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: false + /supports-color/7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -1805,6 +2173,11 @@ packages: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true + /to-fast-properties/2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + dev: false + /to-regex-range/5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1863,6 +2236,17 @@ packages: engines: {node: '>= 10.0.0'} dev: true + /update-browserslist-db/1.0.9_browserslist@4.21.4: + resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.4 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: false + /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: diff --git a/src/bytecode.ts b/src/bytecode.ts new file mode 100644 index 0000000..2b6cc28 --- /dev/null +++ b/src/bytecode.ts @@ -0,0 +1,132 @@ +// Inspired by https://github.com/bytenode/bytenode + +import path from 'node:path' +import { spawn } from 'node:child_process' +import { getElectronPath } from './electron' + +const getBytecodeCompilerPath = (): string => { + return path.resolve(process.cwd(), 'node_modules', 'electron-vite', 'bin', 'electron-bytecode.js') +} + +export const compileToBytecode = (code: string): Promise => { + return new Promise((resolve, reject) => { + let data = Buffer.from([]) + + const electronPath = getElectronPath() + const bytecodePath = getBytecodeCompilerPath() + + const proc = spawn(electronPath, [bytecodePath], { + env: { ELECTRON_RUN_AS_NODE: '1' }, + stdio: ['pipe', 'pipe', 'pipe', 'ipc'] + }) + + if (proc.stdin) { + proc.stdin.write(code) + proc.stdin.end() + } + + if (proc.stdout) { + proc.stdout.on('data', chunk => { + data = Buffer.concat([data, chunk]) + }) + proc.stdout.on('error', err => { + console.error(err) + }) + proc.stdout.on('end', () => { + resolve(data) + }) + } + + if (proc.stderr) { + proc.stderr.on('data', chunk => { + console.error('Error: ', chunk.toString()) + }) + proc.stderr.on('error', err => { + console.error('Error: ', err) + }) + } + + proc.addListener('message', message => console.log(message)) + proc.addListener('error', err => console.error(err)) + + proc.on('error', err => reject(err)) + proc.on('exit', () => { + resolve(data) + }) + }) +} + +export const bytecodeModuleLoaderCode = [ + `"use strict";`, + `const fs = require("fs");`, + `const path = require("path");`, + `const vm = require("vm");`, + `const v8 = require("v8");`, + `const Module = require("module");`, + `v8.setFlagsFromString("--no-lazy");`, + `v8.setFlagsFromString("--no-flush-bytecode");`, + `const FLAG_HASH_OFFSET = 12;`, + `const SOURCE_HASH_OFFSET = 8;`, + `let dummyBytecode;`, + `function setFlagHashHeader(bytecodeBuffer) {`, + ` if (!dummyBytecode) {`, + ` const script = new vm.Script("", {`, + ` produceCachedData: true`, + ` });`, + ` dummyBytecode = script.createCachedData();`, + ` }`, + ` dummyBytecode.slice(FLAG_HASH_OFFSET, FLAG_HASH_OFFSET + 4).copy(bytecodeBuffer, FLAG_HASH_OFFSET);`, + `};`, + `function getSourceHashHeader(bytecodeBuffer) {`, + ` return bytecodeBuffer.slice(SOURCE_HASH_OFFSET, SOURCE_HASH_OFFSET + 4);`, + `};`, + `function buffer2Number(buffer) {`, + ` let ret = 0;`, + ` ret |= buffer[3] << 24;`, + ` ret |= buffer[2] << 16;`, + ` ret |= buffer[1] << 8;`, + ` ret |= buffer[0];`, + ` return ret;`, + `};`, + `Module._extensions[".jsc"] = function (module, filename) {`, + ` const bytecodeBuffer = fs.readFileSync(filename);`, + ` if (!Buffer.isBuffer(bytecodeBuffer)) {`, + ` throw new Error("BytecodeBuffer must be a buffer object.");`, + ` }`, + ` setFlagHashHeader(bytecodeBuffer);`, + ` const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));`, + ` let dummyCode = "";`, + ` if (length > 1) {`, + ` dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";`, + ` }`, + ` const script = new vm.Script(dummyCode, {`, + ` filename: filename,`, + ` lineOffset: 0,`, + ` displayErrors: true,`, + ` cachedData: bytecodeBuffer`, + ` });`, + ` if (script.cachedDataRejected) {`, + ` throw new Error("Invalid or incompatible cached data (cachedDataRejected)");`, + ` }`, + ` const require = function (id) {`, + ` return module.require(id);`, + ` };`, + ` require.resolve = function (request, options) {`, + ` return Module._resolveFilename(request, module, false, options);`, + ` };`, + ` if (process.mainModule) {`, + ` require.main = process.mainModule;`, + ` }`, + ` require.extensions = Module._extensions;`, + ` require.cache = Module._cache;`, + ` const compiledWrapper = script.runInThisContext({`, + ` filename: filename,`, + ` lineOffset: 0,`, + ` columnOffset: 0,`, + ` displayErrors: true`, + ` });`, + ` const dirname = path.dirname(filename);`, + ` const args = [module.exports, require, module, filename, dirname, process, global];`, + ` return compiledWrapper.apply(module.exports, args);`, + `};` +] diff --git a/src/index.ts b/src/index.ts index 6cc9e60..4c23e36 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,3 +4,4 @@ export { createServer } from './server' export { build } from './build' export { preview } from './preview' export * from './plugin' +export { compileToBytecode } from './bytecode' diff --git a/src/plugin.ts b/src/plugin.ts index f7cb2e0..266cb30 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -2,12 +2,20 @@ import path from 'node:path' import fs from 'node:fs' import colors from 'picocolors' import { builtinModules, createRequire } from 'node:module' -import { Plugin, mergeConfig, normalizePath } from 'vite' +import { type Plugin, type ResolvedConfig, mergeConfig, normalizePath } from 'vite' +import { compileToBytecode, bytecodeModuleLoaderCode } from './bytecode' +import * as babel from '@babel/core' export interface ElectronPluginOptions { root?: string } +export interface BytecodeOptions { + chunkAlias?: string | string[] + transformArrowFunctions?: boolean + removeBundleJS?: boolean +} + function findLibEntry(root: string, scope: string): string { for (const name of ['index', scope]) { for (const ext of ['js', 'ts', 'mjs', 'cjs']) { @@ -309,6 +317,147 @@ export function electronConfigServeVitePlugin(options: { } } +export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null { + if (process.env.NODE_ENV_ELECTRON_VITE !== 'production') { + return null + } + + const { chunkAlias = [], transformArrowFunctions = false, removeBundleJS = true } = options + const _chunkAlias = Array.isArray(chunkAlias) ? chunkAlias : [chunkAlias] + const transformAllChunks = _chunkAlias.length === 0 + const bytecodeChunks: string[] = [] + const nonEntryChunks: string[] = [] + const _transform = (code: string): string => { + const re = babel.transform(code, { + plugins: ['@babel/plugin-transform-arrow-functions'] + }) + return re.code || '' + } + const requireBytecodeLoaderStr = '"use strict";\nrequire("./bytecode-loader.js");' + let config: ResolvedConfig + let useInRenderer = false + let bytecodeFiles: { name: string; size: number }[] = [] + return { + name: 'vite:bytecode', + apply: 'build', + enforce: 'post', + configResolved(resolvedConfig): void { + config = resolvedConfig + useInRenderer = config.plugins.some(p => p.name === 'vite:electron-renderer-preset-config') + if (useInRenderer) { + config.logger.warn(colors.yellow('bytecodePlugin is not support renderers')) + } + }, + renderChunk(code, chunk): { code: string } | null { + if (useInRenderer) { + return null + } + if (!transformAllChunks) { + const isBytecodeChunk = _chunkAlias.some(alias => chunk.fileName.startsWith(alias)) + if (isBytecodeChunk) { + bytecodeChunks.push(chunk.fileName) + if (!chunk.isEntry) { + nonEntryChunks.push(chunk.fileName) + } + if (transformArrowFunctions) { + return { + code: _transform(code) + } + } + } + } else { + if (chunk.type === 'chunk') { + bytecodeChunks.push(chunk.fileName) + if (!chunk.isEntry) { + nonEntryChunks.push(chunk.fileName) + } + if (transformArrowFunctions) { + return { + code: _transform(code) + } + } + } + } + return null + }, + generateBundle(): void { + if (!useInRenderer && bytecodeChunks.length) { + this.emitFile({ + type: 'asset', + source: bytecodeModuleLoaderCode.join('\n') + '\n', + name: 'Bytecode Loader File', + fileName: 'bytecode-loader.js' + }) + } + }, + async writeBundle(options, output): Promise { + if (useInRenderer || bytecodeChunks.length === 0) { + return + } + const bundles = Object.keys(output) + const outDir = options.dir! + bytecodeFiles = [] + await Promise.all( + bundles.map(async name => { + const chunk = output[name] + if (chunk.type === 'chunk') { + let _code = chunk.code + nonEntryChunks.forEach(bcc => { + if (bcc !== name) { + const reg = new RegExp(bcc, 'g') + _code = _code.replace(reg, `${bcc}c`) + } + }) + const chunkFileName = path.resolve(outDir, name) + if (bytecodeChunks.includes(name)) { + const bytecodeBuffer = await compileToBytecode(_code) + const bytecodeFileName = path.resolve(outDir, name + 'c') + fs.writeFileSync(bytecodeFileName, bytecodeBuffer) + if (chunk.isEntry) { + if (!removeBundleJS) { + const newFileName = path.resolve(outDir, `_${name}`) + fs.renameSync(chunkFileName, newFileName) + } + const code = requireBytecodeLoaderStr + `\nrequire("./${normalizePath(name + 'c')}");\n` + fs.writeFileSync(chunkFileName, code) + } else { + if (removeBundleJS) { + fs.unlinkSync(chunkFileName) + } else { + const newFileName = path.resolve(outDir, `_${name}`) + fs.renameSync(chunkFileName, newFileName) + } + } + bytecodeFiles.push({ name: name + 'c', size: bytecodeBuffer.length }) + } else { + if (chunk.isEntry) { + _code = _code.replace('"use strict";', requireBytecodeLoaderStr) + } + fs.writeFileSync(chunkFileName, _code) + } + } + }) + ) + }, + closeBundle(): void { + if (!useInRenderer) { + const chunkLimit = config.build.chunkSizeWarningLimit + const outDir = normalizePath(path.relative(config.root, path.resolve(config.root, config.build.outDir))) + '/' + config.logger.info(`${colors.green(`✓`)} ${bytecodeFiles.length} bundles compiled into bytecode.`) + bytecodeFiles.forEach(file => { + const kibs = file.size / 1024 + config.logger.info( + `${colors.gray(colors.white(colors.dim(outDir)))}${colors.green(file.name)} ${ + kibs > chunkLimit ? colors.yellow(`${kibs.toFixed(2)} KiB`) : colors.dim(`${kibs.toFixed(2)} KiB`) + }` + ) + }) + bytecodeFiles = [] + } + } + } +} + function getElectronMainVer(root: string): string { let mainVer = process.env.ELECTRON_MAIN_VER || '' if (!mainVer) {