{"id":14962462,"url":"https://github.com/codec-xyz/vtest","last_synced_at":"2025-09-11T04:33:48.026Z","repository":{"id":253098220,"uuid":"842428060","full_name":"codec-xyz/vtest","owner":"codec-xyz","description":"Template project with Vite, Typescript, Electron Forge, SvelteKit, Tailwind CSS","archived":false,"fork":false,"pushed_at":"2024-12-04T09:55:35.000Z","size":782,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T04:31:49.268Z","etag":null,"topics":["electron","electronforge","nodejs","svelte","sveltejs","sveltekit","sveltekit-template","tailwind","tailwindcss","template","typescript","vite"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codec-xyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-14T10:30:41.000Z","updated_at":"2025-01-15T08:37:16.000Z","dependencies_parsed_at":"2024-09-02T17:10:47.203Z","dependency_job_id":"dea63ad6-b380-4872-9f77-924bc0137ab5","html_url":"https://github.com/codec-xyz/vtest","commit_stats":{"total_commits":16,"total_committers":1,"mean_commits":16.0,"dds":0.0,"last_synced_commit":"8275b92197a83797b8069a1b787815e1a3714292"},"previous_names":["codec-xyz/vtest"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codec-xyz%2Fvtest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codec-xyz%2Fvtest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codec-xyz%2Fvtest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codec-xyz%2Fvtest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codec-xyz","download_url":"https://codeload.github.com/codec-xyz/vtest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238043893,"owners_count":19407117,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electron","electronforge","nodejs","svelte","sveltejs","sveltekit","sveltekit-template","tailwind","tailwindcss","template","typescript","vite"],"created_at":"2024-09-24T13:29:53.328Z","updated_at":"2025-09-11T04:33:48.019Z","avatar_url":"https://github.com/codec-xyz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ***V***ite + ***T***ypescript + ***E***lectron Forge + ***S***velteKit + ***T***ailwind CSS\n\nTemplate project with ***V***ite, ***T***ypescript, ***E***lectron Forge, ***S***velteKit, ***T***ailwind CSS\n\n\u003e [!Note]\n\u003e\n\u003e This template contains numerous comments with explanations and links throughout the source code.\n\n![](readme001.png)\n\n```\ngit clone https://github.com/codec-xyz/vtest MyAwesomeApp\n\ncd MyAwesomeApp\n\nnpm install\n\nnpm run start\n```\n\n\u003e [!Note]\n\u003e\n\u003e Typescript will complain in the editor when you first clone the template. When you first run `npm run start` a `.svelte-kit` folder will be generated and the errors and warnings should go away.\n\n---\n\nThis template project consists of two parts...\n- Example main, preload, and renderer code\n- A build system\n\n# Example code\n\nThe example code is the part that will be bundled with the electron application. It has 3 parts...\n\n- Main Electron Node process - Located in [src-main](./src-main/)\n- Preload - See [Using Preload Scripts](https://www.electronjs.org/docs/latest/tutorial/tutorial-preload) - Located in [src-renderer](./src-renderer/) purely preferentially but done so since it will execute in the same context as the renderer\n- Renderer aka SvelteKit - Located in [src-renderer](./src-renderer/)\n\n## SvelteKit building and adaptor-static\n\nSvelteKit build outputs code to render your files on a server. These will be located in `.svelte-kit/output/` and during `npm run start` a dev server runs to serve files using this code. During `npm run package` [adaptor-static](https://kit.svelte.dev/docs/adapter-static) will then run this same code to make the browser html/css/js files and save them at `.vite/renderer/main_window/` as specified in [`svelte.config.js`](svelte.config.js).\n\nI recommend you do not use SvelteKit's prerendering for your Electron apps. SvelteKit prerendering will slightly speed up the first load (when you open a window). However when navigating, SvelteKit will load Javascript and render pages even if they have been prerendered. Unlike web use cases Electron apps are likely to see almost none of the prerender benefits. Not using the prerendering will slightly simplify development. If you do however want prerendering here is how to do it...\n\n\u003cdetails\u003e\nThese two options placed in `+layout.ts` or `+page.ts` files tell adapter-static how to render the files...\n\n```\nexport const prerender = false;\nexport const ssr = false;\n```\n\n\u003e [!Note]\n\u003e\n\u003e For adaptor-static keep the values the same, so either both true or both false.\n\n- `prerender` - weather or not adapter-static will output an html file for this page\n- `ssr` - weather or no adapter-static will prerender the page aka: false = blank page (and browser js to render the page)\n\nValues of `prerender = false` and `ssr = false` means no html file is output for the this page. It will work as an [SPA (Single Page Application)](https://kit.svelte.dev/docs/single-page-apps) where this or any other page that are not present will use the fallback page `200.html` which is specified to adapter-static in `svelte.config.js`.\n\nValues of `prerender = true` and `ssr = true` will prerender the page at build time and output an html file. One that is not blank. Reactivity, event handlers, and all other svelte features will still work. However this is prerendered during build time meaning no Electron feature and some other features will not be present. For example, state cannot be dependent on preferred color theme or window size. Use this to detect browser vs prerender...\n```\nimport { browser } from '$app/environment';\nif(browser) { ... }\n```\n\u003c/details\u003e\n\n## Typescript\n\nMake sure to put `lang='ts'` in the Svelte files to use Typescript...\n```svelte\n\u003cscript lang=\"ts\"\u003e\n\t// ...\n\u003c/script\u003e\n```\n\n## Serving files\n\nThe Vite SvelteKit dev server serves a fallback html file for all urls that do no point to a file. This is replicated in the built version of the app by registering an `app://` schema and handling resolving urls manual. This uses Electrons `protocol.handle` and `protocol.registerSchemesAsPrivileged`. The window url is set to the dev server in dev mode or `app://-/` when built. The Electron `protocol.handle` simply takes a callback that is invoked to handle every request to the specified schema however it wants. The code is located in [`src-main/main.ts`](./src-main/main.ts). For more see [Electron protocol api](https://www.electronjs.org/docs/latest/api/protocol).\n\n# The build system\n\nThe build system looks like this...\n\n- [`forge.config.ts`](./forge.config.ts) - [Electron forge](https://www.electronforge.io/)\n\t- [`./build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts) - An Electron Forge plugin that builds the project during `start` and `package` using Vite. See [Forge Plugin - Vite](#forge-plugin---vite).\n\t\t- [`vite.main.config.ts`](./vite.main.config.ts)\n\t\t\t- optional [`./build-plugins/vite-plugin.nativeNodeFile.ts`](./build-plugins/vite-plugin.nativeNodeFile.ts) - If your app needs native `.node` files bundled. See [Native node addons](#native-node-addons).\n\t\t- [`vite.preload.config.ts`](./vite.preload.config.ts)\n\t\t- [`vite.renderer.config.ts`](./vite.renderer.config.ts) - Svelte/Svelte Kit is implemented as a Vite plugin which is passed here\n\t\t\t- [`svelte.config.js`](./svelte.config.js)\n\t\t\t- [`tailwind.config.ts`](./tailwind.config.ts)\n\n## Forge Plugin - Vite\n\nLocated in [`./build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts). Its config can be found in [`forge.config.ts`](./forge.config.ts).\n\n\u003e [!NOTE]\n\u003e This template does NOT use the official [`@electron-forge/plugin-vite`](https://www.npmjs.com/package/@electron-forge/plugin-vite) for a few reasons...\n\u003e\n\u003e - It hides away configuration\n\u003e - Its functionality cannot be extended\n\u003e - And I would say its better to own this part of the build process in case you need to change it\n\n### `npm run start`\n\nRuns the app in dev mode with hot reloading.\n\n[`build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts) does the following...\n\n- Starts all vite renderer servers in dev mode - in this template just the one [`vite.renderer.config.ts`](./vite.renderer.config.ts) which has a Svelte Kit plugin\n- Once the servers start and return their urls...\n- Then starts all vite builds with watch enabled - in this template [`vite.main.config.ts`](./vite.main.config.ts) and [`vite.preload.config.ts`](./vite.preload.config.ts)\n\t- Passes the renderer urls to the builds using a [Vite define](https://vite.dev/config/shared-options.html#define)\n- Then allows the electron app to open\n- Vite renderer servers handle hot reloading normally - the plugin does not need to do anything\n- When a vite build sees changes and rebuilds this plugin can as specified in its config...\n\t- Restarting the Electron process\n\t- Or tell all renderers to do a full reload\n\n### `npm run package`\n\nPackages the \"application into a platform-specific executable bundle\"[\u003csup\u003eref\u003c/sup\u003e](https://www.electronforge.io/cli).\n\nFirst Electron Forge copies the entire project to a temporary folder.\n\nThen [`build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts) does the following...\n\n- Calls `@electron/rebuild` - builds native node addons for Electron - Note: In this template there are no native node addons. See [Native node addons](#native-node-addons).\n- Runs Vite build for all renderers and builds - Note: this is done in a separate process because Vite only release config files once the process exits\n- Deletes all files except for `.vite` folder and `package.json` - Note: `package.json` is needed for its `main` and `type` fields\n- Prints fancy ascii art that it is done\n\n\n\u003e [!NOTE]\n\u003e\n\u003e [`./build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts) calls `@electron/rebuild` itself to be able to run Vite and delete all uneccesay files after the rebuild. Electron Forge does NOT give plugins a hook to run after rebuild and before files are packaged in the output folder.\n\n\n## Native node addons\n\nNative node addons allow native code to be imported directly into node. These need to be compiled against Electron to be used. The `@electron/rebuild` that comes with Electron Forge does this. The included [`build-plugins/vite-plugin.nativeNodeFiles.ts`](./build-plugins/vite-plugin.nativeNodeFiles.ts) is a Vite plugin that will bundle the `.node` files into the build.\n\nPackages need custom handling to make this work and all work differently and do their own special things. Good luck trying to make them work. Likely you will need to modify [`./build-plugins/forge-plugin.vite.ts`](./build-plugins/forge-plugin.vite.ts).\n\n### Example - Your own C++ node addon\n\nRun `npm i -D node-gyp node-addon-api`.\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd a \u003ccode\u003ebinding.gyp\u003c/code\u003e file in root...\u003c/summary\u003e\n\n```\n{\n\t\"targets\": [{\n\t\t\"target_name\": \"native\",\n\t\t\"sources\": [ \"src-native/index.cpp\" ],\n\t\t\"include_dirs\": [\"\u003c!@(node -p \\\"require('node-addon-api').include\\\")\"],\n\t\t\"dependencies\": [\"\u003c!(node -p \\\"require('node-addon-api').gyp\\\")\"],\n\t\t\"cflags!\": [ \"-fno-exceptions\" ],\n\t\t\"cflags_cc!\": [ \"-fno-exceptions\" ],\n\t\t\"xcode_settings\": {\n\t\t\"GCC_ENABLE_CPP_EXCEPTIONS\": \"YES\",\n\t\t\"CLANG_CXX_LIBRARY\": \"libc++\",\n\t\t\t\"MACOSX_DEPLOYMENT_TARGET\": \"10.7\"\n\t\t},\n\t\t\"msvs_settings\": {\n\t\t\t\"VCCLCompilerTool\": { \"ExceptionHandling\": 1 },\n\t\t},\n\t\t\"conditions\": [\n\t\t\t[\"OS=='mac'\", {\n\t\t\t\t\"defines\": [ \"MAC_OS\" ],\n\t\t\t\t\"cflags+\": [\"-fvisibility=hidden\"],\n\t\t\t\t\"xcode_settings\": {\n\t\t\t\t\t\"GCC_SYMBOLS_PRIVATE_EXTERN\": \"YES\", # -fvisibility=hidden\n\t\t\t\t}\n\t\t\t}],\n\t\t\t[\"OS=='win'\", {\n\t\t\t\t\"defines\": [ \"WINDOWS_OS\" ]\n\t\t\t}]\n\t\t]\n\t}]\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd a \u003ccode\u003esrc-native/index.cpp\u003c/code\u003e file...\u003c/summary\u003e\n\n```cpp\n#define NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED \n\n#include \u003cnapi.h\u003e\n#include \u003ciostream\u003e\n\nNapi::Value helloWorld(const Napi::CallbackInfo\u0026 info) {\n\tNapi::Env env = info.Env();\n\t\n\tstd::cout \u003c\u003c \"C++: Hello\" \u003c\u003c std::endl;\n\n\treturn Napi::String::New(env, \"World\");\n}\n\nNapi::Object init(Napi::Env env, Napi::Object exports) {\n\texports.Set(Napi::String::New(env, \"helloWorld\"), Napi::Function::New(env, helloWorld));\n\treturn exports;\n}\n\nNODE_API_MODULE(addon, init);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd a \u003ccode\u003esrc-native/native.d.ts\u003c/code\u003e file...\u003c/summary\u003e\n\n```typescript\ndeclare const native: {\n\thelloWorld: () =\u003e string,\n};\n\nexport default native;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eAdd this to your \u003ca href='./vite.main.config.ts'\u003e\u003ccode\u003evite.main.config.ts\u003c/code\u003e\u003c/a\u003e file...\u003c/summary\u003e\n\n```typescript\n//...\nimport { nativeNodeFile } from './build-plugins/vite-plugin.nativeNodeFile';\n\nexport default defineConfig({\n\t//...\n\tplugins: [\n\t\tnativeNodeFile([{\n\t\t\t// Location of the type definition file. Whenever this is imported this plugin\n\t\t\t// will replace the import with an import of the `.node` file.\n\t\t\timport: './src-native/native',\n\t\t\t// Source location of the built `.node` file.\n\t\t\tbuilt: './build/Release/native.node',\n\t\t\t// Location to put the `.node` file relative to output bundle.\n\t\t\tincludePath: '../bin/native.node'\n\t\t}]),\n\t],\n\t//...\n});\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eNow in your \u003ca href='./src-main/main.ts'\u003e\u003ccode\u003esrc-main/main.ts\u003c/code\u003e\u003c/a\u003e file add...\u003c/summary\u003e\n\n```typescript\nimport native from '../src-native/native';\nconsole.log('Javascript:', native.helloWorld());\n```\n\n\u003c/details\u003e\n\nThe native code will NOT be compiled after the first time so...\n- You can uncomment `force: true,` in [`forge.config.ts`](./forge.config.ts) to make sure your code gets compiled every time you `start` or `package`.\n- And/or you can add `\"rebuild\": \"electron-rebuild -f -w native --disable-pre-gyp-copy\"` command to your [`package.json`](./package.json).\n\t- Note: `native` is the name of the module given in [`binding.gyp`](./binding.gyp).\n\n## Electron Forge CLI commands\n\nThe Electron Forge CLI commands in `package.json` run the cli command script file with tsx to fix the Electron Forge CLI's typescript support for the config file. This is a known issue [#3671](https://github.com/electron/forge/issues/3671). Note: You can specify any cli options the usually way.\n\n# License\n\nCode/assets in this template come from...\n- Electron Forge's [Vite Typescript template](https://github.com/electron/forge/tree/main/packages/template/vite-typescript) licensed under [MIT](https://github.com/electron/forge/blob/main/LICENSE).\n- SvelteKit's [create-svelte template](https://github.com/sveltejs/kit/tree/main/packages/create-svelte) licensed under [MIT](https://github.com/sveltejs/kit/blob/main/LICENSE)\n- Logos from https://svgl.app/\n\nAnd everything else done by \u003cspan property=\"cc:attributionName\"\u003eme (codec)\u003c/span\u003e is marked with \u003ca href=\"https://creativecommons.org/publicdomain/zero/1.0/\" target=\"_blank\" rel=\"license noopener noreferrer\" style=\"display:inline-block;\"\u003eCC0 1.0\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/cc.svg\" alt=\"\"\u003e\u003cimg style=\"height:22px!important;margin-left:3px;vertical-align:text-bottom;\" src=\"https://mirrors.creativecommons.org/presskit/icons/zero.svg\" alt=\"\"\u003e\u003c/a\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodec-xyz%2Fvtest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodec-xyz%2Fvtest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodec-xyz%2Fvtest/lists"}