1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-11-12 01:40:53 +01:00
This commit is contained in:
Nayam Amarshe 2022-08-02 14:28:24 +05:30
commit 0e1e2d1229
52 changed files with 8177 additions and 0 deletions

36
.gitignore vendored Normal file
View File

@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# Electron with Typescript application example
This example show how you can use Next.js inside an Electron application to avoid a lot of configuration, use Next.js router as view and use server-render to speed up the initial render of the application. Both Next.js and Electron layers are written in TypeScript and compiled to JavaScript during the build process.
| Part | Source code (Typescript) | Builds (JavaScript) |
| ---------- | ------------------------ | ------------------- |
| Next.js | `/renderer` | `/renderer` |
| Electron | `/electron-src` | `/main` |
| Production | | `/dist` |
For development it's going to run a HTTP server and let Next.js handle routing. In production it use `next export` to pre-generate HTML static files and use them in your app instead of running an HTTP server.
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example with-electron-typescript with-electron-typescript-app
```
```bash
yarn create next-app --example with-electron-typescript with-electron-typescript-app
```
```bash
pnpm create next-app --example with-electron-typescript with-electron-typescript-app
```
Available commands:
```bash
"build-renderer": build and transpile Next.js layer
"build-electron": transpile electron layer
"build": build both layers
"dev": start dev version
"dist": create production electron build
"type-check": check TypeScript in project
```
## Notes
You can create the production app using `npm run dist`.
_note regarding types:_
- Electron provides its own type definitions, so you don't need @types/electron installed!
source: https://www.npmjs.com/package/@types/electron
- There were no types available for `electron-next` at the time of creating this example, so until they are available there is a file `electron-next.d.ts` in `electron-src` directory.

11
electron-src/electron-next.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
declare module 'electron-next' {
interface Directories {
production: string
development: string
}
export default function (
directories: Directories | string,
port?: number
): Promise<void>
}

42
electron-src/index.ts Normal file
View File

@ -0,0 +1,42 @@
// Native
import { join } from 'path'
import { format } from 'url'
// Packages
import { BrowserWindow, app, ipcMain, IpcMainEvent } from 'electron'
import isDev from 'electron-is-dev'
import prepareNext from 'electron-next'
// Prepare the renderer once the app is ready
app.on('ready', async () => {
await prepareNext('./renderer')
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: false,
preload: join(__dirname, 'preload.js'),
},
})
const url = isDev
? 'http://localhost:8000/'
: format({
pathname: join(__dirname, '../renderer/out/index.html'),
protocol: 'file:',
slashes: true,
})
mainWindow.loadURL(url)
})
// Quit the app once all windows are closed
app.on('window-all-closed', app.quit)
// listen the channel `message` and resend the received message to the renderer process
ipcMain.on('message', (event: IpcMainEvent, message: any) => {
console.log(message)
setTimeout(() => event.sender.send('message', 'hi from electron'), 500)
})

17
electron-src/preload.ts Normal file
View File

@ -0,0 +1,17 @@
/* eslint-disable @typescript-eslint/no-namespace */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { ipcRenderer, IpcRenderer } from 'electron'
declare global {
namespace NodeJS {
interface Global {
ipcRenderer: IpcRenderer
}
}
}
// Since we disabled nodeIntegration we can reintroduce
// needed node functionality here
process.once('loaded', () => {
global.ipcRenderer = ipcRenderer
})

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"allowJs": true,
"alwaysStrict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["dom", "es2017"],
"module": "commonjs",
"moduleResolution": "node",
"noEmit": false,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "esnext",
"outDir": "../main"
},
"exclude": ["node_modules"],
"include": ["**/*.ts", "**/*.tsx", "**/*.js"]
}

40
main/index.js Normal file
View File

@ -0,0 +1,40 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// Native
const path_1 = require("path");
const url_1 = require("url");
// Packages
const electron_1 = require("electron");
const electron_is_dev_1 = __importDefault(require("electron-is-dev"));
const electron_next_1 = __importDefault(require("electron-next"));
// Prepare the renderer once the app is ready
electron_1.app.on('ready', async () => {
await (0, electron_next_1.default)('./renderer');
const mainWindow = new electron_1.BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: false,
preload: (0, path_1.join)(__dirname, 'preload.js'),
},
});
const url = electron_is_dev_1.default
? 'http://localhost:8000/'
: (0, url_1.format)({
pathname: (0, path_1.join)(__dirname, '../renderer/out/index.html'),
protocol: 'file:',
slashes: true,
});
mainWindow.loadURL(url);
});
// Quit the app once all windows are closed
electron_1.app.on('window-all-closed', electron_1.app.quit);
// listen the channel `message` and resend the received message to the renderer process
electron_1.ipcMain.on('message', (event, message) => {
console.log(message);
setTimeout(() => event.sender.send('message', 'hi from electron'), 500);
});

10
main/preload.js Normal file
View File

@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable @typescript-eslint/no-namespace */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const electron_1 = require("electron");
// Since we disabled nodeIntegration we can reintroduce
// needed node functionality here
process.once('loaded', () => {
global.ipcRenderer = electron_1.ipcRenderer;
});

38
package.json Normal file
View File

@ -0,0 +1,38 @@
{
"private": true,
"main": "main/index.js",
"productName": "ElectronTypescriptNext",
"scripts": {
"clean": "rimraf dist main renderer/out renderer/.next",
"dev": "npm run build-electron && electron .",
"build-renderer": "next build renderer && next export renderer",
"build-electron": "tsc -p electron-src",
"build": "npm run build-renderer && npm run build-electron",
"pack-app": "npm run build && electron-builder --dir",
"dist": "npm run build && electron-builder",
"type-check": "tsc -p ./renderer/tsconfig.json && tsc -p ./electron-src/tsconfig.json"
},
"dependencies": {
"electron-is-dev": "^1.1.0",
"electron-next": "^3.1.5",
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@types/node": "^14.14.6",
"@types/react": "^16.9.9",
"@types/react-dom": "^16.9.9",
"electron": "^13",
"electron-builder": "^23.0.3",
"next": "latest",
"rimraf": "^3.0.0",
"typescript": "^4.0.5"
},
"build": {
"asar": true,
"files": [
"main",
"renderer/out"
]
}
}

View File

@ -0,0 +1,40 @@
{
"polyfillFiles": [
"static/chunks/polyfills.js"
],
"devFiles": [
"static/chunks/react-refresh.js"
],
"ampDevFiles": [
"static/chunks/webpack.js",
"static/chunks/amp.js"
],
"lowPriorityFiles": [
"static/development/_buildManifest.js",
"static/development/_ssgManifest.js"
],
"rootMainFiles": [],
"pages": {
"/": [
"static/chunks/webpack.js",
"static/chunks/main.js",
"static/chunks/pages/index.js"
],
"/_app": [
"static/chunks/webpack.js",
"static/chunks/main.js",
"static/chunks/pages/_app.js"
],
"/_error": [
"static/chunks/webpack.js",
"static/chunks/main.js",
"static/chunks/pages/_error.js"
],
"/initial-props": [
"static/chunks/webpack.js",
"static/chunks/main.js",
"static/chunks/pages/initial-props.js"
]
},
"ampFirstPages": []
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
{"type": "commonjs"}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,6 @@
{
"sortedMiddleware": [],
"middleware": {},
"functions": {},
"version": 1
}

View File

@ -0,0 +1,7 @@
{
"/_app": "pages/_app.js",
"/_error": "pages/_error.js",
"/_document": "pages/_document.js",
"/": "pages/index.js",
"/initial-props": "pages/initial-props.js"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,168 @@
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({});
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ var threw = true;
/******/ try {
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ threw = false;
/******/ } finally {
/******/ if(threw) delete __webpack_module_cache__[moduleId];
/******/ }
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = __webpack_modules__;
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/ensure chunk */
/******/ (() => {
/******/ __webpack_require__.f = {};
/******/ // This file contains only the entry chunk.
/******/ // The chunk loading function for additional chunks
/******/ __webpack_require__.e = (chunkId) => {
/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
/******/ __webpack_require__.f[key](chunkId, promises);
/******/ return promises;
/******/ }, []));
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/get javascript chunk filename */
/******/ (() => {
/******/ // This function allow to reference async chunks and sibling chunks for the entrypoint
/******/ __webpack_require__.u = (chunkId) => {
/******/ // return url for filenames based on template
/******/ return undefined;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/startup entrypoint */
/******/ (() => {
/******/ __webpack_require__.X = (result, chunkIds, fn) => {
/******/ // arguments: chunkIds, moduleId are deprecated
/******/ var moduleId = chunkIds;
/******/ if(!fn) chunkIds = result, fn = () => (__webpack_require__(__webpack_require__.s = moduleId));
/******/ chunkIds.map(__webpack_require__.e, __webpack_require__)
/******/ var r = fn();
/******/ return r === undefined ? result : r;
/******/ }
/******/ })();
/******/
/******/ /* webpack/runtime/require chunk loading */
/******/ (() => {
/******/ // no baseURI
/******/
/******/ // object to store loaded chunks
/******/ // "1" means "loaded", otherwise not loaded yet
/******/ var installedChunks = {
/******/ "webpack-runtime": 1
/******/ };
/******/
/******/ // no on chunks loaded
/******/
/******/ var installChunk = (chunk) => {
/******/ var moreModules = chunk.modules, chunkIds = chunk.ids, runtime = chunk.runtime;
/******/ for(var moduleId in moreModules) {
/******/ if(__webpack_require__.o(moreModules, moduleId)) {
/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(runtime) runtime(__webpack_require__);
/******/ for(var i = 0; i < chunkIds.length; i++)
/******/ installedChunks[chunkIds[i]] = 1;
/******/
/******/ };
/******/
/******/ // require() chunk loading for javascript
/******/ __webpack_require__.f.require = (chunkId, promises) => {
/******/ // "1" is the signal for "already loaded"
/******/ if(!installedChunks[chunkId]) {
/******/ if("webpack-runtime" != chunkId) {
/******/ installChunk(require("./" + __webpack_require__.u(chunkId)));
/******/ } else installedChunks[chunkId] = 1;
/******/ }
/******/ };
/******/
/******/ module.exports = __webpack_require__;
/******/ __webpack_require__.C = installChunk;
/******/
/******/ // no HMR
/******/
/******/ // no HMR manifest
/******/ })();
/******/
/************************************************************************/
/******/
/******/
/******/ })()
;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,28 @@
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([["pages/_error"],{
/***/ "../node_modules/next/dist/build/webpack/loaders/next-client-pages-loader.js?absolutePagePath=private-next-pages%2F_error&page=%2F_error!":
/*!************************************************************************************************************************************************!*\
!*** ../node_modules/next/dist/build/webpack/loaders/next-client-pages-loader.js?absolutePagePath=private-next-pages%2F_error&page=%2F_error! ***!
\************************************************************************************************************************************************/
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
eval(__webpack_require__.ts("\n (window.__NEXT_P = window.__NEXT_P || []).push([\n \"/_error\",\n function () {\n return __webpack_require__(/*! private-next-pages/_error */ \"../node_modules/next/dist/pages/_error.js\");\n }\n ]);\n if(true) {\n module.hot.dispose(function () {\n window.__NEXT_P.push([\"/_error\"])\n });\n }\n //# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi4vbm9kZV9tb2R1bGVzL25leHQvZGlzdC9idWlsZC93ZWJwYWNrL2xvYWRlcnMvbmV4dC1jbGllbnQtcGFnZXMtbG9hZGVyLmpzP2Fic29sdXRlUGFnZVBhdGg9cHJpdmF0ZS1uZXh0LXBhZ2VzJTJGX2Vycm9yJnBhZ2U9JTJGX2Vycm9yIS5qcyIsIm1hcHBpbmdzIjoiO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxtQkFBTyxDQUFDLDRFQUEyQjtBQUNsRDtBQUNBO0FBQ0EsT0FBTyxJQUFVO0FBQ2pCLE1BQU0sVUFBVTtBQUNoQjtBQUNBLE9BQU87QUFDUDtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vX05fRS8/N2NlYiJdLCJzb3VyY2VzQ29udGVudCI6WyJcbiAgICAod2luZG93Ll9fTkVYVF9QID0gd2luZG93Ll9fTkVYVF9QIHx8IFtdKS5wdXNoKFtcbiAgICAgIFwiL19lcnJvclwiLFxuICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gcmVxdWlyZShcInByaXZhdGUtbmV4dC1wYWdlcy9fZXJyb3JcIik7XG4gICAgICB9XG4gICAgXSk7XG4gICAgaWYobW9kdWxlLmhvdCkge1xuICAgICAgbW9kdWxlLmhvdC5kaXNwb3NlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgd2luZG93Ll9fTkVYVF9QLnB1c2goW1wiL19lcnJvclwiXSlcbiAgICAgIH0pO1xuICAgIH1cbiAgIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///../node_modules/next/dist/build/webpack/loaders/next-client-pages-loader.js?absolutePagePath=private-next-pages%2F_error&page=%2F_error!\n"));
/***/ })
},
/******/ function(__webpack_require__) { // webpackRuntimeModules
/******/ var __webpack_exec__ = function(moduleId) { return __webpack_require__(__webpack_require__.s = moduleId); }
/******/ __webpack_require__.O(0, ["pages/_app","main"], function() { return __webpack_exec__("../node_modules/next/dist/build/webpack/loaders/next-client-pages-loader.js?absolutePagePath=private-next-pages%2F_error&page=%2F_error!"); });
/******/ var __webpack_exports__ = __webpack_require__.O();
/******/ _N_E = __webpack_exports__;
/******/ }
]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
self.__BUILD_MANIFEST = {__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static\u002Fchunks\u002Fpages\u002Findex.js"],"/_error":["static\u002Fchunks\u002Fpages\u002F_error.js"],"/initial-props":["static\u002Fchunks\u002Fpages\u002Finitial-props.js"],sortedPages:["\u002F","\u002F_app","\u002F_error","\u002Finitial-props"]};self.__BUILD_MANIFEST_CB && self.__BUILD_MANIFEST_CB()

View File

@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set;self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

View File

@ -0,0 +1 @@
{"c":["webpack"],"r":[],"m":[]}

View File

@ -0,0 +1 @@
{"c":["webpack"],"r":[],"m":[]}

View File

@ -0,0 +1,66 @@
"use strict";
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
self["webpackHotUpdate_N_E"]("webpack",{},
/******/ function(__webpack_require__) { // webpackRuntimeModules
/******/ /* webpack/runtime/compat get default export */
/******/ !function() {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function() { return module['default']; } :
/******/ function() { return module; };
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ !function() {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = function(exports, definition) {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ !function() {
/******/ __webpack_require__.h = function() { return "f320c99a8c730992"; }
/******/ }();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ !function() {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/compat */
/******/
/******/
/******/ // noop fns to prevent runtime errors during initialization
/******/ if (typeof self !== "undefined") {
/******/ self.$RefreshReg$ = function () {};
/******/ self.$RefreshSig$ = function () {
/******/ return function (type) {
/******/ return type;
/******/ };
/******/ };
/******/ }
/******/
/******/ }
);

View File

@ -0,0 +1,18 @@
"use strict";
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
self["webpackHotUpdate_N_E"]("webpack",{},
/******/ function(__webpack_require__) { // webpackRuntimeModules
/******/ /* webpack/runtime/getFullHash */
/******/ !function() {
/******/ __webpack_require__.h = function() { return "607e8ec64abecbff"; }
/******/ }();
/******/
/******/ }
);

7
renderer/.next/trace Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,40 @@
import React, { ReactNode } from 'react'
import Link from 'next/link'
import Head from 'next/head'
type Props = {
children: ReactNode
title?: string
}
const Layout = ({ children, title = 'This is the default title' }: Props) => (
<div>
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<header>
<nav>
<Link href="/">
<a>Home</a>
</Link>{' '}
|{' '}
<Link href="/about">
<a>About</a>
</Link>{' '}
|{' '}
<Link href="/initial-props">
<a>With Initial Props</a>
</Link>
</nav>
</header>
{children}
<footer>
<hr />
<span>I'm here to stay (Footer)</span>
</footer>
</div>
)
export default Layout

View File

@ -0,0 +1,19 @@
import React from 'react'
import ListItem from './ListItem'
import { User } from '../interfaces'
type Props = {
items: User[]
}
const List = ({ items }: Props) => (
<ul>
{items.map((item) => (
<li key={item.id}>
<ListItem data={item} />
</li>
))}
</ul>
)
export default List

View File

@ -0,0 +1,16 @@
import * as React from 'react'
import { User } from '../interfaces'
type ListDetailProps = {
item: User
}
const ListDetail = ({ item: user }: ListDetailProps) => (
<div>
<h1>Detail for {user.name}</h1>
<p>ID: {user.id}</p>
</div>
)
export default ListDetail

View File

@ -0,0 +1,18 @@
import React from 'react'
import Link from 'next/link'
import { User } from '../interfaces'
type Props = {
data: User
}
const ListItem = ({ data }: Props) => (
<Link href="/detail/[id]" as={`/detail/${data.id}`}>
<a>
{data.id}: {data.name}
</a>
</Link>
)
export default ListItem

View File

@ -0,0 +1,21 @@
// You can include shared interfaces/types in a separate file
// and then use them in any component by importing them. For
// example, to import the interface below do:
//
// import User from 'path/to/interfaces';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { IpcRenderer } from 'electron'
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS {
interface Global {
ipcRenderer: IpcRenderer
}
}
}
export type User = {
id: number
name: string
}

16
renderer/pages/about.tsx Normal file
View File

@ -0,0 +1,16 @@
import Link from 'next/link'
import Layout from '../components/Layout'
const AboutPage = () => (
<Layout title="About | Next.js + TypeScript + Electron Example">
<h1>About</h1>
<p>This is the about page</p>
<p>
<Link href="/">
<a>Go home</a>
</Link>
</p>
</Layout>
)
export default AboutPage

View File

@ -0,0 +1,62 @@
// import { NextPageContext } from 'next'
import Layout from '../../components/Layout'
import { User } from '../../interfaces'
import { findAll, findData } from '../../utils/sample-api'
import ListDetail from '../../components/ListDetail'
import { GetStaticPaths, GetStaticProps } from 'next'
type Params = {
id?: string
}
type Props = {
item?: User
errors?: string
}
const InitialPropsDetail = ({ item, errors }: Props) => {
if (errors) {
return (
<Layout title={`Error | Next.js + TypeScript + Electron Example`}>
<p>
<span style={{ color: 'red' }}>Error:</span> {errors}
</p>
</Layout>
)
}
return (
<Layout
title={`${item ? item.name : 'Detail'} | Next.js + TypeScript Example`}
>
{item && <ListDetail item={item} />}
</Layout>
)
}
export const getStaticPaths: GetStaticPaths = async () => {
const items: User[] = await findAll()
const paths = items.map((item) => `/detail/${item.id}`)
return { paths, fallback: false }
}
export const getStaticProps: GetStaticProps = async ({ params }) => {
const { id } = params as Params
try {
const item = await findData(Array.isArray(id) ? id[0] : id)
return {
props: {
item,
},
}
} catch (err) {
return {
props: {
errors: err.message,
},
}
}
}
export default InitialPropsDetail

34
renderer/pages/index.tsx Normal file
View File

@ -0,0 +1,34 @@
import { useEffect } from 'react'
import Link from 'next/link'
import Layout from '../components/Layout'
const IndexPage = () => {
useEffect(() => {
const handleMessage = (_event, args) => alert(args)
// add a listener to 'message' channel
global.ipcRenderer.addListener('message', handleMessage)
return () => {
global.ipcRenderer.removeListener('message', handleMessage)
}
}, [])
const onSayHiClick = () => {
global.ipcRenderer.send('message', 'hi from next')
}
return (
<Layout title="Home | Next.js + TypeScript + Electron Example">
<h1>Hello Next.js 👋</h1>
<button onClick={onSayHiClick}>Say hi to electron</button>
<p>
<Link href="/about">
<a>About</a>
</Link>
</p>
</Layout>
)
}
export default IndexPage

View File

@ -0,0 +1,35 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import Layout from '../components/Layout'
import List from '../components/List'
import { User } from '../interfaces'
import { findAll } from '../utils/sample-api'
type Props = {
items: User[]
pathname: string
}
const WithInitialProps = ({ items }: Props) => {
const router = useRouter()
return (
<Layout title="List Example (as Function Component) | Next.js + TypeScript + Electron Example">
<h1>List Example (as Function Component)</h1>
<p>You are currently on: {router.pathname}</p>
<List items={items} />
<p>
<Link href="/">
<a>Go home</a>
</Link>
</p>
</Layout>
)
}
export async function getStaticProps() {
const items: User[] = await findAll()
return { props: { items } }
}
export default WithInitialProps

20
renderer/tsconfig.json Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@ -0,0 +1,34 @@
import { User } from '../interfaces'
/** Dummy user data. */
export const dataArray: User[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
]
/**
* Calls a mock API which finds a user by ID from the list above.
*
* Throws an error if not found.
*/
export async function findData(id: number | string) {
const selected = dataArray.find((data) => data.id === Number(id))
if (!selected) {
throw new Error('Cannot find user')
}
return selected
}
/** Calls a mock API which returns the above array to simulate "get all". */
export async function findAll() {
// Throw an error, just for example.
if (!Array.isArray(dataArray)) {
throw new Error('Cannot find users')
}
return dataArray
}

2181
yarn.lock Normal file

File diff suppressed because it is too large Load Diff