basic svelte+vite+windicss app

This commit is contained in:
Philipp Dormann 2021-03-14 19:26:21 +01:00
parent 560b0f4c74
commit e94ce9731d
51 changed files with 476 additions and 5869 deletions

View File

@ -1,18 +0,0 @@
# EditorConfig is awesome: http://EditorConfig.org
# https://github.com/jokeyrhyme/standard-editorconfig
# top-most EditorConfig file
root = true
# defaults
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 2
indent_style = space
[*.md]
trim_trailing_whitespace = false

0
.env
View File

View File

@ -1,4 +0,0 @@
# This is a stub.
# It is needed as a data sample for TypeScript & Typechecking.
# The real value of the variable is set in /bin/watch.js and depend on /config/renderer.vite.js
VITE_DEV_SERVER_URL=http://localhost:3000/

View File

View File

@ -1,44 +0,0 @@
module.exports = {
root: true,
env: {
es2021: true,
node: true,
browser: false,
},
extends: [
/** @see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#recommended-configs */
'plugin:@typescript-eslint/recommended',
],
parserOptions: {
ecmaVersion: 12,
sourceType: 'module',
},
plugins: [
'@typescript-eslint',
],
ignorePatterns: [
'types/env.d.ts',
'node_modules/**',
'dist/**',
],
rules: {
/**
* Having a semicolon helps the optimizer interpret your code correctly.
* This avoids rare errors in optimized code.
*/
semi: ['error', 'always'],
/**
* This will make the history of changes in the hit a little cleaner
*/
'comma-dangle': ['warn', 'always-multiline'],
/**
* Just for beauty
*/
quotes: ['warn', 'single'],
},
};

59
.gitignore vendored
View File

@ -1,56 +1,5 @@
node_modules
/node_modules/
/dist/
.DS_Store
dist
*.local
thumbs.db
types/env.d.ts
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
.idea/artifacts
.idea/compiler.xml
.idea/jarRepositories.xml
.idea/modules.xml
.idea/*.iml
.idea/modules
*.iml
*.ipr
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# Editor-based Rest Client
.idea/httpRequests
.routify/
package-lock.json

362
LICENSE
View File

@ -1,362 +0,0 @@
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Creative
Commons Corporation ("Creative Commons") is not a law firm and does not provide
legal services or legal advice. Distribution of Creative Commons public licenses
does not create a lawyer-client or other relationship. Creative Commons makes
its licenses and related information available on an "as-is" basis. Creative
Commons gives no warranties regarding its licenses, any material licensed
under their terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the fullest
extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and conditions
that creators and other rights holders may use to share original works of
authorship and other material subject to copyright and certain other rights
specified in the public license below. The following considerations are for
informational purposes only, are not exhaustive, and do not form part of our
licenses.
Considerations for licensors: Our public licenses are intended for use by
those authorized to give the public permission to use material in ways otherwise
restricted by copyright and certain other rights. Our licenses are irrevocable.
Licensors should read and understand the terms and conditions of the license
they choose before applying it. Licensors should also secure all rights necessary
before applying our licenses so that the public can reuse the material as
expected. Licensors should clearly mark any material not subject to the license.
This includes other CC-licensed material, or material used under an exception
or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public licenses, a licensor
grants the public permission to use the licensed material under specified
terms and conditions. If the licensor's permission is not necessary for any
reasonfor example, because of any applicable exception or limitation to copyrightthen
that use is not regulated by the license. Our licenses grant only permissions
under copyright and certain other rights that a licensor has authority to
grant. Use of the licensed material may still be restricted for other reasons,
including because others have copyright or other rights in the material. A
licensor may make special requests, such as asking that all changes be marked
or described. Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More considerations for the public
: wiki.creativecommons.org/Considerations_for_licensees
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree to
be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike
4.0 International Public License ("Public License"). To the extent this Public
License may be interpreted as a contract, You are granted the Licensed Rights
in consideration of Your acceptance of these terms and conditions, and the
Licensor grants You such rights in consideration of benefits the Licensor
receives from making the Licensed Material available under these terms and
conditions.
Section 1 Definitions.
a. Adapted Material means material subject to Copyright and Similar Rights
that is derived from or based upon the Licensed Material and in which the
Licensed Material is translated, altered, arranged, transformed, or otherwise
modified in a manner requiring permission under the Copyright and Similar
Rights held by the Licensor. For purposes of this Public License, where the
Licensed Material is a musical work, performance, or sound recording, Adapted
Material is always produced where the Licensed Material is synched in timed
relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright and Similar
Rights in Your contributions to Adapted Material in accordance with the terms
and conditions of this Public License.
c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses,
approved by Creative Commons as essentially the equivalent of this Public
License.
d. Copyright and Similar Rights means copyright and/or similar rights closely
related to copyright including, without limitation, performance, broadcast,
sound recording, and Sui Generis Database Rights, without regard to how the
rights are labeled or categorized. For purposes of this Public License, the
rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
e. Effective Technological Measures means those measures that, in the absence
of proper authority, may not be circumvented under laws fulfilling obligations
under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996,
and/or similar international agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or any other
exception or limitation to Copyright and Similar Rights that applies to Your
use of the Licensed Material.
g. License Elements means the license attributes listed in the name of a Creative
Commons Public License. The License Elements of this Public License are Attribution,
NonCommercial, and ShareAlike.
h. Licensed Material means the artistic or literary work, database, or other
material to which the Licensor applied this Public License.
i. Licensed Rights means the rights granted to You subject to the terms and
conditions of this Public License, which are limited to all Copyright and
Similar Rights that apply to Your use of the Licensed Material and that the
Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights under this
Public License.
k. NonCommercial means not primarily intended for or directed towards commercial
advantage or monetary compensation. For purposes of this Public License, the
exchange of the Licensed Material for other material subject to Copyright
and Similar Rights by digital file-sharing or similar means is NonCommercial
provided there is no payment of monetary compensation in connection with the
exchange.
l. Share means to provide material to the public by any means or process that
requires permission under the Licensed Rights, such as reproduction, public
display, public performance, distribution, dissemination, communication, or
importation, and to make material available to the public including in ways
that members of the public may access the material from a place and at a time
individually chosen by them.
m. Sui Generis Database Rights means rights other than copyright resulting
from Directive 96/9/EC of the European Parliament and of the Council of 11
March 1996 on the legal protection of databases, as amended and/or succeeded,
as well as other essentially equivalent rights anywhere in the world.
n. You means the individual or entity exercising the Licensed Rights under
this Public License. Your has a corresponding meaning.
Section 2 Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License, the Licensor
hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive,
irrevocable license to exercise the Licensed Rights in the Licensed Material
to:
A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial
purposes only; and
B. produce, reproduce, and Share Adapted Material for NonCommercial purposes
only.
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions
and Limitations apply to Your use, this Public License does not apply, and
You do not need to comply with its terms and conditions.
3. Term. The term of this Public License is specified in Section 6(a).
4. Media and formats; technical modifications allowed. The Licensor authorizes
You to exercise the Licensed Rights in all media and formats whether now known
or hereafter created, and to make technical modifications necessary to do
so. The Licensor waives and/or agrees not to assert any right or authority
to forbid You from making technical modifications necessary to exercise the
Licensed Rights, including technical modifications necessary to circumvent
Effective Technological Measures. For purposes of this Public License, simply
making modifications authorized by this Section 2(a)(4) never produces Adapted
Material.
5. Downstream recipients.
A. Offer from the Licensor Licensed Material. Every recipient of the Licensed
Material automatically receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this Public License.
B. Additional offer from the Licensor Adapted Material. Every recipient
of Adapted Material from You automatically receives an offer from the Licensor
to exercise the Licensed Rights in the Adapted Material under the conditions
of the Adapter's License You apply.
C. No downstream restrictions. You may not offer or impose any additional
or different terms or conditions on, or apply any Effective Technological
Measures to, the Licensed Material if doing so restricts exercise of the Licensed
Rights by any recipient of the Licensed Material.
6. No endorsement. Nothing in this Public License constitutes or may be construed
as permission to assert or imply that You are, or that Your use of the Licensed
Material is, connected with, or sponsored, endorsed, or granted official status
by, the Licensor or others designated to receive attribution as provided in
Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not licensed under this
Public License, nor are publicity, privacy, and/or other similar personality
rights; however, to the extent possible, the Licensor waives and/or agrees
not to assert any such rights held by the Licensor to the limited extent necessary
to allow You to exercise the Licensed Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this Public License.
3. To the extent possible, the Licensor waives any right to collect royalties
from You for the exercise of the Licensed Rights, whether directly or through
a collecting society under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly reserves any right
to collect such royalties, including when the Licensed Material is used other
than for NonCommercial purposes.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following
conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified form), You must:
A. retain the following if it is supplied by the Licensor with the Licensed
Material:
i. identification of the creator(s) of the Licensed Material and any others
designated to receive attribution, in any reasonable manner requested by the
Licensor (including by pseudonym if designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of warranties;
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
B. indicate if You modified the Licensed Material and retain an indication
of any previous modifications; and
C. indicate the Licensed Material is licensed under this Public License, and
include the text of, or the URI or hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner
based on the medium, means, and context in which You Share the Licensed Material.
For example, it may be reasonable to satisfy the conditions by providing a
URI or hyperlink to a resource that includes the required information.
3. If requested by the Licensor, You must remove any of the information required
by Section 3(a)(1)(A) to the extent reasonably practicable.
b. ShareAlike.In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons license with
the same License Elements, this version or later, or a BY-NC-SA Compatible
License.
2. You must include the text of, or the URI or hyperlink to, the Adapter's
License You apply. You may satisfy this condition in any reasonable manner
based on the medium, means, and context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms or conditions
on, or apply any Effective Technological Measures to, Adapted Material that
restrict exercise of the rights granted under the Adapter's License You apply.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to
Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
reuse, reproduce, and Share all or a substantial portion of the contents of
the database for NonCommercial purposes only;
b. if You include all or a substantial portion of the database contents in
a database in which You have Sui Generis Database Rights, then the database
in which You have Sui Generis Database Rights (but not its individual contents)
is Adapted Material, including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share all or
a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace
Your obligations under this Public License where the Licensed Rights include
other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
a. Unless otherwise separately undertaken by the Licensor, to the extent possible,
the Licensor offers the Licensed Material as-is and as-available, and makes
no representations or warranties of any kind concerning the Licensed Material,
whether express, implied, statutory, or other. This includes, without limitation,
warranties of title, merchantability, fitness for a particular purpose, non-infringement,
absence of latent or other defects, accuracy, or the presence or absence of
errors, whether or not known or discoverable. Where disclaimers of warranties
are not allowed in full or in part, this disclaimer may not apply to You.
b. To the extent possible, in no event will the Licensor be liable to You
on any legal theory (including, without limitation, negligence) or otherwise
for any direct, special, indirect, incidental, consequential, punitive, exemplary,
or other losses, costs, expenses, or damages arising out of this Public License
or use of the Licensed Material, even if the Licensor has been advised of
the possibility of such losses, costs, expenses, or damages. Where a limitation
of liability is not allowed in full or in part, this limitation may not apply
to You.
c. The disclaimer of warranties and limitation of liability provided above
shall be interpreted in a manner that, to the extent possible, most closely
approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
a. This Public License applies for the term of the Copyright and Similar Rights
licensed here. However, if You fail to comply with this Public License, then
Your rights under this Public License terminate automatically.
b. Where Your right to use the Licensed Material has terminated under Section
6(a), it reinstates:
1. automatically as of the date the violation is cured, provided it is cured
within 30 days of Your discovery of the violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the
Licensor may have to seek remedies for Your violations of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material
under separate terms or conditions or stop distributing the Licensed Material
at any time; however, doing so will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different terms or
conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the Licensed
Material not stated herein are separate from and independent of the terms
and conditions of this Public License.
Section 8 Interpretation.
a. For the avoidance of doubt, this Public License does not, and shall not
be interpreted to, reduce, limit, restrict, or impose conditions on any use
of the Licensed Material that could lawfully be made without permission under
this Public License.
b. To the extent possible, if any provision of this Public License is deemed
unenforceable, it shall be automatically reformed to the minimum extent necessary
to make it enforceable. If the provision cannot be reformed, it shall be severed
from this Public License without affecting the enforceability of the remaining
terms and conditions.
c. No term or condition of this Public License will be waived and no failure
to comply consented to unless expressly agreed to by the Licensor.
d. Nothing in this Public License constitutes or may be interpreted as a limitation
upon, or waiver of, any privileges and immunities that apply to the Licensor
or You, including from the legal processes of any jurisdiction or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, Creative
Commons may elect to apply one of its public licenses to material it publishes
and in those instances will be considered the "Licensor." The text of the
Creative Commons public licenses is dedicated to the public domain under the
CC0 Public Domain Dedication. Except for the limited purpose of indicating
that material is shared under a Creative Commons public license or as otherwise
permitted by the Creative Commons policies published at creativecommons.org/policies,
Creative Commons does not authorize the use of the trademark "Creative Commons"
or any other trademark or logo of Creative Commons without its prior written
consent including, without limitation, in connection with any unauthorized
modifications to any of its public licenses or any other arrangements, understandings,
or agreements concerning use of licensed material. For the avoidance of doubt,
this paragraph does not form part of the public licenses.
Creative Commons may be contacted at creativecommons.org.

215
README.md
View File

@ -1,200 +1,51 @@
# Vite Electron Builder Template
# Svelte Routify WindiCSS Vite
> Vite+Electron = 🔥
A starter template for Svelte Application with Typescript, uses Routify file-based router, WindiCSS to compile TailwindCSS and Vite.
This is a secure template for electron applications. Written following the latest safety requirements, recommendations and best practices.
[Svelte](https://svelte.dev)
[Routify](https://routify.dev)
[Vite](https://vitejs.dev)
[WindiCSS](https://windicss.org/)
[TypeScript](https://www.typescriptlang.org)
Under the hood is used [Vite 2.0][vite] — super fast, nextgen bundler, and [electron-builder] for compilation.
Kudos to all the respective authors, special thanks to [@jakobrosenberg](https://github.com/jakobrosenberg) and [@dominikg](https://github.com/dominikg).
By default, the **Vue framework** is used for the interface, but you can easily use any other frameworks such as **React**, **Preact**, **Angular**, **Svelte** or anything else.
> Vite is framework agnostic
## Support
This template maintained by [Alex Kozack][cawa-93-github]. You can [💖 sponsor him][cawa-93-sponsor] for continued development of this template.
If you have ideas, questions or suggestions - **Welcome to [discussions](https://github.com/cawa-93/vite-electron-builder/discussions)**. 😊
## Recommended requirements
- **Node**: >=14.16
- **npm**: >7.6
## Features
### Electron [![Electron version](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/dev/electron?label=%20)][electron]
- Template use the latest electron version with all the latest security patches.
- The architecture of the application is built according to the security [guids](https://www.electronjs.org/docs/tutorial/security) and best practices.
- The latest version of the [electron-builder] is used to compile the application.
### Vite [![Vite version](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/dev/vite?label=%20)][vite]
- [Vite] is used to bundle all source codes. This is an extremely fast packer that has a bunch of great features. You can learn more about how it is arranged in [this](https://youtu.be/xXrhg26VCSc) video.
- Vite [supports](https://vitejs.dev/guide/env-and-mode.html) reading `.env` files. My template has a separate command to generate `.d.ts` file with type definition your environment variables.
Vite provides you with many useful features, such as: `TypeScript`, `TSX/JSX`, `CSS/JSON Importing`, `CSS Modules`, `Web Assembly` and much more.
[See all Vite features](https://vitejs.dev/guide/features.html).
### TypeScript [![TypeScript version](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/dev/typescript?label=%20) ][typescript] (optional)
- The Latest TypeScript is used for all source code.
- **Vite** supports TypeScript out of the box. However, it does not support type checking.
- Type checking is performed in both `.ts` and `.vue` files thanks to [@vuedx/typecheck].
- Code formatting rules follow the latest TypeScript recommendations and best practices thanks to [@typescript-eslint/eslint-plugin](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin).
**Note**: If you do not need a TypeScript, you can easily abandon it. To do this, You do not need to make any bundler configuration changes, etc. Just replace all `.ts` files with `.js` files. Additionally, it will be useful to delete TS-specific files, plug-ins and dependencies like `tsconfig.json`, `@typescript-eslint/*`, etc.
### Vue [![Vue version](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/vue?label=%20)][vue] (optional)
- By default, web pages are built using the latest version of the [Vue]. However, there are no problems with using any other frameworks or technologies.
- Also, by default, the [vue-router] version [![Vue-router version](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/vue-router?label=%20)][vue-router] is included.
- Code formatting rules follow the latest Vue recommendations and best practices thanks to [eslint-plugin-vue].
- Installed [Vue.js devtools beta](https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg) with Vue 3 support.
### Continuous Integration
- The configured workflow for check the types for each push and PR.
- The configured workflow for check the code style for each push and PR.
- **Automatic tests** used [spectron]. Simple, automated test check:
- Does the main window open
- Is the main window not empty
- Is dev tools closed
### Continuous deployment
- An automatic update from GitHub releases is supported.
- Each time you push changes to the main branch, a workflow starts, which creates a new github release.
- The version number is automatically set based on the current date in the format "yy.mm.dd".
- Notes are automatically generated and added to the new release.
## Status
- ✅ Building main and renderer endpoints in production mode — works great.
- ✅ Development mode with hot reload for renderer endpoint — works great.
- ⚠ Development mode for main and preload endpoints — work fine, but it is possible to reboot the backend faster ([vite#1434](https://github.com/vitejs/vite/issues/1434))
- ✅ Compile the app with electron builder in CD — work.
- ✅ Auto update — work.
- ⚠ Typechecking in `.ts` and `.vue` files — work thanks [![@vuedx/typecheck](https://img.shields.io/github/package-json/dependency-version/cawa-93/vite-electron-builder/dev/@vuedx/typecheck)][@vuedx/typecheck]. Improvement needed.
- ⚠ Linting — work fine, but need review the configuration files and refactor its.
- ✅ Vue.js devtools beta.
- ⏳ Code signing — planned.
## How it works
The template required a minimum [dependencies](package.json). Only **Vite** is used for building, nothing more.
### Using electron API in renderer
As per the security requirements, context isolation is enabled in this template.
> Context Isolation is a feature that ensures that both your `preload` scripts and Electron's internal logic run in a separate context to the website you load in a [`webContents`](https://github.com/electron/electron/blob/master/docs/api/web-contents.md). This is important for security purposes as it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to.
>
> This means that the `window` object that your preload script has access to is actually a **different** object than the website would have access to. For example, if you set `window.hello = 'wave'` in your preload script and context isolation is enabled `window.hello` will be undefined if the website tries to access it.
[Read more about Context Isolation](https://github.com/electron/electron/blob/master/docs/tutorial/context-isolation.md).
Exposing APIs from your `preload script` to the renderer is a common usecase and there is a dedicated module in Electron to help you do this in a painless way.
```ts
// /src/preload/index.ts
const api = {
data: ['foo', 'bar'],
doThing: () => ipcRenderer.send('do-a-thing')
}
contextBridge.exposeInMainWorld('electron', api)
```
To access this API use the `useElectron()` function:
```ts
// /src/renderer/App.vue
import {useElectron} from '/@/use/electron'
const {doThing, data} = useElectron()
```
**Note**: Context isolation disabled for `test` environment. See [#693](https://github.com/electron-userland/spectron/issues/693#issuecomment-747872160).
### Modes and Environment Variables
All environment variables set as part of the `import.meta`, so you can access them as follows: `import.meta.env`.
You can also build type definitions of your variables by running `bin/buildEnvTypes.js`. This command will create `types/env.d.ts` file with describing all environment variables for all modes.
The mode option is used to specify the value of `import.meta.env.MODE` and the corresponding environment variables files that needs to be loaded.
By default, there are two modes:
- `production` is used by default
- `development` is used by `npm run watch` script
- `test` is used by `npm test` script
When running building, environment variables are loaded from the following files in your project root:
## Install
```
.env # loaded in all cases
.env.local # loaded in all cases, ignored by git
.env.[mode] # only loaded in specified env mode
.env.[mode].local # only loaded in specified env mode, ignored by git
git clone https://github.com/reepolee/svelte-routify-windi-vite.git best-dx
cd best-dx
npm i
npm run dev
```
**Note:** only variables prefixed with `VITE_` are exposed to your code (e.g. `VITE_SOME_KEY=123`) and `SOME_KEY=123` will not. you can access `VITE_SOME_KEY` using `import.meta.env.VITE_SOME_KEY`. This is because the `.env` files may be used by some users for server-side or build scripts and may contain sensitive information that should not be exposed in code shipped to browsers.
## SSG
For SSG you can use [Spank](https://github.com/roxiness/spank):
```
npm run build
npx spank
```
### Project Structure
- [`src`](src)
Contains all source code.
- [`src/main`](src/main)
Contain entrypoint for Electron [**main script**](https://www.electronjs.org/docs/tutorial/quick-start#create-the-main-script-file).
- [`src/renderer`](src/renderer)
Contain entrypoint for Electron [**web page**](https://www.electronjs.org/docs/tutorial/quick-start#create-a-web-page). All files in this directory work as a regular Vue application.
- [`src/preload`](src/preload)
Contain entrypoint for custom script. It uses as `preload` script in `BrowserWindow.webPreferences.preload`. See [Checklist: Security Recommendations](https://www.electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content).
- [`src/*`](src) It is assumed any entry points will be added here, for custom scripts, web workers, webassembly compilations, etc.
- [`dist`](dist)
- [`dist/source`](dist/source)
Contains all bundled code.
- [`dist/source/main`](dist/source/main) Bundled *main* entrypoint.
- [`dist/source/renderer`](dist/source/renderer) Bundled *renderer* entrypoint.
- [`dist/source/preload`](dist/source/preload) Bundled *preload* entrypoint.
- [`dist/source/*`](dist/source) Bundled any custom files.
- [`dist/app`](dist/app)
Contain packages and ready-to-distribute electron apps for any platform. Files in this directory created using [electron-builder].
- [`config`](config)
Contains various configuration files for Vite, TypeScript, electron builder, etc.
- [`bin`](bin)
It is believed any scripts for build the application will be located here.
- [`types`](types)
Contains all declaration files to be applied globally to the entire project
- [`tests`](tests)
Contains all tests
Ignore error messages about deleting temp files on Windows.
`dist` folder now contains predrendered pages. It renders pages automatically from Routify config. To serve, just run
```
npx spassr
```
### Development Setup
This project was tested on Node 14.
1. Fork this repository
1. Run `npm install` to install all dependencies
1. Build compile app for production — `npm run compile`
1. Run development environment with file watching — `npm run watch`
1. Run tests — `npm test`
Your web app is now served at port 5000 on localhost.
Upload `dist` to any web server or JAMstack service like Netlify, Vercel or Cloudflare and you're good to go.
## VS Code IntelliSense.
Install the official WindiCSS VS Code plugin for better experience.
[vite]: https://vitejs.dev/
[electron]: https://electronjs.org/
[electron-builder]: https://www.electron.build/
[vue]: https://v3.vuejs.org/
[vue-router]: https://github.com/vuejs/vue-router-next/
[typescript]: https://www.typescriptlang.org/
[spectron]: https://www.electronjs.org/spectron/
[@vuedx/typecheck]: https://github.com/znck/vue-developer-experience/tree/master/packages/typecheck
[eslint-plugin-vue]: https://github.com/vuejs/eslint-plugin-vue
[cawa-93-github]: https://github.com/cawa-93/
[cawa-93-sponsor]: https://www.patreon.com/Kozack/
[WindiCSS Extension](https://marketplace.visualstudio.com/items?itemName=voorjaar.windicss-intellisense)
## WORK IN PROGRESS
Please mind this is an **experimental** template, based on pre-production versions of ViteJS and WindiCSS. It was born out of frustration with slow development experience of other bundlers and compilers, but as technology changes, I might change my focus away from any of used packages.

View File

@ -1,8 +0,0 @@
module.exports = {
env: {
node: true,
},
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
};

View File

@ -1,75 +0,0 @@
#!/usr/bin/node
console.time('Bundling time');
const {build} = require('vite');
const {join} = require('path');
/** @type 'production' | 'development' | 'test' */
const mode = process.env.MODE || 'production';
const configs = [
join(process.cwd(), 'config/main.vite.js'),
join(process.cwd(), 'config/preload.vite.js'),
join(process.cwd(), 'config/renderer.vite.js'),
];
/**
* Run `vite build` for config file
* @param {string} configFile
* @return {Promise<RollupOutput | RollupOutput[]>}
*/
const buildByConfig = (configFile) => build({configFile, mode});
/**
* Creates a separate package.json in which:
* - The version number is set based on the current date in the format yy.mm.dd
* - Removed all dependencies except those marked as "external".
* @see /config/external-packages.js
*
* @return {Promise<void>}
*/
const generatePackageJson = () => {
// Get project package.json
const packageJson = require(join(process.cwd(), 'package.json'));
// Cleanup
delete packageJson.scripts;
{
// Remove all bundled dependencies
// Keep only `external` dependencies
delete packageJson.devDependencies;
const {default: external} = require('../config/external-packages');
for (const type of ['dependencies', 'optionalDependencies']) {
if (packageJson[type] === undefined) {
continue;
}
for (const key of Object.keys(packageJson[type])) {
if (!external.includes(key)) {
delete packageJson[type][key];
}
}
}
}
{
// Set version based on current date in yy.mm.dd format
// The year is calculated on the principle of a `getFullYear() - 2000`, so that in 2120 the version was `120` and not `20` 😅
const now = new Date;
packageJson.version = `${now.getFullYear() - 2000}.${now.getMonth() + 1}.${now.getDate()}`;
}
// Create new package.json
const {writeFile} = require('fs/promises');
return writeFile(join(process.cwd(), 'dist/source/package.json'), JSON.stringify(packageJson));
};
Promise.all(configs.map(buildByConfig))
.then(generatePackageJson)
.then(() => console.timeEnd('Bundling time'))
.catch(e => {
console.error(e);
process.exit(1);
});

View File

@ -1,36 +0,0 @@
#!/usr/bin/env node
const {resolveConfig} = require('vite');
const {writeFileSync, mkdirSync, existsSync} = require('fs');
const {resolve, dirname} = require('path');
/**
* @param {string[]} modes
* @param {string} filePath
*/
async function buildMode(modes, filePath) {
const interfaces = await Promise.all(modes.map(async mode => {
const modeInterfaceName = `${mode}Env`;
const {env} = await resolveConfig({mode, configFile: resolve(process.cwd(), 'config/main.vite.js')}, 'build');
const interfaceDeclaration = `interface ${modeInterfaceName} ${JSON.stringify(env)}`;
return {modeInterfaceName, interfaceDeclaration};
}));
const interfacesDeclarations = interfaces.map(({interfaceDeclaration}) => interfaceDeclaration).join('\n');
const type = interfaces.map(({modeInterfaceName}) => modeInterfaceName).join(' | ');
const dir = dirname(filePath);
if (!existsSync(dir)) {
mkdirSync(dir);
}
writeFileSync(filePath, `${interfacesDeclarations}\ntype ImportMetaEnv = ${type}\n`, {encoding: 'utf-8', flag: 'w'});
}
buildMode(['production', 'development', 'test'], resolve(process.cwd(), './types/env.d.ts'))
.catch(err => {
console.error(err);
process.exit(1);
});

View File

@ -1,88 +0,0 @@
/**
* Temporally
* @deprecated
* @see https://github.com/electron/electron/issues/28006
*/
/**
* @typedef Vendors
* @type {{
* node: string,
* v8: string,
* uv: string,
* zlib: string,
* brotli: string,
* ares: string,
* modules: string,
* nghttp2: string,
* napi: string,
* llhttp: string,
* http_parser: string,
* openssl: string,
* cldr: string,
* icu: string,
* tz: string,
* unicode: string,
* electron: string,
* }}
*/
/**
*
* @type {null | Vendors}
*/
let runtimeCache = null;
/**
* Returns information about dependencies of the specified version of the electron
* @return {Vendors}
*
* @see https://electronjs.org/headers/index.json
*/
const loadDeps = () => {
const stringifiedDeps = require('child_process').execSync(
'electron -p JSON.stringify(process.versions)',
{
encoding: 'utf-8',
env: {
ELECTRON_RUN_AS_NODE: '1',
},
},
);
return JSON.parse(stringifiedDeps);
};
const saveToCache = (dist) => {
runtimeCache = dist;
};
/**
*
* @return {null|Vendors}
*/
const loadFromCache = () => runtimeCache;
/**
*
* @return {Vendors}
*/
const getElectronDist = () => {
let dist = loadFromCache();
if (dist) {
return dist;
}
dist = loadDeps();
saveToCache(dist);
return dist;
};
const {node, modules} = getElectronDist();
module.exports.node = node;
module.exports.chrome = modules;//.split('.')[0];

View File

@ -1,142 +0,0 @@
#!/usr/bin/node
// TODO:
// - Disable dependency optimization during development.
// - Need more tests
// - Refactoring
const slash = require('slash');
const chokidar = require('chokidar');
const {createServer, build, normalizePath} = require('vite');
const electronPath = require('electron');
const {spawn} = require('child_process');
const {join, relative} = require('path');
const mode = process.env.MODE || 'development';
const TIMEOUT = 500;
function debounce(f, ms) {
let isCoolDown = false;
return function () {
if (isCoolDown) return;
f.apply(this, arguments);
isCoolDown = true;
setTimeout(() => isCoolDown = false, ms);
};
}
(async () => {
// Create Vite dev server
const viteDevServer = await createServer({
mode,
configFile: join(process.cwd(), 'config/renderer.vite.js'),
});
await viteDevServer.listen();
// Determining the current URL of the server. It depend on /config/renderer.vite.js
// Write a value to an environment variable to pass it to the main process.
{
const protocol = `http${viteDevServer.config.server.https ? 's' : ''}:`;
const host = viteDevServer.config.server.host || 'localhost';
const port = viteDevServer.config.server.port; // Vite searches for and occupies the first free port: 3000, 3001, 3002 and so on
const path = '/';
process.env.VITE_DEV_SERVER_URL = `${protocol}//${host}:${port}${path}`;
}
/** @type {ChildProcessWithoutNullStreams | null} */
let spawnProcess = null;
const runMain = debounce(() => {
if (spawnProcess !== null) {
spawnProcess.kill('SIGINT');
spawnProcess = null;
}
spawnProcess = spawn(electronPath, [join(process.cwd(), 'dist/source/main/index.cjs.js')]);
spawnProcess.stdout.on('data', d => console.log(d.toString()));
spawnProcess.stderr.on('data', d => console.error(d.toString()));
return spawnProcess;
}, TIMEOUT);
const buildMain = () => {
return build({mode, configFile: join(process.cwd(), 'config/main.vite.js')});
};
const buildMainDebounced = debounce(buildMain, TIMEOUT);
const runPreload = debounce((file) => {
viteDevServer.ws.send({
type: 'full-reload',
path: '/' + slash(relative(viteDevServer.config.root, file)),
});
}, TIMEOUT);
const buildPreload = () => {
return build({mode, configFile: join(process.cwd(), 'config/preload.vite.js')});
};
const buildPreloadDebounced = debounce(buildPreload, TIMEOUT);
await Promise.all([
buildMain(),
buildPreload(),
]);
const watcher = chokidar.watch([
join(process.cwd(), 'src/main/**'),
join(process.cwd(), 'src/preload/**'),
join(process.cwd(), 'dist/source/main/**'),
join(process.cwd(), 'dist/source/preload/**'),
], {ignoreInitial: true});
watcher
.on('unlink', path => {
const normalizedPath = normalizePath(path);
if (spawnProcess !== null && normalizedPath.includes('/dist/source/main/')) {
spawnProcess.kill('SIGINT');
spawnProcess = null;
}
})
.on('add', path => {
const normalizedPath = normalizePath(path);
if (normalizedPath.includes('/dist/source/main/')) {
return runMain();
}
if (spawnProcess !== undefined && normalizedPath.includes('/dist/source/preload/')) {
return runPreload(normalizedPath);
}
})
.on('change', (path) => {
const normalizedPath = normalizePath(path);
if (normalizedPath.includes('/src/main/')) {
return buildMainDebounced();
}
if (normalizedPath.includes('/dist/source/main/')) {
return runMain();
}
if (normalizedPath.includes('/src/preload/')) {
return buildPreloadDebounced();
}
if (normalizedPath.includes('/dist/source/preload/')) {
return runPreload(normalizedPath);
}
});
await runMain();
})();

25
br.js Normal file
View File

@ -0,0 +1,25 @@
const glob = require('glob');
const fs = require('fs');
const compress = require('brotli/compress');
const skipSizeUnderBytes = 10000;
const dir = './dist/**';
const brotliSettings = {
extension: 'br',
skipLarger: true,
mode: 1, // 0 = generic, 1 = text, 2 = font (WOFF2)
quality: 10, // 0 - 11,
lgwin: 12 // default
};
glob(dir, function(er, files) {
files.forEach((file) => {
if (file.endsWith('.js') || file.endsWith('.css') || file.endsWith('.html')) {
const stat = fs.statSync(file).size;
if (stat > skipSizeUnderBytes) {
const result = compress(fs.readFileSync(file), brotliSettings);
fs.writeFileSync(file + '.br', result);
}
}
});
});

View File

@ -1,8 +0,0 @@
module.exports = {
env: {
node: true,
},
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
};

View File

@ -1,11 +0,0 @@
/**
* @type {import('electron-builder').Configuration}
* @see https://www.electron.build/configuration/configuration
*/
module.exports = {
directories: {
output: 'dist/app',
buildResources: 'build',
app: 'dist/source',
},
};

View File

@ -1,4 +0,0 @@
module.exports = {
chrome: 85,
node: 12,
};

View File

@ -1,59 +0,0 @@
/**
By default, vite optimizes and packs all the necessary dependencies into your bundle,
so there is no need to supply them in your application as a node module.
Unfortunately, vite cannot optimize any dependencies:
Some that are designed for a node environment may not work correctly after optimization.
Therefore, such dependencies should be marked as "external":
they will not be optimized, will not be included in your bundle, and will be delivered as a separate node module.
*/
module.exports.external = [
'electron',
'electron-updater',
];
module.exports.builtins = [
'assert',
'async_hooks',
'buffer',
'child_process',
'cluster',
'console',
'constants',
'crypto',
'dgram',
'dns',
'domain',
'events',
'fs',
'http',
'http2',
'https',
'inspector',
'module',
'net',
'os',
'path',
'perf_hooks',
'process',
'punycode',
'querystring',
'readline',
'repl',
'stream',
'string_decoder',
'timers',
'tls',
'trace_events',
'tty',
'url',
'util',
'v8',
'vm',
'zlib',
];
module.exports.default = [
...module.exports.builtins,
...module.exports.external,
];

View File

@ -1,37 +0,0 @@
const {node} = require('./electron-vendors');
const {join} = require('path');
/**
* @type {import('vite').UserConfig}
* @see https://vitejs.dev/config/
*/
module.exports = () => {
return {
resolve: {
alias: {
'/@/': join(process.cwd(), './src/main') + '/',
},
},
build: {
sourcemap: 'inline',
target: `node${node}`,
outDir: 'dist/source/main',
assetsDir: '.',
minify: process.env.MODE === 'development' ? false : 'terser',
lib: {
entry: 'src/main/index.ts',
formats: ['cjs'],
},
rollupOptions: {
external: require('./external-packages').default,
output: {
entryFileNames: '[name].[format].js',
chunkFileNames: '[name].[format].js',
assetFileNames: '[name].[ext]',
},
},
emptyOutDir: true,
},
};
};

View File

@ -1,34 +0,0 @@
const {chrome} = require('./electron-vendors');
const {join} = require('path');
/**
* @type {import('vite').UserConfig}
* @see https://vitejs.dev/config/
*/
module.exports = {
resolve: {
alias: {
'/@/': join(process.cwd(), './src/preload') + '/',
},
},
build: {
sourcemap: 'inline',
target: `chrome${chrome}`,
outDir: 'dist/source/preload',
assetsDir: '.',
minify: process.env.MODE === 'development' ? false : 'terser',
lib: {
entry: 'src/preload/index.ts',
formats: ['cjs'],
},
rollupOptions: {
external: require('./external-packages').default,
output: {
entryFileNames: '[name].[format].js',
chunkFileNames: '[name].[format].js',
assetFileNames: '[name].[ext]',
},
},
emptyOutDir: true,
},
};

View File

@ -1,29 +0,0 @@
const {join} = require('path');
const vue = require('@vitejs/plugin-vue');
const {chrome} = require('./electron-vendors');
/**
* @type {import('vite').UserConfig}
* @see https://vitejs.dev/config/
*/
module.exports = {
root: join(process.cwd(), './src/renderer'),
resolve: {
alias: {
'/@/': join(process.cwd(), './src/renderer') + '/',
},
},
plugins: [vue()],
base: '',
build: {
sourcemap: 'inline',
target: `chrome${chrome}`,
polyfillDynamicImport: false,
outDir: join(process.cwd(), 'dist/source/renderer'),
assetsDir: '.',
rollupOptions: {
external: require('./external-packages').default,
},
emptyOutDir: true,
},
};

View File

@ -1,18 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"sourceMap": true,
"moduleResolution": "Node",
"skipLibCheck": true,
"strict": true,
"isolatedModules": true,
"types": [
"../types/env",
"vite/client"
]
},
"exclude": [
"../**/node_modules"
]
}

View File

@ -1,59 +0,0 @@
# Contributing
First and foremost, thank you! We appreciate that you want to contribute to vite-electron-builder, your time is valuable, and your contributions mean a lot to us.
## Important!
By contributing to this project, you:
* Agree that you have authored 100% of the content
* Agree that you have the necessary rights to the content
* Agree that you have received the necessary permissions from your employer to make the contributions (if applicable)
* Agree that the content you contribute may be provided under the Project license(s)
* Agree that, if you did not author 100% of the content, the appropriate licenses and copyrights have been added along with any other necessary attribution.
## Getting started
### Issues
Do not create issues about bumping dependencies unless a bug has been identified and you can demonstrate that it effects this library.
**Help us to help you**
Remember that were here to help, but not to make guesses about what you need help with:
- Whatever bug or issue you're experiencing, assume that it will not be as obvious to the maintainers as it is to you.
- Spell it out completely. Keep in mind that maintainers need to think about _all potential use cases_ of a library. It's important that you explain how you're using a library so that maintainers can make that connection and solve the issue.
_It can't be understated how frustrating and draining it can be to maintainers to have to ask clarifying questions on the most basic things, before it's even possible to start debugging. Please try to make the best use of everyone's time involved, including yourself, by providing this information up front._
### Before creating an issue
Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues.
Try to follow these guidelines:
- **Investigate the issue** - Search for exising issues (open or closed) that address the issue, and might have even resolved it already.
- **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue.
- Create the issue in the appropriate repository.
### Creating an issue
Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue:
- **description**: (required) What is the bug you're experiencing? How are you using this library/app?
- **OS**: (required) what operating system are you on?
- **version**: (required) please note the version of vite-electron-builder are you using
- **error messages**: (required) please paste any error messages into the issue, or a [gist](https://gist.github.com/)
- **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using
### Closing issues
The original poster or the maintainers of vite-electron-builder may close an issue at any time. Typically, but not exclusively, issues are closed when:
- The issue is resolved
- The project's maintainers have determined the issue is out of scope
- An issue is clearly a duplicate of another issue, in which case the duplicate issue will be linked.
- A discussion has clearly run its course

15
index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LfK!Scan</title>
<link rel="icon" type="image/png" href="/favicon.png" />
</head>
<body class="bg-white font-family-karla h-screen">
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@ -1,50 +1,24 @@
{
"name": "vite-electron-builder",
"private": true,
"engines": {
"node": ">=v14.15.0",
"npm": ">=7.6.1"
},
"main": "main/index.cjs.js",
"name": "@lfk/scanclient",
"version": "0.0.0",
"scripts": {
"buildEnvTypes": "node ./bin/buildEnvTypes.js",
"prebuild": "npm run buildEnvTypes",
"build": "node ./bin/build.js",
"precompile": "cross-env MODE=production npm run build",
"compile": "electron-builder build --config ./config/electron-builder.js",
"pretest": "cross-env MODE=test npm run build",
"test": "node ./tests/app.spec.js",
"prewatch": "npm run buildEnvTypes",
"watch": "node ./bin/watch.js",
"lint": "eslint . --ext js,ts,vue",
"pretypecheck": "npm run buildEnvTypes",
"typecheck-main": "tsc --noEmit -p ./src/main/tsconfig.json",
"typecheck-preload": "tsc --noEmit -p ./src/preload/tsconfig.json",
"typecheck-renderer": "vuedx-typecheck ./src/renderer --no-pretty",
"typecheck": "npm run typecheck-main && npm run typecheck-preload && npm run typecheck-renderer"
"dev": "vite ",
"build": "vite build",
"build:br": "vite build && npm run brotli:dist",
"serve-vite": "vite preview",
"brotli:dist": "node br.js"
},
"devDependencies": {
"@types/electron-devtools-installer": "^2.2.0",
"@typescript-eslint/eslint-plugin": "^4.16.1",
"@typescript-eslint/parser": "^4.16.1",
"@vitejs/plugin-vue": "^1.1.5",
"@vue/compiler-sfc": "^3.0.7",
"@vuedx/typecheck": "^0.6.3",
"chokidar": "^3.5.1",
"cross-env": "^7.0.3",
"electron": "^11.3.0",
"electron-builder": "^22.10.5",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.21.0",
"eslint-plugin-vue": "^7.7.0",
"slash": "^3.0.0",
"spectron": "^13.0.0",
"typescript": "^4.2.3",
"vite": "^2.0.5"
},
"dependencies": {
"electron-updater": "^4.3.8",
"vue": "^3.0.7",
"vue-router": "^4.0.4"
"@svitejs/vite-plugin-svelte": "^0.11.0",
"@tsconfig/svelte": "^1.0.10",
"@types/html-minifier": "^4.0.0",
"axios": "^0.21.1",
"brotli": "^1.3.2",
"glob": "^7.1.6",
"html-minifier": "^4.0.0",
"svelte": "^3.35.0",
"svelte-preprocess": "^4.6.9",
"vite": "^2.0.5",
"vite-plugin-windicss": "^0.8.2"
}
}

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

63
src/App.svelte Normal file
View File

@ -0,0 +1,63 @@
<div class="w-full flex flex-wrap">
<!-- Login Section -->
<div class="w-full md:w-1/2 flex flex-col">
<div class="flex justify-center md:justify-start pt-12 md:pl-12 md:-mb-24">
<div class="bg-black text-white font-bold text-xl p-4"><img src="./favicon.png" alt=""
style="height: 3rem;display: inline;"> LfK!Scan</div>
</div>
<div class="flex flex-col justify-center md:justify-start my-auto pt-8 md:pt-0 px-8 md:px-24 lg:px-32">
<p class="text-center text-3xl">Configuration</p>
<p class="text-center">Please provide the scan client token.<br><a target="_blank" class="underline"
href="https://docs.lauf-fuer-kaya.de/">See our configuration guide.</a></p>
<form class="flex flex-col pt-3 md:pt-8" onsubmit="event.preventDefault();">
<div class="flex flex-col pt-4">
<label for="token" class="text-lg">Client Token</label>
<input type="text" id="token" onchange="tokenchanged()" placeholder="Client Token"
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline">
</div>
<input id="configure" type="submit" value="Configure"
class="bg-black text-white font-bold text-lg hover:bg-gray-700 p-2 mt-8 cursor-pointer">
</form>
<div class="text-center pt-12 pb-12">
<p><svg style="height: 1rem;display: inline;" xmlns="http://www.w3.org/2000/svg" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-zap" viewBox="0 0 24 24">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" />
</svg><span>powered by <a href="https://odit.services" target="_blank"
class="underline">ODIT.Services</a>.</span></p>
</div>
</div>
<div class="w-full p-3">
<div class="inline-block mr-2 mt-2">
<button type="button"
class="bg-black focus:outline-none text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700">Deutsch
<svg class="h-4 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M15.923 345.043C52.094 442.527 145.929 512 256 512s203.906-69.473 240.077-166.957L256 322.783l-240.077 22.26z" fill="#ffda44"/><path d="M256 0C145.929 0 52.094 69.472 15.923 166.957L256 189.217l240.077-22.261C459.906 69.472 366.071 0 256 0z"/><path d="M15.923 166.957C5.633 194.69 0 224.686 0 256s5.633 61.31 15.923 89.043h480.155C506.368 317.31 512 287.314 512 256s-5.632-61.31-15.923-89.043H15.923z" fill="#d80027"/></svg></button>
</div>
<div class="inline-block mr-2 mt-2">
<button type="button"
class="bg-black focus:outline-none text-white text-sm py-2.5 px-5 rounded-md hover:bg-blue-700 bg-blue-700">English
<svg class="h-4 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<circle cx="256" cy="256" r="256" fill="#f0f0f0"></circle>
<g fill="#d80027">
<path
d="M244.87 256H512c0-23.106-3.08-45.49-8.819-66.783H244.87V256zM244.87 122.435h229.556a257.35 257.35 0 00-59.07-66.783H244.87v66.783zM256 512c60.249 0 115.626-20.824 159.356-55.652H96.644C140.374 491.176 195.751 512 256 512zM37.574 389.565h436.852a254.474 254.474 0 0028.755-66.783H8.819a254.474 254.474 0 0028.755 66.783z">
</path>
</g>
<path
d="M118.584 39.978h23.329l-21.7 15.765 8.289 25.509-21.699-15.765-21.699 15.765 7.16-22.037a257.407 257.407 0 00-49.652 55.337h7.475l-13.813 10.035a255.58 255.58 0 00-6.194 10.938l6.596 20.301-12.306-8.941a253.567 253.567 0 00-8.372 19.873l7.267 22.368h26.822l-21.7 15.765 8.289 25.509-21.699-15.765-12.998 9.444A258.468 258.468 0 000 256h256V0c-50.572 0-97.715 14.67-137.416 39.978zm9.918 190.422l-21.699-15.765L85.104 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zM220.328 230.4l-21.699-15.765L176.93 230.4l8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765 8.289 25.509zm-8.289-100.083l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765zm0-74.574l8.289 25.509-21.699-15.765-21.699 15.765 8.289-25.509-21.7-15.765h26.822l8.288-25.509 8.288 25.509h26.822l-21.7 15.765z"
fill="#0052b4"></path>
</svg></button>
</div>
</div>
</div>
<!-- Image Section -->
<div class="w-1/2 shadow-2xl">
<img alt="" class="object-cover w-full h-screen hidden md:block" src="https://source.unsplash.com/IXUM4cJynP0">
</div>
</div>

8
src/main.js Normal file
View File

@ -0,0 +1,8 @@
import App from '@/App.svelte';
import 'windi.css';
const app = new App({
target: document.body
});
export default app;

View File

@ -1,91 +0,0 @@
import {app, BrowserWindow} from 'electron';
import {join} from 'path';
import {URL} from 'url';
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();
} else {
/**
* Workaround for TypeScript bug
* @see https://github.com/microsoft/TypeScript/issues/41468#issuecomment-727543400
*/
const env = import.meta.env;
// Install "Vue.js devtools BETA"
if (env.MODE === 'development') {
app.whenReady()
.then(() => import('electron-devtools-installer'))
.then(({default: installExtension}) => {
/** @see https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg */
const VUE_DEVTOOLS_BETA = 'ljjemllljcmogpfapbkkighbhhppjdbg';
return installExtension(VUE_DEVTOOLS_BETA);
})
.catch(e => console.error('Failed install extension:', e));
}
let mainWindow: BrowserWindow | null = null;
async function createWindow() {
mainWindow = new BrowserWindow({
show: false,
webPreferences: {
preload: join(__dirname, '../preload/index.cjs.js'),
contextIsolation: env.MODE !== 'test', // Spectron tests can't work with contextIsolation: true
enableRemoteModule: env.MODE === 'test', // Spectron tests can't work with enableRemoteModule: false
},
});
/**
* URL for main window.
* Vite dev server for development.
* `file://../renderer/index.html` for production and test
*/
const pageUrl = env.MODE === 'development'
? env.VITE_DEV_SERVER_URL
: new URL('renderer/index.html', 'file://' + __dirname).toString();
await mainWindow.loadURL(pageUrl);
mainWindow.maximize();
mainWindow.show();
if (env.MODE === 'development') {
mainWindow.webContents.openDevTools();
}
}
app.on('second-instance', () => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.whenReady()
.then(createWindow)
.catch((e) => console.error('Failed create window:', e));
// Auto-updates
if (env.PROD) {
app.whenReady()
.then(() => import('electron-updater'))
.then(({autoUpdater}) => autoUpdater.checkForUpdatesAndNotify())
.catch((e) => console.error('Failed check updates:', e));
}
}

View File

@ -1,19 +0,0 @@
{
"extends": "../../config/tsconfig-base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"/@/*": [
"./*"
]
},
"types": [
"../../types/env",
"vite/client",
"electron-devtools-installer"
]
},
"files": [
"./index.ts"
]
}

View File

@ -1,55 +0,0 @@
import {ContextBridge, contextBridge} from 'electron';
const apiKey = 'electron';
/**
* @see https://github.com/electron/electron/issues/21437#issuecomment-573522360
*/
const api = {
versions: process.versions,
} as const;
export type ExposedInMainWorld = Readonly<typeof api>;
if (import.meta.env.MODE !== 'test') {
/**
* The "Main World" is the JavaScript context that your main renderer code runs in.
* By default, the page you load in your renderer executes code in this world.
*
* @see https://www.electronjs.org/docs/api/context-bridge
*/
contextBridge.exposeInMainWorld(apiKey, api);
} else {
type API = Parameters<ContextBridge['exposeInMainWorld']>[1]
/**
* Recursively Object.freeze() on objects and functions
* @see https://github.com/substack/deep-freeze
* @param obj Object on which to lock the attributes
*/
function deepFreeze<T extends API>(obj: T): Readonly<T> {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (obj.hasOwnProperty(prop)
&& obj[prop] !== null
&& (typeof obj[prop] === 'object' || typeof obj[prop] === 'function')
&& !Object.isFrozen(obj[prop])) {
deepFreeze(obj[prop]);
}
});
return obj;
}
deepFreeze(api);
// eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-var-requires
(window as any).electronRequire = require;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any)[apiKey] = api;
}

View File

@ -1,28 +0,0 @@
{
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"sourceMap": true,
"moduleResolution": "Node",
"skipLibCheck": true,
"strict": true,
"isolatedModules": true,
"baseUrl": ".",
"paths": {
"/@/*": [
"./*"
]
},
"types": [
"../../types/env",
"vite/client",
]
},
"files": [
"./index.ts"
],
"exclude": [
"**/node_modules",
"**/.*"
]
}

View File

@ -1,15 +0,0 @@
module.exports = {
env: {
browser: true,
node: false,
},
extends: [
/** @see https://eslint.vuejs.org/rules/ */
'plugin:vue/vue3-recommended',
],
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 12,
sourceType: 'module',
},
};

View File

@ -1,31 +0,0 @@
<template>
<img
alt="Vue logo"
src="./assets/logo.png"
>
<app-navigation />
<router-view />
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import AppNavigation from '/@/components/AppNavigation.vue';
export default defineComponent({
name: 'App',
components: {
AppNavigation,
},
});
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,37 +0,0 @@
<template>
<h2 id="versions">
Lib versions
</h2>
<div>
<ul aria-labelledby="versions">
<li
v-for="(version, lib) in versions"
:key="lib"
>
<strong>{{ lib }}</strong>: v{{ version }}
</li>
</ul>
</div>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import {useElectron} from '/@/use/electron';
export default defineComponent({
name: 'App',
setup() {
const {versions} = useElectron();
// It makes no sense to make "versions" reactive
return {versions};
},
});
</script>
<style scoped>
div {
text-align: left;
display: grid;
justify-content: center;
}
</style>

View File

@ -1,27 +0,0 @@
<template>
<nav>
<router-link to="/">
Home
</router-link>
<span> | </span>
<router-link to="/about">
About
</router-link>
</nav>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
export default defineComponent({
name: 'AppNavigation',
});
</script>
<style scoped>
nav {
display: flex;
gap: 1em;
justify-content: center;
}
</style>

View File

@ -1,51 +0,0 @@
<template>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a
href="https://github.com/cawa-93/vite-electron-builder"
rel="noopener"
target="_blank"
>vite-electron-builder documentation</a>.
</p>
<p>
<a
href="https://vitejs.dev/guide/features.html"
target="_blank"
>Vite Documentation</a> |
<a
href="https://v3.vuejs.org/"
target="_blank"
>Vue 3 Documentation</a>
</p>
<hr>
<button @click="count++">
count is: {{ count }}
</button>
<p>
Edit
<code>renderer/components/Home.vue</code> to test hot module replacement.
</p>
</template>
<script lang="ts">
import {defineComponent, ref} from 'vue';
export default defineComponent({
name: 'HelloWorld',
setup() {
const count = ref(0);
return {count};
},
});
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
a {
color: #42b983;
}
</style>

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' blob:">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script src="./index.ts" type="module"></script>
</body>
</html>

View File

@ -1,7 +0,0 @@
import {createApp} from 'vue';
import App from './App.vue';
import router from '/@/router';
createApp(App)
.use(router)
.mount('#app');

View File

@ -1,12 +0,0 @@
import {createRouter, createWebHashHistory} from 'vue-router';
import Home from '/@/components/Home.vue';
const routes = [
{path: '/', name: 'Home', component: Home},
{path: '/about', name: 'About', component: () => import('/@/components/About.vue')}, // Lazy load route component
];
export default createRouter({
routes,
history: createWebHashHistory(),
});

View File

@ -1,19 +0,0 @@
{
"extends": "../../config/tsconfig-base.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"/@/*": [
"./*"
]
},
"types": [
"../../types/env",
"vite/client",
"./types/shims-vue"
]
},
"files": [
"./index.ts"
]
}

View File

@ -1,5 +0,0 @@
declare module '*.vue' {
import type {DefineComponent} from 'vue';
const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, never>;
export default component;
}

View File

@ -1,6 +0,0 @@
import type {ExposedInMainWorld} from '../../preload';
export function useElectron(): ExposedInMainWorld {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (window as any).electron as ExposedInMainWorld;
}

13
tailwind.config.js Normal file
View File

@ -0,0 +1,13 @@
module.exports = {
theme: {
extend: {
colors: {
reepolee: {
500: "#b40000",
600: "#9c0000",
700: "#750000",
},
},
},
},
};

View File

@ -1,8 +0,0 @@
module.exports = {
env: {
node: true,
},
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
};

View File

@ -1,43 +0,0 @@
const {Application} = require('spectron');
const {strict: assert} = require('assert');
const {join} = require('path');
const app = new Application({
path: require('electron'),
requireName: 'electronRequire',
args: [join(__dirname, '../dist/source')],
});
app.start()
.then(async () => {
const isVisible = await app.browserWindow.isVisible();
assert.ok(isVisible, 'Main window not visible');
})
.then(async () => {
const isDevtoolsOpen = await app.webContents.isDevToolsOpened();
assert.ok(!isDevtoolsOpen, 'DevTools opened');
})
.then(async function () {
// Get the window content
const content = await app.client.$('#app');
assert.notStrictEqual(await content.getHTML(), '<div id="app"></div>', 'Window content is empty');
})
.then(function () {
if (app && app.isRunning()) {
return app.stop();
}
})
.then(() => process.exit(0))
.catch(function (error) {
console.error(error);
if (app && app.isRunning()) {
app.stop();
}
process.exit(1);
});

View File

@ -1,16 +0,0 @@
#!/usr/bin/node
const assert = require ('assert');
const {format} = require ('url');
const {join} = require ('path');
const expected = format({
protocol: 'file',
pathname: join(__dirname, '../renderer/index.html'),
slashes: true,
});
const actual = new URL('renderer/index.html', 'file://' + __dirname);
assert.strictEqual(actual.toString(), expected);

View File

@ -1,25 +0,0 @@
/** @type {import('vls').VeturConfig} */
module.exports = {
settings: {
'vetur.useWorkspaceDependencies': true,
'vetur.experimental.templateInterpolationService': true,
},
projects: [
{
root: './src/renderer',
tsconfig: './tsconfig.json',
snippetFolder: './.vscode/vetur/snippets',
globalComponents: [
'./components/**/*.vue',
],
},
{
root: './src/main',
tsconfig: './tsconfig.json',
},
{
root: './src/preload',
tsconfig: './tsconfig.json',
},
],
};

62
vite.config.ts Normal file
View File

@ -0,0 +1,62 @@
import { resolve } from 'path';
import svelte from '@svitejs/vite-plugin-svelte';
import windiCSS from 'vite-plugin-windicss';
import { minify } from 'html-minifier';
// const { defineConfig } = require("vite");
import { defineConfig } from 'vite';
const indexReplace = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return minify(html, {
collapseWhitespace: true
});
}
};
};
export default defineConfig(({ command, mode }) => {
const isProduction = mode === 'production';
return {
build: {
polyfillDynamicImport: false,
cssCodeSplit: false,
minify: isProduction
},
optimizeDeps: {
exclude: [ '@roxi/routify' ]
},
resolve: {
dedupe: [ '@roxi/routify' ],
alias: {
svelte: resolve(__dirname, 'node_modules/svelte'),
'@': resolve(__dirname, './src')
}
},
plugins: [
windiCSS({
//@ts-ignore
verbose: true,
silent: false,
debug: true,
config: 'tailwind.config.js', // tailwind config file path (optional)
compile: false, // false: interpretation mode; true: compilation mode
prefix: 'windi-', // set compilation mode style prefix
globalPreflight: true, // set preflight style is global or scoped
globalUtility: true // set utility style is global or scoped
}),
svelte({
//@ts-ignore
hot: !isProduction,
emitCss: true,
extensions: [ '.md', '.svx', '.svelte' ],
preprocess: [
//
]
}),
indexReplace()
]
};
});

4279
yarn.lock

File diff suppressed because it is too large Load Diff